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