• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ProgramVk.cpp:
7 //    Implements the class methods for ProgramVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/ProgramVk.h"
11 
12 #include "common/debug.h"
13 #include "common/utilities.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/ProgramLinkedResources.h"
16 #include "libANGLE/renderer/glslang_wrapper_utils.h"
17 #include "libANGLE/renderer/renderer_utils.h"
18 #include "libANGLE/renderer/vulkan/BufferVk.h"
19 #include "libANGLE/renderer/vulkan/GlslangWrapperVk.h"
20 #include "libANGLE/renderer/vulkan/TextureVk.h"
21 
22 namespace rx
23 {
24 
25 namespace
26 {
27 // This size is picked according to the required maxUniformBufferRange in the Vulkan spec.
28 constexpr size_t kUniformBlockDynamicBufferMinSize = 16384u;
29 
30 // Identical to Std140 encoder in all aspects, except it ignores opaque uniform types.
31 class VulkanDefaultBlockEncoder : public sh::Std140BlockEncoder
32 {
33   public:
advanceOffset(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)34     void advanceOffset(GLenum type,
35                        const std::vector<unsigned int> &arraySizes,
36                        bool isRowMajorMatrix,
37                        int arrayStride,
38                        int matrixStride) override
39     {
40         if (gl::IsOpaqueType(type))
41         {
42             return;
43         }
44 
45         sh::Std140BlockEncoder::advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride,
46                                               matrixStride);
47     }
48 };
49 
InitDefaultUniformBlock(const std::vector<sh::ShaderVariable> & uniforms,sh::BlockLayoutMap * blockLayoutMapOut,size_t * blockSizeOut)50 void InitDefaultUniformBlock(const std::vector<sh::ShaderVariable> &uniforms,
51                              sh::BlockLayoutMap *blockLayoutMapOut,
52                              size_t *blockSizeOut)
53 {
54     if (uniforms.empty())
55     {
56         *blockSizeOut = 0;
57         return;
58     }
59 
60     VulkanDefaultBlockEncoder blockEncoder;
61     sh::GetActiveUniformBlockInfo(uniforms, "", &blockEncoder, blockLayoutMapOut);
62 
63     size_t blockSize = blockEncoder.getCurrentOffset();
64 
65     // TODO(jmadill): I think we still need a valid block for the pipeline even if zero sized.
66     if (blockSize == 0)
67     {
68         *blockSizeOut = 0;
69         return;
70     }
71 
72     *blockSizeOut = blockSize;
73     return;
74 }
75 
76 template <typename T>
UpdateDefaultUniformBlock(GLsizei count,uint32_t arrayIndex,int componentCount,const T * v,const sh::BlockMemberInfo & layoutInfo,angle::MemoryBuffer * uniformData)77 void UpdateDefaultUniformBlock(GLsizei count,
78                                uint32_t arrayIndex,
79                                int componentCount,
80                                const T *v,
81                                const sh::BlockMemberInfo &layoutInfo,
82                                angle::MemoryBuffer *uniformData)
83 {
84     const int elementSize = sizeof(T) * componentCount;
85 
86     uint8_t *dst = uniformData->data() + layoutInfo.offset;
87     if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
88     {
89         uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride;
90         uint8_t *writePtr    = dst + arrayOffset;
91         ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size());
92         memcpy(writePtr, v, elementSize * count);
93     }
94     else
95     {
96         // Have to respect the arrayStride between each element of the array.
97         int maxIndex = arrayIndex + count;
98         for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex;
99              writeIndex++, readIndex++)
100         {
101             const int arrayOffset = writeIndex * layoutInfo.arrayStride;
102             uint8_t *writePtr     = dst + arrayOffset;
103             const T *readPtr      = v + (readIndex * componentCount);
104             ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size());
105             memcpy(writePtr, readPtr, elementSize);
106         }
107     }
108 }
109 
110 template <typename T>
ReadFromDefaultUniformBlock(int componentCount,uint32_t arrayIndex,T * dst,const sh::BlockMemberInfo & layoutInfo,const angle::MemoryBuffer * uniformData)111 void ReadFromDefaultUniformBlock(int componentCount,
112                                  uint32_t arrayIndex,
113                                  T *dst,
114                                  const sh::BlockMemberInfo &layoutInfo,
115                                  const angle::MemoryBuffer *uniformData)
116 {
117     ASSERT(layoutInfo.offset != -1);
118 
119     const int elementSize = sizeof(T) * componentCount;
120     const uint8_t *source = uniformData->data() + layoutInfo.offset;
121 
122     if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
123     {
124         const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride;
125         memcpy(dst, readPtr, elementSize);
126     }
127     else
128     {
129         // Have to respect the arrayStride between each element of the array.
130         const int arrayOffset  = arrayIndex * layoutInfo.arrayStride;
131         const uint8_t *readPtr = source + arrayOffset;
132         memcpy(dst, readPtr, elementSize);
133     }
134 }
135 
SyncDefaultUniformBlock(ContextVk * contextVk,vk::DynamicBuffer * dynamicBuffer,const angle::MemoryBuffer & bufferData,uint32_t * outOffset,bool * outBufferModified)136 angle::Result SyncDefaultUniformBlock(ContextVk *contextVk,
137                                       vk::DynamicBuffer *dynamicBuffer,
138                                       const angle::MemoryBuffer &bufferData,
139                                       uint32_t *outOffset,
140                                       bool *outBufferModified)
141 {
142     dynamicBuffer->releaseInFlightBuffers(contextVk);
143 
144     ASSERT(!bufferData.empty());
145     uint8_t *data       = nullptr;
146     VkBuffer *outBuffer = nullptr;
147     VkDeviceSize offset = 0;
148     ANGLE_TRY(dynamicBuffer->allocate(contextVk, bufferData.size(), &data, outBuffer, &offset,
149                                       outBufferModified));
150     *outOffset = static_cast<uint32_t>(offset);
151     memcpy(data, bufferData.data(), bufferData.size());
152     ANGLE_TRY(dynamicBuffer->flush(contextVk));
153     return angle::Result::Continue;
154 }
155 
156 class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
157 {
158   public:
makeEncoder()159     sh::BlockLayoutEncoder *makeEncoder() override { return new sh::Std140BlockEncoder(); }
160 };
161 }  // anonymous namespace
162 
163 // ProgramVk implementation.
ProgramVk(const gl::ProgramState & state)164 ProgramVk::ProgramVk(const gl::ProgramState &state) : ProgramImpl(state)
165 {
166     GlslangWrapperVk::ResetGlslangProgramInterfaceInfo(&mGlslangProgramInterfaceInfo);
167     mExecutable.setProgram(this);
168 }
169 
170 ProgramVk::~ProgramVk() = default;
171 
destroy(const gl::Context * context)172 void ProgramVk::destroy(const gl::Context *context)
173 {
174     ContextVk *contextVk = vk::GetImpl(context);
175     reset(contextVk);
176 }
177 
reset(ContextVk * contextVk)178 void ProgramVk::reset(ContextVk *contextVk)
179 {
180     RendererVk *renderer = contextVk->getRenderer();
181 
182     mShaderInfo.release(contextVk);
183 
184     for (auto &uniformBlock : mDefaultUniformBlocks)
185     {
186         uniformBlock.storage.release(renderer);
187     }
188 
189     GlslangWrapperVk::ResetGlslangProgramInterfaceInfo(&mGlslangProgramInterfaceInfo);
190 
191     mExecutable.reset(contextVk);
192 }
193 
load(const gl::Context * context,gl::BinaryInputStream * stream,gl::InfoLog & infoLog)194 std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
195                                                gl::BinaryInputStream *stream,
196                                                gl::InfoLog &infoLog)
197 {
198     ContextVk *contextVk = vk::GetImpl(context);
199     gl::ShaderMap<size_t> requiredBufferSize;
200     requiredBufferSize.fill(0);
201 
202     reset(contextVk);
203 
204     mShaderInfo.load(stream);
205     mExecutable.load(stream);
206 
207     // Deserializes the uniformLayout data of mDefaultUniformBlocks
208     for (gl::ShaderType shaderType : gl::AllShaderTypes())
209     {
210         const size_t uniformCount = stream->readInt<size_t>();
211         for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
212         {
213             sh::BlockMemberInfo blockInfo;
214             gl::LoadBlockMemberInfo(stream, &blockInfo);
215             mDefaultUniformBlocks[shaderType].uniformLayout.push_back(blockInfo);
216         }
217     }
218 
219     // Deserializes required uniform block memory sizes
220     for (gl::ShaderType shaderType : gl::AllShaderTypes())
221     {
222         requiredBufferSize[shaderType] = stream->readInt<size_t>();
223     }
224 
225     // Initialize and resize the mDefaultUniformBlocks' memory
226     angle::Result status = resizeUniformBlockMemory(contextVk, requiredBufferSize);
227     if (status != angle::Result::Continue)
228     {
229         return std::make_unique<LinkEventDone>(status);
230     }
231 
232     status = mExecutable.createPipelineLayout(context);
233     return std::make_unique<LinkEventDone>(status);
234 }
235 
save(const gl::Context * context,gl::BinaryOutputStream * stream)236 void ProgramVk::save(const gl::Context *context, gl::BinaryOutputStream *stream)
237 {
238     mShaderInfo.save(stream);
239     mExecutable.save(stream);
240 
241     // Serializes the uniformLayout data of mDefaultUniformBlocks
242     for (gl::ShaderType shaderType : gl::AllShaderTypes())
243     {
244         const size_t uniformCount = mDefaultUniformBlocks[shaderType].uniformLayout.size();
245         stream->writeInt<size_t>(uniformCount);
246         for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
247         {
248             sh::BlockMemberInfo &blockInfo =
249                 mDefaultUniformBlocks[shaderType].uniformLayout[uniformIndex];
250             gl::WriteBlockMemberInfo(stream, blockInfo);
251         }
252     }
253 
254     // Serializes required uniform block memory sizes
255     for (gl::ShaderType shaderType : gl::AllShaderTypes())
256     {
257         stream->writeInt(mDefaultUniformBlocks[shaderType].uniformData.size());
258     }
259 }
260 
setBinaryRetrievableHint(bool retrievable)261 void ProgramVk::setBinaryRetrievableHint(bool retrievable)
262 {
263     // Nothing to do here yet.
264 }
265 
setSeparable(bool separable)266 void ProgramVk::setSeparable(bool separable)
267 {
268     // Nothing to do here yet.
269 }
270 
271 // TODO: http://anglebug.com/3570: Move/Copy all of the necessary information into
272 // the ProgramExecutable, so this function can be removed.
fillProgramStateMap(gl::ShaderMap<const gl::ProgramState * > * programStatesOut)273 void ProgramVk::fillProgramStateMap(gl::ShaderMap<const gl::ProgramState *> *programStatesOut)
274 {
275     for (gl::ShaderType shaderType : gl::AllShaderTypes())
276     {
277         (*programStatesOut)[shaderType] = nullptr;
278         if (mState.getExecutable().hasLinkedShaderStage(shaderType))
279         {
280             (*programStatesOut)[shaderType] = &mState;
281         }
282     }
283 }
284 
link(const gl::Context * context,const gl::ProgramLinkedResources & resources,gl::InfoLog & infoLog)285 std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
286                                            const gl::ProgramLinkedResources &resources,
287                                            gl::InfoLog &infoLog)
288 {
289     ContextVk *contextVk = vk::GetImpl(context);
290     // Link resources before calling GetShaderSource to make sure they are ready for the set/binding
291     // assignment done in that function.
292     linkResources(resources);
293 
294     reset(contextVk);
295     mExecutable.clearVariableInfoMap();
296 
297     // Gather variable info and transform sources.
298     gl::ShaderMap<std::string> shaderSources;
299     GlslangWrapperVk::GetShaderSource(contextVk->getRenderer()->getFeatures(), mState, resources,
300                                       &mGlslangProgramInterfaceInfo, &shaderSources,
301                                       &mExecutable.mVariableInfoMap);
302 
303     // Compile the shaders.
304     angle::Result status =
305         mShaderInfo.initShaders(contextVk, mState.getExecutable().getLinkedShaderStages(),
306                                 shaderSources, mExecutable.mVariableInfoMap);
307     if (status != angle::Result::Continue)
308     {
309         return std::make_unique<LinkEventDone>(status);
310     }
311 
312     status = initDefaultUniformBlocks(context);
313     if (status != angle::Result::Continue)
314     {
315         return std::make_unique<LinkEventDone>(status);
316     }
317 
318     // TODO(jie.a.chen@intel.com): Parallelize linking.
319     // http://crbug.com/849576
320     status = mExecutable.createPipelineLayout(context);
321     return std::make_unique<LinkEventDone>(status);
322 }
323 
linkResources(const gl::ProgramLinkedResources & resources)324 void ProgramVk::linkResources(const gl::ProgramLinkedResources &resources)
325 {
326     Std140BlockLayoutEncoderFactory std140EncoderFactory;
327     gl::ProgramLinkedResourcesLinker linker(&std140EncoderFactory);
328 
329     linker.linkResources(mState, resources);
330 }
331 
initDefaultUniformBlocks(const gl::Context * glContext)332 angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
333 {
334     ContextVk *contextVk = vk::GetImpl(glContext);
335 
336     // Process vertex and fragment uniforms into std140 packing.
337     gl::ShaderMap<sh::BlockLayoutMap> layoutMap;
338     gl::ShaderMap<size_t> requiredBufferSize;
339     requiredBufferSize.fill(0);
340 
341     generateUniformLayoutMapping(layoutMap, requiredBufferSize);
342     initDefaultUniformLayoutMapping(layoutMap);
343 
344     // All uniform initializations are complete, now resize the buffers accordingly and return
345     return resizeUniformBlockMemory(contextVk, requiredBufferSize);
346 }
347 
generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> & layoutMap,gl::ShaderMap<size_t> & requiredBufferSize)348 void ProgramVk::generateUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap,
349                                              gl::ShaderMap<size_t> &requiredBufferSize)
350 {
351     const gl::ProgramExecutable &glExecutable = mState.getExecutable();
352 
353     for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
354     {
355         gl::Shader *shader = mState.getAttachedShader(shaderType);
356 
357         if (shader)
358         {
359             const std::vector<sh::ShaderVariable> &uniforms = shader->getUniforms();
360             InitDefaultUniformBlock(uniforms, &layoutMap[shaderType],
361                                     &requiredBufferSize[shaderType]);
362         }
363     }
364 }
365 
initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> & layoutMap)366 void ProgramVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap> &layoutMap)
367 {
368     // Init the default block layout info.
369     const auto &uniforms                      = mState.getUniforms();
370     const gl::ProgramExecutable &glExecutable = mState.getExecutable();
371 
372     for (const gl::VariableLocation &location : mState.getUniformLocations())
373     {
374         gl::ShaderMap<sh::BlockMemberInfo> layoutInfo;
375 
376         if (location.used() && !location.ignored)
377         {
378             const auto &uniform = uniforms[location.index];
379             if (uniform.isInDefaultBlock() && !uniform.isSampler() && !uniform.isImage())
380             {
381                 std::string uniformName = uniform.name;
382                 if (uniform.isArray())
383                 {
384                     // Gets the uniform name without the [0] at the end.
385                     uniformName = gl::StripLastArrayIndex(uniformName);
386                     ASSERT(uniformName.size() != uniform.name.size());
387                 }
388 
389                 bool found = false;
390 
391                 for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
392                 {
393                     auto it = layoutMap[shaderType].find(uniformName);
394                     if (it != layoutMap[shaderType].end())
395                     {
396                         found                  = true;
397                         layoutInfo[shaderType] = it->second;
398                     }
399                 }
400 
401                 ASSERT(found);
402             }
403         }
404 
405         for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
406         {
407             mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]);
408         }
409     }
410 }
411 
resizeUniformBlockMemory(ContextVk * contextVk,gl::ShaderMap<size_t> & requiredBufferSize)412 angle::Result ProgramVk::resizeUniformBlockMemory(ContextVk *contextVk,
413                                                   gl::ShaderMap<size_t> &requiredBufferSize)
414 {
415     RendererVk *renderer                      = contextVk->getRenderer();
416     const gl::ProgramExecutable &glExecutable = mState.getExecutable();
417 
418     for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
419     {
420         if (requiredBufferSize[shaderType] > 0)
421         {
422             if (!mDefaultUniformBlocks[shaderType].uniformData.resize(
423                     requiredBufferSize[shaderType]))
424             {
425                 ANGLE_VK_CHECK(contextVk, false, VK_ERROR_OUT_OF_HOST_MEMORY);
426             }
427             size_t minAlignment = static_cast<size_t>(
428                 renderer->getPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
429 
430             mDefaultUniformBlocks[shaderType].storage.init(
431                 renderer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
432                 minAlignment, kUniformBlockDynamicBufferMinSize, true);
433 
434             // Initialize uniform buffer memory to zero by default.
435             mDefaultUniformBlocks[shaderType].uniformData.fill(0);
436             mDefaultUniformBlocksDirty.set(shaderType);
437         }
438     }
439 
440     return angle::Result::Continue;
441 }
442 
validate(const gl::Caps & caps,gl::InfoLog * infoLog)443 GLboolean ProgramVk::validate(const gl::Caps &caps, gl::InfoLog *infoLog)
444 {
445     // No-op. The spec is very vague about the behavior of validation.
446     return GL_TRUE;
447 }
448 
449 template <typename T>
setUniformImpl(GLint location,GLsizei count,const T * v,GLenum entryPointType)450 void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType)
451 {
452     const gl::VariableLocation &locationInfo  = mState.getUniformLocations()[location];
453     const gl::LinkedUniform &linkedUniform    = mState.getUniforms()[locationInfo.index];
454     const gl::ProgramExecutable &glExecutable = mState.getExecutable();
455 
456     ASSERT(!linkedUniform.isSampler());
457 
458     if (linkedUniform.typeInfo->type == entryPointType)
459     {
460         for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
461         {
462             DefaultUniformBlock &uniformBlock     = mDefaultUniformBlocks[shaderType];
463             const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
464 
465             // Assume an offset of -1 means the block is unused.
466             if (layoutInfo.offset == -1)
467             {
468                 continue;
469             }
470 
471             const GLint componentCount = linkedUniform.typeInfo->componentCount;
472             UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo,
473                                       &uniformBlock.uniformData);
474             mDefaultUniformBlocksDirty.set(shaderType);
475         }
476     }
477     else
478     {
479         for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
480         {
481             DefaultUniformBlock &uniformBlock     = mDefaultUniformBlocks[shaderType];
482             const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
483 
484             // Assume an offset of -1 means the block is unused.
485             if (layoutInfo.offset == -1)
486             {
487                 continue;
488             }
489 
490             const GLint componentCount = linkedUniform.typeInfo->componentCount;
491 
492             ASSERT(linkedUniform.typeInfo->type == gl::VariableBoolVectorType(entryPointType));
493 
494             GLint initialArrayOffset =
495                 locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset;
496             for (GLint i = 0; i < count; i++)
497             {
498                 GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset;
499                 GLint *dest =
500                     reinterpret_cast<GLint *>(uniformBlock.uniformData.data() + elementOffset);
501                 const T *source = v + i * componentCount;
502 
503                 for (int c = 0; c < componentCount; c++)
504                 {
505                     dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
506                 }
507             }
508 
509             mDefaultUniformBlocksDirty.set(shaderType);
510         }
511     }
512 }
513 
514 template <typename T>
getUniformImpl(GLint location,T * v,GLenum entryPointType) const515 void ProgramVk::getUniformImpl(GLint location, T *v, GLenum entryPointType) const
516 {
517     const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
518     const gl::LinkedUniform &linkedUniform   = mState.getUniforms()[locationInfo.index];
519 
520     ASSERT(!linkedUniform.isSampler() && !linkedUniform.isImage());
521 
522     const gl::ShaderType shaderType = linkedUniform.getFirstShaderTypeWhereActive();
523     ASSERT(shaderType != gl::ShaderType::InvalidEnum);
524 
525     const DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
526     const sh::BlockMemberInfo &layoutInfo   = uniformBlock.uniformLayout[location];
527 
528     ASSERT(linkedUniform.typeInfo->componentType == entryPointType ||
529            linkedUniform.typeInfo->componentType == gl::VariableBoolVectorType(entryPointType));
530 
531     if (gl::IsMatrixType(linkedUniform.type))
532     {
533         const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset +
534                                       (locationInfo.arrayIndex * layoutInfo.arrayStride);
535         GetMatrixUniform(linkedUniform.type, v, reinterpret_cast<const T *>(ptrToElement), false);
536     }
537     else
538     {
539         ReadFromDefaultUniformBlock(linkedUniform.typeInfo->componentCount, locationInfo.arrayIndex,
540                                     v, layoutInfo, &uniformBlock.uniformData);
541     }
542 }
543 
setUniform1fv(GLint location,GLsizei count,const GLfloat * v)544 void ProgramVk::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
545 {
546     setUniformImpl(location, count, v, GL_FLOAT);
547 }
548 
setUniform2fv(GLint location,GLsizei count,const GLfloat * v)549 void ProgramVk::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
550 {
551     setUniformImpl(location, count, v, GL_FLOAT_VEC2);
552 }
553 
setUniform3fv(GLint location,GLsizei count,const GLfloat * v)554 void ProgramVk::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
555 {
556     setUniformImpl(location, count, v, GL_FLOAT_VEC3);
557 }
558 
setUniform4fv(GLint location,GLsizei count,const GLfloat * v)559 void ProgramVk::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
560 {
561     setUniformImpl(location, count, v, GL_FLOAT_VEC4);
562 }
563 
setUniform1iv(GLint location,GLsizei count,const GLint * v)564 void ProgramVk::setUniform1iv(GLint location, GLsizei count, const GLint *v)
565 {
566     const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
567     const gl::LinkedUniform &linkedUniform   = mState.getUniforms()[locationInfo.index];
568     if (linkedUniform.isSampler())
569     {
570         // We could potentially cache some indexing here. For now this is a no-op since the mapping
571         // is handled entirely in ContextVk.
572         return;
573     }
574 
575     setUniformImpl(location, count, v, GL_INT);
576 }
577 
setUniform2iv(GLint location,GLsizei count,const GLint * v)578 void ProgramVk::setUniform2iv(GLint location, GLsizei count, const GLint *v)
579 {
580     setUniformImpl(location, count, v, GL_INT_VEC2);
581 }
582 
setUniform3iv(GLint location,GLsizei count,const GLint * v)583 void ProgramVk::setUniform3iv(GLint location, GLsizei count, const GLint *v)
584 {
585     setUniformImpl(location, count, v, GL_INT_VEC3);
586 }
587 
setUniform4iv(GLint location,GLsizei count,const GLint * v)588 void ProgramVk::setUniform4iv(GLint location, GLsizei count, const GLint *v)
589 {
590     setUniformImpl(location, count, v, GL_INT_VEC4);
591 }
592 
setUniform1uiv(GLint location,GLsizei count,const GLuint * v)593 void ProgramVk::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
594 {
595     setUniformImpl(location, count, v, GL_UNSIGNED_INT);
596 }
597 
setUniform2uiv(GLint location,GLsizei count,const GLuint * v)598 void ProgramVk::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
599 {
600     setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC2);
601 }
602 
setUniform3uiv(GLint location,GLsizei count,const GLuint * v)603 void ProgramVk::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
604 {
605     setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC3);
606 }
607 
setUniform4uiv(GLint location,GLsizei count,const GLuint * v)608 void ProgramVk::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
609 {
610     setUniformImpl(location, count, v, GL_UNSIGNED_INT_VEC4);
611 }
612 
613 template <int cols, int rows>
setUniformMatrixfv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)614 void ProgramVk::setUniformMatrixfv(GLint location,
615                                    GLsizei count,
616                                    GLboolean transpose,
617                                    const GLfloat *value)
618 {
619     const gl::VariableLocation &locationInfo  = mState.getUniformLocations()[location];
620     const gl::LinkedUniform &linkedUniform    = mState.getUniforms()[locationInfo.index];
621     const gl::ProgramExecutable &glExecutable = mState.getExecutable();
622 
623     for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
624     {
625         DefaultUniformBlock &uniformBlock     = mDefaultUniformBlocks[shaderType];
626         const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
627 
628         // Assume an offset of -1 means the block is unused.
629         if (layoutInfo.offset == -1)
630         {
631             continue;
632         }
633 
634         SetFloatUniformMatrixGLSL<cols, rows>::Run(
635             locationInfo.arrayIndex, linkedUniform.getArraySizeProduct(), count, transpose, value,
636             uniformBlock.uniformData.data() + layoutInfo.offset);
637 
638         mDefaultUniformBlocksDirty.set(shaderType);
639     }
640 }
641 
setUniformMatrix2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)642 void ProgramVk::setUniformMatrix2fv(GLint location,
643                                     GLsizei count,
644                                     GLboolean transpose,
645                                     const GLfloat *value)
646 {
647     setUniformMatrixfv<2, 2>(location, count, transpose, value);
648 }
649 
setUniformMatrix3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)650 void ProgramVk::setUniformMatrix3fv(GLint location,
651                                     GLsizei count,
652                                     GLboolean transpose,
653                                     const GLfloat *value)
654 {
655     setUniformMatrixfv<3, 3>(location, count, transpose, value);
656 }
657 
setUniformMatrix4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)658 void ProgramVk::setUniformMatrix4fv(GLint location,
659                                     GLsizei count,
660                                     GLboolean transpose,
661                                     const GLfloat *value)
662 {
663     setUniformMatrixfv<4, 4>(location, count, transpose, value);
664 }
665 
setUniformMatrix2x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)666 void ProgramVk::setUniformMatrix2x3fv(GLint location,
667                                       GLsizei count,
668                                       GLboolean transpose,
669                                       const GLfloat *value)
670 {
671     setUniformMatrixfv<2, 3>(location, count, transpose, value);
672 }
673 
setUniformMatrix3x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)674 void ProgramVk::setUniformMatrix3x2fv(GLint location,
675                                       GLsizei count,
676                                       GLboolean transpose,
677                                       const GLfloat *value)
678 {
679     setUniformMatrixfv<3, 2>(location, count, transpose, value);
680 }
681 
setUniformMatrix2x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)682 void ProgramVk::setUniformMatrix2x4fv(GLint location,
683                                       GLsizei count,
684                                       GLboolean transpose,
685                                       const GLfloat *value)
686 {
687     setUniformMatrixfv<2, 4>(location, count, transpose, value);
688 }
689 
setUniformMatrix4x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)690 void ProgramVk::setUniformMatrix4x2fv(GLint location,
691                                       GLsizei count,
692                                       GLboolean transpose,
693                                       const GLfloat *value)
694 {
695     setUniformMatrixfv<4, 2>(location, count, transpose, value);
696 }
697 
setUniformMatrix3x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)698 void ProgramVk::setUniformMatrix3x4fv(GLint location,
699                                       GLsizei count,
700                                       GLboolean transpose,
701                                       const GLfloat *value)
702 {
703     setUniformMatrixfv<3, 4>(location, count, transpose, value);
704 }
705 
setUniformMatrix4x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)706 void ProgramVk::setUniformMatrix4x3fv(GLint location,
707                                       GLsizei count,
708                                       GLboolean transpose,
709                                       const GLfloat *value)
710 {
711     setUniformMatrixfv<4, 3>(location, count, transpose, value);
712 }
713 
getUniformfv(const gl::Context * context,GLint location,GLfloat * params) const714 void ProgramVk::getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const
715 {
716     getUniformImpl(location, params, GL_FLOAT);
717 }
718 
getUniformiv(const gl::Context * context,GLint location,GLint * params) const719 void ProgramVk::getUniformiv(const gl::Context *context, GLint location, GLint *params) const
720 {
721     getUniformImpl(location, params, GL_INT);
722 }
723 
getUniformuiv(const gl::Context * context,GLint location,GLuint * params) const724 void ProgramVk::getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const
725 {
726     getUniformImpl(location, params, GL_UNSIGNED_INT);
727 }
728 
updateShaderUniforms(ContextVk * contextVk,gl::ShaderType shaderType,uint32_t * outOffset,bool * anyNewBufferAllocated)729 angle::Result ProgramVk::updateShaderUniforms(ContextVk *contextVk,
730                                               gl::ShaderType shaderType,
731                                               uint32_t *outOffset,
732                                               bool *anyNewBufferAllocated)
733 {
734     // Update buffer memory by immediate mapping. This immediate update only works once.
735     DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
736 
737     if (mDefaultUniformBlocksDirty[shaderType])
738     {
739         bool bufferModified = false;
740         ANGLE_TRY(SyncDefaultUniformBlock(contextVk, &uniformBlock.storage,
741                                           uniformBlock.uniformData, outOffset, &bufferModified));
742         mDefaultUniformBlocksDirty.reset(shaderType);
743 
744         if (bufferModified)
745         {
746             *anyNewBufferAllocated = true;
747         }
748     }
749 
750     return angle::Result::Continue;
751 }
752 
updateUniforms(ContextVk * contextVk)753 angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
754 {
755     ASSERT(dirtyUniforms());
756 
757     bool anyNewBufferAllocated                = false;
758     uint32_t offsetIndex                      = 0;
759     const gl::ProgramExecutable &glExecutable = mState.getExecutable();
760 
761     // Update buffer memory by immediate mapping. This immediate update only works once.
762     for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
763     {
764         ANGLE_TRY(updateShaderUniforms(contextVk, shaderType,
765                                        &mExecutable.mDynamicBufferOffsets[offsetIndex],
766                                        &anyNewBufferAllocated));
767         ++offsetIndex;
768     }
769 
770     if (anyNewBufferAllocated)
771     {
772         // We need to reinitialize the descriptor sets if we newly allocated buffers since we can't
773         // modify the descriptor sets once initialized.
774         ANGLE_TRY(mExecutable.allocateDescriptorSet(contextVk, kUniformsAndXfbDescriptorSetIndex));
775 
776         mExecutable.mDescriptorBuffersCache.clear();
777         for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
778         {
779             mExecutable.updateDefaultUniformsDescriptorSet(shaderType, mDefaultUniformBlocks,
780                                                            contextVk);
781             mExecutable.updateTransformFeedbackDescriptorSetImpl(mState, contextVk);
782         }
783     }
784 
785     return angle::Result::Continue;
786 }
787 
setDefaultUniformBlocksMinSizeForTesting(size_t minSize)788 void ProgramVk::setDefaultUniformBlocksMinSizeForTesting(size_t minSize)
789 {
790     for (DefaultUniformBlock &block : mDefaultUniformBlocks)
791     {
792         block.storage.setMinimumSizeForTesting(minSize);
793     }
794 }
795 
796 }  // namespace rx
797