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