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