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