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 "libANGLE/renderer/glslang_wrapper_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/GlslangWrapperVk.h"
16 #include "libANGLE/renderer/vulkan/ProgramPipelineVk.h"
17 #include "libANGLE/renderer/vulkan/ProgramVk.h"
18 #include "libANGLE/renderer/vulkan/TextureVk.h"
19 #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
20 #include "libANGLE/renderer/vulkan/vk_helpers.h"
21 #include "libANGLE/renderer/vulkan/vk_utils.h"
22
23 namespace rx
24 {
25 namespace
26 {
LoadShaderInterfaceVariableXfbInfo(gl::BinaryInputStream * stream,ShaderInterfaceVariableXfbInfo * xfb)27 void LoadShaderInterfaceVariableXfbInfo(gl::BinaryInputStream *stream,
28 ShaderInterfaceVariableXfbInfo *xfb)
29 {
30 xfb->buffer = stream->readInt<uint32_t>();
31 xfb->offset = stream->readInt<uint32_t>();
32 xfb->stride = stream->readInt<uint32_t>();
33 xfb->arraySize = stream->readInt<uint32_t>();
34 xfb->columnCount = stream->readInt<uint32_t>();
35 xfb->rowCount = stream->readInt<uint32_t>();
36 xfb->arrayIndex = stream->readInt<uint32_t>();
37 xfb->componentType = stream->readInt<uint32_t>();
38 xfb->arrayElements.resize(stream->readInt<size_t>());
39 for (ShaderInterfaceVariableXfbInfo &arrayElement : xfb->arrayElements)
40 {
41 LoadShaderInterfaceVariableXfbInfo(stream, &arrayElement);
42 }
43 }
44
SaveShaderInterfaceVariableXfbInfo(const ShaderInterfaceVariableXfbInfo & xfb,gl::BinaryOutputStream * stream)45 void SaveShaderInterfaceVariableXfbInfo(const ShaderInterfaceVariableXfbInfo &xfb,
46 gl::BinaryOutputStream *stream)
47 {
48 stream->writeInt(xfb.buffer);
49 stream->writeInt(xfb.offset);
50 stream->writeInt(xfb.stride);
51 stream->writeInt(xfb.arraySize);
52 stream->writeInt(xfb.columnCount);
53 stream->writeInt(xfb.rowCount);
54 stream->writeInt(xfb.arrayIndex);
55 stream->writeInt(xfb.componentType);
56 stream->writeInt(xfb.arrayElements.size());
57 for (const ShaderInterfaceVariableXfbInfo &arrayElement : xfb.arrayElements)
58 {
59 SaveShaderInterfaceVariableXfbInfo(arrayElement, stream);
60 }
61 }
62
ValidateTransformedSpirV(const gl::ShaderBitSet & linkedShaderStages,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ShaderMap<angle::spirv::Blob> & spirvBlobs)63 bool ValidateTransformedSpirV(const gl::ShaderBitSet &linkedShaderStages,
64 const ShaderInterfaceVariableInfoMap &variableInfoMap,
65 const gl::ShaderMap<angle::spirv::Blob> &spirvBlobs)
66 {
67 gl::ShaderType lastPreFragmentStage = gl::GetLastPreFragmentStage(linkedShaderStages);
68
69 for (gl::ShaderType shaderType : linkedShaderStages)
70 {
71 GlslangSpirvOptions options;
72 options.shaderType = shaderType;
73 options.preRotation = SurfaceRotation::FlippedRotated90Degrees;
74 options.negativeViewportSupported = false;
75 options.transformPositionToVulkanClipSpace = true;
76 options.removeDebugInfo = true;
77 options.isTransformFeedbackStage = shaderType == lastPreFragmentStage;
78
79 angle::spirv::Blob transformed;
80 if (GlslangWrapperVk::TransformSpirV(options, variableInfoMap, spirvBlobs[shaderType],
81 &transformed) != angle::Result::Continue)
82 {
83 return false;
84 }
85 }
86 return true;
87 }
88
IsDynamicDescriptor(VkDescriptorType descriptorType)89 constexpr bool IsDynamicDescriptor(VkDescriptorType descriptorType)
90 {
91 switch (descriptorType)
92 {
93 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
94 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
95 return true;
96 default:
97 return false;
98 }
99 }
100
101 constexpr VkDescriptorType kStorageBufferDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
102 } // namespace
103
104 DefaultUniformBlock::DefaultUniformBlock() = default;
105
106 DefaultUniformBlock::~DefaultUniformBlock() = default;
107
108 // ShaderInfo implementation.
ShaderInfo()109 ShaderInfo::ShaderInfo() {}
110
111 ShaderInfo::~ShaderInfo() = default;
112
initShaders(const gl::ShaderBitSet & linkedShaderStages,const gl::ShaderMap<const angle::spirv::Blob * > & spirvBlobs,const ShaderInterfaceVariableInfoMap & variableInfoMap)113 angle::Result ShaderInfo::initShaders(const gl::ShaderBitSet &linkedShaderStages,
114 const gl::ShaderMap<const angle::spirv::Blob *> &spirvBlobs,
115 const ShaderInterfaceVariableInfoMap &variableInfoMap)
116 {
117 clear();
118
119 for (gl::ShaderType shaderType : gl::AllShaderTypes())
120 {
121 if (spirvBlobs[shaderType] != nullptr)
122 {
123 mSpirvBlobs[shaderType] = *spirvBlobs[shaderType];
124 }
125 }
126
127 // Assert that SPIR-V transformation is correct, even if the test never issues a draw call.
128 ASSERT(ValidateTransformedSpirV(linkedShaderStages, variableInfoMap, mSpirvBlobs));
129
130 mIsInitialized = true;
131 return angle::Result::Continue;
132 }
133
initShaderFromProgram(gl::ShaderType shaderType,const ShaderInfo & programShaderInfo)134 void ShaderInfo::initShaderFromProgram(gl::ShaderType shaderType,
135 const ShaderInfo &programShaderInfo)
136 {
137 mSpirvBlobs[shaderType] = programShaderInfo.mSpirvBlobs[shaderType];
138 mIsInitialized = true;
139 }
140
clear()141 void ShaderInfo::clear()
142 {
143 for (angle::spirv::Blob &spirvBlob : mSpirvBlobs)
144 {
145 spirvBlob.clear();
146 }
147 mIsInitialized = false;
148 }
149
load(gl::BinaryInputStream * stream)150 void ShaderInfo::load(gl::BinaryInputStream *stream)
151 {
152 clear();
153
154 // Read in shader codes for all shader types
155 for (gl::ShaderType shaderType : gl::AllShaderTypes())
156 {
157 angle::spirv::Blob *spirvBlob = &mSpirvBlobs[shaderType];
158
159 // Read the SPIR-V
160 stream->readIntVector<uint32_t>(spirvBlob);
161 }
162
163 mIsInitialized = true;
164 }
165
save(gl::BinaryOutputStream * stream)166 void ShaderInfo::save(gl::BinaryOutputStream *stream)
167 {
168 ASSERT(valid());
169
170 // Write out shader codes for all shader types
171 for (gl::ShaderType shaderType : gl::AllShaderTypes())
172 {
173 const angle::spirv::Blob &spirvBlob = mSpirvBlobs[shaderType];
174
175 // Write the SPIR-V
176 stream->writeIntVector(spirvBlob);
177 }
178 }
179
180 // ProgramInfo implementation.
ProgramInfo()181 ProgramInfo::ProgramInfo() {}
182
183 ProgramInfo::~ProgramInfo() = default;
184
initProgram(ContextVk * contextVk,gl::ShaderType shaderType,bool isLastPreFragmentStage,bool isTransformFeedbackProgram,const ShaderInfo & shaderInfo,ProgramTransformOptions optionBits,const ShaderInterfaceVariableInfoMap & variableInfoMap)185 angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
186 gl::ShaderType shaderType,
187 bool isLastPreFragmentStage,
188 bool isTransformFeedbackProgram,
189 const ShaderInfo &shaderInfo,
190 ProgramTransformOptions optionBits,
191 const ShaderInterfaceVariableInfoMap &variableInfoMap)
192 {
193 const gl::ShaderMap<angle::spirv::Blob> &originalSpirvBlobs = shaderInfo.getSpirvBlobs();
194 const angle::spirv::Blob &originalSpirvBlob = originalSpirvBlobs[shaderType];
195 gl::ShaderMap<angle::spirv::Blob> transformedSpirvBlobs;
196 angle::spirv::Blob &transformedSpirvBlob = transformedSpirvBlobs[shaderType];
197
198 GlslangSpirvOptions options;
199 options.shaderType = shaderType;
200 options.removeEarlyFragmentTestsOptimization =
201 shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization;
202 options.removeDebugInfo = !contextVk->getFeatures().retainSPIRVDebugInfo.enabled;
203 options.isTransformFeedbackStage = isLastPreFragmentStage && isTransformFeedbackProgram &&
204 !optionBits.removeTransformFeedbackEmulation;
205 options.isTransformFeedbackEmulated = contextVk->getFeatures().emulateTransformFeedback.enabled;
206 options.negativeViewportSupported = contextVk->getFeatures().supportsNegativeViewport.enabled;
207
208 if (isLastPreFragmentStage)
209 {
210 options.preRotation = static_cast<SurfaceRotation>(optionBits.surfaceRotation);
211 options.transformPositionToVulkanClipSpace =
212 optionBits.enableDepthCorrection &&
213 !contextVk->getFeatures().supportsDepthClipControl.enabled;
214 }
215
216 ANGLE_TRY(GlslangWrapperVk::TransformSpirV(options, variableInfoMap, originalSpirvBlob,
217 &transformedSpirvBlob));
218 ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
219 transformedSpirvBlob.data(),
220 transformedSpirvBlob.size() * sizeof(uint32_t)));
221
222 mProgramHelper.setShader(shaderType, &mShaders[shaderType]);
223
224 mProgramHelper.setSpecializationConstant(sh::vk::SpecializationConstantId::LineRasterEmulation,
225 optionBits.enableLineRasterEmulation);
226 mProgramHelper.setSpecializationConstant(sh::vk::SpecializationConstantId::SurfaceRotation,
227 optionBits.surfaceRotation);
228
229 return angle::Result::Continue;
230 }
231
release(ContextVk * contextVk)232 void ProgramInfo::release(ContextVk *contextVk)
233 {
234 mProgramHelper.release(contextVk);
235
236 for (vk::RefCounted<vk::ShaderAndSerial> &shader : mShaders)
237 {
238 shader.get().destroy(contextVk->getDevice());
239 }
240 }
241
ProgramExecutableVk()242 ProgramExecutableVk::ProgramExecutableVk()
243 : mEmptyDescriptorSets{},
244 mNumDefaultUniformDescriptors(0),
245 mImmutableSamplersMaxDescriptorCount(1),
246 mUniformBufferDescriptorType(VK_DESCRIPTOR_TYPE_MAX_ENUM),
247 mDynamicUniformDescriptorOffsets{},
248 mPerfCounters{},
249 mCumulativePerfCounters{}
250 {
251 for (std::shared_ptr<DefaultUniformBlock> &defaultBlock : mDefaultUniformBlocks)
252 {
253 defaultBlock = std::make_shared<DefaultUniformBlock>();
254 }
255 }
256
~ProgramExecutableVk()257 ProgramExecutableVk::~ProgramExecutableVk() {}
258
reset(ContextVk * contextVk)259 void ProgramExecutableVk::reset(ContextVk *contextVk)
260 {
261 for (auto &descriptorSetLayout : mDescriptorSetLayouts)
262 {
263 descriptorSetLayout.reset();
264 }
265 mImmutableSamplersMaxDescriptorCount = 1;
266 mImmutableSamplerIndexMap.clear();
267 mPipelineLayout.reset();
268
269 mDescriptorSets.fill(VK_NULL_HANDLE);
270 mEmptyDescriptorSets.fill(VK_NULL_HANDLE);
271 mNumDefaultUniformDescriptors = 0;
272 mTransformOptions = {};
273
274 for (vk::RefCountedDescriptorPoolBinding &binding : mDescriptorPoolBindings)
275 {
276 binding.reset();
277 }
278
279 for (vk::DynamicDescriptorPool &descriptorPool : mDynamicDescriptorPools)
280 {
281 descriptorPool.release(contextVk);
282 }
283
284 mTextureDescriptorsCache.clear();
285 mUniformsAndXfbDescriptorsCache.clear();
286 mShaderBufferDescriptorsCache.clear();
287
288 // Initialize with an invalid BufferSerial
289 mCurrentDefaultUniformBufferSerial = vk::BufferSerial();
290
291 for (ProgramInfo &programInfo : mGraphicsProgramInfos)
292 {
293 programInfo.release(contextVk);
294 }
295 mComputeProgramInfo.release(contextVk);
296
297 contextVk->onProgramExecutableReset(this);
298 }
299
load(ContextVk * contextVk,const gl::ProgramExecutable & glExecutable,gl::BinaryInputStream * stream)300 std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(ContextVk *contextVk,
301 const gl::ProgramExecutable &glExecutable,
302 gl::BinaryInputStream *stream)
303 {
304 gl::ShaderMap<ShaderInterfaceVariableInfoMap::VariableTypeToInfoMap> data;
305 gl::ShaderMap<ShaderInterfaceVariableInfoMap::NameToTypeAndIndexMap> nameToTypeAndIndexMap;
306 gl::ShaderMap<ShaderInterfaceVariableInfoMap::VariableTypeToIndexMap> indexedResourceMap;
307
308 for (gl::ShaderType shaderType : gl::AllShaderTypes())
309 {
310 size_t nameCount = stream->readInt<size_t>();
311 for (size_t nameIndex = 0; nameIndex < nameCount; ++nameIndex)
312 {
313 const std::string variableName = stream->readString();
314 ShaderVariableType variableType = stream->readEnum<ShaderVariableType>();
315 uint32_t index = stream->readInt<uint32_t>();
316 nameToTypeAndIndexMap[shaderType][variableName] = {variableType, index};
317 }
318
319 for (ShaderVariableType variableType : angle::AllEnums<ShaderVariableType>())
320 {
321 size_t infoArraySize = stream->readInt<size_t>();
322 for (size_t infoIndex = 0; infoIndex < infoArraySize; ++infoIndex)
323 {
324 ShaderInterfaceVariableInfo info;
325
326 info.descriptorSet = stream->readInt<uint32_t>();
327 info.binding = stream->readInt<uint32_t>();
328 info.location = stream->readInt<uint32_t>();
329 info.component = stream->readInt<uint32_t>();
330 info.index = stream->readInt<uint32_t>();
331 // PackedEnumBitSet uses uint8_t
332 info.activeStages = gl::ShaderBitSet(stream->readInt<uint8_t>());
333 LoadShaderInterfaceVariableXfbInfo(stream, &info.xfb);
334 info.fieldXfb.resize(stream->readInt<size_t>());
335 for (ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
336 {
337 LoadShaderInterfaceVariableXfbInfo(stream, &xfb);
338 }
339 info.useRelaxedPrecision = stream->readBool();
340 info.varyingIsInput = stream->readBool();
341 info.varyingIsOutput = stream->readBool();
342 info.attributeComponentCount = stream->readInt<uint8_t>();
343 info.attributeLocationCount = stream->readInt<uint8_t>();
344 info.isDuplicate = stream->readBool();
345
346 data[shaderType][variableType].push_back(info);
347 }
348
349 uint32_t resourceMapSize = stream->readInt<uint32_t>();
350 for (uint32_t resourceIndex = 0; resourceIndex < resourceMapSize; ++resourceIndex)
351 {
352 uint32_t variableIndex = stream->readInt<uint32_t>();
353 indexedResourceMap[shaderType][variableType][resourceIndex] = variableIndex;
354 }
355 }
356 }
357
358 mVariableInfoMap.load(data, nameToTypeAndIndexMap, indexedResourceMap);
359
360 mOriginalShaderInfo.load(stream);
361
362 // Deserializes the uniformLayout data of mDefaultUniformBlocks
363 for (gl::ShaderType shaderType : gl::AllShaderTypes())
364 {
365 const size_t uniformCount = stream->readInt<size_t>();
366 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
367 {
368 sh::BlockMemberInfo blockInfo;
369 gl::LoadBlockMemberInfo(stream, &blockInfo);
370 mDefaultUniformBlocks[shaderType]->uniformLayout.push_back(blockInfo);
371 }
372 }
373
374 gl::ShaderMap<size_t> requiredBufferSize;
375 requiredBufferSize.fill(0);
376 // Deserializes required uniform block memory sizes
377 for (gl::ShaderType shaderType : gl::AllShaderTypes())
378 {
379 requiredBufferSize[shaderType] = stream->readInt<size_t>();
380 }
381
382 // Initialize and resize the mDefaultUniformBlocks' memory
383 angle::Result status = resizeUniformBlockMemory(contextVk, glExecutable, requiredBufferSize);
384 if (status != angle::Result::Continue)
385 {
386 return std::make_unique<LinkEventDone>(status);
387 }
388
389 status = createPipelineLayout(contextVk, glExecutable, nullptr);
390 return std::make_unique<LinkEventDone>(status);
391 }
392
save(gl::BinaryOutputStream * stream)393 void ProgramExecutableVk::save(gl::BinaryOutputStream *stream)
394 {
395 const gl::ShaderMap<ShaderInterfaceVariableInfoMap::VariableTypeToInfoMap> &data =
396 mVariableInfoMap.getData();
397 const gl::ShaderMap<ShaderInterfaceVariableInfoMap::NameToTypeAndIndexMap>
398 &nameToTypeAndIndexMap = mVariableInfoMap.getNameToTypeAndIndexMap();
399 const gl::ShaderMap<ShaderInterfaceVariableInfoMap::VariableTypeToIndexMap>
400 &indexedResourceMap = mVariableInfoMap.getIndexedResourceMap();
401
402 for (gl::ShaderType shaderType : gl::AllShaderTypes())
403 {
404 stream->writeInt(nameToTypeAndIndexMap[shaderType].size());
405 for (const auto &iter : nameToTypeAndIndexMap[shaderType])
406 {
407 const std::string &name = iter.first;
408 const TypeAndIndex &typeAndIndex = iter.second;
409 stream->writeString(name);
410 stream->writeEnum(typeAndIndex.variableType);
411 stream->writeInt(typeAndIndex.index);
412 }
413
414 for (ShaderVariableType variableType : angle::AllEnums<ShaderVariableType>())
415 {
416 const ShaderInterfaceVariableInfoMap::VariableInfoArray &infoArray =
417 data[shaderType][variableType];
418
419 stream->writeInt(infoArray.size());
420 for (const ShaderInterfaceVariableInfo &info : infoArray)
421 {
422 stream->writeInt(info.descriptorSet);
423 stream->writeInt(info.binding);
424 stream->writeInt(info.location);
425 stream->writeInt(info.component);
426 stream->writeInt(info.index);
427 // PackedEnumBitSet uses uint8_t
428 stream->writeInt(info.activeStages.bits());
429 SaveShaderInterfaceVariableXfbInfo(info.xfb, stream);
430 stream->writeInt(info.fieldXfb.size());
431 for (const ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
432 {
433 SaveShaderInterfaceVariableXfbInfo(xfb, stream);
434 }
435 stream->writeBool(info.useRelaxedPrecision);
436 stream->writeBool(info.varyingIsInput);
437 stream->writeBool(info.varyingIsOutput);
438 stream->writeInt(info.attributeComponentCount);
439 stream->writeInt(info.attributeLocationCount);
440 stream->writeBool(info.isDuplicate);
441 }
442
443 const ShaderInterfaceVariableInfoMap::ResourceIndexMap &resourceIndexMap =
444 indexedResourceMap[shaderType][variableType];
445 stream->writeInt(static_cast<uint32_t>(resourceIndexMap.size()));
446 for (uint32_t resourceIndex = 0; resourceIndex < resourceIndexMap.size();
447 ++resourceIndex)
448 {
449 stream->writeInt(resourceIndexMap[resourceIndex]);
450 }
451 }
452 }
453
454 mOriginalShaderInfo.save(stream);
455
456 // Serializes the uniformLayout data of mDefaultUniformBlocks
457 for (gl::ShaderType shaderType : gl::AllShaderTypes())
458 {
459 const size_t uniformCount = mDefaultUniformBlocks[shaderType]->uniformLayout.size();
460 stream->writeInt(uniformCount);
461 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
462 {
463 sh::BlockMemberInfo &blockInfo =
464 mDefaultUniformBlocks[shaderType]->uniformLayout[uniformIndex];
465 gl::WriteBlockMemberInfo(stream, blockInfo);
466 }
467 }
468
469 // Serializes required uniform block memory sizes
470 for (gl::ShaderType shaderType : gl::AllShaderTypes())
471 {
472 stream->writeInt(mDefaultUniformBlocks[shaderType]->uniformData.size());
473 }
474 }
475
clearVariableInfoMap()476 void ProgramExecutableVk::clearVariableInfoMap()
477 {
478 mVariableInfoMap.clear();
479 }
480
GetInterfaceBlockArraySize(const std::vector<gl::InterfaceBlock> & blocks,uint32_t bufferIndex)481 uint32_t GetInterfaceBlockArraySize(const std::vector<gl::InterfaceBlock> &blocks,
482 uint32_t bufferIndex)
483 {
484 const gl::InterfaceBlock &block = blocks[bufferIndex];
485
486 if (!block.isArray)
487 {
488 return 1;
489 }
490
491 ASSERT(block.arrayElement == 0);
492
493 // Search consecutively until all array indices of this block are visited.
494 uint32_t arraySize;
495 for (arraySize = 1; bufferIndex + arraySize < blocks.size(); ++arraySize)
496 {
497 const gl::InterfaceBlock &nextBlock = blocks[bufferIndex + arraySize];
498
499 if (nextBlock.arrayElement != arraySize)
500 {
501 break;
502 }
503
504 // It's unexpected for an array to start at a non-zero array size, so we can always rely on
505 // the sequential `arrayElement`s to belong to the same block.
506 ASSERT(nextBlock.name == block.name);
507 ASSERT(nextBlock.isArray);
508 }
509
510 return arraySize;
511 }
512
allocUniformAndXfbDescriptorSet(vk::Context * context,vk::ResourceUseList * resourceUseList,vk::BufferHelper * defaultUniformBuffer,const vk::DescriptorSetDesc & xfbBufferDesc,bool * newDescriptorSetAllocated)513 angle::Result ProgramExecutableVk::allocUniformAndXfbDescriptorSet(
514 vk::Context *context,
515 vk::ResourceUseList *resourceUseList,
516 vk::BufferHelper *defaultUniformBuffer,
517 const vk::DescriptorSetDesc &xfbBufferDesc,
518 bool *newDescriptorSetAllocated)
519 {
520 mCurrentDefaultUniformBufferSerial =
521 defaultUniformBuffer ? defaultUniformBuffer->getBufferSerial() : vk::kInvalidBufferSerial;
522
523 // Look up in the cache first
524 VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
525 if (mUniformsAndXfbDescriptorsCache.get(
526 xfbBufferDesc, &descriptorSet,
527 &mPerfCounters.cacheStats[DescriptorSetIndex::UniformsAndXfb]))
528 {
529 *newDescriptorSetAllocated = false;
530 mDescriptorSets[DescriptorSetIndex::UniformsAndXfb] = descriptorSet;
531 // The descriptor pool that this descriptor set was allocated from needs to be retained each
532 // time the descriptor set is used in a new command.
533 mDescriptorPoolBindings[DescriptorSetIndex::UniformsAndXfb].get().retain(resourceUseList);
534 return angle::Result::Continue;
535 }
536
537 bool newPoolAllocated;
538 ANGLE_TRY(allocateDescriptorSetAndGetInfo(
539 context, resourceUseList, DescriptorSetIndex::UniformsAndXfb, &newPoolAllocated));
540
541 // Clear descriptor set cache. It may no longer be valid.
542 if (newPoolAllocated)
543 {
544 mUniformsAndXfbDescriptorsCache.clear();
545 }
546
547 // Add the descriptor set into cache
548 mUniformsAndXfbDescriptorsCache.insert(
549 xfbBufferDesc, mDescriptorSets[DescriptorSetIndex::UniformsAndXfb],
550 &mPerfCounters.cacheStats[DescriptorSetIndex::UniformsAndXfb]);
551 *newDescriptorSetAllocated = true;
552
553 return angle::Result::Continue;
554 }
555
allocateDescriptorSet(vk::Context * context,vk::ResourceUseList * resourceUseList,DescriptorSetIndex descriptorSetIndex)556 angle::Result ProgramExecutableVk::allocateDescriptorSet(vk::Context *context,
557 vk::ResourceUseList *resourceUseList,
558 DescriptorSetIndex descriptorSetIndex)
559 {
560 bool ignoreNewPoolAllocated;
561 return allocateDescriptorSetAndGetInfo(context, resourceUseList, descriptorSetIndex,
562 &ignoreNewPoolAllocated);
563 }
564
allocateDescriptorSetAndGetInfo(vk::Context * context,vk::ResourceUseList * resourceUseList,DescriptorSetIndex descriptorSetIndex,bool * newPoolAllocatedOut)565 angle::Result ProgramExecutableVk::allocateDescriptorSetAndGetInfo(
566 vk::Context *context,
567 vk::ResourceUseList *resourceUseList,
568 DescriptorSetIndex descriptorSetIndex,
569 bool *newPoolAllocatedOut)
570 {
571 vk::DynamicDescriptorPool &dynamicDescriptorPool = mDynamicDescriptorPools[descriptorSetIndex];
572
573 const vk::DescriptorSetLayout &descriptorSetLayout =
574 mDescriptorSetLayouts[descriptorSetIndex].get();
575 ANGLE_TRY(dynamicDescriptorPool.allocateSetsAndGetInfo(
576 context, resourceUseList, descriptorSetLayout, 1,
577 &mDescriptorPoolBindings[descriptorSetIndex], &mDescriptorSets[descriptorSetIndex],
578 newPoolAllocatedOut));
579 mEmptyDescriptorSets[descriptorSetIndex] = VK_NULL_HANDLE;
580
581 return angle::Result::Continue;
582 }
583
addInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> & blocks,gl::ShaderType shaderType,ShaderVariableType variableType,VkDescriptorType descType,vk::DescriptorSetLayoutDesc * descOut)584 void ProgramExecutableVk::addInterfaceBlockDescriptorSetDesc(
585 const std::vector<gl::InterfaceBlock> &blocks,
586 gl::ShaderType shaderType,
587 ShaderVariableType variableType,
588 VkDescriptorType descType,
589 vk::DescriptorSetLayoutDesc *descOut)
590 {
591 for (uint32_t bufferIndex = 0, arraySize = 0; bufferIndex < blocks.size();
592 bufferIndex += arraySize)
593 {
594 gl::InterfaceBlock block = blocks[bufferIndex];
595 arraySize = GetInterfaceBlockArraySize(blocks, bufferIndex);
596
597 if (!block.isActive(shaderType))
598 {
599 continue;
600 }
601
602 const ShaderInterfaceVariableInfo &info =
603 mVariableInfoMap.getIndexedVariableInfo(shaderType, variableType, bufferIndex);
604 if (info.isDuplicate)
605 {
606 continue;
607 }
608
609 VkShaderStageFlags activeStages = gl_vk::GetShaderStageFlags(info.activeStages);
610
611 descOut->update(info.binding, descType, arraySize, activeStages, nullptr);
612 }
613 }
614
addAtomicCounterBufferDescriptorSetDesc(const std::vector<gl::AtomicCounterBuffer> & atomicCounterBuffers,gl::ShaderType shaderType,vk::DescriptorSetLayoutDesc * descOut)615 void ProgramExecutableVk::addAtomicCounterBufferDescriptorSetDesc(
616 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
617 gl::ShaderType shaderType,
618 vk::DescriptorSetLayoutDesc *descOut)
619 {
620 if (atomicCounterBuffers.empty() || !mVariableInfoMap.hasAtomicCounterInfo(shaderType))
621 {
622 return;
623 }
624
625 const ShaderInterfaceVariableInfo &info = mVariableInfoMap.getAtomicCounterInfo(shaderType);
626 if (info.isDuplicate || !info.activeStages[shaderType])
627 {
628 return;
629 }
630
631 VkShaderStageFlags activeStages = gl_vk::GetShaderStageFlags(info.activeStages);
632
633 // A single storage buffer array is used for all stages for simplicity.
634 descOut->update(info.binding, kStorageBufferDescriptorType,
635 gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, activeStages, nullptr);
636 }
637
addImageDescriptorSetDesc(const gl::ProgramExecutable & executable,vk::DescriptorSetLayoutDesc * descOut)638 void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable &executable,
639 vk::DescriptorSetLayoutDesc *descOut)
640 {
641 const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings();
642 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
643
644 for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
645 {
646 uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex);
647 const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
648
649 // 2D arrays are split into multiple 1D arrays when generating LinkedUniforms. Since they
650 // are flattened into one array, ignore the nonzero elements and expand the array to the
651 // total array size.
652 if (imageUniform.outerArrayOffset > 0)
653 {
654 ASSERT(gl::SamplerNameContainsNonZeroArrayElement(imageUniform.name));
655 continue;
656 }
657
658 ASSERT(!gl::SamplerNameContainsNonZeroArrayElement(imageUniform.name));
659
660 // The front-end always binds array image units sequentially.
661 const gl::ImageBinding &imageBinding = imageBindings[imageIndex];
662 uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
663 for (unsigned int outerArraySize : imageUniform.outerArraySizes)
664 {
665 arraySize *= outerArraySize;
666 }
667
668 for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
669 {
670 if (!imageUniform.isActive(shaderType))
671 {
672 continue;
673 }
674
675 const ShaderInterfaceVariableInfo &info = mVariableInfoMap.getIndexedVariableInfo(
676 shaderType, ShaderVariableType::Image, imageIndex);
677 if (info.isDuplicate)
678 {
679 continue;
680 }
681
682 VkShaderStageFlags activeStages = gl_vk::GetShaderStageFlags(info.activeStages);
683
684 const VkDescriptorType descType = imageBinding.textureType == gl::TextureType::Buffer
685 ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
686 : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
687 descOut->update(info.binding, descType, arraySize, activeStages, nullptr);
688 }
689 }
690 }
691
addInputAttachmentDescriptorSetDesc(const gl::ProgramExecutable & executable,gl::ShaderType shaderType,vk::DescriptorSetLayoutDesc * descOut)692 void ProgramExecutableVk::addInputAttachmentDescriptorSetDesc(
693 const gl::ProgramExecutable &executable,
694 gl::ShaderType shaderType,
695 vk::DescriptorSetLayoutDesc *descOut)
696 {
697 if (shaderType != gl::ShaderType::Fragment)
698 {
699 return;
700 }
701
702 if (!executable.usesFramebufferFetch())
703 {
704 return;
705 }
706
707 const ShaderInterfaceVariableInfo &baseInfo =
708 mVariableInfoMap.getFramebufferFetchInfo(shaderType);
709 if (baseInfo.isDuplicate)
710 {
711 return;
712 }
713
714 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
715 const uint32_t baseUniformIndex = executable.getFragmentInoutRange().low();
716 const gl::LinkedUniform &baseInputAttachment = uniforms.at(baseUniformIndex);
717 uint32_t baseBinding = baseInfo.binding - baseInputAttachment.location;
718
719 for (uint32_t colorIndex = 0; colorIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorIndex)
720 {
721 descOut->update(baseBinding, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1,
722 VK_SHADER_STAGE_FRAGMENT_BIT, nullptr);
723 baseBinding++;
724 }
725 }
726
addTextureDescriptorSetDesc(ContextVk * contextVk,const gl::ProgramExecutable & executable,const gl::ActiveTextureArray<vk::TextureUnit> * activeTextures,vk::DescriptorSetLayoutDesc * descOut)727 angle::Result ProgramExecutableVk::addTextureDescriptorSetDesc(
728 ContextVk *contextVk,
729 const gl::ProgramExecutable &executable,
730 const gl::ActiveTextureArray<vk::TextureUnit> *activeTextures,
731 vk::DescriptorSetLayoutDesc *descOut)
732 {
733 const std::vector<gl::SamplerBinding> &samplerBindings = executable.getSamplerBindings();
734 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
735
736 for (uint32_t textureIndex = 0; textureIndex < samplerBindings.size(); ++textureIndex)
737 {
738 uint32_t uniformIndex = executable.getUniformIndexFromSamplerIndex(textureIndex);
739 const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
740
741 // 2D arrays are split into multiple 1D arrays when generating LinkedUniforms. Since they
742 // are flattened into one array, ignore the nonzero elements and expand the array to the
743 // total array size.
744 if (samplerUniform.outerArrayOffset > 0)
745 {
746 ASSERT(gl::SamplerNameContainsNonZeroArrayElement(samplerUniform.name));
747 continue;
748 }
749
750 ASSERT(!gl::SamplerNameContainsNonZeroArrayElement(samplerUniform.name));
751
752 // The front-end always binds array sampler units sequentially.
753 const gl::SamplerBinding &samplerBinding = samplerBindings[textureIndex];
754 uint32_t arraySize = static_cast<uint32_t>(samplerBinding.boundTextureUnits.size());
755 for (unsigned int outerArraySize : samplerUniform.outerArraySizes)
756 {
757 arraySize *= outerArraySize;
758 }
759
760 for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
761 {
762 if (!samplerUniform.isActive(shaderType))
763 {
764 continue;
765 }
766
767 const ShaderInterfaceVariableInfo &info = mVariableInfoMap.getIndexedVariableInfo(
768 shaderType, ShaderVariableType::Texture, textureIndex);
769 if (info.isDuplicate)
770 {
771 continue;
772 }
773
774 VkShaderStageFlags activeStages = gl_vk::GetShaderStageFlags(info.activeStages);
775
776 // TODO: https://issuetracker.google.com/issues/158215272: how do we handle array of
777 // immutable samplers?
778 GLuint textureUnit = samplerBinding.boundTextureUnits[0];
779 if (activeTextures &&
780 ((*activeTextures)[textureUnit].texture->getImage().hasImmutableSampler()))
781 {
782 ASSERT(samplerBinding.boundTextureUnits.size() == 1);
783 // Always take the texture's sampler, that's only way to get to yuv conversion for
784 // externalFormat
785 const TextureVk *textureVk = (*activeTextures)[textureUnit].texture;
786 const vk::Sampler &immutableSampler = textureVk->getSampler().get();
787 descOut->update(info.binding, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, arraySize,
788 activeStages, &immutableSampler);
789 const vk::ImageHelper &image = textureVk->getImage();
790 mImmutableSamplerIndexMap[image.getYcbcrConversionDesc()] = textureIndex;
791 // The Vulkan spec has the following note -
792 // All descriptors in a binding use the same maximum
793 // combinedImageSamplerDescriptorCount descriptors to allow implementations to use a
794 // uniform stride for dynamic indexing of the descriptors in the binding.
795 uint64_t externalFormat = image.getExternalFormat();
796 uint32_t formatDescriptorCount = 0;
797
798 RendererVk *renderer = contextVk->getRenderer();
799
800 if (externalFormat != 0)
801 {
802 ANGLE_TRY(renderer->getFormatDescriptorCountForExternalFormat(
803 contextVk, externalFormat, &formatDescriptorCount));
804 }
805 else
806 {
807 VkFormat vkFormat = image.getActualVkFormat();
808 ASSERT(vkFormat != 0);
809 ANGLE_TRY(renderer->getFormatDescriptorCountForVkFormat(
810 contextVk, vkFormat, &formatDescriptorCount));
811 }
812
813 ASSERT(formatDescriptorCount > 0);
814 mImmutableSamplersMaxDescriptorCount =
815 std::max(mImmutableSamplersMaxDescriptorCount, formatDescriptorCount);
816 }
817 else
818 {
819 const VkDescriptorType descType =
820 samplerBinding.textureType == gl::TextureType::Buffer
821 ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
822 : VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
823 descOut->update(info.binding, descType, arraySize, activeStages, nullptr);
824 }
825 }
826 }
827
828 return angle::Result::Continue;
829 }
830
WriteBufferDescriptorSetBinding(const vk::BufferHelper & buffer,VkDeviceSize offset,VkDeviceSize size,VkDescriptorSet descSet,VkDescriptorType descType,uint32_t bindingIndex,uint32_t arrayElement,VkDeviceSize requiredOffsetAlignment,VkDescriptorBufferInfo * bufferInfoOut,VkWriteDescriptorSet * writeInfoOut)831 void WriteBufferDescriptorSetBinding(const vk::BufferHelper &buffer,
832 VkDeviceSize offset,
833 VkDeviceSize size,
834 VkDescriptorSet descSet,
835 VkDescriptorType descType,
836 uint32_t bindingIndex,
837 uint32_t arrayElement,
838 VkDeviceSize requiredOffsetAlignment,
839 VkDescriptorBufferInfo *bufferInfoOut,
840 VkWriteDescriptorSet *writeInfoOut)
841 {
842 if (IsDynamicDescriptor(descType))
843 {
844 ASSERT(offset == 0);
845 }
846 else
847 {
848 // Adjust offset with buffer's offset since we are sending down buffer.getBuffer() below.
849 offset = buffer.getOffset() + offset;
850
851 // If requiredOffsetAlignment is 0, the buffer offset is guaranteed to have the necessary
852 // alignment through other means (the backend specifying the alignment through a GLES limit
853 // that the frontend then enforces). If it's not 0, we need to bind the buffer at an offset
854 // that's aligned. The difference in offsets is communicated to the shader via driver
855 // uniforms.
856 if (requiredOffsetAlignment)
857 {
858 VkDeviceSize alignedOffset =
859 (offset / requiredOffsetAlignment) * requiredOffsetAlignment;
860 VkDeviceSize offsetDiff = offset - alignedOffset;
861
862 offset = alignedOffset;
863 size += offsetDiff;
864 }
865 }
866
867 bufferInfoOut->buffer = buffer.getBuffer().getHandle();
868 bufferInfoOut->offset = offset;
869 bufferInfoOut->range = size;
870
871 writeInfoOut->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
872 writeInfoOut->pNext = nullptr;
873 writeInfoOut->dstSet = descSet;
874 writeInfoOut->dstBinding = bindingIndex;
875 writeInfoOut->dstArrayElement = arrayElement;
876 writeInfoOut->descriptorCount = 1;
877 writeInfoOut->descriptorType = descType;
878 writeInfoOut->pImageInfo = nullptr;
879 writeInfoOut->pBufferInfo = bufferInfoOut;
880 writeInfoOut->pTexelBufferView = nullptr;
881 ASSERT(writeInfoOut->pBufferInfo[0].buffer != VK_NULL_HANDLE);
882 }
883
updateEarlyFragmentTestsOptimization(ContextVk * contextVk,const gl::ProgramExecutable & glExecutable)884 void ProgramExecutableVk::updateEarlyFragmentTestsOptimization(
885 ContextVk *contextVk,
886 const gl::ProgramExecutable &glExecutable)
887 {
888 const gl::State &glState = contextVk->getState();
889
890 mTransformOptions.removeEarlyFragmentTestsOptimization = false;
891 if (!glState.canEnableEarlyFragmentTestsOptimization())
892 {
893 if (glExecutable.usesEarlyFragmentTestsOptimization())
894 {
895 mTransformOptions.removeEarlyFragmentTestsOptimization = true;
896 }
897 }
898 }
899
getGraphicsPipeline(ContextVk * contextVk,gl::PrimitiveMode mode,const vk::GraphicsPipelineDesc & desc,const gl::ProgramExecutable & glExecutable,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)900 angle::Result ProgramExecutableVk::getGraphicsPipeline(ContextVk *contextVk,
901 gl::PrimitiveMode mode,
902 const vk::GraphicsPipelineDesc &desc,
903 const gl::ProgramExecutable &glExecutable,
904 const vk::GraphicsPipelineDesc **descPtrOut,
905 vk::PipelineHelper **pipelineOut)
906 {
907 const gl::State &glState = contextVk->getState();
908 RendererVk *renderer = contextVk->getRenderer();
909 vk::PipelineCache *pipelineCache = nullptr;
910
911 ASSERT(glExecutable.hasLinkedShaderStage(gl::ShaderType::Vertex));
912
913 mTransformOptions.enableLineRasterEmulation = contextVk->isBresenhamEmulationEnabled(mode);
914 mTransformOptions.surfaceRotation = ToUnderlying(desc.getSurfaceRotation());
915 mTransformOptions.enableDepthCorrection = !glState.isClipControlDepthZeroToOne();
916 mTransformOptions.removeTransformFeedbackEmulation =
917 contextVk->getFeatures().emulateTransformFeedback.enabled &&
918 !glState.isTransformFeedbackActiveUnpaused();
919
920 // This must be called after mTransformOptions have been set.
921 ProgramInfo &programInfo = getGraphicsProgramInfo(mTransformOptions);
922 const gl::ShaderBitSet linkedShaderStages = glExecutable.getLinkedShaderStages();
923 gl::ShaderType lastPreFragmentStage = gl::GetLastPreFragmentStage(linkedShaderStages);
924
925 const bool isTransformFeedbackProgram =
926 !glExecutable.getLinkedTransformFeedbackVaryings().empty();
927
928 for (gl::ShaderType shaderType : linkedShaderStages)
929 {
930 ANGLE_TRY(initGraphicsShaderProgram(
931 contextVk, shaderType, shaderType == lastPreFragmentStage, isTransformFeedbackProgram,
932 mTransformOptions, &programInfo, mVariableInfoMap));
933 }
934
935 vk::ShaderProgramHelper *shaderProgram = programInfo.getShaderProgram();
936 ASSERT(shaderProgram);
937
938 // Drawable size is part of specialization constant, but does not have its own dedicated
939 // programInfo entry. We pick the programInfo entry based on the mTransformOptions and then
940 // update drawable width/height specialization constant. It will go through desc matching and if
941 // spec constant does not match, it will recompile pipeline program.
942 const vk::PackedExtent &dimensions = desc.getDrawableSize();
943 shaderProgram->setSpecializationConstant(sh::vk::SpecializationConstantId::DrawableWidth,
944 dimensions.width);
945 shaderProgram->setSpecializationConstant(sh::vk::SpecializationConstantId::DrawableHeight,
946 dimensions.height);
947 // Similarly with the required dither based on the bound framebuffer attachment formats.
948 shaderProgram->setSpecializationConstant(sh::vk::SpecializationConstantId::Dither,
949 desc.getEmulatedDitherControl());
950
951 // Compare the fragment output interface with the framebuffer interface.
952 const gl::AttributesMask &activeAttribLocations =
953 glExecutable.getNonBuiltinAttribLocationsMask();
954
955 // Calculate missing shader outputs.
956 const gl::DrawBufferMask &shaderOutMask = glExecutable.getActiveOutputVariablesMask();
957 gl::DrawBufferMask framebufferMask = glState.getDrawFramebuffer()->getDrawBufferMask();
958 gl::DrawBufferMask missingOutputsMask = ~shaderOutMask & framebufferMask;
959
960 ANGLE_TRY(renderer->getPipelineCache(&pipelineCache));
961 return shaderProgram->getGraphicsPipeline(
962 contextVk, &contextVk->getRenderPassCache(), *pipelineCache, getPipelineLayout(), desc,
963 activeAttribLocations, glExecutable.getAttributesTypeMask(), missingOutputsMask, descPtrOut,
964 pipelineOut);
965 }
966
getComputePipeline(ContextVk * contextVk,vk::PipelineHelper ** pipelineOut)967 angle::Result ProgramExecutableVk::getComputePipeline(ContextVk *contextVk,
968 vk::PipelineHelper **pipelineOut)
969 {
970 const gl::State &glState = contextVk->getState();
971 const gl::ProgramExecutable *glExecutable = glState.getProgramExecutable();
972 ASSERT(glExecutable && glExecutable->hasLinkedShaderStage(gl::ShaderType::Compute));
973
974 ANGLE_TRY(initComputeProgram(contextVk, &mComputeProgramInfo, mVariableInfoMap));
975
976 vk::ShaderProgramHelper *shaderProgram = mComputeProgramInfo.getShaderProgram();
977 ASSERT(shaderProgram);
978 return shaderProgram->getComputePipeline(contextVk, getPipelineLayout(), pipelineOut);
979 }
980
981 // static
InitDynamicDescriptorPool(vk::Context * context,vk::DescriptorSetLayoutDesc & descriptorSetLayoutDesc,VkDescriptorSetLayout descriptorSetLayout,uint32_t descriptorCountMultiplier,vk::DynamicDescriptorPool * dynamicDescriptorPool)982 angle::Result ProgramExecutableVk::InitDynamicDescriptorPool(
983 vk::Context *context,
984 vk::DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
985 VkDescriptorSetLayout descriptorSetLayout,
986 uint32_t descriptorCountMultiplier,
987 vk::DynamicDescriptorPool *dynamicDescriptorPool)
988 {
989 std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
990 vk::DescriptorSetLayoutBindingVector bindingVector;
991 std::vector<VkSampler> immutableSamplers;
992
993 descriptorSetLayoutDesc.unpackBindings(&bindingVector, &immutableSamplers);
994
995 for (const VkDescriptorSetLayoutBinding &binding : bindingVector)
996 {
997 if (binding.descriptorCount > 0)
998 {
999 VkDescriptorPoolSize poolSize = {};
1000 poolSize.type = binding.descriptorType;
1001 poolSize.descriptorCount = binding.descriptorCount * descriptorCountMultiplier;
1002 descriptorPoolSizes.emplace_back(poolSize);
1003 }
1004 }
1005
1006 if (descriptorPoolSizes.empty())
1007 {
1008 if (context->getRenderer()->getFeatures().bindEmptyForUnusedDescriptorSets.enabled)
1009 {
1010 // For this workaround, we have to create an empty descriptor set for each descriptor
1011 // set index, so make sure their pools are initialized.
1012 VkDescriptorPoolSize poolSize = {};
1013 // The type doesn't matter, since it's not actually used for anything.
1014 poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1015 poolSize.descriptorCount = 1;
1016 descriptorPoolSizes.emplace_back(poolSize);
1017 }
1018 else
1019 {
1020 return angle::Result::Continue;
1021 }
1022 }
1023
1024 ASSERT(!descriptorPoolSizes.empty());
1025
1026 ANGLE_TRY(dynamicDescriptorPool->init(context, descriptorPoolSizes.data(),
1027 descriptorPoolSizes.size(), descriptorSetLayout));
1028
1029 return angle::Result::Continue;
1030 }
1031
createPipelineLayout(ContextVk * contextVk,const gl::ProgramExecutable & glExecutable,gl::ActiveTextureArray<vk::TextureUnit> * activeTextures)1032 angle::Result ProgramExecutableVk::createPipelineLayout(
1033 ContextVk *contextVk,
1034 const gl::ProgramExecutable &glExecutable,
1035 gl::ActiveTextureArray<vk::TextureUnit> *activeTextures)
1036 {
1037 gl::TransformFeedback *transformFeedback = contextVk->getState().getCurrentTransformFeedback();
1038 const gl::ShaderBitSet &linkedShaderStages = glExecutable.getLinkedShaderStages();
1039
1040 reset(contextVk);
1041
1042 // Store a reference to the pipeline and descriptor set layouts. This will create them if they
1043 // don't already exist in the cache.
1044
1045 // Default uniforms and transform feedback:
1046 vk::DescriptorSetLayoutDesc uniformsAndXfbSetDesc;
1047 mNumDefaultUniformDescriptors = 0;
1048 for (gl::ShaderType shaderType : linkedShaderStages)
1049 {
1050 const ShaderInterfaceVariableInfo &info =
1051 mVariableInfoMap.getDefaultUniformInfo(shaderType);
1052 if (info.isDuplicate || !info.activeStages[shaderType])
1053 {
1054 continue;
1055 }
1056
1057 uniformsAndXfbSetDesc.update(info.binding, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
1058 gl_vk::kShaderStageMap[shaderType], nullptr);
1059 mNumDefaultUniformDescriptors++;
1060 }
1061
1062 gl::ShaderType linkedTransformFeedbackStage = glExecutable.getLinkedTransformFeedbackStage();
1063 bool hasXfbVaryings = linkedTransformFeedbackStage != gl::ShaderType::InvalidEnum &&
1064 !glExecutable.getLinkedTransformFeedbackVaryings().empty();
1065 if (transformFeedback && hasXfbVaryings)
1066 {
1067 size_t xfbBufferCount = glExecutable.getTransformFeedbackBufferCount();
1068 TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(transformFeedback);
1069 transformFeedbackVk->updateDescriptorSetLayout(contextVk, mVariableInfoMap, xfbBufferCount,
1070 &uniformsAndXfbSetDesc);
1071 }
1072
1073 ANGLE_TRY(contextVk->getDescriptorSetLayoutCache().getDescriptorSetLayout(
1074 contextVk, uniformsAndXfbSetDesc,
1075 &mDescriptorSetLayouts[DescriptorSetIndex::UniformsAndXfb]));
1076
1077 // Uniform and storage buffers, atomic counter buffers and images:
1078 vk::DescriptorSetLayoutDesc resourcesSetDesc;
1079
1080 // Count the number of active uniform buffer descriptors.
1081 uint32_t numActiveUniformBufferDescriptors = 0;
1082 for (gl::ShaderType shaderType : linkedShaderStages)
1083 {
1084 const std::vector<gl::InterfaceBlock> &blocks = glExecutable.getUniformBlocks();
1085 for (uint32_t bufferIndex = 0; bufferIndex < blocks.size();)
1086 {
1087 const gl::InterfaceBlock &block = blocks[bufferIndex];
1088 const uint32_t arraySize = GetInterfaceBlockArraySize(blocks, bufferIndex);
1089 bufferIndex += arraySize;
1090
1091 if (!block.isActive(shaderType))
1092 {
1093 continue;
1094 }
1095
1096 numActiveUniformBufferDescriptors += arraySize;
1097 }
1098 }
1099
1100 // Decide if we should use dynamic or fixed descriptor types.
1101 VkPhysicalDeviceLimits limits = contextVk->getRenderer()->getPhysicalDeviceProperties().limits;
1102 uint32_t totalDynamicUniformBufferCount = numActiveUniformBufferDescriptors +
1103 mNumDefaultUniformDescriptors +
1104 kReservedDriverUniformBindingCount;
1105 if (totalDynamicUniformBufferCount <= limits.maxDescriptorSetUniformBuffersDynamic)
1106 {
1107 mUniformBufferDescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
1108 }
1109 else
1110 {
1111 mUniformBufferDescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1112 }
1113
1114 for (gl::ShaderType shaderType : linkedShaderStages)
1115 {
1116 addInterfaceBlockDescriptorSetDesc(glExecutable.getUniformBlocks(), shaderType,
1117 ShaderVariableType::UniformBuffer,
1118 mUniformBufferDescriptorType, &resourcesSetDesc);
1119 addInterfaceBlockDescriptorSetDesc(glExecutable.getShaderStorageBlocks(), shaderType,
1120 ShaderVariableType::ShaderStorageBuffer,
1121 kStorageBufferDescriptorType, &resourcesSetDesc);
1122 addAtomicCounterBufferDescriptorSetDesc(glExecutable.getAtomicCounterBuffers(), shaderType,
1123 &resourcesSetDesc);
1124 }
1125
1126 for (gl::ShaderType shaderType : linkedShaderStages)
1127 {
1128 addImageDescriptorSetDesc(glExecutable, &resourcesSetDesc);
1129 addInputAttachmentDescriptorSetDesc(glExecutable, shaderType, &resourcesSetDesc);
1130 }
1131
1132 ANGLE_TRY(contextVk->getDescriptorSetLayoutCache().getDescriptorSetLayout(
1133 contextVk, resourcesSetDesc, &mDescriptorSetLayouts[DescriptorSetIndex::ShaderResource]));
1134
1135 // Textures:
1136 vk::DescriptorSetLayoutDesc texturesSetDesc;
1137 ANGLE_TRY(
1138 addTextureDescriptorSetDesc(contextVk, glExecutable, activeTextures, &texturesSetDesc));
1139
1140 ANGLE_TRY(contextVk->getDescriptorSetLayoutCache().getDescriptorSetLayout(
1141 contextVk, texturesSetDesc, &mDescriptorSetLayouts[DescriptorSetIndex::Texture]));
1142
1143 // Driver uniforms
1144 vk::DescriptorSetLayoutDesc driverUniformsSetDesc =
1145 contextVk->getDriverUniformsDescriptorSetDesc();
1146 ANGLE_TRY(contextVk->getDescriptorSetLayoutCache().getDescriptorSetLayout(
1147 contextVk, driverUniformsSetDesc, &mDescriptorSetLayouts[DescriptorSetIndex::Internal]));
1148
1149 // Create pipeline layout with these 4 descriptor sets.
1150 vk::PipelineLayoutDesc pipelineLayoutDesc;
1151 pipelineLayoutDesc.updateDescriptorSetLayout(DescriptorSetIndex::UniformsAndXfb,
1152 uniformsAndXfbSetDesc);
1153 pipelineLayoutDesc.updateDescriptorSetLayout(DescriptorSetIndex::ShaderResource,
1154 resourcesSetDesc);
1155 pipelineLayoutDesc.updateDescriptorSetLayout(DescriptorSetIndex::Texture, texturesSetDesc);
1156 pipelineLayoutDesc.updateDescriptorSetLayout(DescriptorSetIndex::Internal,
1157 driverUniformsSetDesc);
1158
1159 ANGLE_TRY(contextVk->getPipelineLayoutCache().getPipelineLayout(
1160 contextVk, pipelineLayoutDesc, mDescriptorSetLayouts, &mPipelineLayout));
1161
1162 // Initialize descriptor pools.
1163 ANGLE_TRY(InitDynamicDescriptorPool(
1164 contextVk, uniformsAndXfbSetDesc,
1165 mDescriptorSetLayouts[DescriptorSetIndex::UniformsAndXfb].get().getHandle(), 1,
1166 &mDynamicDescriptorPools[DescriptorSetIndex::UniformsAndXfb]));
1167 ANGLE_TRY(InitDynamicDescriptorPool(
1168 contextVk, resourcesSetDesc,
1169 mDescriptorSetLayouts[DescriptorSetIndex::ShaderResource].get().getHandle(), 1,
1170 &mDynamicDescriptorPools[DescriptorSetIndex::ShaderResource]));
1171 ANGLE_TRY(InitDynamicDescriptorPool(
1172 contextVk, texturesSetDesc,
1173 mDescriptorSetLayouts[DescriptorSetIndex::Texture].get().getHandle(),
1174 mImmutableSamplersMaxDescriptorCount,
1175 &mDynamicDescriptorPools[DescriptorSetIndex::Texture]));
1176 ANGLE_TRY(InitDynamicDescriptorPool(
1177 contextVk, driverUniformsSetDesc,
1178 mDescriptorSetLayouts[DescriptorSetIndex::Internal].get().getHandle(), 1,
1179 &mDynamicDescriptorPools[DescriptorSetIndex::Internal]));
1180
1181 mDynamicUniformDescriptorOffsets.clear();
1182 mDynamicUniformDescriptorOffsets.resize(glExecutable.getLinkedShaderStageCount(), 0);
1183
1184 return angle::Result::Continue;
1185 }
1186
resolvePrecisionMismatch(const gl::ProgramMergedVaryings & mergedVaryings)1187 void ProgramExecutableVk::resolvePrecisionMismatch(const gl::ProgramMergedVaryings &mergedVaryings)
1188 {
1189 for (const gl::ProgramVaryingRef &mergedVarying : mergedVaryings)
1190 {
1191 if (!mergedVarying.frontShader || !mergedVarying.backShader)
1192 {
1193 continue;
1194 }
1195
1196 GLenum frontPrecision = mergedVarying.frontShader->precision;
1197 GLenum backPrecision = mergedVarying.backShader->precision;
1198 if (frontPrecision == backPrecision)
1199 {
1200 continue;
1201 }
1202
1203 ASSERT(frontPrecision >= GL_LOW_FLOAT && frontPrecision <= GL_HIGH_INT);
1204 ASSERT(backPrecision >= GL_LOW_FLOAT && backPrecision <= GL_HIGH_INT);
1205
1206 if (frontPrecision > backPrecision)
1207 {
1208 // The output is higher precision than the input
1209 ShaderInterfaceVariableInfo &info = mVariableInfoMap.getMutable(
1210 mergedVarying.frontShaderStage, ShaderVariableType::Varying,
1211 mergedVarying.frontShader->mappedName);
1212 info.varyingIsOutput = true;
1213 info.useRelaxedPrecision = true;
1214 }
1215 else
1216 {
1217 // The output is lower precision than the input, adjust the input
1218 ASSERT(backPrecision > frontPrecision);
1219 ShaderInterfaceVariableInfo &info = mVariableInfoMap.getMutable(
1220 mergedVarying.backShaderStage, ShaderVariableType::Varying,
1221 mergedVarying.backShader->mappedName);
1222 info.varyingIsInput = true;
1223 info.useRelaxedPrecision = true;
1224 }
1225 }
1226 }
1227
updateDefaultUniformsDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::BufferHelper * emptyBuffer,vk::ResourceUseList * resourceUseList,gl::ShaderType shaderType,const DefaultUniformBlock & defaultUniformBlock,vk::BufferHelper * defaultUniformBuffer)1228 void ProgramExecutableVk::updateDefaultUniformsDescriptorSet(
1229 vk::Context *context,
1230 UpdateDescriptorSetsBuilder *updateBuilder,
1231 vk::BufferHelper *emptyBuffer,
1232 vk::ResourceUseList *resourceUseList,
1233 gl::ShaderType shaderType,
1234 const DefaultUniformBlock &defaultUniformBlock,
1235 vk::BufferHelper *defaultUniformBuffer)
1236 {
1237 const ShaderInterfaceVariableInfo &info = mVariableInfoMap.getDefaultUniformInfo(shaderType);
1238 if (info.isDuplicate || !info.activeStages[shaderType])
1239 {
1240 return;
1241 }
1242
1243 VkWriteDescriptorSet &writeInfo = updateBuilder->allocWriteDescriptorSet();
1244 VkDescriptorBufferInfo &bufferInfo = updateBuilder->allocDescriptorBufferInfo();
1245
1246 VkDeviceSize size = getDefaultUniformAlignedSize(context, shaderType);
1247 vk::BufferHelper *bufferHelper = defaultUniformBuffer;
1248 if (defaultUniformBlock.uniformData.empty())
1249 {
1250 bufferHelper = emptyBuffer;
1251 bufferHelper->retainReadOnly(resourceUseList);
1252 size = bufferHelper->getSize();
1253 }
1254
1255 WriteBufferDescriptorSetBinding(
1256 *bufferHelper, 0, size, mDescriptorSets[DescriptorSetIndex::UniformsAndXfb],
1257 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, info.binding, 0, 0, &bufferInfo, &writeInfo);
1258 }
1259
1260 // Lazily allocate the descriptor set. We may not need one if all of the buffers are inactive.
allocateShaderResourcesDescriptorSet(vk::Context * context,vk::ResourceUseList * resourceUseList,const vk::DescriptorSetDesc * shaderResourcesDesc)1261 angle::Result ProgramExecutableVk::allocateShaderResourcesDescriptorSet(
1262 vk::Context *context,
1263 vk::ResourceUseList *resourceUseList,
1264 const vk::DescriptorSetDesc *shaderResourcesDesc)
1265 {
1266 bool newPoolAllocated = false;
1267 ANGLE_TRY(allocateDescriptorSetAndGetInfo(
1268 context, resourceUseList, DescriptorSetIndex::ShaderResource, &newPoolAllocated));
1269
1270 if (shaderResourcesDesc)
1271 {
1272 // Clear descriptor set cache. It may no longer be valid.
1273 if (newPoolAllocated)
1274 {
1275 mShaderBufferDescriptorsCache.clear();
1276 }
1277
1278 mShaderBufferDescriptorsCache.insert(
1279 *shaderResourcesDesc, mDescriptorSets[DescriptorSetIndex::ShaderResource],
1280 &mPerfCounters.cacheStats[DescriptorSetIndex::ShaderResource]);
1281 }
1282 return angle::Result::Continue;
1283 }
1284
updateBuffersDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::BufferHelper * emptyBuffer,vk::ResourceUseList * resourceUseList,gl::ShaderType shaderType,const vk::DescriptorSetDesc & shaderResourcesDesc,const gl::BufferVector & buffers,const std::vector<gl::InterfaceBlock> & blocks,ShaderVariableType variableType,VkDescriptorType descriptorType,VkDeviceSize maxBoundBufferRange,bool cacheHit)1285 angle::Result ProgramExecutableVk::updateBuffersDescriptorSet(
1286 vk::Context *context,
1287 UpdateDescriptorSetsBuilder *updateBuilder,
1288 vk::BufferHelper *emptyBuffer,
1289 vk::ResourceUseList *resourceUseList,
1290 gl::ShaderType shaderType,
1291 const vk::DescriptorSetDesc &shaderResourcesDesc,
1292 const gl::BufferVector &buffers,
1293 const std::vector<gl::InterfaceBlock> &blocks,
1294 ShaderVariableType variableType,
1295 VkDescriptorType descriptorType,
1296 VkDeviceSize maxBoundBufferRange,
1297 bool cacheHit)
1298 {
1299 // Early exit if no blocks or no update needed.
1300 if (blocks.empty() || (cacheHit && !IsDynamicDescriptor(descriptorType)))
1301 {
1302 return angle::Result::Continue;
1303 }
1304
1305 ASSERT(descriptorType == mUniformBufferDescriptorType ||
1306 descriptorType == kStorageBufferDescriptorType);
1307
1308 VkDescriptorSet descriptorSet = mDescriptorSets[DescriptorSetIndex::ShaderResource];
1309 ASSERT(descriptorSet != VK_NULL_HANDLE);
1310
1311 // Write uniform or storage buffers.
1312 for (uint32_t blockIndex = 0; blockIndex < blocks.size(); ++blockIndex)
1313 {
1314 const gl::InterfaceBlock &block = blocks[blockIndex];
1315 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = buffers[block.binding];
1316
1317 if (!block.isActive(shaderType))
1318 {
1319 continue;
1320 }
1321
1322 const ShaderInterfaceVariableInfo &info =
1323 mVariableInfoMap.getIndexedVariableInfo(shaderType, variableType, blockIndex);
1324 if (info.isDuplicate)
1325 {
1326 continue;
1327 }
1328
1329 uint32_t arrayElement = block.isArray ? block.arrayElement : 0;
1330
1331 if (bufferBinding.get() == nullptr)
1332 {
1333 if (!cacheHit)
1334 {
1335 VkDescriptorBufferInfo &bufferInfo = updateBuilder->allocDescriptorBufferInfo();
1336 VkWriteDescriptorSet &writeInfo = updateBuilder->allocWriteDescriptorSet();
1337
1338 emptyBuffer->retainReadOnly(resourceUseList);
1339 WriteBufferDescriptorSetBinding(*emptyBuffer, 0, emptyBuffer->getSize(),
1340 descriptorSet, descriptorType, info.binding,
1341 arrayElement, 0, &bufferInfo, &writeInfo);
1342 }
1343 if (IsDynamicDescriptor(descriptorType))
1344 {
1345 mDynamicShaderBufferDescriptorOffsets.push_back(
1346 static_cast<uint32_t>(emptyBuffer->getOffset()));
1347 }
1348 continue;
1349 }
1350
1351 // Limit bound buffer size to maximum resource binding size.
1352 GLsizeiptr boundBufferSize = gl::GetBoundBufferAvailableSize(bufferBinding);
1353 VkDeviceSize size = std::min<VkDeviceSize>(boundBufferSize, maxBoundBufferRange);
1354
1355 // Make sure there's no possible under/overflow with binding size.
1356 static_assert(sizeof(VkDeviceSize) >= sizeof(bufferBinding.getSize()),
1357 "VkDeviceSize too small");
1358 ASSERT(bufferBinding.getSize() >= 0);
1359
1360 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
1361 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
1362
1363 if (!cacheHit)
1364 {
1365 VkDescriptorBufferInfo &bufferInfo = updateBuilder->allocDescriptorBufferInfo();
1366 VkWriteDescriptorSet &writeInfo = updateBuilder->allocWriteDescriptorSet();
1367
1368 VkDeviceSize offset =
1369 IsDynamicDescriptor(descriptorType) ? 0 : bufferBinding.getOffset();
1370 WriteBufferDescriptorSetBinding(bufferHelper, offset, size, descriptorSet,
1371 descriptorType, info.binding, arrayElement, 0,
1372 &bufferInfo, &writeInfo);
1373 }
1374 if (IsDynamicDescriptor(descriptorType))
1375 {
1376 mDynamicShaderBufferDescriptorOffsets.push_back(
1377 static_cast<uint32_t>(bufferHelper.getOffset() + bufferBinding.getOffset()));
1378 }
1379 }
1380
1381 return angle::Result::Continue;
1382 }
1383
updateAtomicCounterBuffersDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::BufferHelper * emptyBuffer,vk::ResourceUseList * resourceUseList,const gl::BufferVector & atomicCounterBufferBindings,const gl::ProgramExecutable & executable,gl::ShaderType shaderType,const vk::DescriptorSetDesc & shaderResourcesDesc,bool cacheHit)1384 angle::Result ProgramExecutableVk::updateAtomicCounterBuffersDescriptorSet(
1385 vk::Context *context,
1386 UpdateDescriptorSetsBuilder *updateBuilder,
1387 vk::BufferHelper *emptyBuffer,
1388 vk::ResourceUseList *resourceUseList,
1389 const gl::BufferVector &atomicCounterBufferBindings,
1390 const gl::ProgramExecutable &executable,
1391 gl::ShaderType shaderType,
1392 const vk::DescriptorSetDesc &shaderResourcesDesc,
1393 bool cacheHit)
1394 {
1395 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers =
1396 executable.getAtomicCounterBuffers();
1397
1398 if (atomicCounterBuffers.empty() || cacheHit ||
1399 !mVariableInfoMap.hasAtomicCounterInfo(shaderType))
1400 {
1401 return angle::Result::Continue;
1402 }
1403
1404 const ShaderInterfaceVariableInfo &info = mVariableInfoMap.getAtomicCounterInfo(shaderType);
1405 if (info.isDuplicate || !info.activeStages[shaderType])
1406 {
1407 return angle::Result::Continue;
1408 }
1409
1410 gl::AtomicCounterBufferMask writtenBindings;
1411
1412 RendererVk *rendererVk = context->getRenderer();
1413 const VkDeviceSize requiredOffsetAlignment =
1414 rendererVk->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
1415
1416 VkDescriptorSet descriptorSet = mDescriptorSets[DescriptorSetIndex::ShaderResource];
1417
1418 // Write atomic counter buffers.
1419 for (const gl::AtomicCounterBuffer &atomicCounterBuffer : atomicCounterBuffers)
1420 {
1421 uint32_t binding = atomicCounterBuffer.binding;
1422 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
1423 atomicCounterBufferBindings[binding];
1424
1425 if (bufferBinding.get() == nullptr)
1426 {
1427 continue;
1428 }
1429
1430 static_assert(!IsDynamicDescriptor(kStorageBufferDescriptorType),
1431 "updateAtomicCounterBuffersDescriptorSet needs an update to handle dynamic "
1432 "descriptors");
1433
1434 VkDescriptorBufferInfo &bufferInfo = updateBuilder->allocDescriptorBufferInfo();
1435 VkWriteDescriptorSet &writeInfo = updateBuilder->allocWriteDescriptorSet();
1436
1437 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
1438 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
1439
1440 VkDeviceSize size = gl::GetBoundBufferAvailableSize(bufferBinding);
1441 WriteBufferDescriptorSetBinding(bufferHelper,
1442 static_cast<uint32_t>(bufferBinding.getOffset()), size,
1443 descriptorSet, kStorageBufferDescriptorType, info.binding,
1444 binding, requiredOffsetAlignment, &bufferInfo, &writeInfo);
1445
1446 writtenBindings.set(binding);
1447 }
1448
1449 // Bind the empty buffer to every array slot that's unused.
1450 emptyBuffer->retainReadOnly(resourceUseList);
1451 size_t count = (~writtenBindings).count();
1452 VkDescriptorBufferInfo *bufferInfos = updateBuilder->allocDescriptorBufferInfos(count);
1453 VkWriteDescriptorSet *writeInfos = updateBuilder->allocWriteDescriptorSets(count);
1454 size_t writeCount = 0;
1455 for (size_t binding : ~writtenBindings)
1456 {
1457 WriteBufferDescriptorSetBinding(*emptyBuffer, 0, emptyBuffer->getSize(), descriptorSet,
1458 kStorageBufferDescriptorType, info.binding,
1459 static_cast<uint32_t>(binding), 0, &bufferInfos[writeCount],
1460 &writeInfos[writeCount]);
1461 writeCount++;
1462 }
1463
1464 return angle::Result::Continue;
1465 }
1466
updateImagesDescriptorSet(vk::Context * context,vk::ResourceUseList * resourceUseList,UpdateDescriptorSetsBuilder * updateBuilder,const gl::ActiveTextureArray<TextureVk * > & activeImages,const std::vector<gl::ImageUnit> & imageUnits,const gl::ProgramExecutable & executable,gl::ShaderType shaderType)1467 angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
1468 vk::Context *context,
1469 vk::ResourceUseList *resourceUseList,
1470 UpdateDescriptorSetsBuilder *updateBuilder,
1471 const gl::ActiveTextureArray<TextureVk *> &activeImages,
1472 const std::vector<gl::ImageUnit> &imageUnits,
1473 const gl::ProgramExecutable &executable,
1474 gl::ShaderType shaderType)
1475 {
1476 RendererVk *renderer = context->getRenderer();
1477 const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings();
1478 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
1479
1480 if (imageBindings.empty())
1481 {
1482 return angle::Result::Continue;
1483 }
1484
1485 angle::HashMap<std::string, uint32_t> mappedImageNameToArrayOffset;
1486
1487 VkDescriptorSet descriptorSet = mDescriptorSets[DescriptorSetIndex::ShaderResource];
1488
1489 // Write images.
1490 for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
1491 {
1492 const gl::ImageBinding &imageBinding = imageBindings[imageIndex];
1493 uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex);
1494 const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
1495
1496 if (!imageUniform.isActive(shaderType))
1497 {
1498 continue;
1499 }
1500
1501 uint32_t arrayOffset = imageUniform.outerArrayOffset;
1502 uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
1503
1504 const ShaderInterfaceVariableInfo &info = mVariableInfoMap.getIndexedVariableInfo(
1505 shaderType, ShaderVariableType::Image, imageIndex);
1506 if (info.isDuplicate)
1507 {
1508 continue;
1509 }
1510
1511 // Texture buffers use buffer views, so they are especially handled.
1512 if (imageBinding.textureType == gl::TextureType::Buffer)
1513 {
1514 // Handle format reinterpretation by looking for a view with the format specified in
1515 // the shader (if any, instead of the format specified to glTexBuffer).
1516 const vk::Format *format = nullptr;
1517 if (imageUniform.imageUnitFormat != GL_NONE)
1518 {
1519 format = &renderer->getFormat(imageUniform.imageUnitFormat);
1520 }
1521
1522 VkWriteDescriptorSet *writeInfos = updateBuilder->allocWriteDescriptorSets(arraySize);
1523
1524 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
1525 {
1526 GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
1527 TextureVk *textureVk = activeImages[imageUnit];
1528
1529 const vk::BufferView *view = nullptr;
1530 ANGLE_TRY(textureVk->getBufferViewAndRecordUse(context, format, true, &view));
1531
1532 writeInfos[arrayElement].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1533 writeInfos[arrayElement].pNext = nullptr;
1534 writeInfos[arrayElement].dstSet = descriptorSet;
1535 writeInfos[arrayElement].dstBinding = info.binding;
1536 writeInfos[arrayElement].dstArrayElement = arrayOffset + arrayElement;
1537 writeInfos[arrayElement].descriptorCount = 1;
1538 writeInfos[arrayElement].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
1539 writeInfos[arrayElement].pImageInfo = nullptr;
1540 writeInfos[arrayElement].pBufferInfo = nullptr;
1541 writeInfos[arrayElement].pTexelBufferView = view->ptr();
1542 }
1543 continue;
1544 }
1545
1546 VkWriteDescriptorSet *writeInfos = updateBuilder->allocWriteDescriptorSets(arraySize);
1547 VkDescriptorImageInfo *imageInfos = updateBuilder->allocDescriptorImageInfos(arraySize);
1548 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
1549 {
1550 GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
1551 const gl::ImageUnit &binding = imageUnits[imageUnit];
1552 TextureVk *textureVk = activeImages[imageUnit];
1553
1554 vk::ImageHelper *image = &textureVk->getImage();
1555 const vk::ImageView *imageView = nullptr;
1556
1557 ANGLE_TRY(textureVk->getStorageImageView(context, binding, &imageView));
1558
1559 // Note: binding.access is unused because it is implied by the shader.
1560
1561 imageInfos[arrayElement].sampler = VK_NULL_HANDLE;
1562 imageInfos[arrayElement].imageView = imageView->getHandle();
1563 imageInfos[arrayElement].imageLayout = image->getCurrentLayout();
1564
1565 writeInfos[arrayElement].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1566 writeInfos[arrayElement].pNext = nullptr;
1567 writeInfos[arrayElement].dstSet = descriptorSet;
1568 writeInfos[arrayElement].dstBinding = info.binding;
1569 writeInfos[arrayElement].dstArrayElement = arrayOffset + arrayElement;
1570 writeInfos[arrayElement].descriptorCount = 1;
1571 writeInfos[arrayElement].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
1572 writeInfos[arrayElement].pImageInfo = &imageInfos[arrayElement];
1573 writeInfos[arrayElement].pBufferInfo = nullptr;
1574 writeInfos[arrayElement].pTexelBufferView = nullptr;
1575 }
1576 }
1577
1578 return angle::Result::Continue;
1579 }
1580
updateShaderResourcesDescriptorSet(ContextVk * contextVk,const gl::ProgramExecutable * executable,UpdateDescriptorSetsBuilder * updateBuilder,vk::BufferHelper * emptyBuffer,vk::ResourceUseList * resourceUseList,FramebufferVk * framebufferVk,const vk::DescriptorSetDesc & shaderResourcesDesc)1581 angle::Result ProgramExecutableVk::updateShaderResourcesDescriptorSet(
1582 ContextVk *contextVk,
1583 const gl::ProgramExecutable *executable,
1584 UpdateDescriptorSetsBuilder *updateBuilder,
1585 vk::BufferHelper *emptyBuffer,
1586 vk::ResourceUseList *resourceUseList,
1587 FramebufferVk *framebufferVk,
1588 const vk::DescriptorSetDesc &shaderResourcesDesc)
1589 {
1590 // Reset the descriptor set handles so we only allocate a new one when necessary.
1591 mDescriptorSets[DescriptorSetIndex::ShaderResource] = VK_NULL_HANDLE;
1592 mEmptyDescriptorSets[DescriptorSetIndex::ShaderResource] = VK_NULL_HANDLE;
1593 mDynamicShaderBufferDescriptorOffsets.clear();
1594
1595 if (!mDynamicDescriptorPools[DescriptorSetIndex::ShaderResource].valid())
1596 {
1597 return angle::Result::Continue;
1598 }
1599
1600 bool cacheHit = false;
1601
1602 if (!executable->hasImages() && !executable->usesFramebufferFetch())
1603 {
1604 VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
1605 if (mShaderBufferDescriptorsCache.get(
1606 shaderResourcesDesc, &descriptorSet,
1607 &mPerfCounters.cacheStats[DescriptorSetIndex::ShaderResource]))
1608 {
1609 mDescriptorSets[DescriptorSetIndex::ShaderResource] = descriptorSet;
1610 // The descriptor pool that this descriptor set was allocated from needs to be retained
1611 // each time the descriptor set is used in a new command.
1612 mDescriptorPoolBindings[DescriptorSetIndex::ShaderResource].get().retain(
1613 &contextVk->getResourceUseList());
1614 cacheHit = true;
1615 }
1616 else
1617 {
1618 ANGLE_TRY(allocateShaderResourcesDescriptorSet(contextVk, resourceUseList,
1619 &shaderResourcesDesc));
1620 }
1621 }
1622 else
1623 {
1624 ANGLE_TRY(allocateShaderResourcesDescriptorSet(contextVk, resourceUseList, nullptr));
1625 }
1626
1627 ASSERT(mDescriptorSets[DescriptorSetIndex::ShaderResource] != VK_NULL_HANDLE);
1628
1629 const VkPhysicalDeviceLimits &limits =
1630 contextVk->getRenderer()->getPhysicalDeviceProperties().limits;
1631
1632 const gl::State &glState = contextVk->getState();
1633 const gl::BufferVector &atomicCounterBufferBindings =
1634 glState.getOffsetBindingPointerAtomicCounterBuffers();
1635
1636 const gl::BufferVector &uniformBuffers = glState.getOffsetBindingPointerUniformBuffers();
1637 const gl::BufferVector &storageBuffers = glState.getOffsetBindingPointerShaderStorageBuffers();
1638 const gl::ActiveTextureArray<TextureVk *> &activeImages = contextVk->getActiveImages();
1639
1640 for (gl::ShaderType shaderType : executable->getLinkedShaderStages())
1641 {
1642 ANGLE_TRY(updateBuffersDescriptorSet(
1643 contextVk, updateBuilder, emptyBuffer, resourceUseList, shaderType, shaderResourcesDesc,
1644 uniformBuffers, executable->getUniformBlocks(), ShaderVariableType::UniformBuffer,
1645 mUniformBufferDescriptorType, limits.maxUniformBufferRange, cacheHit));
1646 ANGLE_TRY(updateBuffersDescriptorSet(
1647 contextVk, updateBuilder, emptyBuffer, resourceUseList, shaderType, shaderResourcesDesc,
1648 storageBuffers, executable->getShaderStorageBlocks(),
1649 ShaderVariableType::ShaderStorageBuffer, kStorageBufferDescriptorType,
1650 limits.maxStorageBufferRange, cacheHit));
1651 ANGLE_TRY(updateAtomicCounterBuffersDescriptorSet(
1652 contextVk, updateBuilder, emptyBuffer, resourceUseList, atomicCounterBufferBindings,
1653 *executable, shaderType, shaderResourcesDesc, cacheHit));
1654 ANGLE_TRY(updateImagesDescriptorSet(contextVk, resourceUseList, updateBuilder, activeImages,
1655 glState.getImageUnits(), *executable, shaderType));
1656 ANGLE_TRY(updateInputAttachmentDescriptorSet(contextVk, resourceUseList, updateBuilder,
1657 *executable, shaderType, framebufferVk));
1658 }
1659
1660 return angle::Result::Continue;
1661 }
1662
updateInputAttachmentDescriptorSet(vk::Context * context,vk::ResourceUseList * resourceUseList,UpdateDescriptorSetsBuilder * updateBuilder,const gl::ProgramExecutable & executable,gl::ShaderType shaderType,FramebufferVk * framebufferVk)1663 angle::Result ProgramExecutableVk::updateInputAttachmentDescriptorSet(
1664 vk::Context *context,
1665 vk::ResourceUseList *resourceUseList,
1666 UpdateDescriptorSetsBuilder *updateBuilder,
1667 const gl::ProgramExecutable &executable,
1668 gl::ShaderType shaderType,
1669 FramebufferVk *framebufferVk)
1670 {
1671 if (shaderType != gl::ShaderType::Fragment)
1672 {
1673 return angle::Result::Continue;
1674 }
1675
1676 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
1677
1678 if (!executable.usesFramebufferFetch())
1679 {
1680 return angle::Result::Continue;
1681 }
1682
1683 const uint32_t baseUniformIndex = executable.getFragmentInoutRange().low();
1684 const gl::LinkedUniform &baseInputAttachment = uniforms.at(baseUniformIndex);
1685
1686 const ShaderInterfaceVariableInfo &baseInfo =
1687 mVariableInfoMap.getFramebufferFetchInfo(shaderType);
1688 if (baseInfo.isDuplicate)
1689 {
1690 return angle::Result::Continue;
1691 }
1692
1693 uint32_t baseBinding = baseInfo.binding - baseInputAttachment.location;
1694
1695 VkDescriptorSet descriptorSet = mDescriptorSets[DescriptorSetIndex::ShaderResource];
1696
1697 for (size_t colorIndex : framebufferVk->getState().getColorAttachmentsMask())
1698 {
1699 VkWriteDescriptorSet *writeInfos = updateBuilder->allocWriteDescriptorSets(1);
1700 VkDescriptorImageInfo *imageInfos = updateBuilder->allocDescriptorImageInfos(1);
1701 RenderTargetVk *renderTargetVk = framebufferVk->getColorDrawRenderTarget(colorIndex);
1702 const vk::ImageView *imageView = nullptr;
1703
1704 ANGLE_TRY(renderTargetVk->getImageView(context, &imageView));
1705
1706 imageInfos[0].sampler = VK_NULL_HANDLE;
1707 imageInfos[0].imageView = imageView->getHandle();
1708 imageInfos[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
1709
1710 writeInfos[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1711 writeInfos[0].pNext = nullptr;
1712 writeInfos[0].dstSet = descriptorSet;
1713 writeInfos[0].dstBinding = baseBinding + static_cast<uint32_t>(colorIndex);
1714 writeInfos[0].dstArrayElement = 0;
1715 writeInfos[0].descriptorCount = 1;
1716 writeInfos[0].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
1717 writeInfos[0].pImageInfo = &imageInfos[0];
1718 writeInfos[0].pBufferInfo = nullptr;
1719 writeInfos[0].pTexelBufferView = nullptr;
1720 }
1721
1722 return angle::Result::Continue;
1723 }
1724
updateUniformsAndXfbDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::ResourceUseList * resourceUseList,vk::BufferHelper * emptyBuffer,const gl::ProgramExecutable & executable,vk::BufferHelper * defaultUniformBuffer,const vk::DescriptorSetDesc & uniformsAndXfbDesc,bool isTransformFeedbackActiveUnpaused,TransformFeedbackVk * transformFeedbackVk)1725 angle::Result ProgramExecutableVk::updateUniformsAndXfbDescriptorSet(
1726 vk::Context *context,
1727 UpdateDescriptorSetsBuilder *updateBuilder,
1728 vk::ResourceUseList *resourceUseList,
1729 vk::BufferHelper *emptyBuffer,
1730 const gl::ProgramExecutable &executable,
1731 vk::BufferHelper *defaultUniformBuffer,
1732 const vk::DescriptorSetDesc &uniformsAndXfbDesc,
1733 bool isTransformFeedbackActiveUnpaused,
1734 TransformFeedbackVk *transformFeedbackVk)
1735 {
1736 ASSERT(executable.hasTransformFeedbackOutput());
1737
1738 bool newDescriptorSetAllocated;
1739 ANGLE_TRY(allocUniformAndXfbDescriptorSet(context, resourceUseList, defaultUniformBuffer,
1740 uniformsAndXfbDesc, &newDescriptorSetAllocated));
1741
1742 if (newDescriptorSetAllocated)
1743 {
1744 for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
1745 {
1746 updateDefaultUniformsDescriptorSet(context, updateBuilder, emptyBuffer, resourceUseList,
1747 shaderType, *mDefaultUniformBlocks[shaderType],
1748 defaultUniformBuffer);
1749 }
1750 updateTransformFeedbackDescriptorSetImpl(context, updateBuilder, emptyBuffer, executable,
1751 isTransformFeedbackActiveUnpaused,
1752 transformFeedbackVk);
1753 }
1754
1755 return angle::Result::Continue;
1756 }
1757
updateTransformFeedbackDescriptorSetImpl(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::BufferHelper * emptyBuffer,const gl::ProgramExecutable & executable,bool isTransformFeedbackActiveUnpaused,TransformFeedbackVk * transformFeedbackVk)1758 void ProgramExecutableVk::updateTransformFeedbackDescriptorSetImpl(
1759 vk::Context *context,
1760 UpdateDescriptorSetsBuilder *updateBuilder,
1761 vk::BufferHelper *emptyBuffer,
1762 const gl::ProgramExecutable &executable,
1763 bool isTransformFeedbackActiveUnpaused,
1764 TransformFeedbackVk *transformFeedbackVk)
1765 {
1766 if (!executable.hasTransformFeedbackOutput())
1767 {
1768 // If xfb has no output there is no need to update descriptor set.
1769 return;
1770 }
1771 if (!isTransformFeedbackActiveUnpaused)
1772 {
1773 // We set empty Buffer to xfb descriptor set because xfb descriptor set
1774 // requires valid buffer bindings, even if they are empty buffer,
1775 // otherwise Vulkan validation layer generates errors.
1776 if (transformFeedbackVk)
1777 {
1778 transformFeedbackVk->initDescriptorSet(
1779 context, updateBuilder, emptyBuffer, mVariableInfoMap,
1780 executable.getTransformFeedbackBufferCount(),
1781 mDescriptorSets[DescriptorSetIndex::UniformsAndXfb]);
1782 }
1783 return;
1784 }
1785 transformFeedbackVk->updateDescriptorSet(context, updateBuilder, executable, mVariableInfoMap,
1786 mDescriptorSets[DescriptorSetIndex::UniformsAndXfb]);
1787 }
1788
updateTexturesDescriptorSet(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::ResourceUseList * resourceUseList,const gl::ProgramExecutable & executable,const gl::ActiveTextureArray<vk::TextureUnit> & activeTextures,const vk::DescriptorSetDesc & texturesDesc,bool emulateSeamfulCubeMapSampling)1789 angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(
1790 vk::Context *context,
1791 UpdateDescriptorSetsBuilder *updateBuilder,
1792 vk::ResourceUseList *resourceUseList,
1793 const gl::ProgramExecutable &executable,
1794 const gl::ActiveTextureArray<vk::TextureUnit> &activeTextures,
1795 const vk::DescriptorSetDesc &texturesDesc,
1796 bool emulateSeamfulCubeMapSampling)
1797 {
1798 if (!executable.hasTextures())
1799 {
1800 return angle::Result::Continue;
1801 }
1802
1803 VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
1804 if (mTextureDescriptorsCache.get(texturesDesc, &descriptorSet,
1805 &mPerfCounters.cacheStats[DescriptorSetIndex::Texture]))
1806 {
1807 mDescriptorSets[DescriptorSetIndex::Texture] = descriptorSet;
1808 // The descriptor pool that this descriptor set was allocated from needs to be retained each
1809 // time the descriptor set is used in a new command.
1810 mDescriptorPoolBindings[DescriptorSetIndex::Texture].get().retain(resourceUseList);
1811 return angle::Result::Continue;
1812 }
1813
1814 const std::vector<gl::SamplerBinding> &samplerBindings = executable.getSamplerBindings();
1815
1816 for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
1817 {
1818 for (uint32_t textureIndex = 0; textureIndex < executable.getSamplerBindings().size();
1819 ++textureIndex)
1820 {
1821 const gl::SamplerBinding &samplerBinding = samplerBindings[textureIndex];
1822 uint32_t uniformIndex = executable.getUniformIndexFromSamplerIndex(textureIndex);
1823 const gl::LinkedUniform &samplerUniform = executable.getUniforms()[uniformIndex];
1824
1825 if (!samplerUniform.isActive(shaderType))
1826 {
1827 continue;
1828 }
1829
1830 uint32_t arrayOffset = samplerUniform.outerArrayOffset;
1831 uint32_t arraySize = static_cast<uint32_t>(samplerBinding.boundTextureUnits.size());
1832
1833 const ShaderInterfaceVariableInfo &info = mVariableInfoMap.getIndexedVariableInfo(
1834 shaderType, ShaderVariableType::Texture, textureIndex);
1835 if (info.isDuplicate)
1836 {
1837 continue;
1838 }
1839
1840 // Lazily allocate the descriptor set, since we may not need one if all of the
1841 // sampler uniforms are inactive.
1842 if (descriptorSet == VK_NULL_HANDLE)
1843 {
1844 bool newPoolAllocated;
1845 ANGLE_TRY(allocateDescriptorSetAndGetInfo(
1846 context, resourceUseList, DescriptorSetIndex::Texture, &newPoolAllocated));
1847
1848 // Clear descriptor set cache. It may no longer be valid.
1849 if (newPoolAllocated)
1850 {
1851 mTextureDescriptorsCache.clear();
1852 }
1853
1854 descriptorSet = mDescriptorSets[DescriptorSetIndex::Texture];
1855 mTextureDescriptorsCache.insert(
1856 texturesDesc, descriptorSet,
1857 &mPerfCounters.cacheStats[DescriptorSetIndex::Texture]);
1858 }
1859 ASSERT(descriptorSet != VK_NULL_HANDLE);
1860
1861 VkWriteDescriptorSet *writeInfos = updateBuilder->allocWriteDescriptorSets(arraySize);
1862
1863 // Texture buffers use buffer views, so they are especially handled.
1864 if (samplerBinding.textureType == gl::TextureType::Buffer)
1865 {
1866 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
1867 {
1868 GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement];
1869 TextureVk *textureVk = activeTextures[textureUnit].texture;
1870 const vk::BufferView *view = nullptr;
1871 ANGLE_TRY(textureVk->getBufferViewAndRecordUse(context, nullptr, false, &view));
1872
1873 writeInfos[arrayElement].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1874 writeInfos[arrayElement].pNext = nullptr;
1875 writeInfos[arrayElement].dstSet = descriptorSet;
1876 writeInfos[arrayElement].dstBinding = info.binding;
1877 writeInfos[arrayElement].dstArrayElement = arrayOffset + arrayElement;
1878 writeInfos[arrayElement].descriptorCount = 1;
1879 writeInfos[arrayElement].descriptorType =
1880 VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
1881 writeInfos[arrayElement].pImageInfo = nullptr;
1882 writeInfos[arrayElement].pBufferInfo = nullptr;
1883 writeInfos[arrayElement].pTexelBufferView = view->ptr();
1884 }
1885 continue;
1886 }
1887
1888 VkDescriptorImageInfo *imageInfos = updateBuilder->allocDescriptorImageInfos(arraySize);
1889 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
1890 {
1891 GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement];
1892 const vk::TextureUnit &unit = activeTextures[textureUnit];
1893 TextureVk *textureVk = unit.texture;
1894 const vk::SamplerHelper &samplerHelper = *unit.sampler;
1895
1896 ASSERT(textureVk);
1897
1898 vk::ImageHelper &image = textureVk->getImage();
1899
1900 imageInfos[arrayElement].sampler = samplerHelper.get().getHandle();
1901 imageInfos[arrayElement].imageLayout = image.getCurrentLayout();
1902
1903 if (emulateSeamfulCubeMapSampling)
1904 {
1905 // If emulating seamful cube mapping, use the fetch image view. This is
1906 // basically the same image view as read, except it's a 2DArray view for
1907 // cube maps.
1908 const vk::ImageView &imageView = textureVk->getFetchImageView(
1909 context, unit.srgbDecode, samplerUniform.texelFetchStaticUse);
1910 imageInfos[arrayElement].imageView = imageView.getHandle();
1911 }
1912 else
1913 {
1914 const vk::ImageView &imageView = textureVk->getReadImageView(
1915 context, unit.srgbDecode, samplerUniform.texelFetchStaticUse);
1916 imageInfos[arrayElement].imageView = imageView.getHandle();
1917 }
1918
1919 if (textureVk->getImage().hasImmutableSampler())
1920 {
1921 imageInfos[arrayElement].sampler = textureVk->getSampler().get().getHandle();
1922 }
1923
1924 writeInfos[arrayElement].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1925 writeInfos[arrayElement].pNext = nullptr;
1926 writeInfos[arrayElement].dstSet = descriptorSet;
1927 writeInfos[arrayElement].dstBinding = info.binding;
1928 writeInfos[arrayElement].dstArrayElement = arrayOffset + arrayElement;
1929 writeInfos[arrayElement].descriptorCount = 1;
1930 writeInfos[arrayElement].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1931 writeInfos[arrayElement].pImageInfo = &imageInfos[arrayElement];
1932 writeInfos[arrayElement].pBufferInfo = nullptr;
1933 writeInfos[arrayElement].pTexelBufferView = nullptr;
1934 }
1935 }
1936 }
1937
1938 return angle::Result::Continue;
1939 }
1940
1941 template <typename CommandBufferT>
updateDescriptorSets(vk::Context * context,vk::ResourceUseList * resourceUseList,CommandBufferT * commandBuffer,PipelineType pipelineType)1942 angle::Result ProgramExecutableVk::updateDescriptorSets(vk::Context *context,
1943 vk::ResourceUseList *resourceUseList,
1944 CommandBufferT *commandBuffer,
1945 PipelineType pipelineType)
1946 {
1947 // Can probably use better dirty bits here.
1948
1949 // Find the maximum non-null descriptor set. This is used in conjunction with a driver
1950 // workaround to bind empty descriptor sets only for gaps in between 0 and max and avoid
1951 // binding unnecessary empty descriptor sets for the sets beyond max.
1952 DescriptorSetIndex lastNonNullDescriptorSetIndex = DescriptorSetIndex::InvalidEnum;
1953 for (DescriptorSetIndex descriptorSetIndex : angle::AllEnums<DescriptorSetIndex>())
1954 {
1955 if (descriptorSetIndex == DescriptorSetIndex::Internal)
1956 {
1957 continue;
1958 }
1959 if (mDescriptorSets[descriptorSetIndex] != VK_NULL_HANDLE)
1960 {
1961 lastNonNullDescriptorSetIndex = descriptorSetIndex;
1962 }
1963 }
1964
1965 const VkPipelineBindPoint pipelineBindPoint = pipelineType == PipelineType::Compute
1966 ? VK_PIPELINE_BIND_POINT_COMPUTE
1967 : VK_PIPELINE_BIND_POINT_GRAPHICS;
1968
1969 for (DescriptorSetIndex descriptorSetIndex : angle::AllEnums<DescriptorSetIndex>())
1970 {
1971 if (descriptorSetIndex == DescriptorSetIndex::Internal ||
1972 ToUnderlying(descriptorSetIndex) > ToUnderlying(lastNonNullDescriptorSetIndex))
1973 {
1974 continue;
1975 }
1976
1977 VkDescriptorSet descSet = mDescriptorSets[descriptorSetIndex];
1978 if (descSet == VK_NULL_HANDLE)
1979 {
1980 if (!context->getRenderer()->getFeatures().bindEmptyForUnusedDescriptorSets.enabled)
1981 {
1982 continue;
1983 }
1984
1985 // Workaround a driver bug where missing (though unused) descriptor sets indices cause
1986 // later sets to misbehave.
1987 if (mEmptyDescriptorSets[descriptorSetIndex] == VK_NULL_HANDLE)
1988 {
1989 const vk::DescriptorSetLayout &descriptorSetLayout =
1990 mDescriptorSetLayouts[descriptorSetIndex].get();
1991
1992 ANGLE_TRY(mDynamicDescriptorPools[descriptorSetIndex].allocateDescriptorSets(
1993 context, resourceUseList, descriptorSetLayout, 1,
1994 &mDescriptorPoolBindings[descriptorSetIndex],
1995 &mEmptyDescriptorSets[descriptorSetIndex]));
1996 }
1997 descSet = mEmptyDescriptorSets[descriptorSetIndex];
1998 }
1999
2000 // Default uniforms are encompassed in a block per shader stage, and they are assigned
2001 // through dynamic uniform buffers (requiring dynamic offsets). No other descriptor
2002 // requires a dynamic offset.
2003 if (descriptorSetIndex == DescriptorSetIndex::UniformsAndXfb)
2004 {
2005 commandBuffer->bindDescriptorSets(
2006 getPipelineLayout(), pipelineBindPoint, descriptorSetIndex, 1, &descSet,
2007 static_cast<uint32_t>(mDynamicUniformDescriptorOffsets.size()),
2008 mDynamicUniformDescriptorOffsets.data());
2009 }
2010 else if (descriptorSetIndex == DescriptorSetIndex::ShaderResource)
2011 {
2012 commandBuffer->bindDescriptorSets(
2013 getPipelineLayout(), pipelineBindPoint, descriptorSetIndex, 1, &descSet,
2014 static_cast<uint32_t>(mDynamicShaderBufferDescriptorOffsets.size()),
2015 mDynamicShaderBufferDescriptorOffsets.data());
2016 }
2017 else
2018 {
2019 commandBuffer->bindDescriptorSets(getPipelineLayout(), pipelineBindPoint,
2020 descriptorSetIndex, 1, &descSet, 0, nullptr);
2021 }
2022 }
2023
2024 return angle::Result::Continue;
2025 }
2026
2027 template angle::Result ProgramExecutableVk::updateDescriptorSets<vk::priv::SecondaryCommandBuffer>(
2028 vk::Context *context,
2029 vk::ResourceUseList *resourceUseList,
2030 vk::priv::SecondaryCommandBuffer *commandBuffer,
2031 PipelineType pipelineType);
2032 template angle::Result ProgramExecutableVk::updateDescriptorSets<vk::VulkanSecondaryCommandBuffer>(
2033 vk::Context *context,
2034 vk::ResourceUseList *resourceUseList,
2035 vk::VulkanSecondaryCommandBuffer *commandBuffer,
2036 PipelineType pipelineType);
2037
getDescriptorSetPerfCounters()2038 ProgramExecutablePerfCounters ProgramExecutableVk::getDescriptorSetPerfCounters()
2039 {
2040 mPerfCounters.descriptorSetCacheKeySizesBytes = {};
2041 mPerfCounters.descriptorSetCacheKeySizesBytes[DescriptorSetIndex::UniformsAndXfb] =
2042 static_cast<uint32_t>(mUniformsAndXfbDescriptorsCache.getTotalCacheKeySizeBytes());
2043 mPerfCounters.descriptorSetCacheKeySizesBytes[DescriptorSetIndex::Texture] =
2044 static_cast<uint32_t>(mTextureDescriptorsCache.getTotalCacheKeySizeBytes());
2045 mPerfCounters.descriptorSetCacheKeySizesBytes[DescriptorSetIndex::ShaderResource] =
2046 static_cast<uint32_t>(mShaderBufferDescriptorsCache.getTotalCacheKeySizeBytes());
2047
2048 return mPerfCounters;
2049 }
2050
resetDescriptorSetPerfCounters()2051 void ProgramExecutableVk::resetDescriptorSetPerfCounters()
2052 {
2053 for (CacheStats &cacheStats : mPerfCounters.cacheStats)
2054 {
2055 cacheStats.resetHitAndMissCount();
2056 }
2057 }
2058
setAllDefaultUniformsDirty(const gl::ProgramExecutable & executable)2059 void ProgramExecutableVk::setAllDefaultUniformsDirty(const gl::ProgramExecutable &executable)
2060 {
2061 mDefaultUniformBlocksDirty.reset();
2062 for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
2063 {
2064 if (!mDefaultUniformBlocks[shaderType]->uniformData.empty())
2065 {
2066 mDefaultUniformBlocksDirty.set(shaderType);
2067 }
2068 }
2069 }
2070
updateUniforms(vk::Context * context,UpdateDescriptorSetsBuilder * updateBuilder,vk::ResourceUseList * resourceUseList,vk::BufferHelper * emptyBuffer,const gl::ProgramExecutable & glExecutable,vk::DynamicBuffer * defaultUniformStorage,bool isTransformFeedbackActiveUnpaused,TransformFeedbackVk * transformFeedbackVk)2071 angle::Result ProgramExecutableVk::updateUniforms(vk::Context *context,
2072 UpdateDescriptorSetsBuilder *updateBuilder,
2073 vk::ResourceUseList *resourceUseList,
2074 vk::BufferHelper *emptyBuffer,
2075 const gl::ProgramExecutable &glExecutable,
2076 vk::DynamicBuffer *defaultUniformStorage,
2077 bool isTransformFeedbackActiveUnpaused,
2078 TransformFeedbackVk *transformFeedbackVk)
2079 {
2080 ASSERT(hasDirtyUniforms());
2081
2082 vk::BufferHelper *defaultUniformBuffer;
2083 bool anyNewBufferAllocated = false;
2084 gl::ShaderMap<VkDeviceSize> offsets = {}; // offset to the beginning of bufferData
2085 uint32_t offsetIndex = 0;
2086 size_t requiredSpace;
2087
2088 // We usually only update uniform data for shader stages that are actually dirty. But when the
2089 // buffer for uniform data have switched, because all shader stages are using the same buffer,
2090 // we then must update uniform data for all shader stages to keep all shader stages' uniform
2091 // data in the same buffer.
2092 requiredSpace = calcUniformUpdateRequiredSpace(context, glExecutable, &offsets);
2093 ASSERT(requiredSpace > 0);
2094
2095 // Allocate space from dynamicBuffer. Always try to allocate from the current buffer first.
2096 // If that failed, we deal with fall out and try again.
2097 if (!defaultUniformStorage->allocateFromCurrentBuffer(requiredSpace, &defaultUniformBuffer))
2098 {
2099 setAllDefaultUniformsDirty(glExecutable);
2100
2101 requiredSpace = calcUniformUpdateRequiredSpace(context, glExecutable, &offsets);
2102 ANGLE_TRY(defaultUniformStorage->allocate(context, requiredSpace, &defaultUniformBuffer,
2103 &anyNewBufferAllocated));
2104 }
2105
2106 uint8_t *bufferData = defaultUniformBuffer->getMappedMemory();
2107 VkDeviceSize bufferOffset = defaultUniformBuffer->getOffset();
2108 for (gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
2109 {
2110 if (mDefaultUniformBlocksDirty[shaderType])
2111 {
2112 const angle::MemoryBuffer &uniformData = mDefaultUniformBlocks[shaderType]->uniformData;
2113 memcpy(&bufferData[offsets[shaderType]], uniformData.data(), uniformData.size());
2114 mDynamicUniformDescriptorOffsets[offsetIndex] =
2115 static_cast<uint32_t>(bufferOffset + offsets[shaderType]);
2116 mDefaultUniformBlocksDirty.reset(shaderType);
2117 }
2118 ++offsetIndex;
2119 }
2120 ANGLE_TRY(defaultUniformBuffer->flush(context->getRenderer()));
2121
2122 // Because the uniform buffers are per context, we can't rely on dynamicBuffer's allocate
2123 // function to tell us if you have got a new buffer or not. Other program's use of the buffer
2124 // might already pushed dynamicBuffer to a new buffer. We record which buffer (represented by
2125 // the unique BufferSerial number) we were using with the current descriptor set and then we
2126 // use that recorded BufferSerial compare to the current uniform buffer to quickly detect if
2127 // there is a buffer switch or not. We need to retrieve from the descriptor set cache or
2128 // allocate a new descriptor set whenever there is uniform buffer switch.
2129 if (mCurrentDefaultUniformBufferSerial != defaultUniformBuffer->getBufferSerial())
2130 {
2131 // We need to reinitialize the descriptor sets if we newly allocated buffers since we can't
2132 // modify the descriptor sets once initialized.
2133 vk::DescriptorSetDesc defaultUniformsDesc;
2134 vk::DescriptorSetDesc *uniformsAndXfbBufferDesc;
2135
2136 if (glExecutable.hasTransformFeedbackOutput())
2137 {
2138 uniformsAndXfbBufferDesc = &transformFeedbackVk->getTransformFeedbackDesc();
2139 uniformsAndXfbBufferDesc->updateDefaultUniformBuffer(
2140 defaultUniformBuffer->getBufferSerial());
2141 }
2142 else
2143 {
2144 defaultUniformsDesc.updateDefaultUniformBuffer(defaultUniformBuffer->getBufferSerial());
2145 uniformsAndXfbBufferDesc = &defaultUniformsDesc;
2146 }
2147
2148 bool newDescriptorSetAllocated;
2149 ANGLE_TRY(allocUniformAndXfbDescriptorSet(context, resourceUseList, defaultUniformBuffer,
2150 *uniformsAndXfbBufferDesc,
2151 &newDescriptorSetAllocated));
2152
2153 if (newDescriptorSetAllocated)
2154 {
2155 for (gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
2156 {
2157 updateDefaultUniformsDescriptorSet(
2158 context, updateBuilder, emptyBuffer, resourceUseList, shaderType,
2159 *mDefaultUniformBlocks[shaderType], defaultUniformBuffer);
2160 updateTransformFeedbackDescriptorSetImpl(
2161 context, updateBuilder, emptyBuffer, glExecutable,
2162 isTransformFeedbackActiveUnpaused, transformFeedbackVk);
2163 }
2164 }
2165 }
2166
2167 return angle::Result::Continue;
2168 }
2169
calcUniformUpdateRequiredSpace(vk::Context * context,const gl::ProgramExecutable & glExecutable,gl::ShaderMap<VkDeviceSize> * uniformOffsets) const2170 size_t ProgramExecutableVk::calcUniformUpdateRequiredSpace(
2171 vk::Context *context,
2172 const gl::ProgramExecutable &glExecutable,
2173 gl::ShaderMap<VkDeviceSize> *uniformOffsets) const
2174 {
2175 size_t requiredSpace = 0;
2176 for (gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
2177 {
2178 if (mDefaultUniformBlocksDirty[shaderType])
2179 {
2180 (*uniformOffsets)[shaderType] = requiredSpace;
2181 requiredSpace += getDefaultUniformAlignedSize(context, shaderType);
2182 }
2183 }
2184 return requiredSpace;
2185 }
2186
onProgramBind(const gl::ProgramExecutable & glExecutable)2187 void ProgramExecutableVk::onProgramBind(const gl::ProgramExecutable &glExecutable)
2188 {
2189 // Because all programs share default uniform buffers, when we switch programs, we have to
2190 // re-update all uniform data. We could do more tracking to avoid update if the context's
2191 // current uniform buffer is still the same buffer we last time used and buffer has not been
2192 // recycled. But statistics gathered on gfxbench shows that app always update uniform data on
2193 // program bind anyway, so not really worth it to add more tracking logic here.
2194 setAllDefaultUniformsDirty(glExecutable);
2195 }
2196
resizeUniformBlockMemory(ContextVk * contextVk,const gl::ProgramExecutable & glExecutable,const gl::ShaderMap<size_t> & requiredBufferSize)2197 angle::Result ProgramExecutableVk::resizeUniformBlockMemory(
2198 ContextVk *contextVk,
2199 const gl::ProgramExecutable &glExecutable,
2200 const gl::ShaderMap<size_t> &requiredBufferSize)
2201 {
2202 for (gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
2203 {
2204 if (requiredBufferSize[shaderType] > 0)
2205 {
2206 if (!mDefaultUniformBlocks[shaderType]->uniformData.resize(
2207 requiredBufferSize[shaderType]))
2208 {
2209 ANGLE_VK_CHECK(contextVk, false, VK_ERROR_OUT_OF_HOST_MEMORY);
2210 }
2211
2212 // Initialize uniform buffer memory to zero by default.
2213 mDefaultUniformBlocks[shaderType]->uniformData.fill(0);
2214 mDefaultUniformBlocksDirty.set(shaderType);
2215 }
2216 }
2217
2218 return angle::Result::Continue;
2219 }
2220 } // namespace rx
2221