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