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