• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 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 // ProgramExecutableVk.cpp: Collects the information and interfaces common to both ProgramVks and
7 // ProgramPipelineVks in order to execute/draw with either.
8 
9 #include "libANGLE/renderer/vulkan/ProgramExecutableVk.h"
10 
11 #include "common/string_utils.h"
12 #include "libANGLE/renderer/vulkan/BufferVk.h"
13 #include "libANGLE/renderer/vulkan/DisplayVk.h"
14 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
15 #include "libANGLE/renderer/vulkan/ProgramPipelineVk.h"
16 #include "libANGLE/renderer/vulkan/ProgramVk.h"
17 #include "libANGLE/renderer/vulkan/TextureVk.h"
18 #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
19 #include "libANGLE/renderer/vulkan/vk_helpers.h"
20 #include "libANGLE/renderer/vulkan/vk_utils.h"
21 
22 namespace rx
23 {
24 namespace
25 {
26 
27 // Limit decompressed vulkan pipelines to 10MB per program.
28 static constexpr size_t kMaxLocalPipelineCacheSize = 10 * 1024 * 1024;
29 
ValidateTransformedSpirV(vk::Context * context,const gl::ShaderBitSet & linkedShaderStages,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ShaderMap<angle::spirv::Blob> & spirvBlobs)30 bool ValidateTransformedSpirV(vk::Context *context,
31                               const gl::ShaderBitSet &linkedShaderStages,
32                               const ShaderInterfaceVariableInfoMap &variableInfoMap,
33                               const gl::ShaderMap<angle::spirv::Blob> &spirvBlobs)
34 {
35     gl::ShaderType lastPreFragmentStage = gl::GetLastPreFragmentStage(linkedShaderStages);
36 
37     for (gl::ShaderType shaderType : linkedShaderStages)
38     {
39         SpvTransformOptions options;
40         options.shaderType = shaderType;
41         options.isLastPreFragmentStage =
42             shaderType == lastPreFragmentStage && shaderType != gl::ShaderType::TessControl;
43         options.isTransformFeedbackStage = options.isLastPreFragmentStage;
44         options.useSpirvVaryingPrecisionFixer =
45             context->getFeatures().varyingsRequireMatchingPrecisionInSpirv.enabled;
46 
47         angle::spirv::Blob transformed;
48         if (SpvTransformSpirvCode(options, variableInfoMap, spirvBlobs[shaderType], &transformed) !=
49             angle::Result::Continue)
50         {
51             return false;
52         }
53     }
54     return true;
55 }
56 
GetInterfaceBlockArraySize(const std::vector<gl::InterfaceBlock> & blocks,uint32_t bufferIndex)57 uint32_t GetInterfaceBlockArraySize(const std::vector<gl::InterfaceBlock> &blocks,
58                                     uint32_t bufferIndex)
59 {
60     const gl::InterfaceBlock &block = blocks[bufferIndex];
61 
62     if (!block.pod.isArray)
63     {
64         return 1;
65     }
66 
67     ASSERT(block.pod.arrayElement == 0);
68 
69     // Search consecutively until all array indices of this block are visited.
70     uint32_t arraySize;
71     for (arraySize = 1; bufferIndex + arraySize < blocks.size(); ++arraySize)
72     {
73         const gl::InterfaceBlock &nextBlock = blocks[bufferIndex + arraySize];
74 
75         if (nextBlock.pod.arrayElement != arraySize)
76         {
77             break;
78         }
79 
80         // It's unexpected for an array to start at a non-zero array size, so we can always rely on
81         // the sequential `arrayElement`s to belong to the same block.
82         ASSERT(nextBlock.name == block.name);
83         ASSERT(nextBlock.pod.isArray);
84     }
85 
86     return arraySize;
87 }
88 
SetupDefaultPipelineState(const vk::Context * context,const gl::ProgramExecutable & glExecutable,gl::PrimitiveMode mode,vk::PipelineRobustness pipelineRobustness,vk::PipelineProtectedAccess pipelineProtectedAccess,vk::GraphicsPipelineSubset subset,vk::GraphicsPipelineDesc * graphicsPipelineDescOut)89 void SetupDefaultPipelineState(const vk::Context *context,
90                                const gl::ProgramExecutable &glExecutable,
91                                gl::PrimitiveMode mode,
92                                vk::PipelineRobustness pipelineRobustness,
93                                vk::PipelineProtectedAccess pipelineProtectedAccess,
94                                vk::GraphicsPipelineSubset subset,
95                                vk::GraphicsPipelineDesc *graphicsPipelineDescOut)
96 {
97     graphicsPipelineDescOut->initDefaults(context, vk::GraphicsPipelineSubset::Complete,
98                                           pipelineRobustness, pipelineProtectedAccess);
99 
100     // Set render pass state, affecting both complete and shaders-only pipelines.
101     graphicsPipelineDescOut->setTopology(mode);
102     graphicsPipelineDescOut->setRenderPassSampleCount(1);
103     graphicsPipelineDescOut->setRenderPassFramebufferFetchMode(glExecutable.usesFramebufferFetch());
104 
105     const std::vector<gl::ProgramOutput> &outputVariables    = glExecutable.getOutputVariables();
106     const std::vector<gl::VariableLocation> &outputLocations = glExecutable.getOutputLocations();
107 
108     gl::DrawBufferMask drawBuffers;
109 
110     for (const gl::VariableLocation &outputLocation : outputLocations)
111     {
112         if (outputLocation.arrayIndex == 0 && outputLocation.used() && !outputLocation.ignored)
113         {
114             const gl::ProgramOutput &outputVar = outputVariables[outputLocation.index];
115 
116             if (angle::BeginsWith(outputVar.name, "gl_") && outputVar.name != "gl_FragColor")
117             {
118                 continue;
119             }
120 
121             uint32_t location = 0;
122             if (outputVar.pod.location != -1)
123             {
124                 location = outputVar.pod.location;
125             }
126 
127             GLenum type            = gl::VariableComponentType(outputVar.pod.type);
128             angle::FormatID format = angle::FormatID::R8G8B8A8_UNORM;
129             if (type == GL_INT)
130             {
131                 format = angle::FormatID::R8G8B8A8_SINT;
132             }
133             else if (type == GL_UNSIGNED_INT)
134             {
135                 format = angle::FormatID::R8G8B8A8_UINT;
136             }
137 
138             const size_t arraySize = outputVar.isArray() ? outputVar.getOutermostArraySize() : 1;
139             for (size_t arrayIndex = 0; arrayIndex < arraySize; ++arrayIndex)
140             {
141                 graphicsPipelineDescOut->setRenderPassColorAttachmentFormat(location + arrayIndex,
142                                                                             format);
143                 drawBuffers.set(location + arrayIndex);
144             }
145         }
146     }
147 
148     for (const gl::ProgramOutput &outputVar : outputVariables)
149     {
150         if (outputVar.name == "gl_FragColor" || outputVar.name == "gl_FragData")
151         {
152             const size_t arraySize = outputVar.isArray() ? outputVar.getOutermostArraySize() : 1;
153             for (size_t arrayIndex = 0; arrayIndex < arraySize; ++arrayIndex)
154             {
155                 graphicsPipelineDescOut->setRenderPassColorAttachmentFormat(
156                     arrayIndex, angle::FormatID::R8G8B8A8_UNORM);
157                 drawBuffers.set(arrayIndex);
158             }
159         }
160     }
161 
162     if (subset == vk::GraphicsPipelineSubset::Complete)
163     {
164         // Include vertex input state
165         graphicsPipelineDescOut->setVertexShaderComponentTypes(
166             glExecutable.getNonBuiltinAttribLocationsMask(), glExecutable.getAttributesTypeMask());
167 
168         // Include fragment output state
169         gl::BlendStateExt::ColorMaskStorage::Type colorMask =
170             gl::BlendStateExt::ColorMaskStorage::GetReplicatedValue(
171                 gl::BlendStateExt::PackColorMask(true, true, true, true),
172                 gl::BlendStateExt::ColorMaskStorage::GetMask(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS));
173         graphicsPipelineDescOut->setColorWriteMasks(colorMask, {}, drawBuffers);
174     }
175 }
176 
GetPipelineCacheData(ContextVk * contextVk,const vk::PipelineCache & pipelineCache,angle::MemoryBuffer * cacheDataOut)177 void GetPipelineCacheData(ContextVk *contextVk,
178                           const vk::PipelineCache &pipelineCache,
179                           angle::MemoryBuffer *cacheDataOut)
180 {
181     ASSERT(pipelineCache.valid() || contextVk->getState().isGLES1() ||
182            !contextVk->getFeatures().warmUpPipelineCacheAtLink.enabled ||
183            !contextVk->getFeatures().hasEffectivePipelineCacheSerialization.enabled);
184     if (!pipelineCache.valid() ||
185         !contextVk->getFeatures().hasEffectivePipelineCacheSerialization.enabled)
186     {
187         return;
188     }
189 
190     // Extract the pipeline data.  If failed, or empty, it's simply not stored on disk.
191     size_t pipelineCacheSize = 0;
192     VkResult result =
193         pipelineCache.getCacheData(contextVk->getDevice(), &pipelineCacheSize, nullptr);
194     if (result != VK_SUCCESS || pipelineCacheSize == 0)
195     {
196         return;
197     }
198 
199     if (contextVk->getFeatures().enablePipelineCacheDataCompression.enabled)
200     {
201         std::vector<uint8_t> pipelineCacheData(pipelineCacheSize);
202         result = pipelineCache.getCacheData(contextVk->getDevice(), &pipelineCacheSize,
203                                             pipelineCacheData.data());
204         if (result != VK_SUCCESS && result != VK_INCOMPLETE)
205         {
206             return;
207         }
208 
209         // Compress it.
210         if (!angle::CompressBlob(pipelineCacheData.size(), pipelineCacheData.data(), cacheDataOut))
211         {
212             cacheDataOut->clear();
213         }
214     }
215     else
216     {
217         if (!cacheDataOut->resize(pipelineCacheSize))
218         {
219             ERR() << "Failed to allocate memory for pipeline cache data.";
220             return;
221         }
222         result = pipelineCache.getCacheData(contextVk->getDevice(), &pipelineCacheSize,
223                                             cacheDataOut->data());
224         if (result != VK_SUCCESS && result != VK_INCOMPLETE)
225         {
226             cacheDataOut->clear();
227         }
228     }
229 }
230 
MakeSpecConsts(ProgramTransformOptions transformOptions,const vk::GraphicsPipelineDesc & desc)231 vk::SpecializationConstants MakeSpecConsts(ProgramTransformOptions transformOptions,
232                                            const vk::GraphicsPipelineDesc &desc)
233 {
234     vk::SpecializationConstants specConsts;
235 
236     specConsts.surfaceRotation = transformOptions.surfaceRotation;
237     specConsts.dither          = desc.getEmulatedDitherControl();
238 
239     return specConsts;
240 }
241 
242 template <typename T>
UpdateDefaultUniformBlock(GLsizei count,uint32_t arrayIndex,int componentCount,const T * v,const sh::BlockMemberInfo & layoutInfo,angle::MemoryBuffer * uniformData)243 void UpdateDefaultUniformBlock(GLsizei count,
244                                uint32_t arrayIndex,
245                                int componentCount,
246                                const T *v,
247                                const sh::BlockMemberInfo &layoutInfo,
248                                angle::MemoryBuffer *uniformData)
249 {
250     const int elementSize = sizeof(T) * componentCount;
251 
252     uint8_t *dst = uniformData->data() + layoutInfo.offset;
253     if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
254     {
255         uint32_t arrayOffset = arrayIndex * layoutInfo.arrayStride;
256         uint8_t *writePtr    = dst + arrayOffset;
257         ASSERT(writePtr + (elementSize * count) <= uniformData->data() + uniformData->size());
258         memcpy(writePtr, v, elementSize * count);
259     }
260     else
261     {
262         // Have to respect the arrayStride between each element of the array.
263         int maxIndex = arrayIndex + count;
264         for (int writeIndex = arrayIndex, readIndex = 0; writeIndex < maxIndex;
265              writeIndex++, readIndex++)
266         {
267             const int arrayOffset = writeIndex * layoutInfo.arrayStride;
268             uint8_t *writePtr     = dst + arrayOffset;
269             const T *readPtr      = v + (readIndex * componentCount);
270             ASSERT(writePtr + elementSize <= uniformData->data() + uniformData->size());
271             memcpy(writePtr, readPtr, elementSize);
272         }
273     }
274 }
275 
276 template <typename T>
ReadFromDefaultUniformBlock(int componentCount,uint32_t arrayIndex,T * dst,const sh::BlockMemberInfo & layoutInfo,const angle::MemoryBuffer * uniformData)277 void ReadFromDefaultUniformBlock(int componentCount,
278                                  uint32_t arrayIndex,
279                                  T *dst,
280                                  const sh::BlockMemberInfo &layoutInfo,
281                                  const angle::MemoryBuffer *uniformData)
282 {
283     ASSERT(layoutInfo.offset != -1);
284 
285     const int elementSize = sizeof(T) * componentCount;
286     const uint8_t *source = uniformData->data() + layoutInfo.offset;
287 
288     if (layoutInfo.arrayStride == 0 || layoutInfo.arrayStride == elementSize)
289     {
290         const uint8_t *readPtr = source + arrayIndex * layoutInfo.arrayStride;
291         memcpy(dst, readPtr, elementSize);
292     }
293     else
294     {
295         // Have to respect the arrayStride between each element of the array.
296         const int arrayOffset  = arrayIndex * layoutInfo.arrayStride;
297         const uint8_t *readPtr = source + arrayOffset;
298         memcpy(dst, readPtr, elementSize);
299     }
300 }
301 
302 template <typename T>
SetUniformImpl(const gl::ProgramExecutable * executable,GLint location,GLsizei count,const T * v,GLenum entryPointType,DefaultUniformBlockMap * defaultUniformBlocks,gl::ShaderBitSet * defaultUniformBlocksDirty)303 void SetUniformImpl(const gl::ProgramExecutable *executable,
304                     GLint location,
305                     GLsizei count,
306                     const T *v,
307                     GLenum entryPointType,
308                     DefaultUniformBlockMap *defaultUniformBlocks,
309                     gl::ShaderBitSet *defaultUniformBlocksDirty)
310 {
311     const gl::VariableLocation &locationInfo = executable->getUniformLocations()[location];
312     const gl::LinkedUniform &linkedUniform   = executable->getUniforms()[locationInfo.index];
313 
314     ASSERT(!linkedUniform.isSampler());
315 
316     if (linkedUniform.getType() == entryPointType)
317     {
318         for (const gl::ShaderType shaderType : executable->getLinkedShaderStages())
319         {
320             DefaultUniformBlockVk &uniformBlock   = *(*defaultUniformBlocks)[shaderType];
321             const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
322 
323             // Assume an offset of -1 means the block is unused.
324             if (layoutInfo.offset == -1)
325             {
326                 continue;
327             }
328 
329             const GLint componentCount = linkedUniform.getElementComponents();
330             UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo,
331                                       &uniformBlock.uniformData);
332             defaultUniformBlocksDirty->set(shaderType);
333         }
334     }
335     else
336     {
337         for (const gl::ShaderType shaderType : executable->getLinkedShaderStages())
338         {
339             DefaultUniformBlockVk &uniformBlock   = *(*defaultUniformBlocks)[shaderType];
340             const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
341 
342             // Assume an offset of -1 means the block is unused.
343             if (layoutInfo.offset == -1)
344             {
345                 continue;
346             }
347 
348             const GLint componentCount = linkedUniform.getElementComponents();
349 
350             ASSERT(linkedUniform.getType() == gl::VariableBoolVectorType(entryPointType));
351 
352             GLint initialArrayOffset =
353                 locationInfo.arrayIndex * layoutInfo.arrayStride + layoutInfo.offset;
354             for (GLint i = 0; i < count; i++)
355             {
356                 GLint elementOffset = i * layoutInfo.arrayStride + initialArrayOffset;
357                 GLint *dst =
358                     reinterpret_cast<GLint *>(uniformBlock.uniformData.data() + elementOffset);
359                 const T *source = v + i * componentCount;
360 
361                 for (int c = 0; c < componentCount; c++)
362                 {
363                     dst[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
364                 }
365             }
366 
367             defaultUniformBlocksDirty->set(shaderType);
368         }
369     }
370 }
371 
372 template <int cols, int rows>
SetUniformMatrixfv(const gl::ProgramExecutable * executable,GLint location,GLsizei count,GLboolean transpose,const GLfloat * value,DefaultUniformBlockMap * defaultUniformBlocks,gl::ShaderBitSet * defaultUniformBlocksDirty)373 void SetUniformMatrixfv(const gl::ProgramExecutable *executable,
374                         GLint location,
375                         GLsizei count,
376                         GLboolean transpose,
377                         const GLfloat *value,
378                         DefaultUniformBlockMap *defaultUniformBlocks,
379                         gl::ShaderBitSet *defaultUniformBlocksDirty)
380 {
381     const gl::VariableLocation &locationInfo = executable->getUniformLocations()[location];
382     const gl::LinkedUniform &linkedUniform   = executable->getUniforms()[locationInfo.index];
383 
384     for (const gl::ShaderType shaderType : executable->getLinkedShaderStages())
385     {
386         DefaultUniformBlockVk &uniformBlock   = *(*defaultUniformBlocks)[shaderType];
387         const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
388 
389         // Assume an offset of -1 means the block is unused.
390         if (layoutInfo.offset == -1)
391         {
392             continue;
393         }
394 
395         SetFloatUniformMatrixGLSL<cols, rows>::Run(
396             locationInfo.arrayIndex, linkedUniform.getBasicTypeElementCount(), count, transpose,
397             value, uniformBlock.uniformData.data() + layoutInfo.offset);
398 
399         defaultUniformBlocksDirty->set(shaderType);
400     }
401 }
402 }  // namespace
403 
404 class ProgramExecutableVk::WarmUpTaskCommon : public vk::Context, public LinkSubTask
405 {
406   public:
WarmUpTaskCommon(vk::Renderer * renderer)407     WarmUpTaskCommon(vk::Renderer *renderer) : vk::Context(renderer) {}
WarmUpTaskCommon(vk::Renderer * renderer,ProgramExecutableVk * executableVk,vk::PipelineRobustness pipelineRobustness,vk::PipelineProtectedAccess pipelineProtectedAccess)408     WarmUpTaskCommon(vk::Renderer *renderer,
409                      ProgramExecutableVk *executableVk,
410                      vk::PipelineRobustness pipelineRobustness,
411                      vk::PipelineProtectedAccess pipelineProtectedAccess)
412         : vk::Context(renderer),
413           mExecutableVk(executableVk),
414           mPipelineRobustness(pipelineRobustness),
415           mPipelineProtectedAccess(pipelineProtectedAccess)
416     {}
417     ~WarmUpTaskCommon() override = default;
418 
handleError(VkResult result,const char * file,const char * function,unsigned int line)419     void handleError(VkResult result,
420                      const char *file,
421                      const char *function,
422                      unsigned int line) override
423     {
424         mErrorCode     = result;
425         mErrorFile     = file;
426         mErrorFunction = function;
427         mErrorLine     = line;
428     }
429 
operator ()()430     void operator()() override { UNREACHABLE(); }
431 
getResult(const gl::Context * context,gl::InfoLog & infoLog)432     angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
433     {
434         ContextVk *contextVk = vk::GetImpl(context);
435         return getResultImpl(contextVk, infoLog);
436     }
437 
getResultImpl(ContextVk * contextVk,gl::InfoLog & infoLog)438     angle::Result getResultImpl(ContextVk *contextVk, gl::InfoLog &infoLog)
439     {
440         // Forward any errors
441         if (mErrorCode != VK_SUCCESS)
442         {
443             contextVk->handleError(mErrorCode, mErrorFile, mErrorFunction, mErrorLine);
444             return angle::Result::Stop;
445         }
446 
447         // Accumulate relevant perf counters
448         const angle::VulkanPerfCounters &from = getPerfCounters();
449         angle::VulkanPerfCounters &to         = contextVk->getPerfCounters();
450 
451         to.pipelineCreationCacheHits += from.pipelineCreationCacheHits;
452         to.pipelineCreationCacheMisses += from.pipelineCreationCacheMisses;
453         to.pipelineCreationTotalCacheHitsDurationNs +=
454             from.pipelineCreationTotalCacheHitsDurationNs;
455         to.pipelineCreationTotalCacheMissesDurationNs +=
456             from.pipelineCreationTotalCacheMissesDurationNs;
457 
458         return angle::Result::Continue;
459     }
460 
461   protected:
mergeProgramExecutablePipelineCacheToRenderer()462     void mergeProgramExecutablePipelineCacheToRenderer()
463     {
464         angle::Result mergeResult = mExecutableVk->mergePipelineCacheToRenderer(this);
465 
466         // Treat error during merge as non fatal, log it and move on
467         if (mergeResult != angle::Result::Continue)
468         {
469             INFO() << "Error while merging to Renderer's pipeline cache";
470         }
471     }
472 
473     // The front-end ensures that the program is not modified while the subtask is running, so it is
474     // safe to directly access the executable from this parallel job.  Note that this is the reason
475     // why the front-end does not let the parallel job continue when a relink happens or the first
476     // draw with this program.
477     ProgramExecutableVk *mExecutableVk               = nullptr;
478     const vk::PipelineRobustness mPipelineRobustness = vk::PipelineRobustness::NonRobust;
479     const vk::PipelineProtectedAccess mPipelineProtectedAccess =
480         vk::PipelineProtectedAccess::Unprotected;
481 
482     // Error handling
483     VkResult mErrorCode        = VK_SUCCESS;
484     const char *mErrorFile     = nullptr;
485     const char *mErrorFunction = nullptr;
486     unsigned int mErrorLine    = 0;
487 };
488 
489 class ProgramExecutableVk::WarmUpComputeTask : public WarmUpTaskCommon
490 {
491   public:
WarmUpComputeTask(vk::Renderer * renderer,ProgramExecutableVk * executableVk,vk::PipelineRobustness pipelineRobustness,vk::PipelineProtectedAccess pipelineProtectedAccess)492     WarmUpComputeTask(vk::Renderer *renderer,
493                       ProgramExecutableVk *executableVk,
494                       vk::PipelineRobustness pipelineRobustness,
495                       vk::PipelineProtectedAccess pipelineProtectedAccess)
496         : WarmUpTaskCommon(renderer, executableVk, pipelineRobustness, pipelineProtectedAccess)
497     {}
498     ~WarmUpComputeTask() override = default;
499 
operator ()()500     void operator()() override
501     {
502         angle::Result result = mExecutableVk->warmUpComputePipelineCache(this, mPipelineRobustness,
503                                                                          mPipelineProtectedAccess);
504         ASSERT((result == angle::Result::Continue) == (mErrorCode == VK_SUCCESS));
505 
506         mergeProgramExecutablePipelineCacheToRenderer();
507     }
508 };
509 
510 using SharedRenderPass = vk::AtomicRefCounted<vk::RenderPass>;
511 class ProgramExecutableVk::WarmUpGraphicsTask : public WarmUpTaskCommon
512 {
513   public:
WarmUpGraphicsTask(vk::Renderer * renderer,ProgramExecutableVk * executableVk,vk::PipelineRobustness pipelineRobustness,vk::PipelineProtectedAccess pipelineProtectedAccess,vk::GraphicsPipelineSubset subset,const bool isSurfaceRotated,const vk::GraphicsPipelineDesc & graphicsPipelineDesc,SharedRenderPass * compatibleRenderPass,vk::PipelineHelper * placeholderPipelineHelper)514     WarmUpGraphicsTask(vk::Renderer *renderer,
515                        ProgramExecutableVk *executableVk,
516                        vk::PipelineRobustness pipelineRobustness,
517                        vk::PipelineProtectedAccess pipelineProtectedAccess,
518                        vk::GraphicsPipelineSubset subset,
519                        const bool isSurfaceRotated,
520                        const vk::GraphicsPipelineDesc &graphicsPipelineDesc,
521                        SharedRenderPass *compatibleRenderPass,
522                        vk::PipelineHelper *placeholderPipelineHelper)
523         : WarmUpTaskCommon(renderer, executableVk, pipelineRobustness, pipelineProtectedAccess),
524           mPipelineSubset(subset),
525           mIsSurfaceRotated(isSurfaceRotated),
526           mGraphicsPipelineDesc(graphicsPipelineDesc),
527           mWarmUpPipelineHelper(placeholderPipelineHelper),
528           mCompatibleRenderPass(compatibleRenderPass)
529     {
530         ASSERT(mCompatibleRenderPass);
531         mCompatibleRenderPass->addRef();
532     }
533     ~WarmUpGraphicsTask() override = default;
534 
operator ()()535     void operator()() override
536     {
537         angle::Result result = mExecutableVk->warmUpGraphicsPipelineCache(
538             this, mPipelineRobustness, mPipelineProtectedAccess, mPipelineSubset, mIsSurfaceRotated,
539             mGraphicsPipelineDesc, mCompatibleRenderPass->get(), mWarmUpPipelineHelper);
540         ASSERT((result == angle::Result::Continue) == (mErrorCode == VK_SUCCESS));
541 
542         // Release reference to shared renderpass. If this is the last reference -
543         // 1. merge ProgramExecutableVk's pipeline cache into the Renderer's cache
544         // 2. cleanup temporary renderpass
545         const bool isLastWarmUpTask = mCompatibleRenderPass->getAndReleaseRef() == 1;
546         if (isLastWarmUpTask)
547         {
548             mergeProgramExecutablePipelineCacheToRenderer();
549 
550             mCompatibleRenderPass->get().destroy(getDevice());
551             SafeDelete(mCompatibleRenderPass);
552         }
553     }
554 
555   private:
556     vk::GraphicsPipelineSubset mPipelineSubset;
557     bool mIsSurfaceRotated;
558     vk::GraphicsPipelineDesc mGraphicsPipelineDesc;
559     vk::PipelineHelper *mWarmUpPipelineHelper;
560 
561     // Temporary objects to clean up at the end
562     SharedRenderPass *mCompatibleRenderPass;
563 };
564 
565 DefaultUniformBlockVk::DefaultUniformBlockVk() = default;
566 
567 DefaultUniformBlockVk::~DefaultUniformBlockVk() = default;
568 
569 // ShaderInfo implementation.
ShaderInfo()570 ShaderInfo::ShaderInfo() {}
571 
572 ShaderInfo::~ShaderInfo() = default;
573 
initShaders(vk::Context * context,const gl::ShaderBitSet & linkedShaderStages,const gl::ShaderMap<const angle::spirv::Blob * > & spirvBlobs,const ShaderInterfaceVariableInfoMap & variableInfoMap,bool isGLES1)574 angle::Result ShaderInfo::initShaders(vk::Context *context,
575                                       const gl::ShaderBitSet &linkedShaderStages,
576                                       const gl::ShaderMap<const angle::spirv::Blob *> &spirvBlobs,
577                                       const ShaderInterfaceVariableInfoMap &variableInfoMap,
578                                       bool isGLES1)
579 {
580     clear();
581 
582     for (gl::ShaderType shaderType : gl::AllShaderTypes())
583     {
584         if (spirvBlobs[shaderType] != nullptr)
585         {
586             mSpirvBlobs[shaderType] = *spirvBlobs[shaderType];
587         }
588     }
589 
590     // Assert that SPIR-V transformation is correct, even if the test never issues a draw call.
591     // Don't validate GLES1 programs because they are always created right before a draw, so they
592     // will naturally be validated.  This improves GLES1 test run times.
593     if (!isGLES1)
594     {
595         ASSERT(ValidateTransformedSpirV(context, linkedShaderStages, variableInfoMap, mSpirvBlobs));
596     }
597 
598     mIsInitialized = true;
599     return angle::Result::Continue;
600 }
601 
initShaderFromProgram(gl::ShaderType shaderType,const ShaderInfo & programShaderInfo)602 void ShaderInfo::initShaderFromProgram(gl::ShaderType shaderType,
603                                        const ShaderInfo &programShaderInfo)
604 {
605     mSpirvBlobs[shaderType] = programShaderInfo.mSpirvBlobs[shaderType];
606     mIsInitialized          = true;
607 }
608 
clear()609 void ShaderInfo::clear()
610 {
611     for (angle::spirv::Blob &spirvBlob : mSpirvBlobs)
612     {
613         spirvBlob.clear();
614     }
615     mIsInitialized = false;
616 }
617 
load(gl::BinaryInputStream * stream)618 void ShaderInfo::load(gl::BinaryInputStream *stream)
619 {
620     clear();
621 
622     // Read in shader codes for all shader types
623     for (gl::ShaderType shaderType : gl::AllShaderTypes())
624     {
625         stream->readVector(&mSpirvBlobs[shaderType]);
626     }
627 
628     mIsInitialized = true;
629 }
630 
save(gl::BinaryOutputStream * stream)631 void ShaderInfo::save(gl::BinaryOutputStream *stream)
632 {
633     ASSERT(valid());
634 
635     // Write out shader codes for all shader types
636     for (gl::ShaderType shaderType : gl::AllShaderTypes())
637     {
638         stream->writeVector(mSpirvBlobs[shaderType]);
639     }
640 }
641 
642 // ProgramInfo implementation.
ProgramInfo()643 ProgramInfo::ProgramInfo() {}
644 
645 ProgramInfo::~ProgramInfo() = default;
646 
initProgram(vk::Context * context,gl::ShaderType shaderType,bool isLastPreFragmentStage,bool isTransformFeedbackProgram,const ShaderInfo & shaderInfo,ProgramTransformOptions optionBits,const ShaderInterfaceVariableInfoMap & variableInfoMap)647 angle::Result ProgramInfo::initProgram(vk::Context *context,
648                                        gl::ShaderType shaderType,
649                                        bool isLastPreFragmentStage,
650                                        bool isTransformFeedbackProgram,
651                                        const ShaderInfo &shaderInfo,
652                                        ProgramTransformOptions optionBits,
653                                        const ShaderInterfaceVariableInfoMap &variableInfoMap)
654 {
655     const gl::ShaderMap<angle::spirv::Blob> &originalSpirvBlobs = shaderInfo.getSpirvBlobs();
656     const angle::spirv::Blob &originalSpirvBlob                 = originalSpirvBlobs[shaderType];
657     gl::ShaderMap<angle::spirv::Blob> transformedSpirvBlobs;
658     angle::spirv::Blob &transformedSpirvBlob = transformedSpirvBlobs[shaderType];
659 
660     SpvTransformOptions options;
661     options.shaderType               = shaderType;
662     options.isLastPreFragmentStage   = isLastPreFragmentStage;
663     options.isTransformFeedbackStage = isLastPreFragmentStage && isTransformFeedbackProgram &&
664                                        !optionBits.removeTransformFeedbackEmulation;
665     options.isTransformFeedbackEmulated = context->getFeatures().emulateTransformFeedback.enabled;
666     options.isMultisampledFramebufferFetch =
667         optionBits.multiSampleFramebufferFetch && shaderType == gl::ShaderType::Fragment;
668     options.enableSampleShading = optionBits.enableSampleShading;
669 
670     options.useSpirvVaryingPrecisionFixer =
671         context->getFeatures().varyingsRequireMatchingPrecisionInSpirv.enabled;
672 
673     ANGLE_TRY(
674         SpvTransformSpirvCode(options, variableInfoMap, originalSpirvBlob, &transformedSpirvBlob));
675     ANGLE_TRY(vk::InitShaderModule(context, &mShaders[shaderType].get(),
676                                    transformedSpirvBlob.data(),
677                                    transformedSpirvBlob.size() * sizeof(uint32_t)));
678 
679     mProgramHelper.setShader(shaderType, &mShaders[shaderType]);
680 
681     return angle::Result::Continue;
682 }
683 
release(ContextVk * contextVk)684 void ProgramInfo::release(ContextVk *contextVk)
685 {
686     mProgramHelper.release(contextVk);
687 
688     for (vk::RefCounted<vk::ShaderModule> &shader : mShaders)
689     {
690         shader.get().destroy(contextVk->getDevice());
691     }
692 }
693 
ProgramExecutableVk(const gl::ProgramExecutable * executable)694 ProgramExecutableVk::ProgramExecutableVk(const gl::ProgramExecutable *executable)
695     : ProgramExecutableImpl(executable),
696       mImmutableSamplersMaxDescriptorCount(1),
697       mUniformBufferDescriptorType(VK_DESCRIPTOR_TYPE_MAX_ENUM),
698       mDynamicUniformDescriptorOffsets{},
699       mValidPermutations{}
700 {
701     mDescriptorSets.fill(VK_NULL_HANDLE);
702     for (std::shared_ptr<DefaultUniformBlockVk> &defaultBlock : mDefaultUniformBlocks)
703     {
704         defaultBlock = std::make_shared<DefaultUniformBlockVk>();
705     }
706 }
707 
~ProgramExecutableVk()708 ProgramExecutableVk::~ProgramExecutableVk()
709 {
710     ASSERT(!mPipelineCache.valid());
711 }
712 
destroy(const gl::Context * context)713 void ProgramExecutableVk::destroy(const gl::Context *context)
714 {
715     reset(vk::GetImpl(context));
716 }
717 
resetLayout(ContextVk * contextVk)718 void ProgramExecutableVk::resetLayout(ContextVk *contextVk)
719 {
720     waitForPostLinkTasksImpl(contextVk);
721 
722     for (auto &descriptorSetLayout : mDescriptorSetLayouts)
723     {
724         descriptorSetLayout.reset();
725     }
726     mImmutableSamplersMaxDescriptorCount = 1;
727     mImmutableSamplerIndexMap.clear();
728 
729     mDescriptorSets.fill(VK_NULL_HANDLE);
730 
731     for (vk::RefCountedDescriptorPoolBinding &binding : mDescriptorPoolBindings)
732     {
733         binding.reset();
734     }
735 
736     for (vk::DescriptorPoolPointer &pool : mDescriptorPools)
737     {
738         pool.reset();
739     }
740 
741     // Initialize with an invalid BufferSerial
742     mCurrentDefaultUniformBufferSerial = vk::BufferSerial();
743 
744     for (size_t index : mValidPermutations)
745     {
746         mCompleteGraphicsPipelines[index].release(contextVk);
747         mShadersGraphicsPipelines[index].release(contextVk);
748 
749         // Program infos and pipeline layout must be released after pipelines are; they might be
750         // having pending jobs that are referencing them.
751         mGraphicsProgramInfos[index].release(contextVk);
752     }
753     mValidPermutations.reset();
754 
755     for (vk::PipelineHelper &pipeline : mComputePipelines)
756     {
757         pipeline.release(contextVk);
758     }
759     mComputeProgramInfo.release(contextVk);
760 
761     mPipelineLayout.reset();
762 
763     contextVk->onProgramExecutableReset(this);
764 }
765 
reset(ContextVk * contextVk)766 void ProgramExecutableVk::reset(ContextVk *contextVk)
767 {
768     resetLayout(contextVk);
769 
770     if (mPipelineCache.valid())
771     {
772         mPipelineCache.destroy(contextVk->getDevice());
773     }
774 }
775 
initializePipelineCache(vk::Context * context,bool compressed,const std::vector<uint8_t> & pipelineData)776 angle::Result ProgramExecutableVk::initializePipelineCache(vk::Context *context,
777                                                            bool compressed,
778                                                            const std::vector<uint8_t> &pipelineData)
779 {
780     ASSERT(!mPipelineCache.valid());
781 
782     size_t dataSize            = pipelineData.size();
783     const uint8_t *dataPointer = pipelineData.data();
784 
785     angle::MemoryBuffer uncompressedData;
786     if (compressed)
787     {
788         if (!angle::DecompressBlob(dataPointer, dataSize, kMaxLocalPipelineCacheSize,
789                                    &uncompressedData))
790         {
791             return angle::Result::Stop;
792         }
793         dataSize    = uncompressedData.size();
794         dataPointer = uncompressedData.data();
795     }
796 
797     VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {};
798     pipelineCacheCreateInfo.sType           = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
799     pipelineCacheCreateInfo.initialDataSize = dataSize;
800     pipelineCacheCreateInfo.pInitialData    = dataPointer;
801 
802     ANGLE_VK_TRY(context, mPipelineCache.init(context->getDevice(), pipelineCacheCreateInfo));
803 
804     // Merge the pipeline cache into Renderer's.
805     if (context->getFeatures().mergeProgramPipelineCachesToGlobalCache.enabled)
806     {
807         ANGLE_TRY(context->getRenderer()->mergeIntoPipelineCache(context, mPipelineCache));
808     }
809 
810     return angle::Result::Continue;
811 }
812 
ensurePipelineCacheInitialized(vk::Context * context)813 angle::Result ProgramExecutableVk::ensurePipelineCacheInitialized(vk::Context *context)
814 {
815     if (!mPipelineCache.valid())
816     {
817         VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {};
818         pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
819 
820         ANGLE_VK_TRY(context, mPipelineCache.init(context->getDevice(), pipelineCacheCreateInfo));
821     }
822 
823     return angle::Result::Continue;
824 }
825 
load(ContextVk * contextVk,bool isSeparable,gl::BinaryInputStream * stream,egl::CacheGetResult * resultOut)826 angle::Result ProgramExecutableVk::load(ContextVk *contextVk,
827                                         bool isSeparable,
828                                         gl::BinaryInputStream *stream,
829                                         egl::CacheGetResult *resultOut)
830 {
831     mVariableInfoMap.load(stream);
832     mOriginalShaderInfo.load(stream);
833 
834     // Deserializes the uniformLayout data of mDefaultUniformBlocks
835     for (gl::ShaderType shaderType : gl::AllShaderTypes())
836     {
837         stream->readVector(&mDefaultUniformBlocks[shaderType]->uniformLayout);
838     }
839 
840     // Deserializes required uniform block memory sizes
841     gl::ShaderMap<size_t> requiredBufferSize;
842     stream->readPackedEnumMap(&requiredBufferSize);
843 
844     if (!isSeparable)
845     {
846         size_t compressedPipelineDataSize = 0;
847         stream->readInt<size_t>(&compressedPipelineDataSize);
848 
849         std::vector<uint8_t> compressedPipelineData(compressedPipelineDataSize);
850         if (compressedPipelineDataSize > 0)
851         {
852             bool compressedData = false;
853             stream->readBool(&compressedData);
854             stream->readBytes(compressedPipelineData.data(), compressedPipelineDataSize);
855             // Initialize the pipeline cache based on cached data.
856             ANGLE_TRY(initializePipelineCache(contextVk, compressedData, compressedPipelineData));
857         }
858     }
859 
860     // Initialize and resize the mDefaultUniformBlocks' memory
861     ANGLE_TRY(resizeUniformBlockMemory(contextVk, requiredBufferSize));
862 
863     resetLayout(contextVk);
864     ANGLE_TRY(createPipelineLayout(contextVk, &contextVk->getPipelineLayoutCache(),
865                                    &contextVk->getDescriptorSetLayoutCache(), nullptr));
866 
867     ANGLE_TRY(initializeDescriptorPools(contextVk, &contextVk->getDescriptorSetLayoutCache(),
868                                         &contextVk->getMetaDescriptorPools()));
869 
870     *resultOut = egl::CacheGetResult::Success;
871     return angle::Result::Continue;
872 }
873 
save(ContextVk * contextVk,bool isSeparable,gl::BinaryOutputStream * stream)874 void ProgramExecutableVk::save(ContextVk *contextVk,
875                                bool isSeparable,
876                                gl::BinaryOutputStream *stream)
877 {
878     mVariableInfoMap.save(stream);
879     mOriginalShaderInfo.save(stream);
880 
881     // Serializes the uniformLayout data of mDefaultUniformBlocks
882     for (gl::ShaderType shaderType : gl::AllShaderTypes())
883     {
884         stream->writeVector(mDefaultUniformBlocks[shaderType]->uniformLayout);
885     }
886 
887     // Serializes required uniform block memory sizes
888     gl::ShaderMap<size_t> uniformDataSize;
889     for (gl::ShaderType shaderType : gl::AllShaderTypes())
890     {
891         uniformDataSize[shaderType] = mDefaultUniformBlocks[shaderType]->uniformData.size();
892     }
893     stream->writePackedEnumMap(uniformDataSize);
894 
895     // Need to wait for warm up tasks to complete.
896     waitForPostLinkTasksImpl(contextVk);
897 
898     // Compress and save mPipelineCache.  Separable programs don't warm up the cache, while program
899     // pipelines do.  However, currently ANGLE doesn't sync program pipelines to cache.  ANGLE could
900     // potentially use VK_EXT_graphics_pipeline_library to create separate pipelines for
901     // pre-rasterization and fragment subsets, but currently those subsets are bundled together.
902     if (!isSeparable)
903     {
904         angle::MemoryBuffer cacheData;
905 
906         GetPipelineCacheData(contextVk, mPipelineCache, &cacheData);
907         stream->writeInt(cacheData.size());
908         if (cacheData.size() > 0)
909         {
910             stream->writeBool(contextVk->getFeatures().enablePipelineCacheDataCompression.enabled);
911             stream->writeBytes(cacheData.data(), cacheData.size());
912         }
913     }
914 }
915 
clearVariableInfoMap()916 void ProgramExecutableVk::clearVariableInfoMap()
917 {
918     mVariableInfoMap.clear();
919 }
920 
getPipelineCacheWarmUpTasks(vk::Renderer * renderer,vk::PipelineRobustness pipelineRobustness,vk::PipelineProtectedAccess pipelineProtectedAccess,vk::GraphicsPipelineSubset subset,std::vector<std::shared_ptr<LinkSubTask>> * postLinkSubTasksOut)921 angle::Result ProgramExecutableVk::getPipelineCacheWarmUpTasks(
922     vk::Renderer *renderer,
923     vk::PipelineRobustness pipelineRobustness,
924     vk::PipelineProtectedAccess pipelineProtectedAccess,
925     vk::GraphicsPipelineSubset subset,
926     std::vector<std::shared_ptr<LinkSubTask>> *postLinkSubTasksOut)
927 {
928     ASSERT(!postLinkSubTasksOut || postLinkSubTasksOut->empty());
929 
930     bool isCompute                                        = false;
931     angle::FixedVector<bool, 2> surfaceRotationVariations = {false};
932     vk::GraphicsPipelineDesc *graphicsPipelineDesc        = nullptr;
933     vk::RenderPass compatibleRenderPass;
934 
935     WarmUpTaskCommon prepForWarmUpContext(renderer);
936     ANGLE_TRY(prepareForWarmUpPipelineCache(
937         &prepForWarmUpContext, pipelineRobustness, pipelineProtectedAccess, subset, &isCompute,
938         &surfaceRotationVariations, &graphicsPipelineDesc, &compatibleRenderPass));
939 
940     std::vector<std::shared_ptr<rx::LinkSubTask>> warmUpSubTasks;
941     if (isCompute)
942     {
943         ASSERT(!compatibleRenderPass.valid());
944 
945         warmUpSubTasks.push_back(std::make_shared<WarmUpComputeTask>(
946             renderer, this, pipelineRobustness, pipelineProtectedAccess));
947     }
948     else
949     {
950         ProgramTransformOptions transformOptions = {};
951         SharedRenderPass *sharedRenderPass = new SharedRenderPass(std::move(compatibleRenderPass));
952         for (bool surfaceRotation : surfaceRotationVariations)
953         {
954             // Add a placeholder entry in GraphicsPipelineCache
955             transformOptions.surfaceRotation   = surfaceRotation;
956             const uint8_t programIndex         = transformOptions.permutationIndex;
957             vk::PipelineHelper *pipelineHelper = nullptr;
958             if (subset == vk::GraphicsPipelineSubset::Complete)
959             {
960                 CompleteGraphicsPipelineCache &pipelines = mCompleteGraphicsPipelines[programIndex];
961                 pipelines.populate(mWarmUpGraphicsPipelineDesc, vk::Pipeline(), &pipelineHelper);
962             }
963             else
964             {
965                 ASSERT(subset == vk::GraphicsPipelineSubset::Shaders);
966                 ShadersGraphicsPipelineCache &pipelines = mShadersGraphicsPipelines[programIndex];
967                 pipelines.populate(mWarmUpGraphicsPipelineDesc, vk::Pipeline(), &pipelineHelper);
968             }
969 
970             warmUpSubTasks.push_back(std::make_shared<WarmUpGraphicsTask>(
971                 renderer, this, pipelineRobustness, pipelineProtectedAccess, subset,
972                 surfaceRotation, *graphicsPipelineDesc, sharedRenderPass, pipelineHelper));
973         }
974     }
975 
976     // If the caller hasn't provided a valid async task container, inline the warmUp tasks.
977     if (postLinkSubTasksOut)
978     {
979         *postLinkSubTasksOut = std::move(warmUpSubTasks);
980     }
981     else
982     {
983         for (std::shared_ptr<rx::LinkSubTask> &task : warmUpSubTasks)
984         {
985             (*task)();
986         }
987         warmUpSubTasks.clear();
988     }
989 
990     ASSERT(warmUpSubTasks.empty());
991 
992     return angle::Result::Continue;
993 }
994 
prepareForWarmUpPipelineCache(vk::Context * context,vk::PipelineRobustness pipelineRobustness,vk::PipelineProtectedAccess pipelineProtectedAccess,vk::GraphicsPipelineSubset subset,bool * isComputeOut,angle::FixedVector<bool,2> * surfaceRotationVariationsOut,vk::GraphicsPipelineDesc ** graphicsPipelineDescOut,vk::RenderPass * renderPassOut)995 angle::Result ProgramExecutableVk::prepareForWarmUpPipelineCache(
996     vk::Context *context,
997     vk::PipelineRobustness pipelineRobustness,
998     vk::PipelineProtectedAccess pipelineProtectedAccess,
999     vk::GraphicsPipelineSubset subset,
1000     bool *isComputeOut,
1001     angle::FixedVector<bool, 2> *surfaceRotationVariationsOut,
1002     vk::GraphicsPipelineDesc **graphicsPipelineDescOut,
1003     vk::RenderPass *renderPassOut)
1004 {
1005     ASSERT(isComputeOut);
1006     ASSERT(surfaceRotationVariationsOut);
1007     ASSERT(graphicsPipelineDescOut);
1008     ASSERT(renderPassOut);
1009     ASSERT(context->getFeatures().warmUpPipelineCacheAtLink.enabled);
1010 
1011     ANGLE_TRY(ensurePipelineCacheInitialized(context));
1012 
1013     *isComputeOut        = false;
1014     const bool isCompute = mExecutable->hasLinkedShaderStage(gl::ShaderType::Compute);
1015     if (isCompute)
1016     {
1017         // Initialize compute program.
1018         ANGLE_TRY(initComputeProgram(context, &mComputeProgramInfo, mVariableInfoMap));
1019 
1020         *isComputeOut = true;
1021         return angle::Result::Continue;
1022     }
1023 
1024     // It is only at drawcall time that we will have complete information required to build the
1025     // graphics pipeline descriptor. Use the most "commonly seen" state values and create the
1026     // pipeline.
1027     gl::PrimitiveMode mode = (mExecutable->hasLinkedShaderStage(gl::ShaderType::TessControl) ||
1028                               mExecutable->hasLinkedShaderStage(gl::ShaderType::TessEvaluation))
1029                                  ? gl::PrimitiveMode::Patches
1030                                  : gl::PrimitiveMode::TriangleStrip;
1031     SetupDefaultPipelineState(context, *mExecutable, mode, pipelineRobustness,
1032                               pipelineProtectedAccess, subset, &mWarmUpGraphicsPipelineDesc);
1033 
1034     // Create a temporary compatible RenderPass.  The render pass cache in ContextVk cannot be used
1035     // because this function may be called from a worker thread.
1036     vk::AttachmentOpsArray ops;
1037     RenderPassCache::InitializeOpsForCompatibleRenderPass(
1038         mWarmUpGraphicsPipelineDesc.getRenderPassDesc(), &ops);
1039     ANGLE_TRY(RenderPassCache::MakeRenderPass(
1040         context, mWarmUpGraphicsPipelineDesc.getRenderPassDesc(), ops, renderPassOut, nullptr));
1041 
1042     *graphicsPipelineDescOut = &mWarmUpGraphicsPipelineDesc;
1043 
1044     // Variations that definitely matter:
1045     //
1046     // - PreRotation: It's a boolean specialization constant
1047     // - Depth correction: It's a SPIR-V transformation
1048     //
1049     // There are a number of states that are not currently dynamic (and may never be, such as sample
1050     // shading), but pre-creating shaders for them is impractical.  Most such state is likely unused
1051     // by most applications, but variations can be added here for certain apps that are known to
1052     // benefit from it.
1053     *surfaceRotationVariationsOut = {false};
1054     if (context->getFeatures().enablePreRotateSurfaces.enabled &&
1055         !context->getFeatures().preferDriverUniformOverSpecConst.enabled)
1056     {
1057         surfaceRotationVariationsOut->push_back(true);
1058     }
1059 
1060     ProgramTransformOptions transformOptions = {};
1061     for (bool rotation : *surfaceRotationVariationsOut)
1062     {
1063         // Initialize graphics programs.
1064         transformOptions.surfaceRotation = rotation;
1065         ANGLE_TRY(initGraphicsShaderPrograms(context, transformOptions));
1066     }
1067 
1068     return angle::Result::Continue;
1069 }
1070 
warmUpComputePipelineCache(vk::Context * context,vk::PipelineRobustness pipelineRobustness,vk::PipelineProtectedAccess pipelineProtectedAccess)1071 angle::Result ProgramExecutableVk::warmUpComputePipelineCache(
1072     vk::Context *context,
1073     vk::PipelineRobustness pipelineRobustness,
1074     vk::PipelineProtectedAccess pipelineProtectedAccess)
1075 {
1076     ANGLE_TRACE_EVENT0("gpu.angle", "ProgramExecutableVk::warmUpComputePipelineCache");
1077 
1078     // This method assumes that all the state necessary to create a compute pipeline has already
1079     // been setup by the caller. Assert that all required state is valid so all that is left will
1080     // be the call to `vkCreateComputePipelines`
1081 
1082     // Make sure the shader module for compute shader stage is valid.
1083     ASSERT(mComputeProgramInfo.valid(gl::ShaderType::Compute));
1084 
1085     // No synchronization necessary since mPipelineCache is internally synchronized.
1086     vk::PipelineCacheAccess pipelineCache;
1087     pipelineCache.init(&mPipelineCache, nullptr);
1088 
1089     // There is no state associated with compute programs, so only one pipeline needs creation
1090     // to warm up the cache.
1091     vk::PipelineHelper *pipeline = nullptr;
1092     ANGLE_TRY(getOrCreateComputePipeline(context, &pipelineCache, PipelineSource::WarmUp,
1093                                          pipelineRobustness, pipelineProtectedAccess, &pipeline));
1094 
1095     return angle::Result::Continue;
1096 }
1097 
warmUpGraphicsPipelineCache(vk::Context * context,vk::PipelineRobustness pipelineRobustness,vk::PipelineProtectedAccess pipelineProtectedAccess,vk::GraphicsPipelineSubset subset,const bool isSurfaceRotated,const vk::GraphicsPipelineDesc & graphicsPipelineDesc,const vk::RenderPass & renderPass,vk::PipelineHelper * placeholderPipelineHelper)1098 angle::Result ProgramExecutableVk::warmUpGraphicsPipelineCache(
1099     vk::Context *context,
1100     vk::PipelineRobustness pipelineRobustness,
1101     vk::PipelineProtectedAccess pipelineProtectedAccess,
1102     vk::GraphicsPipelineSubset subset,
1103     const bool isSurfaceRotated,
1104     const vk::GraphicsPipelineDesc &graphicsPipelineDesc,
1105     const vk::RenderPass &renderPass,
1106     vk::PipelineHelper *placeholderPipelineHelper)
1107 {
1108     ANGLE_TRACE_EVENT0("gpu.angle", "ProgramExecutableVk::warmUpGraphicsPipelineCache");
1109 
1110     ASSERT(placeholderPipelineHelper && !placeholderPipelineHelper->valid());
1111 
1112     // No synchronization necessary since mPipelineCache is internally synchronized.
1113     vk::PipelineCacheAccess pipelineCache;
1114     pipelineCache.init(&mPipelineCache, nullptr);
1115 
1116     const vk::GraphicsPipelineDesc *descPtr  = nullptr;
1117     ProgramTransformOptions transformOptions = {};
1118     transformOptions.surfaceRotation         = isSurfaceRotated;
1119 
1120     ANGLE_TRY(createGraphicsPipelineImpl(context, transformOptions, subset, &pipelineCache,
1121                                          PipelineSource::WarmUp, graphicsPipelineDesc, renderPass,
1122                                          &descPtr, &placeholderPipelineHelper));
1123 
1124     ASSERT(placeholderPipelineHelper->valid());
1125     return angle::Result::Continue;
1126 }
1127 
waitForPostLinkTasksImpl(ContextVk * contextVk)1128 void ProgramExecutableVk::waitForPostLinkTasksImpl(ContextVk *contextVk)
1129 {
1130     const std::vector<std::shared_ptr<rx::LinkSubTask>> &postLinkSubTasks =
1131         mExecutable->getPostLinkSubTasks();
1132 
1133     if (postLinkSubTasks.empty())
1134     {
1135         return;
1136     }
1137 
1138     // Wait for all post-link tasks to finish
1139     angle::WaitableEvent::WaitMany(&mExecutable->getPostLinkSubTaskWaitableEvents());
1140 
1141     // Get results and clean up
1142     for (const std::shared_ptr<rx::LinkSubTask> &task : postLinkSubTasks)
1143     {
1144         WarmUpTaskCommon *warmUpTask = static_cast<WarmUpTaskCommon *>(task.get());
1145 
1146         // As these tasks can be run post-link, their results are ignored.  Failure is harmless, but
1147         // more importantly the error (effectively due to a link event) may not be allowed through
1148         // the entry point that results in this call.
1149         gl::InfoLog infoLog;
1150         angle::Result result = warmUpTask->getResultImpl(contextVk, infoLog);
1151         if (result != angle::Result::Continue)
1152         {
1153             ANGLE_PERF_WARNING(contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW,
1154                                "Post-link task unexpectedly failed. Performance may degrade, or "
1155                                "device may soon be lost");
1156         }
1157     }
1158 
1159     mExecutable->onPostLinkTasksComplete();
1160 }
1161 
waitForGraphicsPostLinkTasks(ContextVk * contextVk,const vk::GraphicsPipelineDesc & currentGraphicsPipelineDesc)1162 void ProgramExecutableVk::waitForGraphicsPostLinkTasks(
1163     ContextVk *contextVk,
1164     const vk::GraphicsPipelineDesc &currentGraphicsPipelineDesc)
1165 {
1166     ASSERT(mExecutable->hasLinkedShaderStage(gl::ShaderType::Vertex));
1167 
1168     if (mExecutable->getPostLinkSubTasks().empty())
1169     {
1170         return;
1171     }
1172 
1173     const vk::GraphicsPipelineSubset subset =
1174         contextVk->getFeatures().supportsGraphicsPipelineLibrary.enabled
1175             ? vk::GraphicsPipelineSubset::Shaders
1176             : vk::GraphicsPipelineSubset::Complete;
1177 
1178     if (!mWarmUpGraphicsPipelineDesc.keyEqual(currentGraphicsPipelineDesc, subset))
1179     {
1180         // The GraphicsPipelineDesc used for warmup differs from the one used by the draw call.
1181         // There is no need to wait for the warmup tasks to complete.
1182         ANGLE_PERF_WARNING(
1183             contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW,
1184             "GraphicsPipelineDesc used for warmup differs from the one used by draw.");
1185 
1186         // If the warm up tasks are finished anyway, let |waitForPostLinkTasksImpl| clean them up.
1187         if (!angle::WaitableEvent::AllReady(&mExecutable->getPostLinkSubTaskWaitableEvents()))
1188         {
1189             return;
1190         }
1191     }
1192 
1193     waitForPostLinkTasksImpl(contextVk);
1194 }
1195 
mergePipelineCacheToRenderer(vk::Context * context) const1196 angle::Result ProgramExecutableVk::mergePipelineCacheToRenderer(vk::Context *context) const
1197 {
1198     // Merge the cache with Renderer's
1199     if (context->getFeatures().mergeProgramPipelineCachesToGlobalCache.enabled)
1200     {
1201         ANGLE_TRACE_EVENT0("gpu.angle", "ProgramExecutableVk::mergePipelineCacheToRenderer");
1202         ANGLE_TRY(context->getRenderer()->mergeIntoPipelineCache(context, mPipelineCache));
1203     }
1204 
1205     return angle::Result::Continue;
1206 }
1207 
addInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> & blocks,gl::ShaderBitSet shaderTypes,VkDescriptorType descType,vk::DescriptorSetLayoutDesc * descOut)1208 void ProgramExecutableVk::addInterfaceBlockDescriptorSetDesc(
1209     const std::vector<gl::InterfaceBlock> &blocks,
1210     gl::ShaderBitSet shaderTypes,
1211     VkDescriptorType descType,
1212     vk::DescriptorSetLayoutDesc *descOut)
1213 {
1214     for (uint32_t bufferIndex = 0, arraySize = 0; bufferIndex < blocks.size();
1215          bufferIndex += arraySize)
1216     {
1217         gl::InterfaceBlock block = blocks[bufferIndex];
1218         arraySize                = GetInterfaceBlockArraySize(blocks, bufferIndex);
1219 
1220         if (block.activeShaders().none())
1221         {
1222             continue;
1223         }
1224 
1225         const gl::ShaderType firstShaderType = block.getFirstActiveShaderType();
1226         const ShaderInterfaceVariableInfo &info =
1227             mVariableInfoMap.getVariableById(firstShaderType, block.getId(firstShaderType));
1228 
1229         const VkShaderStageFlags activeStages = gl_vk::GetShaderStageFlags(info.activeStages);
1230 
1231         descOut->update(info.binding, descType, arraySize, activeStages, nullptr);
1232     }
1233 }
1234 
addAtomicCounterBufferDescriptorSetDesc(const std::vector<gl::AtomicCounterBuffer> & atomicCounterBuffers,vk::DescriptorSetLayoutDesc * descOut)1235 void ProgramExecutableVk::addAtomicCounterBufferDescriptorSetDesc(
1236     const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
1237     vk::DescriptorSetLayoutDesc *descOut)
1238 {
1239     if (atomicCounterBuffers.empty())
1240     {
1241         return;
1242     }
1243 
1244     const ShaderInterfaceVariableInfo &info =
1245         mVariableInfoMap.getAtomicCounterInfo(atomicCounterBuffers[0].getFirstActiveShaderType());
1246     VkShaderStageFlags activeStages = gl_vk::GetShaderStageFlags(info.activeStages);
1247 
1248     // A single storage buffer array is used for all stages for simplicity.
1249     descOut->update(info.binding, vk::kStorageBufferDescriptorType,
1250                     gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, activeStages, nullptr);
1251 }
1252 
addImageDescriptorSetDesc(vk::DescriptorSetLayoutDesc * descOut)1253 void ProgramExecutableVk::addImageDescriptorSetDesc(vk::DescriptorSetLayoutDesc *descOut)
1254 {
1255     const std::vector<gl::ImageBinding> &imageBindings = mExecutable->getImageBindings();
1256     const std::vector<gl::LinkedUniform> &uniforms     = mExecutable->getUniforms();
1257 
1258     for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
1259     {
1260         uint32_t uniformIndex = mExecutable->getUniformIndexFromImageIndex(imageIndex);
1261         const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
1262 
1263         // 2D arrays are split into multiple 1D arrays when generating LinkedUniforms. Since they
1264         // are flattened into one array, ignore the nonzero elements and expand the array to the
1265         // total array size.
1266         if (imageUniform.activeShaders().none() || imageUniform.getOuterArrayOffset() > 0)
1267         {
1268             ASSERT(gl::SamplerNameContainsNonZeroArrayElement(
1269                 mExecutable->getUniformNameByIndex(uniformIndex)));
1270             continue;
1271         }
1272 
1273         ASSERT(!gl::SamplerNameContainsNonZeroArrayElement(
1274             mExecutable->getUniformNameByIndex(uniformIndex)));
1275 
1276         // The front-end always binds array image units sequentially.
1277         const gl::ImageBinding &imageBinding = imageBindings[imageIndex];
1278         uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
1279         arraySize *= imageUniform.getOuterArraySizeProduct();
1280 
1281         const gl::ShaderType firstShaderType = imageUniform.getFirstActiveShaderType();
1282         const ShaderInterfaceVariableInfo &info =
1283             mVariableInfoMap.getVariableById(firstShaderType, imageUniform.getId(firstShaderType));
1284 
1285         const VkShaderStageFlags activeStages = gl_vk::GetShaderStageFlags(info.activeStages);
1286 
1287         const VkDescriptorType descType = imageBinding.textureType == gl::TextureType::Buffer
1288                                               ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
1289                                               : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
1290         descOut->update(info.binding, descType, arraySize, activeStages, nullptr);
1291     }
1292 }
1293 
addInputAttachmentDescriptorSetDesc(vk::DescriptorSetLayoutDesc * descOut)1294 void ProgramExecutableVk::addInputAttachmentDescriptorSetDesc(vk::DescriptorSetLayoutDesc *descOut)
1295 {
1296     if (!mExecutable->getLinkedShaderStages()[gl::ShaderType::Fragment])
1297     {
1298         return;
1299     }
1300 
1301     if (!mExecutable->usesFramebufferFetch())
1302     {
1303         return;
1304     }
1305 
1306     const uint32_t firstInputAttachment =
1307         static_cast<uint32_t>(mExecutable->getFragmentInoutIndices().first());
1308 
1309     const ShaderInterfaceVariableInfo &baseInfo = mVariableInfoMap.getVariableById(
1310         gl::ShaderType::Fragment, sh::vk::spirv::kIdInputAttachment0 + firstInputAttachment);
1311 
1312     uint32_t baseBinding = baseInfo.binding - firstInputAttachment;
1313 
1314     for (uint32_t colorIndex = 0; colorIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorIndex)
1315     {
1316         descOut->update(baseBinding, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1,
1317                         VK_SHADER_STAGE_FRAGMENT_BIT, nullptr);
1318         baseBinding++;
1319     }
1320 }
1321 
addTextureDescriptorSetDesc(vk::Context * context,const gl::ActiveTextureArray<TextureVk * > * activeTextures,vk::DescriptorSetLayoutDesc * descOut)1322 angle::Result ProgramExecutableVk::addTextureDescriptorSetDesc(
1323     vk::Context *context,
1324     const gl::ActiveTextureArray<TextureVk *> *activeTextures,
1325     vk::DescriptorSetLayoutDesc *descOut)
1326 {
1327     const std::vector<gl::SamplerBinding> &samplerBindings = mExecutable->getSamplerBindings();
1328     const std::vector<gl::LinkedUniform> &uniforms         = mExecutable->getUniforms();
1329     const std::vector<GLuint> &samplerBoundTextureUnits =
1330         mExecutable->getSamplerBoundTextureUnits();
1331 
1332     for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
1333     {
1334         uint32_t uniformIndex = mExecutable->getUniformIndexFromSamplerIndex(samplerIndex);
1335         const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
1336 
1337         // 2D arrays are split into multiple 1D arrays when generating LinkedUniforms. Since they
1338         // are flattened into one array, ignore the nonzero elements and expand the array to the
1339         // total array size.
1340         if (samplerUniform.activeShaders().none() || samplerUniform.getOuterArrayOffset() > 0)
1341         {
1342             ASSERT(gl::SamplerNameContainsNonZeroArrayElement(
1343                 mExecutable->getUniformNameByIndex(uniformIndex)));
1344             continue;
1345         }
1346 
1347         ASSERT(!gl::SamplerNameContainsNonZeroArrayElement(
1348             mExecutable->getUniformNameByIndex(uniformIndex)));
1349 
1350         // The front-end always binds array sampler units sequentially.
1351         const gl::SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
1352         uint32_t arraySize = static_cast<uint32_t>(samplerBinding.textureUnitsCount);
1353         arraySize *= samplerUniform.getOuterArraySizeProduct();
1354 
1355         const gl::ShaderType firstShaderType    = samplerUniform.getFirstActiveShaderType();
1356         const ShaderInterfaceVariableInfo &info = mVariableInfoMap.getVariableById(
1357             firstShaderType, samplerUniform.getId(firstShaderType));
1358 
1359         const VkShaderStageFlags activeStages = gl_vk::GetShaderStageFlags(info.activeStages);
1360 
1361         // TODO: https://issuetracker.google.com/issues/158215272: how do we handle array of
1362         // immutable samplers?
1363         GLuint textureUnit = samplerBinding.getTextureUnit(samplerBoundTextureUnits, 0);
1364         if (activeTextures != nullptr &&
1365             (*activeTextures)[textureUnit]->getImage().hasImmutableSampler())
1366         {
1367             ASSERT(samplerBinding.textureUnitsCount == 1);
1368 
1369             // In the case of samplerExternal2DY2YEXT, we need
1370             // samplerYcbcrConversion object with IDENTITY conversion model
1371             bool isSamplerExternalY2Y =
1372                 samplerBinding.samplerType == GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT;
1373 
1374             // Always take the texture's sampler, that's only way to get to yuv conversion for
1375             // externalFormat
1376             const TextureVk *textureVk          = (*activeTextures)[textureUnit];
1377             const vk::Sampler &immutableSampler = textureVk->getSampler(isSamplerExternalY2Y).get();
1378             descOut->update(info.binding, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, arraySize,
1379                             activeStages, &immutableSampler);
1380             const vk::ImageHelper &image = textureVk->getImage();
1381             const vk::YcbcrConversionDesc ycbcrConversionDesc =
1382                 isSamplerExternalY2Y ? image.getY2YConversionDesc()
1383                                      : image.getYcbcrConversionDesc();
1384             mImmutableSamplerIndexMap[ycbcrConversionDesc] = samplerIndex;
1385             // The Vulkan spec has the following note -
1386             // All descriptors in a binding use the same maximum
1387             // combinedImageSamplerDescriptorCount descriptors to allow implementations to use a
1388             // uniform stride for dynamic indexing of the descriptors in the binding.
1389             uint64_t externalFormat        = image.getExternalFormat();
1390             uint32_t formatDescriptorCount = 0;
1391 
1392             vk::Renderer *renderer = context->getRenderer();
1393 
1394             if (externalFormat != 0)
1395             {
1396                 ANGLE_TRY(renderer->getFormatDescriptorCountForExternalFormat(
1397                     context, externalFormat, &formatDescriptorCount));
1398             }
1399             else
1400             {
1401                 VkFormat vkFormat = image.getActualVkFormat();
1402                 ASSERT(vkFormat != 0);
1403                 ANGLE_TRY(renderer->getFormatDescriptorCountForVkFormat(context, vkFormat,
1404                                                                         &formatDescriptorCount));
1405             }
1406 
1407             ASSERT(formatDescriptorCount > 0);
1408             mImmutableSamplersMaxDescriptorCount =
1409                 std::max(mImmutableSamplersMaxDescriptorCount, formatDescriptorCount);
1410         }
1411         else
1412         {
1413             const VkDescriptorType descType = samplerBinding.textureType == gl::TextureType::Buffer
1414                                                   ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
1415                                                   : VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1416             descOut->update(info.binding, descType, arraySize, activeStages, nullptr);
1417         }
1418     }
1419 
1420     return angle::Result::Continue;
1421 }
1422 
initializeWriteDescriptorDesc(vk::Context * context)1423 void ProgramExecutableVk::initializeWriteDescriptorDesc(vk::Context *context)
1424 {
1425     const gl::ShaderBitSet &linkedShaderStages = mExecutable->getLinkedShaderStages();
1426 
1427     // Update mShaderResourceWriteDescriptorDescBuilder
1428     mShaderResourceWriteDescriptorDescs.reset();
1429     mShaderResourceWriteDescriptorDescs.updateShaderBuffers(
1430         mVariableInfoMap, mExecutable->getUniformBlocks(), getUniformBufferDescriptorType());
1431     mShaderResourceWriteDescriptorDescs.updateShaderBuffers(
1432         mVariableInfoMap, mExecutable->getShaderStorageBlocks(), getStorageBufferDescriptorType());
1433     mShaderResourceWriteDescriptorDescs.updateAtomicCounters(
1434         mVariableInfoMap, mExecutable->getAtomicCounterBuffers());
1435     mShaderResourceWriteDescriptorDescs.updateImages(*mExecutable, mVariableInfoMap);
1436     mShaderResourceWriteDescriptorDescs.updateDynamicDescriptorsCount();
1437 
1438     // Update mTextureWriteDescriptors
1439     mTextureWriteDescriptorDescs.reset();
1440     mTextureWriteDescriptorDescs.updateExecutableActiveTextures(mVariableInfoMap, *mExecutable);
1441     mTextureWriteDescriptorDescs.updateDynamicDescriptorsCount();
1442 
1443     // Update mDefaultUniformWriteDescriptors
1444     mDefaultUniformWriteDescriptorDescs.reset();
1445     mDefaultUniformWriteDescriptorDescs.updateDefaultUniform(linkedShaderStages, mVariableInfoMap,
1446                                                              *mExecutable);
1447     mDefaultUniformWriteDescriptorDescs.updateDynamicDescriptorsCount();
1448 
1449     mDefaultUniformAndXfbWriteDescriptorDescs.reset();
1450     if (mExecutable->hasTransformFeedbackOutput() &&
1451         context->getRenderer()->getFeatures().emulateTransformFeedback.enabled)
1452     {
1453         // Update mDefaultUniformAndXfbWriteDescriptorDescs for the emulation code path.
1454         mDefaultUniformAndXfbWriteDescriptorDescs.updateDefaultUniform(
1455             linkedShaderStages, mVariableInfoMap, *mExecutable);
1456         if (linkedShaderStages[gl::ShaderType::Vertex])
1457         {
1458             mDefaultUniformAndXfbWriteDescriptorDescs.updateTransformFeedbackWrite(mVariableInfoMap,
1459                                                                                    *mExecutable);
1460         }
1461         mDefaultUniformAndXfbWriteDescriptorDescs.updateDynamicDescriptorsCount();
1462     }
1463     else
1464     {
1465         // Otherwise it will be the same as default uniform
1466         mDefaultUniformAndXfbWriteDescriptorDescs = mDefaultUniformWriteDescriptorDescs;
1467     }
1468 }
1469 
getTransformOptions(ContextVk * contextVk,const vk::GraphicsPipelineDesc & desc)1470 ProgramTransformOptions ProgramExecutableVk::getTransformOptions(
1471     ContextVk *contextVk,
1472     const vk::GraphicsPipelineDesc &desc)
1473 {
1474     ProgramTransformOptions transformOptions = {};
1475 
1476     transformOptions.surfaceRotation = desc.getSurfaceRotation();
1477     transformOptions.removeTransformFeedbackEmulation =
1478         contextVk->getFeatures().emulateTransformFeedback.enabled &&
1479         !contextVk->getState().isTransformFeedbackActiveUnpaused();
1480     FramebufferVk *drawFrameBuffer = vk::GetImpl(contextVk->getState().getDrawFramebuffer());
1481     const bool hasFramebufferFetch = mExecutable->usesFramebufferFetch();
1482     const bool isMultisampled      = drawFrameBuffer->getSamples() > 1;
1483     transformOptions.multiSampleFramebufferFetch = hasFramebufferFetch && isMultisampled;
1484     transformOptions.enableSampleShading =
1485         contextVk->getState().isSampleShadingEnabled() && isMultisampled;
1486 
1487     return transformOptions;
1488 }
1489 
initGraphicsShaderPrograms(vk::Context * context,ProgramTransformOptions transformOptions)1490 angle::Result ProgramExecutableVk::initGraphicsShaderPrograms(
1491     vk::Context *context,
1492     ProgramTransformOptions transformOptions)
1493 {
1494     ASSERT(mExecutable->hasLinkedShaderStage(gl::ShaderType::Vertex));
1495 
1496     const uint8_t programIndex                = transformOptions.permutationIndex;
1497     ProgramInfo &programInfo                  = mGraphicsProgramInfos[programIndex];
1498     const gl::ShaderBitSet linkedShaderStages = mExecutable->getLinkedShaderStages();
1499     gl::ShaderType lastPreFragmentStage       = gl::GetLastPreFragmentStage(linkedShaderStages);
1500 
1501     const bool isTransformFeedbackProgram =
1502         !mExecutable->getLinkedTransformFeedbackVaryings().empty();
1503 
1504     for (gl::ShaderType shaderType : linkedShaderStages)
1505     {
1506         ANGLE_TRY(initGraphicsShaderProgram(context, shaderType, shaderType == lastPreFragmentStage,
1507                                             isTransformFeedbackProgram, transformOptions,
1508                                             &programInfo, mVariableInfoMap));
1509     }
1510 
1511     return angle::Result::Continue;
1512 }
1513 
initProgramThenCreateGraphicsPipeline(vk::Context * context,ProgramTransformOptions transformOptions,vk::GraphicsPipelineSubset pipelineSubset,vk::PipelineCacheAccess * pipelineCache,PipelineSource source,const vk::GraphicsPipelineDesc & desc,const vk::RenderPass & compatibleRenderPass,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)1514 angle::Result ProgramExecutableVk::initProgramThenCreateGraphicsPipeline(
1515     vk::Context *context,
1516     ProgramTransformOptions transformOptions,
1517     vk::GraphicsPipelineSubset pipelineSubset,
1518     vk::PipelineCacheAccess *pipelineCache,
1519     PipelineSource source,
1520     const vk::GraphicsPipelineDesc &desc,
1521     const vk::RenderPass &compatibleRenderPass,
1522     const vk::GraphicsPipelineDesc **descPtrOut,
1523     vk::PipelineHelper **pipelineOut)
1524 {
1525     ANGLE_TRY(initGraphicsShaderPrograms(context, transformOptions));
1526 
1527     return createGraphicsPipelineImpl(context, transformOptions, pipelineSubset, pipelineCache,
1528                                       source, desc, compatibleRenderPass, descPtrOut, pipelineOut);
1529 }
1530 
createGraphicsPipelineImpl(vk::Context * context,ProgramTransformOptions transformOptions,vk::GraphicsPipelineSubset pipelineSubset,vk::PipelineCacheAccess * pipelineCache,PipelineSource source,const vk::GraphicsPipelineDesc & desc,const vk::RenderPass & compatibleRenderPass,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)1531 angle::Result ProgramExecutableVk::createGraphicsPipelineImpl(
1532     vk::Context *context,
1533     ProgramTransformOptions transformOptions,
1534     vk::GraphicsPipelineSubset pipelineSubset,
1535     vk::PipelineCacheAccess *pipelineCache,
1536     PipelineSource source,
1537     const vk::GraphicsPipelineDesc &desc,
1538     const vk::RenderPass &compatibleRenderPass,
1539     const vk::GraphicsPipelineDesc **descPtrOut,
1540     vk::PipelineHelper **pipelineOut)
1541 {
1542     // This method assumes that all the state necessary to create a graphics pipeline has already
1543     // been setup by the caller. Assert that all required state is valid so all that is left will
1544     // be the call to `vkCreateGraphicsPipelines`
1545 
1546     // Make sure program index is within range
1547     const uint8_t programIndex = transformOptions.permutationIndex;
1548     ASSERT(programIndex >= 0 && programIndex < ProgramTransformOptions::kPermutationCount);
1549 
1550     // Make sure the shader modules for all linked shader stages are valid.
1551     ProgramInfo &programInfo = mGraphicsProgramInfos[programIndex];
1552     for (gl::ShaderType shaderType : mExecutable->getLinkedShaderStages())
1553     {
1554         ASSERT(programInfo.valid(shaderType));
1555     }
1556 
1557     // Generate spec consts, a change in which results in a new pipeline.
1558     vk::SpecializationConstants specConsts = MakeSpecConsts(transformOptions, desc);
1559 
1560     // Choose appropriate pipeline cache based on pipeline subset
1561     if (pipelineSubset == vk::GraphicsPipelineSubset::Complete)
1562     {
1563         CompleteGraphicsPipelineCache &pipelines = mCompleteGraphicsPipelines[programIndex];
1564         return programInfo.getShaderProgram().createGraphicsPipeline(
1565             context, &pipelines, pipelineCache, compatibleRenderPass, getPipelineLayout(), source,
1566             desc, specConsts, descPtrOut, pipelineOut);
1567     }
1568     else
1569     {
1570         // Vertex input and fragment output subsets are independent of shaders, and are not created
1571         // through the program executable.
1572         ASSERT(pipelineSubset == vk::GraphicsPipelineSubset::Shaders);
1573 
1574         ShadersGraphicsPipelineCache &pipelines = mShadersGraphicsPipelines[programIndex];
1575         return programInfo.getShaderProgram().createGraphicsPipeline(
1576             context, &pipelines, pipelineCache, compatibleRenderPass, getPipelineLayout(), source,
1577             desc, specConsts, descPtrOut, pipelineOut);
1578     }
1579 }
1580 
getGraphicsPipeline(ContextVk * contextVk,vk::GraphicsPipelineSubset pipelineSubset,const vk::GraphicsPipelineDesc & desc,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)1581 angle::Result ProgramExecutableVk::getGraphicsPipeline(ContextVk *contextVk,
1582                                                        vk::GraphicsPipelineSubset pipelineSubset,
1583                                                        const vk::GraphicsPipelineDesc &desc,
1584                                                        const vk::GraphicsPipelineDesc **descPtrOut,
1585                                                        vk::PipelineHelper **pipelineOut)
1586 {
1587     ProgramTransformOptions transformOptions = getTransformOptions(contextVk, desc);
1588 
1589     ANGLE_TRY(initGraphicsShaderPrograms(contextVk, transformOptions));
1590 
1591     const uint8_t programIndex = transformOptions.permutationIndex;
1592 
1593     *descPtrOut  = nullptr;
1594     *pipelineOut = nullptr;
1595 
1596     if (pipelineSubset == vk::GraphicsPipelineSubset::Complete)
1597     {
1598         mCompleteGraphicsPipelines[programIndex].getPipeline(desc, descPtrOut, pipelineOut);
1599     }
1600     else
1601     {
1602         // Vertex input and fragment output subsets are independent of shaders, and are not created
1603         // through the program executable.
1604         ASSERT(pipelineSubset == vk::GraphicsPipelineSubset::Shaders);
1605 
1606         mShadersGraphicsPipelines[programIndex].getPipeline(desc, descPtrOut, pipelineOut);
1607     }
1608 
1609     return angle::Result::Continue;
1610 }
1611 
createGraphicsPipeline(ContextVk * contextVk,vk::GraphicsPipelineSubset pipelineSubset,vk::PipelineCacheAccess * pipelineCache,PipelineSource source,const vk::GraphicsPipelineDesc & desc,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)1612 angle::Result ProgramExecutableVk::createGraphicsPipeline(
1613     ContextVk *contextVk,
1614     vk::GraphicsPipelineSubset pipelineSubset,
1615     vk::PipelineCacheAccess *pipelineCache,
1616     PipelineSource source,
1617     const vk::GraphicsPipelineDesc &desc,
1618     const vk::GraphicsPipelineDesc **descPtrOut,
1619     vk::PipelineHelper **pipelineOut)
1620 {
1621     ProgramTransformOptions transformOptions = getTransformOptions(contextVk, desc);
1622 
1623     // When creating monolithic pipelines, the renderer's pipeline cache is used as passed in.
1624     // When creating the shaders subset of pipelines, the program's own pipeline cache is used.
1625     vk::PipelineCacheAccess perProgramPipelineCache;
1626     const bool useProgramPipelineCache = pipelineSubset == vk::GraphicsPipelineSubset::Shaders;
1627     if (useProgramPipelineCache)
1628     {
1629         ANGLE_TRY(ensurePipelineCacheInitialized(contextVk));
1630 
1631         perProgramPipelineCache.init(&mPipelineCache, nullptr);
1632         pipelineCache = &perProgramPipelineCache;
1633     }
1634 
1635     // Pull in a compatible RenderPass.
1636     const vk::RenderPass *compatibleRenderPass = nullptr;
1637     ANGLE_TRY(contextVk->getRenderPassCache().getCompatibleRenderPass(
1638         contextVk, desc.getRenderPassDesc(), &compatibleRenderPass));
1639 
1640     ANGLE_TRY(initProgramThenCreateGraphicsPipeline(
1641         contextVk, transformOptions, pipelineSubset, pipelineCache, source, desc,
1642         *compatibleRenderPass, descPtrOut, pipelineOut));
1643 
1644     if (useProgramPipelineCache &&
1645         contextVk->getFeatures().mergeProgramPipelineCachesToGlobalCache.enabled)
1646     {
1647         ANGLE_TRY(contextVk->getRenderer()->mergeIntoPipelineCache(contextVk, mPipelineCache));
1648     }
1649 
1650     return angle::Result::Continue;
1651 }
1652 
linkGraphicsPipelineLibraries(ContextVk * contextVk,vk::PipelineCacheAccess * pipelineCache,const vk::GraphicsPipelineDesc & desc,vk::PipelineHelper * vertexInputPipeline,vk::PipelineHelper * shadersPipeline,vk::PipelineHelper * fragmentOutputPipeline,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)1653 angle::Result ProgramExecutableVk::linkGraphicsPipelineLibraries(
1654     ContextVk *contextVk,
1655     vk::PipelineCacheAccess *pipelineCache,
1656     const vk::GraphicsPipelineDesc &desc,
1657     vk::PipelineHelper *vertexInputPipeline,
1658     vk::PipelineHelper *shadersPipeline,
1659     vk::PipelineHelper *fragmentOutputPipeline,
1660     const vk::GraphicsPipelineDesc **descPtrOut,
1661     vk::PipelineHelper **pipelineOut)
1662 {
1663     ProgramTransformOptions transformOptions = getTransformOptions(contextVk, desc);
1664     const uint8_t programIndex               = transformOptions.permutationIndex;
1665 
1666     ANGLE_TRY(mCompleteGraphicsPipelines[programIndex].linkLibraries(
1667         contextVk, pipelineCache, desc, getPipelineLayout(), vertexInputPipeline, shadersPipeline,
1668         fragmentOutputPipeline, descPtrOut, pipelineOut));
1669 
1670     // If monolithic pipelines are preferred over libraries, create a task so that it can be created
1671     // asynchronously.
1672     if (contextVk->getFeatures().preferMonolithicPipelinesOverLibraries.enabled)
1673     {
1674         vk::SpecializationConstants specConsts = MakeSpecConsts(transformOptions, desc);
1675 
1676         mGraphicsProgramInfos[programIndex].getShaderProgram().createMonolithicPipelineCreationTask(
1677             contextVk, pipelineCache, desc, getPipelineLayout(), specConsts, *pipelineOut);
1678     }
1679 
1680     return angle::Result::Continue;
1681 }
1682 
getOrCreateComputePipeline(vk::Context * context,vk::PipelineCacheAccess * pipelineCache,PipelineSource source,vk::PipelineRobustness pipelineRobustness,vk::PipelineProtectedAccess pipelineProtectedAccess,vk::PipelineHelper ** pipelineOut)1683 angle::Result ProgramExecutableVk::getOrCreateComputePipeline(
1684     vk::Context *context,
1685     vk::PipelineCacheAccess *pipelineCache,
1686     PipelineSource source,
1687     vk::PipelineRobustness pipelineRobustness,
1688     vk::PipelineProtectedAccess pipelineProtectedAccess,
1689     vk::PipelineHelper **pipelineOut)
1690 {
1691     ASSERT(mExecutable->hasLinkedShaderStage(gl::ShaderType::Compute));
1692 
1693     ANGLE_TRY(initComputeProgram(context, &mComputeProgramInfo, mVariableInfoMap));
1694 
1695     vk::ComputePipelineFlags pipelineFlags = {};
1696     if (pipelineRobustness == vk::PipelineRobustness::Robust)
1697     {
1698         pipelineFlags.set(vk::ComputePipelineFlag::Robust);
1699     }
1700     if (pipelineProtectedAccess == vk::PipelineProtectedAccess::Protected)
1701     {
1702         pipelineFlags.set(vk::ComputePipelineFlag::Protected);
1703     }
1704 
1705     return mComputeProgramInfo.getShaderProgram().getOrCreateComputePipeline(
1706         context, &mComputePipelines, pipelineCache, getPipelineLayout(), pipelineFlags, source,
1707         pipelineOut, nullptr, nullptr);
1708 }
1709 
createPipelineLayout(vk::Context * context,PipelineLayoutCache * pipelineLayoutCache,DescriptorSetLayoutCache * descriptorSetLayoutCache,gl::ActiveTextureArray<TextureVk * > * activeTextures)1710 angle::Result ProgramExecutableVk::createPipelineLayout(
1711     vk::Context *context,
1712     PipelineLayoutCache *pipelineLayoutCache,
1713     DescriptorSetLayoutCache *descriptorSetLayoutCache,
1714     gl::ActiveTextureArray<TextureVk *> *activeTextures)
1715 {
1716     const gl::ShaderBitSet &linkedShaderStages = mExecutable->getLinkedShaderStages();
1717 
1718     // Store a reference to the pipeline and descriptor set layouts. This will create them if they
1719     // don't already exist in the cache.
1720 
1721     // Default uniforms and transform feedback:
1722     mDefaultUniformAndXfbSetDesc          = {};
1723     uint32_t numDefaultUniformDescriptors = 0;
1724     for (gl::ShaderType shaderType : linkedShaderStages)
1725     {
1726         const ShaderInterfaceVariableInfo &info =
1727             mVariableInfoMap.getDefaultUniformInfo(shaderType);
1728         // Note that currently the default uniform block is added unconditionally.
1729         ASSERT(info.activeStages[shaderType]);
1730 
1731         mDefaultUniformAndXfbSetDesc.update(info.binding, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
1732                                             1, gl_vk::kShaderStageMap[shaderType], nullptr);
1733         numDefaultUniformDescriptors++;
1734     }
1735 
1736     gl::ShaderType linkedTransformFeedbackStage = mExecutable->getLinkedTransformFeedbackStage();
1737     bool hasXfbVaryings = linkedTransformFeedbackStage != gl::ShaderType::InvalidEnum &&
1738                           !mExecutable->getLinkedTransformFeedbackVaryings().empty();
1739     if (context->getFeatures().emulateTransformFeedback.enabled && hasXfbVaryings)
1740     {
1741         size_t xfbBufferCount = mExecutable->getTransformFeedbackBufferCount();
1742         for (uint32_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
1743         {
1744             const uint32_t binding = mVariableInfoMap.getEmulatedXfbBufferBinding(bufferIndex);
1745             ASSERT(binding != std::numeric_limits<uint32_t>::max());
1746 
1747             mDefaultUniformAndXfbSetDesc.update(binding, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
1748                                                 VK_SHADER_STAGE_VERTEX_BIT, nullptr);
1749         }
1750     }
1751 
1752     ANGLE_TRY(descriptorSetLayoutCache->getDescriptorSetLayout(
1753         context, mDefaultUniformAndXfbSetDesc,
1754         &mDescriptorSetLayouts[DescriptorSetIndex::UniformsAndXfb]));
1755 
1756     // Uniform and storage buffers, atomic counter buffers and images:
1757     mShaderResourceSetDesc = {};
1758 
1759     // Count the number of active uniform buffer descriptors.
1760     uint32_t numActiveUniformBufferDescriptors    = 0;
1761     const std::vector<gl::InterfaceBlock> &blocks = mExecutable->getUniformBlocks();
1762     for (uint32_t bufferIndex = 0; bufferIndex < blocks.size();)
1763     {
1764         const gl::InterfaceBlock &block = blocks[bufferIndex];
1765         const uint32_t arraySize        = GetInterfaceBlockArraySize(blocks, bufferIndex);
1766         bufferIndex += arraySize;
1767 
1768         if (block.activeShaders().any())
1769         {
1770             numActiveUniformBufferDescriptors += arraySize;
1771         }
1772     }
1773 
1774     // Decide if we should use dynamic or fixed descriptor types.
1775     VkPhysicalDeviceLimits limits = context->getRenderer()->getPhysicalDeviceProperties().limits;
1776     uint32_t totalDynamicUniformBufferCount =
1777         numActiveUniformBufferDescriptors + numDefaultUniformDescriptors;
1778     if (totalDynamicUniformBufferCount <= limits.maxDescriptorSetUniformBuffersDynamic)
1779     {
1780         mUniformBufferDescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
1781     }
1782     else
1783     {
1784         mUniformBufferDescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1785     }
1786 
1787     addInterfaceBlockDescriptorSetDesc(mExecutable->getUniformBlocks(), linkedShaderStages,
1788                                        mUniformBufferDescriptorType, &mShaderResourceSetDesc);
1789     addInterfaceBlockDescriptorSetDesc(mExecutable->getShaderStorageBlocks(), linkedShaderStages,
1790                                        vk::kStorageBufferDescriptorType, &mShaderResourceSetDesc);
1791     addAtomicCounterBufferDescriptorSetDesc(mExecutable->getAtomicCounterBuffers(),
1792                                             &mShaderResourceSetDesc);
1793     addImageDescriptorSetDesc(&mShaderResourceSetDesc);
1794     addInputAttachmentDescriptorSetDesc(&mShaderResourceSetDesc);
1795 
1796     ANGLE_TRY(descriptorSetLayoutCache->getDescriptorSetLayout(
1797         context, mShaderResourceSetDesc,
1798         &mDescriptorSetLayouts[DescriptorSetIndex::ShaderResource]));
1799 
1800     // Textures:
1801     mTextureSetDesc = {};
1802     ANGLE_TRY(addTextureDescriptorSetDesc(context, activeTextures, &mTextureSetDesc));
1803 
1804     ANGLE_TRY(descriptorSetLayoutCache->getDescriptorSetLayout(
1805         context, mTextureSetDesc, &mDescriptorSetLayouts[DescriptorSetIndex::Texture]));
1806 
1807     // Create pipeline layout with these 3 descriptor sets.
1808     vk::PipelineLayoutDesc pipelineLayoutDesc;
1809     pipelineLayoutDesc.updateDescriptorSetLayout(DescriptorSetIndex::UniformsAndXfb,
1810                                                  mDefaultUniformAndXfbSetDesc);
1811     pipelineLayoutDesc.updateDescriptorSetLayout(DescriptorSetIndex::ShaderResource,
1812                                                  mShaderResourceSetDesc);
1813     pipelineLayoutDesc.updateDescriptorSetLayout(DescriptorSetIndex::Texture, mTextureSetDesc);
1814 
1815     // Set up driver uniforms as push constants. The size is set for a graphics pipeline, as there
1816     // are more driver uniforms for a graphics pipeline than there are for a compute pipeline. As
1817     // for the shader stages, both graphics and compute stages are used.
1818     VkShaderStageFlags pushConstantShaderStageFlags =
1819         context->getRenderer()->getSupportedVulkanShaderStageMask();
1820 
1821     uint32_t pushConstantSize = GetDriverUniformSize(context, PipelineType::Graphics);
1822     pipelineLayoutDesc.updatePushConstantRange(pushConstantShaderStageFlags, 0, pushConstantSize);
1823 
1824     ANGLE_TRY(pipelineLayoutCache->getPipelineLayout(context, pipelineLayoutDesc,
1825                                                      mDescriptorSetLayouts, &mPipelineLayout));
1826 
1827     mDynamicUniformDescriptorOffsets.clear();
1828     mDynamicUniformDescriptorOffsets.resize(mExecutable->getLinkedShaderStageCount(), 0);
1829 
1830     initializeWriteDescriptorDesc(context);
1831 
1832     return angle::Result::Continue;
1833 }
1834 
initializeDescriptorPools(vk::Context * context,DescriptorSetLayoutCache * descriptorSetLayoutCache,vk::DescriptorSetArray<vk::MetaDescriptorPool> * metaDescriptorPools)1835 angle::Result ProgramExecutableVk::initializeDescriptorPools(
1836     vk::Context *context,
1837     DescriptorSetLayoutCache *descriptorSetLayoutCache,
1838     vk::DescriptorSetArray<vk::MetaDescriptorPool> *metaDescriptorPools)
1839 {
1840     ANGLE_TRY((*metaDescriptorPools)[DescriptorSetIndex::UniformsAndXfb].bindCachedDescriptorPool(
1841         context, mDefaultUniformAndXfbSetDesc, 1, descriptorSetLayoutCache,
1842         &mDescriptorPools[DescriptorSetIndex::UniformsAndXfb]));
1843     ANGLE_TRY((*metaDescriptorPools)[DescriptorSetIndex::Texture].bindCachedDescriptorPool(
1844         context, mTextureSetDesc, mImmutableSamplersMaxDescriptorCount, descriptorSetLayoutCache,
1845         &mDescriptorPools[DescriptorSetIndex::Texture]));
1846     return (*metaDescriptorPools)[DescriptorSetIndex::ShaderResource].bindCachedDescriptorPool(
1847         context, mShaderResourceSetDesc, 1, descriptorSetLayoutCache,
1848         &mDescriptorPools[DescriptorSetIndex::ShaderResource]);
1849 }
1850 
resolvePrecisionMismatch(const gl::ProgramMergedVaryings & mergedVaryings)1851 void ProgramExecutableVk::resolvePrecisionMismatch(const gl::ProgramMergedVaryings &mergedVaryings)
1852 {
1853     for (const gl::ProgramVaryingRef &mergedVarying : mergedVaryings)
1854     {
1855         if (!mergedVarying.frontShader || !mergedVarying.backShader)
1856         {
1857             continue;
1858         }
1859 
1860         GLenum frontPrecision = mergedVarying.frontShader->precision;
1861         GLenum backPrecision  = mergedVarying.backShader->precision;
1862         if (frontPrecision == backPrecision)
1863         {
1864             continue;
1865         }
1866 
1867         ASSERT(frontPrecision >= GL_LOW_FLOAT && frontPrecision <= GL_HIGH_INT);
1868         ASSERT(backPrecision >= GL_LOW_FLOAT && backPrecision <= GL_HIGH_INT);
1869 
1870         if (frontPrecision > backPrecision)
1871         {
1872             // The output is higher precision than the input
1873             ShaderInterfaceVariableInfo &info = mVariableInfoMap.getMutable(
1874                 mergedVarying.frontShaderStage, mergedVarying.frontShader->id);
1875             info.varyingIsOutput     = true;
1876             info.useRelaxedPrecision = true;
1877         }
1878         else
1879         {
1880             // The output is lower precision than the input, adjust the input
1881             ASSERT(backPrecision > frontPrecision);
1882             ShaderInterfaceVariableInfo &info = mVariableInfoMap.getMutable(
1883                 mergedVarying.backShaderStage, mergedVarying.backShader->id);
1884             info.varyingIsInput      = true;
1885             info.useRelaxedPrecision = true;
1886         }
1887     }
1888 }
1889 
getOrAllocateDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::CommandBufferHelperCommon * commandBufferHelper,const vk::DescriptorSetDescBuilder & descriptorSetDesc,const vk::WriteDescriptorDescs & writeDescriptorDescs,DescriptorSetIndex setIndex,vk::SharedDescriptorSetCacheKey * newSharedCacheKeyOut)1890 angle::Result ProgramExecutableVk::getOrAllocateDescriptorSet(
1891     vk::Context *context,
1892     UpdateDescriptorSetsBuilder *updateBuilder,
1893     vk::CommandBufferHelperCommon *commandBufferHelper,
1894     const vk::DescriptorSetDescBuilder &descriptorSetDesc,
1895     const vk::WriteDescriptorDescs &writeDescriptorDescs,
1896     DescriptorSetIndex setIndex,
1897     vk::SharedDescriptorSetCacheKey *newSharedCacheKeyOut)
1898 {
1899     ANGLE_TRY(mDescriptorPools[setIndex].get().getOrAllocateDescriptorSet(
1900         context, commandBufferHelper, descriptorSetDesc.getDesc(),
1901         mDescriptorSetLayouts[setIndex].get(), &mDescriptorPoolBindings[setIndex],
1902         &mDescriptorSets[setIndex], newSharedCacheKeyOut));
1903     ASSERT(mDescriptorSets[setIndex] != VK_NULL_HANDLE);
1904 
1905     if (*newSharedCacheKeyOut != nullptr)
1906     {
1907         // Cache miss. A new cache entry has been created.
1908         descriptorSetDesc.updateDescriptorSet(context->getRenderer(), writeDescriptorDescs,
1909                                               updateBuilder, mDescriptorSets[setIndex]);
1910     }
1911     else
1912     {
1913         commandBufferHelper->retainResource(&mDescriptorPoolBindings[setIndex].get());
1914     }
1915 
1916     return angle::Result::Continue;
1917 }
1918 
updateShaderResourcesDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,const vk::WriteDescriptorDescs & writeDescriptorDescs,vk::CommandBufferHelperCommon * commandBufferHelper,const vk::DescriptorSetDescBuilder & shaderResourcesDesc,vk::SharedDescriptorSetCacheKey * newSharedCacheKeyOut)1919 angle::Result ProgramExecutableVk::updateShaderResourcesDescriptorSet(
1920     vk::Context *context,
1921     UpdateDescriptorSetsBuilder *updateBuilder,
1922     const vk::WriteDescriptorDescs &writeDescriptorDescs,
1923     vk::CommandBufferHelperCommon *commandBufferHelper,
1924     const vk::DescriptorSetDescBuilder &shaderResourcesDesc,
1925     vk::SharedDescriptorSetCacheKey *newSharedCacheKeyOut)
1926 {
1927     if (!mDescriptorPools[DescriptorSetIndex::ShaderResource].get().valid())
1928     {
1929         *newSharedCacheKeyOut = nullptr;
1930         return angle::Result::Continue;
1931     }
1932 
1933     ANGLE_TRY(getOrAllocateDescriptorSet(context, updateBuilder, commandBufferHelper,
1934                                          shaderResourcesDesc, writeDescriptorDescs,
1935                                          DescriptorSetIndex::ShaderResource, newSharedCacheKeyOut));
1936 
1937     size_t numOffsets = writeDescriptorDescs.getDynamicDescriptorSetCount();
1938     mDynamicShaderResourceDescriptorOffsets.resize(numOffsets);
1939     if (numOffsets > 0)
1940     {
1941         memcpy(mDynamicShaderResourceDescriptorOffsets.data(),
1942                shaderResourcesDesc.getDynamicOffsets(), numOffsets * sizeof(uint32_t));
1943     }
1944 
1945     return angle::Result::Continue;
1946 }
1947 
updateUniformsAndXfbDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,const vk::WriteDescriptorDescs & writeDescriptorDescs,vk::CommandBufferHelperCommon * commandBufferHelper,vk::BufferHelper * defaultUniformBuffer,vk::DescriptorSetDescBuilder * uniformsAndXfbDesc,vk::SharedDescriptorSetCacheKey * sharedCacheKeyOut)1948 angle::Result ProgramExecutableVk::updateUniformsAndXfbDescriptorSet(
1949     vk::Context *context,
1950     UpdateDescriptorSetsBuilder *updateBuilder,
1951     const vk::WriteDescriptorDescs &writeDescriptorDescs,
1952     vk::CommandBufferHelperCommon *commandBufferHelper,
1953     vk::BufferHelper *defaultUniformBuffer,
1954     vk::DescriptorSetDescBuilder *uniformsAndXfbDesc,
1955     vk::SharedDescriptorSetCacheKey *sharedCacheKeyOut)
1956 {
1957     mCurrentDefaultUniformBufferSerial =
1958         defaultUniformBuffer ? defaultUniformBuffer->getBufferSerial() : vk::kInvalidBufferSerial;
1959 
1960     return getOrAllocateDescriptorSet(context, updateBuilder, commandBufferHelper,
1961                                       *uniformsAndXfbDesc, writeDescriptorDescs,
1962                                       DescriptorSetIndex::UniformsAndXfb, sharedCacheKeyOut);
1963 }
1964 
updateTexturesDescriptorSet(vk::Context * context,const gl::ActiveTextureArray<TextureVk * > & textures,const gl::SamplerBindingVector & samplers,bool emulateSeamfulCubeMapSampling,PipelineType pipelineType,UpdateDescriptorSetsBuilder * updateBuilder,vk::CommandBufferHelperCommon * commandBufferHelper,const vk::DescriptorSetDesc & texturesDesc)1965 angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(
1966     vk::Context *context,
1967     const gl::ActiveTextureArray<TextureVk *> &textures,
1968     const gl::SamplerBindingVector &samplers,
1969     bool emulateSeamfulCubeMapSampling,
1970     PipelineType pipelineType,
1971     UpdateDescriptorSetsBuilder *updateBuilder,
1972     vk::CommandBufferHelperCommon *commandBufferHelper,
1973     const vk::DescriptorSetDesc &texturesDesc)
1974 {
1975     vk::SharedDescriptorSetCacheKey newSharedCacheKey;
1976     ANGLE_TRY(mDescriptorPools[DescriptorSetIndex::Texture].get().getOrAllocateDescriptorSet(
1977         context, commandBufferHelper, texturesDesc,
1978         mDescriptorSetLayouts[DescriptorSetIndex::Texture].get(),
1979         &mDescriptorPoolBindings[DescriptorSetIndex::Texture],
1980         &mDescriptorSets[DescriptorSetIndex::Texture], &newSharedCacheKey));
1981     ASSERT(mDescriptorSets[DescriptorSetIndex::Texture] != VK_NULL_HANDLE);
1982 
1983     if (newSharedCacheKey != nullptr)
1984     {
1985         vk::DescriptorSetDescBuilder fullDesc(
1986             mTextureWriteDescriptorDescs.getTotalDescriptorCount());
1987         // Cache miss. A new cache entry has been created.
1988         ANGLE_TRY(fullDesc.updateFullActiveTextures(
1989             context, mVariableInfoMap, mTextureWriteDescriptorDescs, *mExecutable, textures,
1990             samplers, emulateSeamfulCubeMapSampling, pipelineType, newSharedCacheKey));
1991         fullDesc.updateDescriptorSet(context->getRenderer(), mTextureWriteDescriptorDescs,
1992                                      updateBuilder, mDescriptorSets[DescriptorSetIndex::Texture]);
1993     }
1994     else
1995     {
1996         commandBufferHelper->retainResource(
1997             &mDescriptorPoolBindings[DescriptorSetIndex::Texture].get());
1998     }
1999 
2000     return angle::Result::Continue;
2001 }
2002 
2003 template <typename CommandBufferT>
bindDescriptorSets(vk::Context * context,vk::CommandBufferHelperCommon * commandBufferHelper,CommandBufferT * commandBuffer,PipelineType pipelineType)2004 angle::Result ProgramExecutableVk::bindDescriptorSets(
2005     vk::Context *context,
2006     vk::CommandBufferHelperCommon *commandBufferHelper,
2007     CommandBufferT *commandBuffer,
2008     PipelineType pipelineType)
2009 {
2010     // Can probably use better dirty bits here.
2011 
2012     // Find the maximum non-null descriptor set.  This is used in conjunction with a driver
2013     // workaround to bind empty descriptor sets only for gaps in between 0 and max and avoid
2014     // binding unnecessary empty descriptor sets for the sets beyond max.
2015     DescriptorSetIndex lastNonNullDescriptorSetIndex = DescriptorSetIndex::InvalidEnum;
2016     for (DescriptorSetIndex descriptorSetIndex : angle::AllEnums<DescriptorSetIndex>())
2017     {
2018         if (mDescriptorSets[descriptorSetIndex] != VK_NULL_HANDLE)
2019         {
2020             lastNonNullDescriptorSetIndex = descriptorSetIndex;
2021         }
2022     }
2023 
2024     const VkPipelineBindPoint pipelineBindPoint = pipelineType == PipelineType::Compute
2025                                                       ? VK_PIPELINE_BIND_POINT_COMPUTE
2026                                                       : VK_PIPELINE_BIND_POINT_GRAPHICS;
2027 
2028     for (DescriptorSetIndex descriptorSetIndex : angle::AllEnums<DescriptorSetIndex>())
2029     {
2030         if (ToUnderlying(descriptorSetIndex) > ToUnderlying(lastNonNullDescriptorSetIndex))
2031         {
2032             continue;
2033         }
2034 
2035         VkDescriptorSet descSet = mDescriptorSets[descriptorSetIndex];
2036         if (descSet == VK_NULL_HANDLE)
2037         {
2038             continue;
2039         }
2040 
2041         // Default uniforms are encompassed in a block per shader stage, and they are assigned
2042         // through dynamic uniform buffers (requiring dynamic offsets).  No other descriptor
2043         // requires a dynamic offset.
2044         if (descriptorSetIndex == DescriptorSetIndex::UniformsAndXfb)
2045         {
2046             commandBuffer->bindDescriptorSets(
2047                 getPipelineLayout(), pipelineBindPoint, descriptorSetIndex, 1, &descSet,
2048                 static_cast<uint32_t>(mDynamicUniformDescriptorOffsets.size()),
2049                 mDynamicUniformDescriptorOffsets.data());
2050         }
2051         else if (descriptorSetIndex == DescriptorSetIndex::ShaderResource)
2052         {
2053             commandBuffer->bindDescriptorSets(
2054                 getPipelineLayout(), pipelineBindPoint, descriptorSetIndex, 1, &descSet,
2055                 static_cast<uint32_t>(mDynamicShaderResourceDescriptorOffsets.size()),
2056                 mDynamicShaderResourceDescriptorOffsets.data());
2057         }
2058         else
2059         {
2060             commandBuffer->bindDescriptorSets(getPipelineLayout(), pipelineBindPoint,
2061                                               descriptorSetIndex, 1, &descSet, 0, nullptr);
2062         }
2063     }
2064 
2065     return angle::Result::Continue;
2066 }
2067 
2068 template angle::Result ProgramExecutableVk::bindDescriptorSets<vk::priv::SecondaryCommandBuffer>(
2069     vk::Context *context,
2070     vk::CommandBufferHelperCommon *commandBufferHelper,
2071     vk::priv::SecondaryCommandBuffer *commandBuffer,
2072     PipelineType pipelineType);
2073 template angle::Result ProgramExecutableVk::bindDescriptorSets<vk::VulkanSecondaryCommandBuffer>(
2074     vk::Context *context,
2075     vk::CommandBufferHelperCommon *commandBufferHelper,
2076     vk::VulkanSecondaryCommandBuffer *commandBuffer,
2077     PipelineType pipelineType);
2078 
setAllDefaultUniformsDirty()2079 void ProgramExecutableVk::setAllDefaultUniformsDirty()
2080 {
2081     mDefaultUniformBlocksDirty.reset();
2082     for (gl::ShaderType shaderType : mExecutable->getLinkedShaderStages())
2083     {
2084         if (!mDefaultUniformBlocks[shaderType]->uniformData.empty())
2085         {
2086             mDefaultUniformBlocksDirty.set(shaderType);
2087         }
2088     }
2089 }
2090 
updateUniforms(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::CommandBufferHelperCommon * commandBufferHelper,vk::BufferHelper * emptyBuffer,vk::DynamicBuffer * defaultUniformStorage,bool isTransformFeedbackActiveUnpaused,TransformFeedbackVk * transformFeedbackVk)2091 angle::Result ProgramExecutableVk::updateUniforms(
2092     vk::Context *context,
2093     UpdateDescriptorSetsBuilder *updateBuilder,
2094     vk::CommandBufferHelperCommon *commandBufferHelper,
2095     vk::BufferHelper *emptyBuffer,
2096     vk::DynamicBuffer *defaultUniformStorage,
2097     bool isTransformFeedbackActiveUnpaused,
2098     TransformFeedbackVk *transformFeedbackVk)
2099 {
2100     ASSERT(mDefaultUniformBlocksDirty.any());
2101 
2102     vk::BufferHelper *defaultUniformBuffer;
2103     bool anyNewBufferAllocated          = false;
2104     gl::ShaderMap<VkDeviceSize> offsets = {};  // offset to the beginning of bufferData
2105     uint32_t offsetIndex                = 0;
2106     size_t requiredSpace;
2107 
2108     // We usually only update uniform data for shader stages that are actually dirty. But when the
2109     // buffer for uniform data have switched, because all shader stages are using the same buffer,
2110     // we then must update uniform data for all shader stages to keep all shader stages' uniform
2111     // data in the same buffer.
2112     requiredSpace = calcUniformUpdateRequiredSpace(context, &offsets);
2113     ASSERT(requiredSpace > 0);
2114 
2115     // Allocate space from dynamicBuffer. Always try to allocate from the current buffer first.
2116     // If that failed, we deal with fall out and try again.
2117     if (!defaultUniformStorage->allocateFromCurrentBuffer(requiredSpace, &defaultUniformBuffer))
2118     {
2119         setAllDefaultUniformsDirty();
2120 
2121         requiredSpace = calcUniformUpdateRequiredSpace(context, &offsets);
2122         ANGLE_TRY(defaultUniformStorage->allocate(context, requiredSpace, &defaultUniformBuffer,
2123                                                   &anyNewBufferAllocated));
2124     }
2125 
2126     ASSERT(defaultUniformBuffer);
2127 
2128     uint8_t *bufferData       = defaultUniformBuffer->getMappedMemory();
2129     VkDeviceSize bufferOffset = defaultUniformBuffer->getOffset();
2130     for (gl::ShaderType shaderType : mExecutable->getLinkedShaderStages())
2131     {
2132         if (mDefaultUniformBlocksDirty[shaderType])
2133         {
2134             const angle::MemoryBuffer &uniformData = mDefaultUniformBlocks[shaderType]->uniformData;
2135             memcpy(&bufferData[offsets[shaderType]], uniformData.data(), uniformData.size());
2136             mDynamicUniformDescriptorOffsets[offsetIndex] =
2137                 static_cast<uint32_t>(bufferOffset + offsets[shaderType]);
2138             mDefaultUniformBlocksDirty.reset(shaderType);
2139         }
2140         ++offsetIndex;
2141     }
2142     ANGLE_TRY(defaultUniformBuffer->flush(context->getRenderer()));
2143 
2144     // Because the uniform buffers are per context, we can't rely on dynamicBuffer's allocate
2145     // function to tell us if you have got a new buffer or not. Other program's use of the buffer
2146     // might already pushed dynamicBuffer to a new buffer. We record which buffer (represented by
2147     // the unique BufferSerial number) we were using with the current descriptor set and then we
2148     // use that recorded BufferSerial compare to the current uniform buffer to quickly detect if
2149     // there is a buffer switch or not. We need to retrieve from the descriptor set cache or
2150     // allocate a new descriptor set whenever there is uniform buffer switch.
2151     if (mCurrentDefaultUniformBufferSerial != defaultUniformBuffer->getBufferSerial())
2152     {
2153         // We need to reinitialize the descriptor sets if we newly allocated buffers since we can't
2154         // modify the descriptor sets once initialized.
2155         const vk::WriteDescriptorDescs &writeDescriptorDescs =
2156             getDefaultUniformWriteDescriptorDescs(transformFeedbackVk);
2157 
2158         vk::DescriptorSetDescBuilder uniformsAndXfbDesc(
2159             writeDescriptorDescs.getTotalDescriptorCount());
2160         uniformsAndXfbDesc.updateUniformsAndXfb(
2161             context, *mExecutable, writeDescriptorDescs, defaultUniformBuffer, *emptyBuffer,
2162             isTransformFeedbackActiveUnpaused,
2163             mExecutable->hasTransformFeedbackOutput() ? transformFeedbackVk : nullptr);
2164 
2165         vk::SharedDescriptorSetCacheKey newSharedCacheKey;
2166         ANGLE_TRY(updateUniformsAndXfbDescriptorSet(context, updateBuilder, writeDescriptorDescs,
2167                                                     commandBufferHelper, defaultUniformBuffer,
2168                                                     &uniformsAndXfbDesc, &newSharedCacheKey));
2169         if (newSharedCacheKey)
2170         {
2171             defaultUniformBuffer->getBufferBlock()->onNewDescriptorSet(newSharedCacheKey);
2172             if (mExecutable->hasTransformFeedbackOutput() &&
2173                 context->getFeatures().emulateTransformFeedback.enabled)
2174             {
2175                 transformFeedbackVk->onNewDescriptorSet(*mExecutable, newSharedCacheKey);
2176             }
2177         }
2178     }
2179 
2180     return angle::Result::Continue;
2181 }
2182 
calcUniformUpdateRequiredSpace(vk::Context * context,gl::ShaderMap<VkDeviceSize> * uniformOffsets) const2183 size_t ProgramExecutableVk::calcUniformUpdateRequiredSpace(
2184     vk::Context *context,
2185     gl::ShaderMap<VkDeviceSize> *uniformOffsets) const
2186 {
2187     size_t requiredSpace = 0;
2188     for (gl::ShaderType shaderType : mExecutable->getLinkedShaderStages())
2189     {
2190         if (mDefaultUniformBlocksDirty[shaderType])
2191         {
2192             (*uniformOffsets)[shaderType] = requiredSpace;
2193             requiredSpace += getDefaultUniformAlignedSize(context, shaderType);
2194         }
2195     }
2196     return requiredSpace;
2197 }
2198 
onProgramBind()2199 void ProgramExecutableVk::onProgramBind()
2200 {
2201     // Because all programs share default uniform buffers, when we switch programs, we have to
2202     // re-update all uniform data. We could do more tracking to avoid update if the context's
2203     // current uniform buffer is still the same buffer we last time used and buffer has not been
2204     // recycled. But statistics gathered on gfxbench shows that app always update uniform data on
2205     // program bind anyway, so not really worth it to add more tracking logic here.
2206     //
2207     // Note: if this is changed, PPO uniform checks need to be updated as well
2208     setAllDefaultUniformsDirty();
2209 }
2210 
resizeUniformBlockMemory(vk::Context * context,const gl::ShaderMap<size_t> & requiredBufferSize)2211 angle::Result ProgramExecutableVk::resizeUniformBlockMemory(
2212     vk::Context *context,
2213     const gl::ShaderMap<size_t> &requiredBufferSize)
2214 {
2215     for (gl::ShaderType shaderType : mExecutable->getLinkedShaderStages())
2216     {
2217         if (requiredBufferSize[shaderType] > 0)
2218         {
2219             if (!mDefaultUniformBlocks[shaderType]->uniformData.resize(
2220                     requiredBufferSize[shaderType]))
2221             {
2222                 ANGLE_VK_CHECK(context, false, VK_ERROR_OUT_OF_HOST_MEMORY);
2223             }
2224 
2225             // Initialize uniform buffer memory to zero by default.
2226             mDefaultUniformBlocks[shaderType]->uniformData.fill(0);
2227             mDefaultUniformBlocksDirty.set(shaderType);
2228         }
2229     }
2230 
2231     return angle::Result::Continue;
2232 }
2233 
2234 template <typename T>
getUniformImpl(GLint location,T * v,GLenum entryPointType) const2235 void ProgramExecutableVk::getUniformImpl(GLint location, T *v, GLenum entryPointType) const
2236 {
2237     const gl::VariableLocation &locationInfo = mExecutable->getUniformLocations()[location];
2238     const gl::LinkedUniform &linkedUniform   = mExecutable->getUniforms()[locationInfo.index];
2239 
2240     ASSERT(!linkedUniform.isSampler() && !linkedUniform.isImage());
2241 
2242     const gl::ShaderType shaderType = linkedUniform.getFirstActiveShaderType();
2243     ASSERT(shaderType != gl::ShaderType::InvalidEnum);
2244 
2245     const DefaultUniformBlockVk &uniformBlock = *mDefaultUniformBlocks[shaderType];
2246     const sh::BlockMemberInfo &layoutInfo     = uniformBlock.uniformLayout[location];
2247 
2248     ASSERT(linkedUniform.getUniformTypeInfo().componentType == entryPointType ||
2249            linkedUniform.getUniformTypeInfo().componentType ==
2250                gl::VariableBoolVectorType(entryPointType));
2251 
2252     if (gl::IsMatrixType(linkedUniform.getType()))
2253     {
2254         const uint8_t *ptrToElement = uniformBlock.uniformData.data() + layoutInfo.offset +
2255                                       (locationInfo.arrayIndex * layoutInfo.arrayStride);
2256         GetMatrixUniform(linkedUniform.getType(), v, reinterpret_cast<const T *>(ptrToElement),
2257                          false);
2258     }
2259     else
2260     {
2261         ReadFromDefaultUniformBlock(linkedUniform.getElementComponents(), locationInfo.arrayIndex,
2262                                     v, layoutInfo, &uniformBlock.uniformData);
2263     }
2264 }
2265 
setUniform1fv(GLint location,GLsizei count,const GLfloat * v)2266 void ProgramExecutableVk::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
2267 {
2268     SetUniformImpl(mExecutable, location, count, v, GL_FLOAT, &mDefaultUniformBlocks,
2269                    &mDefaultUniformBlocksDirty);
2270 }
2271 
setUniform2fv(GLint location,GLsizei count,const GLfloat * v)2272 void ProgramExecutableVk::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
2273 {
2274     SetUniformImpl(mExecutable, location, count, v, GL_FLOAT_VEC2, &mDefaultUniformBlocks,
2275                    &mDefaultUniformBlocksDirty);
2276 }
2277 
setUniform3fv(GLint location,GLsizei count,const GLfloat * v)2278 void ProgramExecutableVk::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
2279 {
2280     SetUniformImpl(mExecutable, location, count, v, GL_FLOAT_VEC3, &mDefaultUniformBlocks,
2281                    &mDefaultUniformBlocksDirty);
2282 }
2283 
setUniform4fv(GLint location,GLsizei count,const GLfloat * v)2284 void ProgramExecutableVk::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
2285 {
2286     SetUniformImpl(mExecutable, location, count, v, GL_FLOAT_VEC4, &mDefaultUniformBlocks,
2287                    &mDefaultUniformBlocksDirty);
2288 }
2289 
setUniform1iv(GLint location,GLsizei count,const GLint * v)2290 void ProgramExecutableVk::setUniform1iv(GLint location, GLsizei count, const GLint *v)
2291 {
2292     const gl::VariableLocation &locationInfo = mExecutable->getUniformLocations()[location];
2293     const gl::LinkedUniform &linkedUniform   = mExecutable->getUniforms()[locationInfo.index];
2294     if (linkedUniform.isSampler())
2295     {
2296         // We could potentially cache some indexing here. For now this is a no-op since the mapping
2297         // is handled entirely in ContextVk.
2298         return;
2299     }
2300 
2301     SetUniformImpl(mExecutable, location, count, v, GL_INT, &mDefaultUniformBlocks,
2302                    &mDefaultUniformBlocksDirty);
2303 }
2304 
setUniform2iv(GLint location,GLsizei count,const GLint * v)2305 void ProgramExecutableVk::setUniform2iv(GLint location, GLsizei count, const GLint *v)
2306 {
2307     SetUniformImpl(mExecutable, location, count, v, GL_INT_VEC2, &mDefaultUniformBlocks,
2308                    &mDefaultUniformBlocksDirty);
2309 }
2310 
setUniform3iv(GLint location,GLsizei count,const GLint * v)2311 void ProgramExecutableVk::setUniform3iv(GLint location, GLsizei count, const GLint *v)
2312 {
2313     SetUniformImpl(mExecutable, location, count, v, GL_INT_VEC3, &mDefaultUniformBlocks,
2314                    &mDefaultUniformBlocksDirty);
2315 }
2316 
setUniform4iv(GLint location,GLsizei count,const GLint * v)2317 void ProgramExecutableVk::setUniform4iv(GLint location, GLsizei count, const GLint *v)
2318 {
2319     SetUniformImpl(mExecutable, location, count, v, GL_INT_VEC4, &mDefaultUniformBlocks,
2320                    &mDefaultUniformBlocksDirty);
2321 }
2322 
setUniform1uiv(GLint location,GLsizei count,const GLuint * v)2323 void ProgramExecutableVk::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
2324 {
2325     SetUniformImpl(mExecutable, location, count, v, GL_UNSIGNED_INT, &mDefaultUniformBlocks,
2326                    &mDefaultUniformBlocksDirty);
2327 }
2328 
setUniform2uiv(GLint location,GLsizei count,const GLuint * v)2329 void ProgramExecutableVk::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
2330 {
2331     SetUniformImpl(mExecutable, location, count, v, GL_UNSIGNED_INT_VEC2, &mDefaultUniformBlocks,
2332                    &mDefaultUniformBlocksDirty);
2333 }
2334 
setUniform3uiv(GLint location,GLsizei count,const GLuint * v)2335 void ProgramExecutableVk::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
2336 {
2337     SetUniformImpl(mExecutable, location, count, v, GL_UNSIGNED_INT_VEC3, &mDefaultUniformBlocks,
2338                    &mDefaultUniformBlocksDirty);
2339 }
2340 
setUniform4uiv(GLint location,GLsizei count,const GLuint * v)2341 void ProgramExecutableVk::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
2342 {
2343     SetUniformImpl(mExecutable, location, count, v, GL_UNSIGNED_INT_VEC4, &mDefaultUniformBlocks,
2344                    &mDefaultUniformBlocksDirty);
2345 }
2346 
setUniformMatrix2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)2347 void ProgramExecutableVk::setUniformMatrix2fv(GLint location,
2348                                               GLsizei count,
2349                                               GLboolean transpose,
2350                                               const GLfloat *value)
2351 {
2352     SetUniformMatrixfv<2, 2>(mExecutable, location, count, transpose, value, &mDefaultUniformBlocks,
2353                              &mDefaultUniformBlocksDirty);
2354 }
2355 
setUniformMatrix3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)2356 void ProgramExecutableVk::setUniformMatrix3fv(GLint location,
2357                                               GLsizei count,
2358                                               GLboolean transpose,
2359                                               const GLfloat *value)
2360 {
2361     SetUniformMatrixfv<3, 3>(mExecutable, location, count, transpose, value, &mDefaultUniformBlocks,
2362                              &mDefaultUniformBlocksDirty);
2363 }
2364 
setUniformMatrix4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)2365 void ProgramExecutableVk::setUniformMatrix4fv(GLint location,
2366                                               GLsizei count,
2367                                               GLboolean transpose,
2368                                               const GLfloat *value)
2369 {
2370     SetUniformMatrixfv<4, 4>(mExecutable, location, count, transpose, value, &mDefaultUniformBlocks,
2371                              &mDefaultUniformBlocksDirty);
2372 }
2373 
setUniformMatrix2x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)2374 void ProgramExecutableVk::setUniformMatrix2x3fv(GLint location,
2375                                                 GLsizei count,
2376                                                 GLboolean transpose,
2377                                                 const GLfloat *value)
2378 {
2379     SetUniformMatrixfv<2, 3>(mExecutable, location, count, transpose, value, &mDefaultUniformBlocks,
2380                              &mDefaultUniformBlocksDirty);
2381 }
2382 
setUniformMatrix3x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)2383 void ProgramExecutableVk::setUniformMatrix3x2fv(GLint location,
2384                                                 GLsizei count,
2385                                                 GLboolean transpose,
2386                                                 const GLfloat *value)
2387 {
2388     SetUniformMatrixfv<3, 2>(mExecutable, location, count, transpose, value, &mDefaultUniformBlocks,
2389                              &mDefaultUniformBlocksDirty);
2390 }
2391 
setUniformMatrix2x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)2392 void ProgramExecutableVk::setUniformMatrix2x4fv(GLint location,
2393                                                 GLsizei count,
2394                                                 GLboolean transpose,
2395                                                 const GLfloat *value)
2396 {
2397     SetUniformMatrixfv<2, 4>(mExecutable, location, count, transpose, value, &mDefaultUniformBlocks,
2398                              &mDefaultUniformBlocksDirty);
2399 }
2400 
setUniformMatrix4x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)2401 void ProgramExecutableVk::setUniformMatrix4x2fv(GLint location,
2402                                                 GLsizei count,
2403                                                 GLboolean transpose,
2404                                                 const GLfloat *value)
2405 {
2406     SetUniformMatrixfv<4, 2>(mExecutable, location, count, transpose, value, &mDefaultUniformBlocks,
2407                              &mDefaultUniformBlocksDirty);
2408 }
2409 
setUniformMatrix3x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)2410 void ProgramExecutableVk::setUniformMatrix3x4fv(GLint location,
2411                                                 GLsizei count,
2412                                                 GLboolean transpose,
2413                                                 const GLfloat *value)
2414 {
2415     SetUniformMatrixfv<3, 4>(mExecutable, location, count, transpose, value, &mDefaultUniformBlocks,
2416                              &mDefaultUniformBlocksDirty);
2417 }
2418 
setUniformMatrix4x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)2419 void ProgramExecutableVk::setUniformMatrix4x3fv(GLint location,
2420                                                 GLsizei count,
2421                                                 GLboolean transpose,
2422                                                 const GLfloat *value)
2423 {
2424     SetUniformMatrixfv<4, 3>(mExecutable, location, count, transpose, value, &mDefaultUniformBlocks,
2425                              &mDefaultUniformBlocksDirty);
2426 }
2427 
getUniformfv(const gl::Context * context,GLint location,GLfloat * params) const2428 void ProgramExecutableVk::getUniformfv(const gl::Context *context,
2429                                        GLint location,
2430                                        GLfloat *params) const
2431 {
2432     getUniformImpl(location, params, GL_FLOAT);
2433 }
2434 
getUniformiv(const gl::Context * context,GLint location,GLint * params) const2435 void ProgramExecutableVk::getUniformiv(const gl::Context *context,
2436                                        GLint location,
2437                                        GLint *params) const
2438 {
2439     getUniformImpl(location, params, GL_INT);
2440 }
2441 
getUniformuiv(const gl::Context * context,GLint location,GLuint * params) const2442 void ProgramExecutableVk::getUniformuiv(const gl::Context *context,
2443                                         GLint location,
2444                                         GLuint *params) const
2445 {
2446     getUniformImpl(location, params, GL_UNSIGNED_INT);
2447 }
2448 }  // namespace rx
2449