1 //
2 // Copyright 2018 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 // vk_cache_utils.cpp:
7 // Contains the classes for the Pipeline State Object cache as well as the RenderPass cache.
8 // Also contains the structures for the packed descriptions for the RenderPass and Pipeline.
9 //
10
11 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
12
13 #include "common/aligned_memory.h"
14 #include "common/system_utils.h"
15 #include "libANGLE/BlobCache.h"
16 #include "libANGLE/VertexAttribute.h"
17 #include "libANGLE/renderer/vulkan/DisplayVk.h"
18 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
19 #include "libANGLE/renderer/vulkan/ProgramVk.h"
20 #include "libANGLE/renderer/vulkan/TextureVk.h"
21 #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
22 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
23 #include "libANGLE/renderer/vulkan/vk_helpers.h"
24 #include "libANGLE/renderer/vulkan/vk_renderer.h"
25
26 #include <type_traits>
27
28 namespace rx
29 {
30 #if defined(ANGLE_DUMP_PIPELINE_CACHE_GRAPH)
31 constexpr bool kDumpPipelineCacheGraph = true;
32 #else
33 constexpr bool kDumpPipelineCacheGraph = false;
34 #endif // ANGLE_DUMP_PIPELINE_CACHE_GRAPH
35
36 template <typename T>
AllCacheEntriesHaveUniqueReference(const T & payload)37 bool AllCacheEntriesHaveUniqueReference(const T &payload)
38 {
39 bool unique = true;
40 for (auto &item : payload)
41 {
42 if (!item.second.unique())
43 {
44 unique = false;
45 }
46 }
47 return unique;
48 }
49
50 namespace vk
51 {
52 namespace
53 {
54 static_assert(static_cast<uint32_t>(RenderPassLoadOp::Load) == VK_ATTACHMENT_LOAD_OP_LOAD,
55 "ConvertRenderPassLoadOpToVkLoadOp must be updated");
56 static_assert(static_cast<uint32_t>(RenderPassLoadOp::Clear) == VK_ATTACHMENT_LOAD_OP_CLEAR,
57 "ConvertRenderPassLoadOpToVkLoadOp must be updated");
58 static_assert(static_cast<uint32_t>(RenderPassLoadOp::DontCare) == VK_ATTACHMENT_LOAD_OP_DONT_CARE,
59 "ConvertRenderPassLoadOpToVkLoadOp must be updated");
60 static_assert(static_cast<uint32_t>(RenderPassLoadOp::None) == 3,
61 "ConvertRenderPassLoadOpToVkLoadOp must be updated");
62
63 static_assert(static_cast<uint32_t>(RenderPassStoreOp::Store) == VK_ATTACHMENT_STORE_OP_STORE,
64 "ConvertRenderPassStoreOpToVkStoreOp must be updated");
65 static_assert(static_cast<uint32_t>(RenderPassStoreOp::DontCare) ==
66 VK_ATTACHMENT_STORE_OP_DONT_CARE,
67 "ConvertRenderPassStoreOpToVkStoreOp must be updated");
68 static_assert(static_cast<uint32_t>(RenderPassStoreOp::None) == 2,
69 "ConvertRenderPassStoreOpToVkStoreOp must be updated");
70
71 constexpr uint16_t kMinSampleShadingScale = angle::BitMask<uint16_t>(8);
72
ConvertRenderPassLoadOpToVkLoadOp(RenderPassLoadOp loadOp)73 VkAttachmentLoadOp ConvertRenderPassLoadOpToVkLoadOp(RenderPassLoadOp loadOp)
74 {
75 return loadOp == RenderPassLoadOp::None ? VK_ATTACHMENT_LOAD_OP_NONE_EXT
76 : static_cast<VkAttachmentLoadOp>(loadOp);
77 }
ConvertRenderPassStoreOpToVkStoreOp(RenderPassStoreOp storeOp)78 VkAttachmentStoreOp ConvertRenderPassStoreOpToVkStoreOp(RenderPassStoreOp storeOp)
79 {
80 return storeOp == RenderPassStoreOp::None ? VK_ATTACHMENT_STORE_OP_NONE_EXT
81 : static_cast<VkAttachmentStoreOp>(storeOp);
82 }
83
TransitionBits(size_t size)84 constexpr size_t TransitionBits(size_t size)
85 {
86 return size / kGraphicsPipelineDirtyBitBytes;
87 }
88
89 constexpr size_t kPipelineShadersDescOffset = 0;
90 constexpr size_t kPipelineShadersDescSize =
91 kGraphicsPipelineShadersStateSize + kGraphicsPipelineSharedNonVertexInputStateSize;
92
93 constexpr size_t kPipelineFragmentOutputDescOffset = kGraphicsPipelineShadersStateSize;
94 constexpr size_t kPipelineFragmentOutputDescSize =
95 kGraphicsPipelineSharedNonVertexInputStateSize + kGraphicsPipelineFragmentOutputStateSize;
96
97 constexpr size_t kPipelineVertexInputDescOffset =
98 kGraphicsPipelineShadersStateSize + kPipelineFragmentOutputDescSize;
99 constexpr size_t kPipelineVertexInputDescSize = kGraphicsPipelineVertexInputStateSize;
100
101 static_assert(kPipelineShadersDescOffset % kGraphicsPipelineDirtyBitBytes == 0);
102 static_assert(kPipelineShadersDescSize % kGraphicsPipelineDirtyBitBytes == 0);
103
104 static_assert(kPipelineFragmentOutputDescOffset % kGraphicsPipelineDirtyBitBytes == 0);
105 static_assert(kPipelineFragmentOutputDescSize % kGraphicsPipelineDirtyBitBytes == 0);
106
107 static_assert(kPipelineVertexInputDescOffset % kGraphicsPipelineDirtyBitBytes == 0);
108 static_assert(kPipelineVertexInputDescSize % kGraphicsPipelineDirtyBitBytes == 0);
109
110 constexpr GraphicsPipelineTransitionBits kPipelineShadersTransitionBitsMask =
111 GraphicsPipelineTransitionBits::Mask(TransitionBits(kPipelineShadersDescSize) +
112 TransitionBits(kPipelineShadersDescOffset)) &
113 ~GraphicsPipelineTransitionBits::Mask(TransitionBits(kPipelineShadersDescOffset));
114
GraphicsPipelineHasVertexInput(GraphicsPipelineSubset subset)115 bool GraphicsPipelineHasVertexInput(GraphicsPipelineSubset subset)
116 {
117 return subset == GraphicsPipelineSubset::Complete;
118 }
119
GraphicsPipelineHasShaders(GraphicsPipelineSubset subset)120 bool GraphicsPipelineHasShaders(GraphicsPipelineSubset subset)
121 {
122 return subset == GraphicsPipelineSubset::Complete || subset == GraphicsPipelineSubset::Shaders;
123 }
124
GraphicsPipelineHasShadersOrFragmentOutput(GraphicsPipelineSubset subset)125 bool GraphicsPipelineHasShadersOrFragmentOutput(GraphicsPipelineSubset subset)
126 {
127 return true;
128 }
129
GraphicsPipelineHasFragmentOutput(GraphicsPipelineSubset subset)130 bool GraphicsPipelineHasFragmentOutput(GraphicsPipelineSubset subset)
131 {
132 return subset == GraphicsPipelineSubset::Complete;
133 }
134
PackGLBlendOp(gl::BlendEquationType blendOp)135 uint8_t PackGLBlendOp(gl::BlendEquationType blendOp)
136 {
137 switch (blendOp)
138 {
139 case gl::BlendEquationType::Add:
140 return static_cast<uint8_t>(VK_BLEND_OP_ADD);
141 case gl::BlendEquationType::Subtract:
142 return static_cast<uint8_t>(VK_BLEND_OP_SUBTRACT);
143 case gl::BlendEquationType::ReverseSubtract:
144 return static_cast<uint8_t>(VK_BLEND_OP_REVERSE_SUBTRACT);
145 case gl::BlendEquationType::Min:
146 return static_cast<uint8_t>(VK_BLEND_OP_MIN);
147 case gl::BlendEquationType::Max:
148 return static_cast<uint8_t>(VK_BLEND_OP_MAX);
149 case gl::BlendEquationType::Multiply:
150 return static_cast<uint8_t>(VK_BLEND_OP_MULTIPLY_EXT - VK_BLEND_OP_ZERO_EXT);
151 case gl::BlendEquationType::Screen:
152 return static_cast<uint8_t>(VK_BLEND_OP_SCREEN_EXT - VK_BLEND_OP_ZERO_EXT);
153 case gl::BlendEquationType::Overlay:
154 return static_cast<uint8_t>(VK_BLEND_OP_OVERLAY_EXT - VK_BLEND_OP_ZERO_EXT);
155 case gl::BlendEquationType::Darken:
156 return static_cast<uint8_t>(VK_BLEND_OP_DARKEN_EXT - VK_BLEND_OP_ZERO_EXT);
157 case gl::BlendEquationType::Lighten:
158 return static_cast<uint8_t>(VK_BLEND_OP_LIGHTEN_EXT - VK_BLEND_OP_ZERO_EXT);
159 case gl::BlendEquationType::Colordodge:
160 return static_cast<uint8_t>(VK_BLEND_OP_COLORDODGE_EXT - VK_BLEND_OP_ZERO_EXT);
161 case gl::BlendEquationType::Colorburn:
162 return static_cast<uint8_t>(VK_BLEND_OP_COLORBURN_EXT - VK_BLEND_OP_ZERO_EXT);
163 case gl::BlendEquationType::Hardlight:
164 return static_cast<uint8_t>(VK_BLEND_OP_HARDLIGHT_EXT - VK_BLEND_OP_ZERO_EXT);
165 case gl::BlendEquationType::Softlight:
166 return static_cast<uint8_t>(VK_BLEND_OP_SOFTLIGHT_EXT - VK_BLEND_OP_ZERO_EXT);
167 case gl::BlendEquationType::Difference:
168 return static_cast<uint8_t>(VK_BLEND_OP_DIFFERENCE_EXT - VK_BLEND_OP_ZERO_EXT);
169 case gl::BlendEquationType::Exclusion:
170 return static_cast<uint8_t>(VK_BLEND_OP_EXCLUSION_EXT - VK_BLEND_OP_ZERO_EXT);
171 case gl::BlendEquationType::HslHue:
172 return static_cast<uint8_t>(VK_BLEND_OP_HSL_HUE_EXT - VK_BLEND_OP_ZERO_EXT);
173 case gl::BlendEquationType::HslSaturation:
174 return static_cast<uint8_t>(VK_BLEND_OP_HSL_SATURATION_EXT - VK_BLEND_OP_ZERO_EXT);
175 case gl::BlendEquationType::HslColor:
176 return static_cast<uint8_t>(VK_BLEND_OP_HSL_COLOR_EXT - VK_BLEND_OP_ZERO_EXT);
177 case gl::BlendEquationType::HslLuminosity:
178 return static_cast<uint8_t>(VK_BLEND_OP_HSL_LUMINOSITY_EXT - VK_BLEND_OP_ZERO_EXT);
179 default:
180 UNREACHABLE();
181 return 0;
182 }
183 }
184
UnpackBlendOp(uint8_t packedBlendOp)185 VkBlendOp UnpackBlendOp(uint8_t packedBlendOp)
186 {
187 if (packedBlendOp <= VK_BLEND_OP_MAX)
188 {
189 return static_cast<VkBlendOp>(packedBlendOp);
190 }
191 return static_cast<VkBlendOp>(packedBlendOp + VK_BLEND_OP_ZERO_EXT);
192 }
193
PackGLBlendFactor(gl::BlendFactorType blendFactor)194 uint8_t PackGLBlendFactor(gl::BlendFactorType blendFactor)
195 {
196 switch (blendFactor)
197 {
198 case gl::BlendFactorType::Zero:
199 return static_cast<uint8_t>(VK_BLEND_FACTOR_ZERO);
200 case gl::BlendFactorType::One:
201 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
202 case gl::BlendFactorType::SrcColor:
203 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC_COLOR);
204 case gl::BlendFactorType::DstColor:
205 return static_cast<uint8_t>(VK_BLEND_FACTOR_DST_COLOR);
206 case gl::BlendFactorType::OneMinusSrcColor:
207 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR);
208 case gl::BlendFactorType::SrcAlpha:
209 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC_ALPHA);
210 case gl::BlendFactorType::OneMinusSrcAlpha:
211 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
212 case gl::BlendFactorType::DstAlpha:
213 return static_cast<uint8_t>(VK_BLEND_FACTOR_DST_ALPHA);
214 case gl::BlendFactorType::OneMinusDstAlpha:
215 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA);
216 case gl::BlendFactorType::OneMinusDstColor:
217 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR);
218 case gl::BlendFactorType::SrcAlphaSaturate:
219 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC_ALPHA_SATURATE);
220 case gl::BlendFactorType::ConstantColor:
221 return static_cast<uint8_t>(VK_BLEND_FACTOR_CONSTANT_COLOR);
222 case gl::BlendFactorType::ConstantAlpha:
223 return static_cast<uint8_t>(VK_BLEND_FACTOR_CONSTANT_ALPHA);
224 case gl::BlendFactorType::OneMinusConstantColor:
225 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR);
226 case gl::BlendFactorType::OneMinusConstantAlpha:
227 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA);
228 case gl::BlendFactorType::Src1Color:
229 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC1_COLOR);
230 case gl::BlendFactorType::Src1Alpha:
231 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC1_ALPHA);
232 case gl::BlendFactorType::OneMinusSrc1Color:
233 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR);
234 case gl::BlendFactorType::OneMinusSrc1Alpha:
235 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA);
236 default:
237 UNREACHABLE();
238 return 0;
239 }
240 }
241
242 // A struct that contains render pass information derived from RenderPassDesc. It contains dynamic
243 // rendering structs that could be directly used when creating pipelines or starting a render pass.
244 // When using render pass objects, the contents are converted to RenderPassInfo.
245 struct DynamicRenderingInfo : angle::NonCopyable
246 {
247 VkRenderingInfo renderingInfo;
248 // Storage for VkRenderingInfo
249 gl::DrawBuffersArray<VkRenderingAttachmentInfo> colorAttachmentInfo;
250 VkRenderingAttachmentInfo depthAttachmentInfo;
251 VkRenderingAttachmentInfo stencilAttachmentInfo;
252
253 // Attachment formats for VkPipelineRenderingCreateInfo and
254 // VkCommandBufferInheritanceRenderingInfo.
255 gl::DrawBuffersArray<VkFormat> colorAttachmentFormats;
256 VkFormat depthAttachmentFormat;
257 VkFormat stencilAttachmentFormat;
258
259 // Attachment and input location mapping for VkRenderingAttachmentLocationInfoKHR and
260 // VkRenderingInputAttachmentIndexInfoKHR respectively.
261 gl::DrawBuffersArray<uint32_t> colorAttachmentLocations;
262
263 // Support for VK_EXT_multisampled_render_to_single_sampled
264 VkMultisampledRenderToSingleSampledInfoEXT msrtss;
265
266 // Support for VK_KHR_fragment_shading_rate
267 VkRenderingFragmentShadingRateAttachmentInfoKHR fragmentShadingRateInfo;
268
269 #if defined(ANGLE_PLATFORM_ANDROID)
270 // For VK_ANDROID_external_format_resolve
271 VkExternalFormatANDROID externalFormat;
272 #endif
273 };
274
UnpackAttachmentInfo(VkImageLayout layout,RenderPassLoadOp loadOp,RenderPassStoreOp storeOp,VkImageLayout resolveLayout,VkResolveModeFlagBits resolveMode,VkRenderingAttachmentInfo * infoOut)275 void UnpackAttachmentInfo(VkImageLayout layout,
276 RenderPassLoadOp loadOp,
277 RenderPassStoreOp storeOp,
278 VkImageLayout resolveLayout,
279 VkResolveModeFlagBits resolveMode,
280 VkRenderingAttachmentInfo *infoOut)
281 {
282 *infoOut = {};
283 infoOut->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
284 infoOut->imageLayout = layout;
285 infoOut->resolveImageLayout = resolveLayout;
286 infoOut->resolveMode = resolveMode;
287 infoOut->loadOp = ConvertRenderPassLoadOpToVkLoadOp(loadOp);
288 infoOut->storeOp = ConvertRenderPassStoreOpToVkStoreOp(storeOp);
289 // The image views and clear values are specified when starting the render pass itself.
290 }
291
292 enum class DynamicRenderingInfoSubset
293 {
294 // The complete info as needed by vkCmdBeginRendering.
295 Full,
296 // Only the subset that is needed for pipeline creation / inheritance info. Equivalent to a
297 // compatible render pass. Note that parts of renderingInfo may still be filled, such as
298 // viewMask etc.
299 Pipeline,
300 };
301
DeriveRenderingInfo(Renderer * renderer,const RenderPassDesc & desc,DynamicRenderingInfoSubset subset,const gl::Rectangle & renderArea,VkSubpassContents subpassContents,const FramebufferAttachmentsVector<VkImageView> & attachmentViews,const vk::AttachmentOpsArray & ops,const PackedClearValuesArray & clearValues,uint32_t layerCount,DynamicRenderingInfo * infoOut)302 void DeriveRenderingInfo(Renderer *renderer,
303 const RenderPassDesc &desc,
304 DynamicRenderingInfoSubset subset,
305 const gl::Rectangle &renderArea,
306 VkSubpassContents subpassContents,
307 const FramebufferAttachmentsVector<VkImageView> &attachmentViews,
308 const vk::AttachmentOpsArray &ops,
309 const PackedClearValuesArray &clearValues,
310 uint32_t layerCount,
311 DynamicRenderingInfo *infoOut)
312 {
313 ASSERT(renderer->getFeatures().preferDynamicRendering.enabled);
314 // MSRTT cannot be emulated over dynamic rendering.
315 ASSERT(!renderer->getFeatures().enableMultisampledRenderToTexture.enabled ||
316 renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled);
317
318 #if defined(ANGLE_ENABLE_ASSERTS)
319 // Try to catch errors if the entire struct is not filled but uninitialized data is
320 // retrieved later.
321 memset(infoOut, 0xab, sizeof(*infoOut));
322 #endif
323
324 const bool hasDitheringThroughExtension = desc.isLegacyDitherEnabled();
325 ASSERT(!hasDitheringThroughExtension ||
326 renderer->getFeatures().supportsLegacyDithering.enabled);
327
328 // renderArea and layerCount are determined when beginning the render pass
329 infoOut->renderingInfo = {};
330 infoOut->renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
331 infoOut->renderingInfo.flags =
332 hasDitheringThroughExtension ? VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT : 0;
333 if (subpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS)
334 {
335 infoOut->renderingInfo.flags |= VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT;
336 }
337
338 infoOut->renderingInfo.viewMask =
339 desc.viewCount() > 0 ? angle::BitMask<uint32_t>(desc.viewCount()) : 0;
340
341 // Pack color attachments
342 vk::PackedAttachmentIndex attachmentCount(0);
343 for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
344 {
345 // For dynamic rendering, the mapping of attachments to shader output locations is given in
346 // VkRenderingAttachmentLocationInfoKHR.
347 //
348 // For render pass objects, the mapping is specified by
349 // VkSubpassDescription2::pColorAttachments.
350
351 if (!desc.isColorAttachmentEnabled(colorIndexGL))
352 {
353 ASSERT(!desc.hasColorResolveAttachment(colorIndexGL));
354 continue;
355 }
356
357 infoOut->colorAttachmentLocations[attachmentCount.get()] = colorIndexGL;
358
359 angle::FormatID attachmentFormatID = desc[colorIndexGL];
360 ASSERT(attachmentFormatID != angle::FormatID::NONE);
361 VkFormat attachmentFormat = GetVkFormatFromFormatID(renderer, attachmentFormatID);
362
363 const bool isYUVExternalFormat = vk::IsYUVExternalFormat(attachmentFormatID);
364 #if defined(ANGLE_PLATFORM_ANDROID)
365 // if yuv, we're going to chain this on to VkCommandBufferInheritanceRenderingInfo and
366 // VkPipelineRenderingCreateInfo (or some VkAttachmentDescription2 if falling back to render
367 // pass objects).
368 if (isYUVExternalFormat)
369 {
370 infoOut->externalFormat = {VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID, nullptr, 0};
371
372 const vk::ExternalYuvFormatInfo &externalFormatInfo =
373 renderer->getExternalFormatTable()->getExternalFormatInfo(attachmentFormatID);
374 infoOut->externalFormat.externalFormat = externalFormatInfo.externalFormat;
375 attachmentFormat = externalFormatInfo.colorAttachmentFormat;
376 }
377 #endif
378
379 ASSERT(attachmentFormat != VK_FORMAT_UNDEFINED);
380 infoOut->colorAttachmentFormats[attachmentCount.get()] = attachmentFormat;
381
382 if (subset == DynamicRenderingInfoSubset::Full)
383 {
384 ASSERT(static_cast<vk::ImageLayout>(ops[attachmentCount].initialLayout) !=
385 vk::ImageLayout::SharedPresent ||
386 static_cast<vk::ImageLayout>(ops[attachmentCount].finalLayout) ==
387 vk::ImageLayout::SharedPresent);
388 const VkImageLayout layout = vk::ConvertImageLayoutToVkImageLayout(
389 static_cast<vk::ImageLayout>(ops[attachmentCount].initialLayout));
390 const VkImageLayout resolveImageLayout =
391 (static_cast<vk::ImageLayout>(ops[attachmentCount].finalResolveLayout) ==
392 vk::ImageLayout::SharedPresent
393 ? VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
394 : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
395 const VkResolveModeFlagBits resolveMode =
396 isYUVExternalFormat ? VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID
397 : desc.hasColorResolveAttachment(colorIndexGL) ? VK_RESOLVE_MODE_AVERAGE_BIT
398 : VK_RESOLVE_MODE_NONE;
399 const RenderPassLoadOp loadOp =
400 static_cast<RenderPassLoadOp>(ops[attachmentCount].loadOp);
401 const RenderPassStoreOp storeOp =
402 static_cast<RenderPassStoreOp>(ops[attachmentCount].storeOp);
403
404 UnpackAttachmentInfo(layout, loadOp, storeOp, resolveImageLayout, resolveMode,
405 &infoOut->colorAttachmentInfo[attachmentCount.get()]);
406
407 // See description of RenderPassFramebuffer::mImageViews regarding the layout of the
408 // attachmentViews. In short, the draw attachments are packed, while the resolve
409 // attachments are not.
410 if (isYUVExternalFormat && renderer->nullColorAttachmentWithExternalFormatResolve())
411 {
412 // If nullColorAttachmentWithExternalFormatResolve is VK_TRUE, attachmentViews has
413 // no color attachment imageView and only has resolveImageView.
414 infoOut->colorAttachmentInfo[attachmentCount.get()].imageView = VK_NULL_HANDLE;
415 infoOut->colorAttachmentInfo[attachmentCount.get()].resolveImageView =
416 attachmentViews[attachmentCount.get()];
417 infoOut->colorAttachmentInfo[attachmentCount.get()].clearValue =
418 clearValues[attachmentCount];
419
420 ++attachmentCount;
421 continue;
422 }
423 infoOut->colorAttachmentInfo[attachmentCount.get()].imageView =
424 attachmentViews[attachmentCount.get()];
425 if (resolveMode != VK_RESOLVE_MODE_NONE)
426 {
427 infoOut->colorAttachmentInfo[attachmentCount.get()].resolveImageView =
428 attachmentViews[RenderPassFramebuffer::kColorResolveAttachmentBegin +
429 colorIndexGL];
430 }
431 infoOut->colorAttachmentInfo[attachmentCount.get()].clearValue =
432 clearValues[attachmentCount];
433 }
434
435 ++attachmentCount;
436 }
437
438 infoOut->renderingInfo.colorAttachmentCount = attachmentCount.get();
439 infoOut->renderingInfo.pColorAttachments = infoOut->colorAttachmentInfo.data();
440
441 infoOut->depthAttachmentFormat = VK_FORMAT_UNDEFINED;
442 infoOut->stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
443
444 // Depth/stencil attachment, if any
445 if (desc.hasDepthStencilAttachment())
446 {
447 const uint32_t depthStencilIndexGL =
448 static_cast<uint32_t>(desc.depthStencilAttachmentIndex());
449
450 const angle::FormatID attachmentFormatID = desc[depthStencilIndexGL];
451 ASSERT(attachmentFormatID != angle::FormatID::NONE);
452 const angle::Format &angleFormat = angle::Format::Get(attachmentFormatID);
453 const VkFormat attachmentFormat = GetVkFormatFromFormatID(renderer, attachmentFormatID);
454
455 infoOut->depthAttachmentFormat =
456 angleFormat.depthBits == 0 ? VK_FORMAT_UNDEFINED : attachmentFormat;
457 infoOut->stencilAttachmentFormat =
458 angleFormat.stencilBits == 0 ? VK_FORMAT_UNDEFINED : attachmentFormat;
459
460 if (subset == DynamicRenderingInfoSubset::Full)
461 {
462 const bool resolveDepth =
463 angleFormat.depthBits != 0 && desc.hasDepthResolveAttachment();
464 const bool resolveStencil =
465 angleFormat.stencilBits != 0 && desc.hasStencilResolveAttachment();
466
467 const VkImageLayout layout = ConvertImageLayoutToVkImageLayout(
468 static_cast<vk::ImageLayout>(ops[attachmentCount].initialLayout));
469 const VkImageLayout resolveImageLayout =
470 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
471 const VkResolveModeFlagBits depthResolveMode =
472 resolveDepth ? VK_RESOLVE_MODE_SAMPLE_ZERO_BIT : VK_RESOLVE_MODE_NONE;
473 const VkResolveModeFlagBits stencilResolveMode =
474 resolveStencil ? VK_RESOLVE_MODE_SAMPLE_ZERO_BIT : VK_RESOLVE_MODE_NONE;
475 const RenderPassLoadOp loadOp =
476 static_cast<RenderPassLoadOp>(ops[attachmentCount].loadOp);
477 const RenderPassStoreOp storeOp =
478 static_cast<RenderPassStoreOp>(ops[attachmentCount].storeOp);
479 const RenderPassLoadOp stencilLoadOp =
480 static_cast<RenderPassLoadOp>(ops[attachmentCount].stencilLoadOp);
481 const RenderPassStoreOp stencilStoreOp =
482 static_cast<RenderPassStoreOp>(ops[attachmentCount].stencilStoreOp);
483
484 UnpackAttachmentInfo(layout, loadOp, storeOp, resolveImageLayout, depthResolveMode,
485 &infoOut->depthAttachmentInfo);
486 UnpackAttachmentInfo(layout, stencilLoadOp, stencilStoreOp, resolveImageLayout,
487 stencilResolveMode, &infoOut->stencilAttachmentInfo);
488
489 infoOut->depthAttachmentInfo.imageView = attachmentViews[attachmentCount.get()];
490 if (resolveDepth)
491 {
492 infoOut->depthAttachmentInfo.resolveImageView =
493 attachmentViews[RenderPassFramebuffer::kDepthStencilResolveAttachment];
494 }
495 infoOut->depthAttachmentInfo.clearValue = clearValues[attachmentCount];
496
497 infoOut->stencilAttachmentInfo.imageView = attachmentViews[attachmentCount.get()];
498 if (resolveStencil)
499 {
500 infoOut->stencilAttachmentInfo.resolveImageView =
501 attachmentViews[RenderPassFramebuffer::kDepthStencilResolveAttachment];
502 }
503 infoOut->stencilAttachmentInfo.clearValue = clearValues[attachmentCount];
504
505 infoOut->renderingInfo.pDepthAttachment =
506 angleFormat.depthBits == 0 ? nullptr : &infoOut->depthAttachmentInfo;
507 infoOut->renderingInfo.pStencilAttachment =
508 angleFormat.stencilBits == 0 ? nullptr : &infoOut->stencilAttachmentInfo;
509 }
510
511 ++attachmentCount;
512 }
513
514 if (subset == DynamicRenderingInfoSubset::Full)
515 {
516 infoOut->renderingInfo.renderArea.offset.x = static_cast<uint32_t>(renderArea.x);
517 infoOut->renderingInfo.renderArea.offset.y = static_cast<uint32_t>(renderArea.y);
518 infoOut->renderingInfo.renderArea.extent.width = static_cast<uint32_t>(renderArea.width);
519 infoOut->renderingInfo.renderArea.extent.height = static_cast<uint32_t>(renderArea.height);
520 infoOut->renderingInfo.layerCount = layerCount;
521
522 if (desc.isRenderToTexture())
523 {
524 ASSERT(renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled);
525
526 infoOut->msrtss = {};
527 infoOut->msrtss.sType =
528 VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT;
529 infoOut->msrtss.multisampledRenderToSingleSampledEnable = true;
530 infoOut->msrtss.rasterizationSamples = gl_vk::GetSamples(
531 desc.samples(), renderer->getFeatures().limitSampleCountTo2.enabled);
532 AddToPNextChain(&infoOut->renderingInfo, &infoOut->msrtss);
533 }
534
535 // Fragment shading rate attachment, if any
536 if (desc.hasFragmentShadingAttachment())
537 {
538 infoOut->fragmentShadingRateInfo = {};
539 infoOut->fragmentShadingRateInfo.sType =
540 VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
541 infoOut->fragmentShadingRateInfo.imageView = attachmentViews[attachmentCount.get()];
542 infoOut->fragmentShadingRateInfo.imageLayout =
543 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
544 infoOut->fragmentShadingRateInfo.shadingRateAttachmentTexelSize =
545 renderer->getMaxFragmentShadingRateAttachmentTexelSize();
546
547 AddToPNextChain(&infoOut->renderingInfo, &infoOut->fragmentShadingRateInfo);
548 }
549 }
550 }
551
552 enum class ShadersStateSource
553 {
554 ThisPipeline,
555 PipelineLibrary,
556 };
557
AttachPipelineRenderingInfo(ErrorContext * context,const RenderPassDesc & desc,const DynamicRenderingInfo & renderingInfo,GraphicsPipelineSubset subset,ShadersStateSource shadersSource,VkPipelineRenderingCreateInfoKHR * pipelineRenderingInfoOut,VkRenderingAttachmentLocationInfoKHR * attachmentLocationsOut,VkRenderingInputAttachmentIndexInfoKHR * inputLocationsOut,VkPipelineCreateFlags2CreateInfoKHR * createFlags2,VkGraphicsPipelineCreateInfo * createInfoOut)558 void AttachPipelineRenderingInfo(ErrorContext *context,
559 const RenderPassDesc &desc,
560 const DynamicRenderingInfo &renderingInfo,
561 GraphicsPipelineSubset subset,
562 ShadersStateSource shadersSource,
563 VkPipelineRenderingCreateInfoKHR *pipelineRenderingInfoOut,
564 VkRenderingAttachmentLocationInfoKHR *attachmentLocationsOut,
565 VkRenderingInputAttachmentIndexInfoKHR *inputLocationsOut,
566 VkPipelineCreateFlags2CreateInfoKHR *createFlags2,
567 VkGraphicsPipelineCreateInfo *createInfoOut)
568 {
569 *pipelineRenderingInfoOut = {};
570 pipelineRenderingInfoOut->sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
571 pipelineRenderingInfoOut->viewMask = renderingInfo.renderingInfo.viewMask;
572 // Note: the formats only affect the fragment output subset.
573 if (GraphicsPipelineHasFragmentOutput(subset))
574 {
575 pipelineRenderingInfoOut->colorAttachmentCount =
576 renderingInfo.renderingInfo.colorAttachmentCount;
577 pipelineRenderingInfoOut->pColorAttachmentFormats =
578 renderingInfo.colorAttachmentFormats.data();
579 pipelineRenderingInfoOut->depthAttachmentFormat = renderingInfo.depthAttachmentFormat;
580 pipelineRenderingInfoOut->stencilAttachmentFormat = renderingInfo.stencilAttachmentFormat;
581 }
582 AddToPNextChain(createInfoOut, pipelineRenderingInfoOut);
583
584 *attachmentLocationsOut = {};
585 attachmentLocationsOut->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR;
586 attachmentLocationsOut->colorAttachmentCount = renderingInfo.renderingInfo.colorAttachmentCount;
587 attachmentLocationsOut->pColorAttachmentLocations =
588 renderingInfo.colorAttachmentLocations.data();
589 AddToPNextChain(createInfoOut, attachmentLocationsOut);
590
591 // Note: VkRenderingInputAttachmentIndexInfoKHR only affects the fragment stage subset, and is
592 // needed only when the shaders stage is not coming from a pipeline library (where this mapping
593 // is already specified).
594 if (desc.hasColorFramebufferFetch() && shadersSource == ShadersStateSource::ThisPipeline &&
595 GraphicsPipelineHasShaders(subset))
596 {
597 *inputLocationsOut = {};
598 inputLocationsOut->sType = VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR;
599 if (desc.hasColorFramebufferFetch())
600 {
601 inputLocationsOut->colorAttachmentCount =
602 renderingInfo.renderingInfo.colorAttachmentCount;
603 inputLocationsOut->pColorAttachmentInputIndices =
604 renderingInfo.colorAttachmentLocations.data();
605 }
606 // Note: for depth/stencil, there is no need to explicitly set |pDepthInputAttachmentIndex|,
607 // |pStencilInputAttachmentIndex|. When NULL, they automatically map to input attachments
608 // without a |InputAttachmentIndex| decoration, which is exactly how ANGLE produces its
609 // SPIR-V.
610
611 AddToPNextChain(createInfoOut, inputLocationsOut);
612 }
613
614 if (desc.hasFragmentShadingAttachment())
615 {
616 createInfoOut->flags |=
617 VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
618 }
619
620 if (desc.isLegacyDitherEnabled())
621 {
622 ASSERT(context->getFeatures().supportsMaintenance5.enabled);
623 ASSERT(context->getFeatures().supportsLegacyDithering.enabled);
624
625 *createFlags2 = {};
626 createFlags2->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO_KHR;
627 createFlags2->flags = createInfoOut->flags;
628 createFlags2->flags |= VK_PIPELINE_CREATE_2_ENABLE_LEGACY_DITHERING_BIT_EXT;
629 createInfoOut->flags = 0;
630
631 AddToPNextChain(createInfoOut, createFlags2);
632 }
633 }
634
UnpackAttachmentDesc(Renderer * renderer,VkAttachmentDescription2 * desc,angle::FormatID formatID,uint8_t samples,const PackedAttachmentOpsDesc & ops)635 void UnpackAttachmentDesc(Renderer *renderer,
636 VkAttachmentDescription2 *desc,
637 angle::FormatID formatID,
638 uint8_t samples,
639 const PackedAttachmentOpsDesc &ops)
640 {
641 *desc = {};
642 desc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
643 desc->format = GetVkFormatFromFormatID(renderer, formatID);
644 desc->samples = gl_vk::GetSamples(samples, renderer->getFeatures().limitSampleCountTo2.enabled);
645 desc->loadOp = ConvertRenderPassLoadOpToVkLoadOp(static_cast<RenderPassLoadOp>(ops.loadOp));
646 desc->storeOp =
647 ConvertRenderPassStoreOpToVkStoreOp(static_cast<RenderPassStoreOp>(ops.storeOp));
648 desc->stencilLoadOp =
649 ConvertRenderPassLoadOpToVkLoadOp(static_cast<RenderPassLoadOp>(ops.stencilLoadOp));
650 desc->stencilStoreOp =
651 ConvertRenderPassStoreOpToVkStoreOp(static_cast<RenderPassStoreOp>(ops.stencilStoreOp));
652 desc->initialLayout =
653 ConvertImageLayoutToVkImageLayout(static_cast<ImageLayout>(ops.initialLayout));
654 desc->finalLayout =
655 ConvertImageLayoutToVkImageLayout(static_cast<ImageLayout>(ops.finalLayout));
656 }
657
658 struct AttachmentInfo
659 {
660 bool usedAsInputAttachment;
661 bool isInvalidated;
662 // If only one aspect of a depth/stencil image is resolved, the following is used to retain the
663 // other aspect.
664 bool isUnused;
665 };
666
UnpackColorResolveAttachmentDesc(Renderer * renderer,VkAttachmentDescription2 * desc,angle::FormatID formatID,const AttachmentInfo & info,VkImageLayout initialLayout,VkImageLayout finalLayout)667 void UnpackColorResolveAttachmentDesc(Renderer *renderer,
668 VkAttachmentDescription2 *desc,
669 angle::FormatID formatID,
670 const AttachmentInfo &info,
671 VkImageLayout initialLayout,
672 VkImageLayout finalLayout)
673 {
674 *desc = {};
675 desc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
676 desc->format = GetVkFormatFromFormatID(renderer, formatID);
677
678 // This function is for color resolve attachments.
679 const angle::Format &angleFormat = angle::Format::Get(formatID);
680 ASSERT(angleFormat.depthBits == 0 && angleFormat.stencilBits == 0);
681
682 // Resolve attachments always have a sample count of 1.
683 //
684 // If the corresponding color attachment needs to take its initial value from the resolve
685 // attachment (i.e. needs to be unresolved), loadOp needs to be set to LOAD, otherwise it should
686 // be DONT_CARE as it gets overwritten during resolve.
687 //
688 // storeOp should be STORE. If the attachment is invalidated, it is set to DONT_CARE.
689 desc->samples = VK_SAMPLE_COUNT_1_BIT;
690 desc->loadOp =
691 info.usedAsInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
692 desc->storeOp =
693 info.isInvalidated ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
694 desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
695 desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
696 desc->initialLayout = initialLayout;
697 desc->finalLayout = finalLayout;
698 }
699
UnpackDepthStencilResolveAttachmentDesc(vk::ErrorContext * context,VkAttachmentDescription2 * desc,angle::FormatID formatID,const AttachmentInfo & depthInfo,const AttachmentInfo & stencilInfo)700 void UnpackDepthStencilResolveAttachmentDesc(vk::ErrorContext *context,
701 VkAttachmentDescription2 *desc,
702 angle::FormatID formatID,
703 const AttachmentInfo &depthInfo,
704 const AttachmentInfo &stencilInfo)
705 {
706 vk::Renderer *renderer = context->getRenderer();
707 *desc = {};
708 desc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
709 desc->format = GetVkFormatFromFormatID(renderer, formatID);
710
711 // This function is for depth/stencil resolve attachment.
712 const angle::Format &angleFormat = angle::Format::Get(formatID);
713 ASSERT(angleFormat.depthBits != 0 || angleFormat.stencilBits != 0);
714
715 // Missing aspects are folded in isInvalidate parameters, so no need to double check.
716 ASSERT(angleFormat.depthBits > 0 || depthInfo.isInvalidated);
717 ASSERT(angleFormat.stencilBits > 0 || stencilInfo.isInvalidated);
718
719 const bool supportsLoadStoreOpNone =
720 context->getFeatures().supportsRenderPassLoadStoreOpNone.enabled;
721 const bool supportsStoreOpNone =
722 supportsLoadStoreOpNone || context->getFeatures().supportsRenderPassStoreOpNone.enabled;
723
724 const VkAttachmentLoadOp preserveLoadOp =
725 supportsLoadStoreOpNone ? VK_ATTACHMENT_LOAD_OP_NONE_EXT : VK_ATTACHMENT_LOAD_OP_LOAD;
726 const VkAttachmentStoreOp preserveStoreOp =
727 supportsStoreOpNone ? VK_ATTACHMENT_STORE_OP_NONE : VK_ATTACHMENT_STORE_OP_STORE;
728
729 // Similarly to color resolve attachments, sample count is 1, loadOp is LOAD or DONT_CARE based
730 // on whether unresolve is required, and storeOp is STORE or DONT_CARE based on whether the
731 // attachment is invalidated or the aspect exists.
732 desc->samples = VK_SAMPLE_COUNT_1_BIT;
733 if (depthInfo.isUnused)
734 {
735 desc->loadOp = preserveLoadOp;
736 desc->storeOp = preserveStoreOp;
737 }
738 else
739 {
740 desc->loadOp = depthInfo.usedAsInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD
741 : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
742 desc->storeOp = depthInfo.isInvalidated ? VK_ATTACHMENT_STORE_OP_DONT_CARE
743 : VK_ATTACHMENT_STORE_OP_STORE;
744 }
745 if (stencilInfo.isUnused)
746 {
747 desc->stencilLoadOp = preserveLoadOp;
748 desc->stencilStoreOp = preserveStoreOp;
749 }
750 else
751 {
752 desc->stencilLoadOp = stencilInfo.usedAsInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD
753 : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
754 desc->stencilStoreOp = stencilInfo.isInvalidated ? VK_ATTACHMENT_STORE_OP_DONT_CARE
755 : VK_ATTACHMENT_STORE_OP_STORE;
756 }
757 desc->initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
758 desc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
759 }
760
UnpackFragmentShadingRateAttachmentDesc(VkAttachmentDescription2 * desc)761 void UnpackFragmentShadingRateAttachmentDesc(VkAttachmentDescription2 *desc)
762 {
763 *desc = {};
764 desc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
765 desc->flags = 0;
766 desc->format = VK_FORMAT_R8_UINT;
767 desc->samples = VK_SAMPLE_COUNT_1_BIT;
768 desc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
769 desc->storeOp = VK_ATTACHMENT_STORE_OP_NONE;
770 desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
771 desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
772 desc->initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
773 desc->finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
774 }
775
UnpackStencilState(const PackedStencilOpState & packedState,VkStencilOpState * stateOut,bool writeMaskWorkaround)776 void UnpackStencilState(const PackedStencilOpState &packedState,
777 VkStencilOpState *stateOut,
778 bool writeMaskWorkaround)
779 {
780 // Any non-zero value works for the purposes of the useNonZeroStencilWriteMaskStaticState driver
781 // bug workaround.
782 constexpr uint32_t kNonZeroWriteMaskForWorkaround = 1;
783
784 stateOut->failOp = static_cast<VkStencilOp>(packedState.fail);
785 stateOut->passOp = static_cast<VkStencilOp>(packedState.pass);
786 stateOut->depthFailOp = static_cast<VkStencilOp>(packedState.depthFail);
787 stateOut->compareOp = static_cast<VkCompareOp>(packedState.compare);
788 stateOut->compareMask = 0;
789 stateOut->writeMask = writeMaskWorkaround ? kNonZeroWriteMaskForWorkaround : 0;
790 stateOut->reference = 0;
791 }
792
UnpackBlendAttachmentState(const PackedColorBlendAttachmentState & packedState,VkPipelineColorBlendAttachmentState * stateOut)793 void UnpackBlendAttachmentState(const PackedColorBlendAttachmentState &packedState,
794 VkPipelineColorBlendAttachmentState *stateOut)
795 {
796 stateOut->srcColorBlendFactor = static_cast<VkBlendFactor>(packedState.srcColorBlendFactor);
797 stateOut->dstColorBlendFactor = static_cast<VkBlendFactor>(packedState.dstColorBlendFactor);
798 stateOut->colorBlendOp = UnpackBlendOp(packedState.colorBlendOp);
799 stateOut->srcAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.srcAlphaBlendFactor);
800 stateOut->dstAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.dstAlphaBlendFactor);
801 stateOut->alphaBlendOp = UnpackBlendOp(packedState.alphaBlendOp);
802 }
803
SetPipelineShaderStageInfo(const VkStructureType type,const VkShaderStageFlagBits stage,const VkShaderModule module,const VkSpecializationInfo & specializationInfo,VkPipelineShaderStageCreateInfo * shaderStage)804 void SetPipelineShaderStageInfo(const VkStructureType type,
805 const VkShaderStageFlagBits stage,
806 const VkShaderModule module,
807 const VkSpecializationInfo &specializationInfo,
808 VkPipelineShaderStageCreateInfo *shaderStage)
809 {
810 shaderStage->sType = type;
811 shaderStage->flags = 0;
812 shaderStage->stage = stage;
813 shaderStage->module = module;
814 shaderStage->pName = "main";
815 shaderStage->pSpecializationInfo = &specializationInfo;
816 }
817
818 // Defines a subpass that uses the resolve attachments as input attachments to initialize color and
819 // depth/stencil attachments that need to be "unresolved" at the start of the render pass. The
820 // subpass will only contain the attachments that need to be unresolved to simplify the shader that
821 // performs the operations.
InitializeUnresolveSubpass(const RenderPassDesc & desc,const gl::DrawBuffersVector<VkAttachmentReference2> & drawSubpassColorAttachmentRefs,const gl::DrawBuffersVector<VkAttachmentReference2> & drawSubpassResolveAttachmentRefs,const VkAttachmentReference2 & depthStencilAttachmentRef,const VkAttachmentReference2 & depthStencilResolveAttachmentRef,gl::DrawBuffersVector<VkAttachmentReference2> * unresolveColorAttachmentRefs,VkAttachmentReference2 * unresolveDepthStencilAttachmentRef,FramebufferAttachmentsVector<VkAttachmentReference2> * unresolveInputAttachmentRefs,FramebufferAttachmentsVector<uint32_t> * unresolvePreserveAttachmentRefs,VkSubpassDescription2 * subpassDesc)822 void InitializeUnresolveSubpass(
823 const RenderPassDesc &desc,
824 const gl::DrawBuffersVector<VkAttachmentReference2> &drawSubpassColorAttachmentRefs,
825 const gl::DrawBuffersVector<VkAttachmentReference2> &drawSubpassResolveAttachmentRefs,
826 const VkAttachmentReference2 &depthStencilAttachmentRef,
827 const VkAttachmentReference2 &depthStencilResolveAttachmentRef,
828 gl::DrawBuffersVector<VkAttachmentReference2> *unresolveColorAttachmentRefs,
829 VkAttachmentReference2 *unresolveDepthStencilAttachmentRef,
830 FramebufferAttachmentsVector<VkAttachmentReference2> *unresolveInputAttachmentRefs,
831 FramebufferAttachmentsVector<uint32_t> *unresolvePreserveAttachmentRefs,
832 VkSubpassDescription2 *subpassDesc)
833 {
834 // Assume the GL Framebuffer has the following attachments enabled:
835 //
836 // GL Color 0
837 // GL Color 3
838 // GL Color 4
839 // GL Color 6
840 // GL Color 7
841 // GL Depth/Stencil
842 //
843 // Additionally, assume Color 0, 4 and 6 are multisampled-render-to-texture (or for any other
844 // reason) have corresponding resolve attachments. Furthermore, say Color 4 and 6 require an
845 // initial unresolve operation.
846 //
847 // In the above example, the render pass is created with the following attachments:
848 //
849 // RP Attachment[0] <- corresponding to GL Color 0
850 // RP Attachment[1] <- corresponding to GL Color 3
851 // RP Attachment[2] <- corresponding to GL Color 4
852 // RP Attachment[3] <- corresponding to GL Color 6
853 // RP Attachment[4] <- corresponding to GL Color 7
854 // RP Attachment[5] <- corresponding to GL Depth/Stencil
855 // RP Attachment[6] <- corresponding to resolve attachment of GL Color 0
856 // RP Attachment[7] <- corresponding to resolve attachment of GL Color 4
857 // RP Attachment[8] <- corresponding to resolve attachment of GL Color 6
858 //
859 // If the depth/stencil attachment is to be resolved, the following attachment would also be
860 // present:
861 //
862 // RP Attachment[9] <- corresponding to resolve attachment of GL Depth/Stencil
863 //
864 // The subpass that takes the application draw calls has the following attachments, creating the
865 // mapping from the Vulkan attachment indices (i.e. RP attachment indices) to GL indices as
866 // indicated by the GL shaders:
867 //
868 // Subpass[1] Color[0] -> RP Attachment[0]
869 // Subpass[1] Color[1] -> VK_ATTACHMENT_UNUSED
870 // Subpass[1] Color[2] -> VK_ATTACHMENT_UNUSED
871 // Subpass[1] Color[3] -> RP Attachment[1]
872 // Subpass[1] Color[4] -> RP Attachment[2]
873 // Subpass[1] Color[5] -> VK_ATTACHMENT_UNUSED
874 // Subpass[1] Color[6] -> RP Attachment[3]
875 // Subpass[1] Color[7] -> RP Attachment[4]
876 // Subpass[1] Depth/Stencil -> RP Attachment[5]
877 // Subpass[1] Resolve[0] -> RP Attachment[6]
878 // Subpass[1] Resolve[1] -> VK_ATTACHMENT_UNUSED
879 // Subpass[1] Resolve[2] -> VK_ATTACHMENT_UNUSED
880 // Subpass[1] Resolve[3] -> VK_ATTACHMENT_UNUSED
881 // Subpass[1] Resolve[4] -> RP Attachment[7]
882 // Subpass[1] Resolve[5] -> VK_ATTACHMENT_UNUSED
883 // Subpass[1] Resolve[6] -> RP Attachment[8]
884 // Subpass[1] Resolve[7] -> VK_ATTACHMENT_UNUSED
885 //
886 // With depth/stencil resolve attachment:
887 //
888 // Subpass[1] Depth/Stencil Resolve -> RP Attachment[9]
889 //
890 // The initial subpass that's created here is (remember that in the above example Color 4 and 6
891 // need to be unresolved):
892 //
893 // Subpass[0] Input[0] -> RP Attachment[7] = Subpass[1] Resolve[4]
894 // Subpass[0] Input[1] -> RP Attachment[8] = Subpass[1] Resolve[6]
895 // Subpass[0] Color[0] -> RP Attachment[2] = Subpass[1] Color[4]
896 // Subpass[0] Color[1] -> RP Attachment[3] = Subpass[1] Color[6]
897 //
898 // The trick here therefore is to use the color attachment refs already created for the
899 // application draw subpass indexed with colorIndexGL.
900 //
901 // If depth/stencil needs to be unresolved (note that as input attachment, it's inserted before
902 // the color attachments. See UtilsVk::unresolve()):
903 //
904 // Subpass[0] Input[0] -> RP Attachment[9] = Subpass[1] Depth/Stencil Resolve
905 // Subpass[0] Depth/Stencil -> RP Attachment[5] = Subpass[1] Depth/Stencil
906 //
907 // As an additional note, the attachments that are not used in the unresolve subpass must be
908 // preserved. That is color attachments and the depth/stencil attachment if any. Resolve
909 // attachments are rewritten by the next subpass, so they don't need to be preserved. Note that
910 // there's no need to preserve attachments whose loadOp is DONT_CARE. For simplicity, we
911 // preserve those as well. The driver would ideally avoid preserving attachments with
912 // loadOp=DONT_CARE.
913 //
914 // With the above example:
915 //
916 // Subpass[0] Preserve[0] -> RP Attachment[0] = Subpass[1] Color[0]
917 // Subpass[0] Preserve[1] -> RP Attachment[1] = Subpass[1] Color[3]
918 // Subpass[0] Preserve[2] -> RP Attachment[4] = Subpass[1] Color[7]
919 //
920 // If depth/stencil is not unresolved:
921 //
922 // Subpass[0] Preserve[3] -> RP Attachment[5] = Subpass[1] Depth/Stencil
923 //
924 // Again, the color attachment refs already created for the application draw subpass can be used
925 // indexed with colorIndexGL.
926 if (desc.hasDepthStencilUnresolveAttachment())
927 {
928 ASSERT(desc.hasDepthStencilAttachment());
929 ASSERT(desc.hasDepthStencilResolveAttachment());
930
931 *unresolveDepthStencilAttachmentRef = depthStencilAttachmentRef;
932
933 VkAttachmentReference2 unresolveDepthStencilInputAttachmentRef = {};
934 unresolveDepthStencilInputAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
935 unresolveDepthStencilInputAttachmentRef.attachment =
936 depthStencilResolveAttachmentRef.attachment;
937 unresolveDepthStencilInputAttachmentRef.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
938
939 unresolveDepthStencilInputAttachmentRef.aspectMask = 0;
940 if (desc.hasDepthUnresolveAttachment())
941 {
942 unresolveDepthStencilInputAttachmentRef.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
943 }
944 if (desc.hasStencilUnresolveAttachment())
945 {
946 unresolveDepthStencilInputAttachmentRef.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
947 }
948
949 unresolveInputAttachmentRefs->push_back(unresolveDepthStencilInputAttachmentRef);
950 }
951 else if (desc.hasDepthStencilAttachment())
952 {
953 // Preserve the depth/stencil attachment if not unresolved. Again, there's no need to
954 // preserve this attachment if loadOp=DONT_CARE, but we do for simplicity.
955 unresolvePreserveAttachmentRefs->push_back(depthStencilAttachmentRef.attachment);
956 }
957
958 for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
959 {
960 if (!desc.hasColorUnresolveAttachment(colorIndexGL))
961 {
962 if (desc.isColorAttachmentEnabled(colorIndexGL))
963 {
964 unresolvePreserveAttachmentRefs->push_back(
965 drawSubpassColorAttachmentRefs[colorIndexGL].attachment);
966 }
967 continue;
968 }
969 ASSERT(desc.isColorAttachmentEnabled(colorIndexGL));
970 ASSERT(desc.hasColorResolveAttachment(colorIndexGL));
971 ASSERT(drawSubpassColorAttachmentRefs[colorIndexGL].attachment != VK_ATTACHMENT_UNUSED);
972 ASSERT(drawSubpassResolveAttachmentRefs[colorIndexGL].attachment != VK_ATTACHMENT_UNUSED);
973
974 unresolveColorAttachmentRefs->push_back(drawSubpassColorAttachmentRefs[colorIndexGL]);
975 unresolveInputAttachmentRefs->push_back(drawSubpassResolveAttachmentRefs[colorIndexGL]);
976
977 // Note the input attachment layout should be shader read-only. The subpass dependency
978 // will take care of transitioning the layout of the resolve attachment to color attachment
979 // automatically.
980 unresolveInputAttachmentRefs->back().layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
981 }
982
983 ASSERT(!unresolveColorAttachmentRefs->empty() ||
984 unresolveDepthStencilAttachmentRef->attachment != VK_ATTACHMENT_UNUSED);
985 ASSERT(unresolveColorAttachmentRefs->size() +
986 (desc.hasDepthStencilUnresolveAttachment() ? 1 : 0) ==
987 unresolveInputAttachmentRefs->size());
988
989 subpassDesc->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
990 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
991 subpassDesc->inputAttachmentCount = static_cast<uint32_t>(unresolveInputAttachmentRefs->size());
992 subpassDesc->pInputAttachments = unresolveInputAttachmentRefs->data();
993 subpassDesc->colorAttachmentCount = static_cast<uint32_t>(unresolveColorAttachmentRefs->size());
994 subpassDesc->pColorAttachments = unresolveColorAttachmentRefs->data();
995 subpassDesc->pDepthStencilAttachment = unresolveDepthStencilAttachmentRef;
996 subpassDesc->preserveAttachmentCount =
997 static_cast<uint32_t>(unresolvePreserveAttachmentRefs->size());
998 subpassDesc->pPreserveAttachments = unresolvePreserveAttachmentRefs->data();
999 }
1000
1001 // There is normally one subpass, and occasionally another for the unresolve operation.
1002 constexpr size_t kSubpassFastVectorSize = 2;
1003 template <typename T>
1004 using SubpassVector = angle::FastVector<T, kSubpassFastVectorSize>;
1005
InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescription2> & subpassDesc,bool unresolveColor,bool unresolveDepthStencil,std::vector<VkSubpassDependency2> * subpassDependencies)1006 void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescription2> &subpassDesc,
1007 bool unresolveColor,
1008 bool unresolveDepthStencil,
1009 std::vector<VkSubpassDependency2> *subpassDependencies)
1010 {
1011 ASSERT(subpassDesc.size() >= 2);
1012 ASSERT(unresolveColor || unresolveDepthStencil);
1013
1014 // The unresolve subpass is the first subpass. The application draw subpass is the next one.
1015 constexpr uint32_t kUnresolveSubpassIndex = 0;
1016 constexpr uint32_t kDrawSubpassIndex = 1;
1017
1018 // A subpass dependency is needed between the unresolve and draw subpasses. There are two
1019 // hazards here:
1020 //
1021 // - Subpass 0 writes to color/depth/stencil attachments, subpass 1 writes to the same
1022 // attachments. This is a WaW hazard (color/depth/stencil write -> color/depth/stencil write)
1023 // similar to when two subsequent render passes write to the same images.
1024 // - Subpass 0 reads from resolve attachments, subpass 1 writes to the same resolve attachments.
1025 // This is a WaR hazard (fragment shader read -> color write) which only requires an execution
1026 // barrier.
1027 //
1028 // Note: the DEPENDENCY_BY_REGION flag is necessary to create a "framebuffer-local" dependency,
1029 // as opposed to "framebuffer-global". The latter is effectively a render pass break. The
1030 // former creates a dependency per framebuffer region. If dependency scopes correspond to
1031 // attachments with:
1032 //
1033 // - Same sample count: dependency is at sample granularity
1034 // - Different sample count: dependency is at pixel granularity
1035 //
1036 // The latter is clarified by the spec as such:
1037 //
1038 // > Practically, the pixel vs sample granularity dependency means that if an input attachment
1039 // > has a different number of samples than the pipeline's rasterizationSamples, then a fragment
1040 // > can access any sample in the input attachment's pixel even if it only uses
1041 // > framebuffer-local dependencies.
1042 //
1043 // The dependency for the first hazard above (attachment write -> attachment write) is on
1044 // same-sample attachments, so it will not allow the use of input attachments as required by the
1045 // unresolve subpass. As a result, even though the second hazard seems to be subsumed by the
1046 // first (its src stage is earlier and its dst stage is the same), a separate dependency is
1047 // created for it just to obtain a pixel granularity dependency.
1048 //
1049 // Note: depth/stencil resolve is considered to be done in the color write stage:
1050 //
1051 // > Moving to the next subpass automatically performs any multisample resolve operations in the
1052 // > subpass being ended. End-of-subpass multisample resolves are treated as color attachment
1053 // > writes for the purposes of synchronization. This applies to resolve operations for both
1054 // > color and depth/stencil attachments. That is, they are considered to execute in the
1055 // > VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT pipeline stage and their writes are
1056 // > synchronized with VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT.
1057
1058 subpassDependencies->push_back({});
1059 VkSubpassDependency2 *dependency = &subpassDependencies->back();
1060
1061 constexpr VkPipelineStageFlags kColorWriteStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1062 constexpr VkPipelineStageFlags kColorReadWriteStage =
1063 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1064 constexpr VkAccessFlags kColorWriteFlags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1065 constexpr VkAccessFlags kColorReadWriteFlags =
1066 kColorWriteFlags | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
1067
1068 constexpr VkPipelineStageFlags kDepthStencilWriteStage =
1069 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
1070 constexpr VkPipelineStageFlags kDepthStencilReadWriteStage =
1071 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
1072 constexpr VkAccessFlags kDepthStencilWriteFlags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1073 constexpr VkAccessFlags kDepthStencilReadWriteFlags =
1074 kDepthStencilWriteFlags | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
1075
1076 VkPipelineStageFlags attachmentWriteStages = 0;
1077 VkPipelineStageFlags attachmentReadWriteStages = 0;
1078 VkAccessFlags attachmentWriteFlags = 0;
1079 VkAccessFlags attachmentReadWriteFlags = 0;
1080
1081 if (unresolveColor)
1082 {
1083 attachmentWriteStages |= kColorWriteStage;
1084 attachmentReadWriteStages |= kColorReadWriteStage;
1085 attachmentWriteFlags |= kColorWriteFlags;
1086 attachmentReadWriteFlags |= kColorReadWriteFlags;
1087 }
1088
1089 if (unresolveDepthStencil)
1090 {
1091 attachmentWriteStages |= kDepthStencilWriteStage;
1092 attachmentReadWriteStages |= kDepthStencilReadWriteStage;
1093 attachmentWriteFlags |= kDepthStencilWriteFlags;
1094 attachmentReadWriteFlags |= kDepthStencilReadWriteFlags;
1095 }
1096
1097 dependency->sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
1098 dependency->srcSubpass = kUnresolveSubpassIndex;
1099 dependency->dstSubpass = kDrawSubpassIndex;
1100 dependency->srcStageMask = attachmentWriteStages;
1101 dependency->dstStageMask = attachmentReadWriteStages;
1102 dependency->srcAccessMask = attachmentWriteFlags;
1103 dependency->dstAccessMask = attachmentReadWriteFlags;
1104 dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
1105
1106 subpassDependencies->push_back({});
1107 dependency = &subpassDependencies->back();
1108
1109 // Note again that depth/stencil resolve is considered to be done in the color output stage.
1110 dependency->sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
1111 dependency->srcSubpass = kUnresolveSubpassIndex;
1112 dependency->dstSubpass = kDrawSubpassIndex;
1113 dependency->srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
1114 dependency->dstStageMask = kColorWriteStage;
1115 dependency->srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
1116 dependency->dstAccessMask = kColorWriteFlags;
1117 dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
1118 }
1119
1120 // glFramebufferFetchBarrierEXT and glBlendBarrierKHR require a pipeline barrier to be inserted in
1121 // the render pass. This requires a subpass self-dependency.
1122 //
1123 // For framebuffer fetch:
1124 //
1125 // srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
1126 // dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
1127 // srcAccess = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
1128 // dstAccess = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
1129 //
1130 // For advanced blend:
1131 //
1132 // srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
1133 // dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
1134 // srcAccess = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
1135 // dstAccess = VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT
1136 //
1137 // Subpass dependencies cannot be added after the fact at the end of the render pass due to render
1138 // pass compatibility rules. ANGLE specifies a subpass self-dependency with the above stage/access
1139 // masks in preparation of potential framebuffer fetch and advanced blend barriers. This is known
1140 // not to add any overhead on any hardware we have been able to gather information from.
InitializeDefaultSubpassSelfDependencies(ErrorContext * context,const RenderPassDesc & desc,uint32_t subpassIndex,std::vector<VkSubpassDependency2> * subpassDependencies)1141 void InitializeDefaultSubpassSelfDependencies(
1142 ErrorContext *context,
1143 const RenderPassDesc &desc,
1144 uint32_t subpassIndex,
1145 std::vector<VkSubpassDependency2> *subpassDependencies)
1146 {
1147 Renderer *renderer = context->getRenderer();
1148 const bool hasRasterizationOrderAttachmentAccess =
1149 renderer->getFeatures().supportsRasterizationOrderAttachmentAccess.enabled;
1150 const bool hasBlendOperationAdvanced =
1151 renderer->getFeatures().supportsBlendOperationAdvanced.enabled;
1152 const bool hasCoherentBlendOperationAdvanced =
1153 renderer->getFeatures().supportsBlendOperationAdvancedCoherent.enabled;
1154
1155 if (hasRasterizationOrderAttachmentAccess &&
1156 (!hasBlendOperationAdvanced || hasCoherentBlendOperationAdvanced))
1157 {
1158 // No need to specify a subpass dependency if VK_EXT_rasterization_order_attachment_access
1159 // is enabled, as that extension makes this subpass dependency implicit.
1160 return;
1161 }
1162
1163 subpassDependencies->push_back({});
1164 VkSubpassDependency2 *dependency = &subpassDependencies->back();
1165
1166 dependency->sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
1167 dependency->srcSubpass = subpassIndex;
1168 dependency->dstSubpass = subpassIndex;
1169 dependency->srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1170 dependency->dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1171 dependency->srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1172 dependency->dstAccessMask = 0;
1173 if (!hasRasterizationOrderAttachmentAccess)
1174 {
1175 dependency->dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
1176 dependency->dstAccessMask |= VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
1177 }
1178 if (hasBlendOperationAdvanced && !hasCoherentBlendOperationAdvanced)
1179 {
1180 dependency->dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT;
1181 }
1182 dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
1183 if (desc.viewCount() > 0)
1184 {
1185 dependency->dependencyFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
1186 }
1187 }
1188
InitializeMSRTSS(ErrorContext * context,uint8_t renderToTextureSamples,VkSubpassDescription2 * subpass,VkSubpassDescriptionDepthStencilResolve * msrtssResolve,VkMultisampledRenderToSingleSampledInfoEXT * msrtss)1189 void InitializeMSRTSS(ErrorContext *context,
1190 uint8_t renderToTextureSamples,
1191 VkSubpassDescription2 *subpass,
1192 VkSubpassDescriptionDepthStencilResolve *msrtssResolve,
1193 VkMultisampledRenderToSingleSampledInfoEXT *msrtss)
1194 {
1195 Renderer *renderer = context->getRenderer();
1196
1197 ASSERT(renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled);
1198
1199 *msrtssResolve = {};
1200 msrtssResolve->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
1201 msrtssResolve->depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1202 msrtssResolve->stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1203
1204 *msrtss = {};
1205 msrtss->sType = VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT;
1206 msrtss->pNext = msrtssResolve;
1207 msrtss->multisampledRenderToSingleSampledEnable = true;
1208 msrtss->rasterizationSamples = gl_vk::GetSamples(
1209 renderToTextureSamples, context->getFeatures().limitSampleCountTo2.enabled);
1210
1211 // msrtss->pNext is not null so can't use AddToPNextChain
1212 AppendToPNextChain(subpass, msrtss);
1213 }
1214
SetRenderPassViewMask(ErrorContext * context,const uint32_t * viewMask,VkRenderPassCreateInfo2 * createInfo,SubpassVector<VkSubpassDescription2> * subpassDesc)1215 void SetRenderPassViewMask(ErrorContext *context,
1216 const uint32_t *viewMask,
1217 VkRenderPassCreateInfo2 *createInfo,
1218 SubpassVector<VkSubpassDescription2> *subpassDesc)
1219 {
1220 for (VkSubpassDescription2 &subpass : *subpassDesc)
1221 {
1222 subpass.viewMask = *viewMask;
1223 }
1224
1225 // For VR, the views are correlated, so this would be an optimization. However, an
1226 // application can also use multiview for example to render to all 6 faces of a cubemap, in
1227 // which case the views are actually not so correlated. In the absence of any hints from
1228 // the application, we have to decide on one or the other. Since VR is more expensive, the
1229 // views are marked as correlated to optimize that use case.
1230 createInfo->correlatedViewMaskCount = 1;
1231 createInfo->pCorrelatedViewMasks = viewMask;
1232 }
1233
ToAttachmentDesciption1(const VkAttachmentDescription2 & desc,VkAttachmentDescription * desc1Out)1234 void ToAttachmentDesciption1(const VkAttachmentDescription2 &desc,
1235 VkAttachmentDescription *desc1Out)
1236 {
1237 ASSERT(desc.pNext == nullptr);
1238
1239 *desc1Out = {};
1240 desc1Out->flags = desc.flags;
1241 desc1Out->format = desc.format;
1242 desc1Out->samples = desc.samples;
1243 desc1Out->loadOp = desc.loadOp;
1244 desc1Out->storeOp = desc.storeOp;
1245 desc1Out->stencilLoadOp = desc.stencilLoadOp;
1246 desc1Out->stencilStoreOp = desc.stencilStoreOp;
1247 desc1Out->initialLayout = desc.initialLayout;
1248 desc1Out->finalLayout = desc.finalLayout;
1249 }
1250
ToAttachmentReference1(const VkAttachmentReference2 & ref,VkAttachmentReference * ref1Out)1251 void ToAttachmentReference1(const VkAttachmentReference2 &ref, VkAttachmentReference *ref1Out)
1252 {
1253 ASSERT(ref.pNext == nullptr);
1254
1255 *ref1Out = {};
1256 ref1Out->attachment = ref.attachment;
1257 ref1Out->layout = ref.layout;
1258 }
1259
ToSubpassDescription1(const VkSubpassDescription2 & desc,const FramebufferAttachmentsVector<VkAttachmentReference> & inputRefs,const gl::DrawBuffersVector<VkAttachmentReference> & colorRefs,const gl::DrawBuffersVector<VkAttachmentReference> & resolveRefs,const VkAttachmentReference & depthStencilRef,VkSubpassDescription * desc1Out)1260 void ToSubpassDescription1(const VkSubpassDescription2 &desc,
1261 const FramebufferAttachmentsVector<VkAttachmentReference> &inputRefs,
1262 const gl::DrawBuffersVector<VkAttachmentReference> &colorRefs,
1263 const gl::DrawBuffersVector<VkAttachmentReference> &resolveRefs,
1264 const VkAttachmentReference &depthStencilRef,
1265 VkSubpassDescription *desc1Out)
1266 {
1267 ASSERT(desc.pNext == nullptr);
1268
1269 *desc1Out = {};
1270 desc1Out->flags = desc.flags;
1271 desc1Out->pipelineBindPoint = desc.pipelineBindPoint;
1272 desc1Out->inputAttachmentCount = static_cast<uint32_t>(inputRefs.size());
1273 desc1Out->pInputAttachments = !inputRefs.empty() ? inputRefs.data() : nullptr;
1274 desc1Out->colorAttachmentCount = static_cast<uint32_t>(colorRefs.size());
1275 desc1Out->pColorAttachments = !colorRefs.empty() ? colorRefs.data() : nullptr;
1276 desc1Out->pResolveAttachments = !resolveRefs.empty() ? resolveRefs.data() : nullptr;
1277 desc1Out->pDepthStencilAttachment = desc.pDepthStencilAttachment ? &depthStencilRef : nullptr;
1278 desc1Out->preserveAttachmentCount = desc.preserveAttachmentCount;
1279 desc1Out->pPreserveAttachments = desc.pPreserveAttachments;
1280 }
1281
ToSubpassDependency1(const VkSubpassDependency2 & dep,VkSubpassDependency * dep1Out)1282 void ToSubpassDependency1(const VkSubpassDependency2 &dep, VkSubpassDependency *dep1Out)
1283 {
1284 ASSERT(dep.pNext == nullptr);
1285
1286 *dep1Out = {};
1287 dep1Out->srcSubpass = dep.srcSubpass;
1288 dep1Out->dstSubpass = dep.dstSubpass;
1289 dep1Out->srcStageMask = dep.srcStageMask;
1290 dep1Out->dstStageMask = dep.dstStageMask;
1291 dep1Out->srcAccessMask = dep.srcAccessMask;
1292 dep1Out->dstAccessMask = dep.dstAccessMask;
1293 dep1Out->dependencyFlags = dep.dependencyFlags;
1294 }
1295
ToRenderPassMultiviewCreateInfo(const VkRenderPassCreateInfo2 & createInfo,VkRenderPassCreateInfo * createInfo1,SubpassVector<uint32_t> * viewMasks,VkRenderPassMultiviewCreateInfo * multiviewInfo)1296 void ToRenderPassMultiviewCreateInfo(const VkRenderPassCreateInfo2 &createInfo,
1297 VkRenderPassCreateInfo *createInfo1,
1298 SubpassVector<uint32_t> *viewMasks,
1299 VkRenderPassMultiviewCreateInfo *multiviewInfo)
1300 {
1301 ASSERT(createInfo.correlatedViewMaskCount == 1);
1302 const uint32_t viewMask = createInfo.pCorrelatedViewMasks[0];
1303
1304 viewMasks->resize(createInfo.subpassCount, viewMask);
1305
1306 multiviewInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
1307 multiviewInfo->subpassCount = createInfo.subpassCount;
1308 multiviewInfo->pViewMasks = viewMasks->data();
1309 multiviewInfo->correlationMaskCount = createInfo.correlatedViewMaskCount;
1310 multiviewInfo->pCorrelationMasks = createInfo.pCorrelatedViewMasks;
1311
1312 AddToPNextChain(createInfo1, multiviewInfo);
1313 }
1314
CreateRenderPass1(ErrorContext * context,const VkRenderPassCreateInfo2 & createInfo,uint8_t viewCount,RenderPass * renderPass)1315 angle::Result CreateRenderPass1(ErrorContext *context,
1316 const VkRenderPassCreateInfo2 &createInfo,
1317 uint8_t viewCount,
1318 RenderPass *renderPass)
1319 {
1320 // Convert the attachments to VkAttachmentDescription.
1321 FramebufferAttachmentArray<VkAttachmentDescription> attachmentDescs;
1322 for (uint32_t index = 0; index < createInfo.attachmentCount; ++index)
1323 {
1324 ToAttachmentDesciption1(createInfo.pAttachments[index], &attachmentDescs[index]);
1325 }
1326
1327 // Convert subpass attachments to VkAttachmentReference and the subpass description to
1328 // VkSubpassDescription.
1329 SubpassVector<FramebufferAttachmentsVector<VkAttachmentReference>> subpassInputAttachmentRefs(
1330 createInfo.subpassCount);
1331 SubpassVector<gl::DrawBuffersVector<VkAttachmentReference>> subpassColorAttachmentRefs(
1332 createInfo.subpassCount);
1333 SubpassVector<gl::DrawBuffersVector<VkAttachmentReference>> subpassResolveAttachmentRefs(
1334 createInfo.subpassCount);
1335 SubpassVector<VkAttachmentReference> subpassDepthStencilAttachmentRefs(createInfo.subpassCount);
1336 SubpassVector<VkSubpassDescription> subpassDescriptions(createInfo.subpassCount);
1337 for (uint32_t subpass = 0; subpass < createInfo.subpassCount; ++subpass)
1338 {
1339 const VkSubpassDescription2 &desc = createInfo.pSubpasses[subpass];
1340 FramebufferAttachmentsVector<VkAttachmentReference> &inputRefs =
1341 subpassInputAttachmentRefs[subpass];
1342 gl::DrawBuffersVector<VkAttachmentReference> &colorRefs =
1343 subpassColorAttachmentRefs[subpass];
1344 gl::DrawBuffersVector<VkAttachmentReference> &resolveRefs =
1345 subpassResolveAttachmentRefs[subpass];
1346 VkAttachmentReference &depthStencilRef = subpassDepthStencilAttachmentRefs[subpass];
1347
1348 inputRefs.resize(desc.inputAttachmentCount);
1349 colorRefs.resize(desc.colorAttachmentCount);
1350
1351 for (uint32_t index = 0; index < desc.inputAttachmentCount; ++index)
1352 {
1353 ToAttachmentReference1(desc.pInputAttachments[index], &inputRefs[index]);
1354 }
1355
1356 for (uint32_t index = 0; index < desc.colorAttachmentCount; ++index)
1357 {
1358 ToAttachmentReference1(desc.pColorAttachments[index], &colorRefs[index]);
1359 }
1360 if (desc.pResolveAttachments)
1361 {
1362 resolveRefs.resize(desc.colorAttachmentCount);
1363 for (uint32_t index = 0; index < desc.colorAttachmentCount; ++index)
1364 {
1365 ToAttachmentReference1(desc.pResolveAttachments[index], &resolveRefs[index]);
1366 }
1367 }
1368 if (desc.pDepthStencilAttachment)
1369 {
1370 ToAttachmentReference1(*desc.pDepthStencilAttachment, &depthStencilRef);
1371 }
1372
1373 // Convert subpass itself.
1374 ToSubpassDescription1(desc, inputRefs, colorRefs, resolveRefs, depthStencilRef,
1375 &subpassDescriptions[subpass]);
1376 }
1377
1378 // Convert subpass dependencies to VkSubpassDependency.
1379 std::vector<VkSubpassDependency> subpassDependencies(createInfo.dependencyCount);
1380 for (uint32_t index = 0; index < createInfo.dependencyCount; ++index)
1381 {
1382 ToSubpassDependency1(createInfo.pDependencies[index], &subpassDependencies[index]);
1383 }
1384
1385 // Convert CreateInfo itself
1386 VkRenderPassCreateInfo createInfo1 = {};
1387 createInfo1.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1388 createInfo1.flags = createInfo.flags;
1389 createInfo1.attachmentCount = createInfo.attachmentCount;
1390 createInfo1.pAttachments = attachmentDescs.data();
1391 createInfo1.subpassCount = createInfo.subpassCount;
1392 createInfo1.pSubpasses = subpassDescriptions.data();
1393 createInfo1.dependencyCount = static_cast<uint32_t>(subpassDependencies.size());
1394 createInfo1.pDependencies = !subpassDependencies.empty() ? subpassDependencies.data() : nullptr;
1395
1396 SubpassVector<uint32_t> viewMasks;
1397 VkRenderPassMultiviewCreateInfo multiviewInfo = {};
1398 if (viewCount > 0)
1399 {
1400 ToRenderPassMultiviewCreateInfo(createInfo, &createInfo1, &viewMasks, &multiviewInfo);
1401 }
1402
1403 // Initialize the render pass.
1404 ANGLE_VK_TRY(context, renderPass->init(context->getDevice(), createInfo1));
1405
1406 return angle::Result::Continue;
1407 }
1408
UpdateRenderPassColorPerfCounters(const VkRenderPassCreateInfo2 & createInfo,FramebufferAttachmentMask depthStencilAttachmentIndices,RenderPassPerfCounters * countersOut)1409 void UpdateRenderPassColorPerfCounters(const VkRenderPassCreateInfo2 &createInfo,
1410 FramebufferAttachmentMask depthStencilAttachmentIndices,
1411 RenderPassPerfCounters *countersOut)
1412 {
1413 for (uint32_t index = 0; index < createInfo.attachmentCount; index++)
1414 {
1415 if (depthStencilAttachmentIndices.test(index))
1416 {
1417 continue;
1418 }
1419
1420 VkAttachmentLoadOp loadOp = createInfo.pAttachments[index].loadOp;
1421 VkAttachmentStoreOp storeOp = createInfo.pAttachments[index].storeOp;
1422 countersOut->colorLoadOpClears += loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
1423 countersOut->colorLoadOpLoads += loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
1424 countersOut->colorLoadOpNones += loadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT ? 1 : 0;
1425 countersOut->colorStoreOpStores += storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
1426 countersOut->colorStoreOpNones += storeOp == VK_ATTACHMENT_STORE_OP_NONE_EXT ? 1 : 0;
1427 }
1428 }
1429
UpdateSubpassColorPerfCounters(const VkRenderPassCreateInfo2 & createInfo,const VkSubpassDescription2 & subpass,RenderPassPerfCounters * countersOut)1430 void UpdateSubpassColorPerfCounters(const VkRenderPassCreateInfo2 &createInfo,
1431 const VkSubpassDescription2 &subpass,
1432 RenderPassPerfCounters *countersOut)
1433 {
1434 // Color resolve counters.
1435 if (subpass.pResolveAttachments == nullptr)
1436 {
1437 return;
1438 }
1439
1440 for (uint32_t colorSubpassIndex = 0; colorSubpassIndex < subpass.colorAttachmentCount;
1441 ++colorSubpassIndex)
1442 {
1443 uint32_t resolveRenderPassIndex = subpass.pResolveAttachments[colorSubpassIndex].attachment;
1444
1445 if (resolveRenderPassIndex == VK_ATTACHMENT_UNUSED)
1446 {
1447 continue;
1448 }
1449
1450 ++countersOut->colorAttachmentResolves;
1451 }
1452 }
1453
UpdateRenderPassDepthStencilPerfCounters(const VkRenderPassCreateInfo2 & createInfo,size_t renderPassIndex,RenderPassPerfCounters * countersOut)1454 void UpdateRenderPassDepthStencilPerfCounters(const VkRenderPassCreateInfo2 &createInfo,
1455 size_t renderPassIndex,
1456 RenderPassPerfCounters *countersOut)
1457 {
1458 ASSERT(renderPassIndex != VK_ATTACHMENT_UNUSED);
1459
1460 // Depth/stencil ops counters.
1461 const VkAttachmentDescription2 &ds = createInfo.pAttachments[renderPassIndex];
1462
1463 countersOut->depthLoadOpClears += ds.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
1464 countersOut->depthLoadOpLoads += ds.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
1465 countersOut->depthLoadOpNones += ds.loadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT ? 1 : 0;
1466 countersOut->depthStoreOpStores += ds.storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
1467 countersOut->depthStoreOpNones += ds.storeOp == VK_ATTACHMENT_STORE_OP_NONE_EXT ? 1 : 0;
1468
1469 countersOut->stencilLoadOpClears += ds.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
1470 countersOut->stencilLoadOpLoads += ds.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
1471 countersOut->stencilLoadOpNones += ds.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT ? 1 : 0;
1472 countersOut->stencilStoreOpStores += ds.stencilStoreOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
1473 countersOut->stencilStoreOpNones +=
1474 ds.stencilStoreOp == VK_ATTACHMENT_STORE_OP_NONE_EXT ? 1 : 0;
1475
1476 // Depth/stencil read-only mode.
1477 countersOut->readOnlyDepthStencil +=
1478 ds.finalLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL ? 1 : 0;
1479 }
1480
UpdateRenderPassDepthStencilResolvePerfCounters(const VkRenderPassCreateInfo2 & createInfo,const VkSubpassDescriptionDepthStencilResolve & depthStencilResolve,RenderPassPerfCounters * countersOut)1481 void UpdateRenderPassDepthStencilResolvePerfCounters(
1482 const VkRenderPassCreateInfo2 &createInfo,
1483 const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve,
1484 RenderPassPerfCounters *countersOut)
1485 {
1486 if (depthStencilResolve.pDepthStencilResolveAttachment == nullptr)
1487 {
1488 return;
1489 }
1490
1491 uint32_t resolveRenderPassIndex =
1492 depthStencilResolve.pDepthStencilResolveAttachment->attachment;
1493
1494 if (resolveRenderPassIndex == VK_ATTACHMENT_UNUSED)
1495 {
1496 return;
1497 }
1498
1499 const VkAttachmentDescription2 &dsResolve = createInfo.pAttachments[resolveRenderPassIndex];
1500
1501 // Resolve depth/stencil ops counters.
1502 countersOut->depthLoadOpClears += dsResolve.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
1503 countersOut->depthLoadOpLoads += dsResolve.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
1504 countersOut->depthStoreOpStores +=
1505 dsResolve.storeOp == static_cast<uint16_t>(RenderPassStoreOp::Store) ? 1 : 0;
1506
1507 countersOut->stencilLoadOpClears +=
1508 dsResolve.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
1509 countersOut->stencilLoadOpLoads +=
1510 dsResolve.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
1511 countersOut->stencilStoreOpStores +=
1512 dsResolve.stencilStoreOp == static_cast<uint16_t>(RenderPassStoreOp::Store) ? 1 : 0;
1513
1514 // Depth/stencil resolve counters.
1515 countersOut->depthAttachmentResolves +=
1516 depthStencilResolve.depthResolveMode != VK_RESOLVE_MODE_NONE ? 1 : 0;
1517 countersOut->stencilAttachmentResolves +=
1518 depthStencilResolve.stencilResolveMode != VK_RESOLVE_MODE_NONE ? 1 : 0;
1519 }
1520
UpdateRenderPassPerfCounters(const RenderPassDesc & desc,const VkRenderPassCreateInfo2 & createInfo,const VkSubpassDescriptionDepthStencilResolve & depthStencilResolve,RenderPassPerfCounters * countersOut)1521 void UpdateRenderPassPerfCounters(
1522 const RenderPassDesc &desc,
1523 const VkRenderPassCreateInfo2 &createInfo,
1524 const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve,
1525 RenderPassPerfCounters *countersOut)
1526 {
1527 // Accumulate depth/stencil attachment indices in all subpasses to avoid double-counting
1528 // counters.
1529 FramebufferAttachmentMask depthStencilAttachmentIndices;
1530
1531 for (uint32_t subpassIndex = 0; subpassIndex < createInfo.subpassCount; ++subpassIndex)
1532 {
1533 const VkSubpassDescription2 &subpass = createInfo.pSubpasses[subpassIndex];
1534
1535 // Color counters.
1536 // NOTE: For simplicity, this will accumulate counts for all subpasses in the renderpass.
1537 UpdateSubpassColorPerfCounters(createInfo, subpass, countersOut);
1538
1539 // Record index of depth/stencil attachment.
1540 if (subpass.pDepthStencilAttachment != nullptr)
1541 {
1542 uint32_t attachmentRenderPassIndex = subpass.pDepthStencilAttachment->attachment;
1543 if (attachmentRenderPassIndex != VK_ATTACHMENT_UNUSED)
1544 {
1545 depthStencilAttachmentIndices.set(attachmentRenderPassIndex);
1546 }
1547 }
1548 }
1549
1550 UpdateRenderPassColorPerfCounters(createInfo, depthStencilAttachmentIndices, countersOut);
1551
1552 // Depth/stencil counters. Currently, both subpasses use the same depth/stencil attachment (if
1553 // any).
1554 ASSERT(depthStencilAttachmentIndices.count() <= 1);
1555 for (size_t attachmentRenderPassIndex : depthStencilAttachmentIndices)
1556 {
1557 UpdateRenderPassDepthStencilPerfCounters(createInfo, attachmentRenderPassIndex,
1558 countersOut);
1559 }
1560
1561 UpdateRenderPassDepthStencilResolvePerfCounters(createInfo, depthStencilResolve, countersOut);
1562
1563 // Determine unresolve counters from the render pass desc, to avoid making guesses from subpass
1564 // count etc.
1565 countersOut->colorAttachmentUnresolves += desc.getColorUnresolveAttachmentMask().count();
1566 countersOut->depthAttachmentUnresolves += desc.hasDepthUnresolveAttachment() ? 1 : 0;
1567 countersOut->stencilAttachmentUnresolves += desc.hasStencilUnresolveAttachment() ? 1 : 0;
1568 }
1569
GetRenderPassAndUpdateCounters(ContextVk * contextVk,bool updatePerfCounters,RenderPassHelper * renderPassHelper,const RenderPass ** renderPassOut)1570 void GetRenderPassAndUpdateCounters(ContextVk *contextVk,
1571 bool updatePerfCounters,
1572 RenderPassHelper *renderPassHelper,
1573 const RenderPass **renderPassOut)
1574 {
1575 *renderPassOut = &renderPassHelper->getRenderPass();
1576 if (updatePerfCounters)
1577 {
1578 angle::VulkanPerfCounters &counters = contextVk->getPerfCounters();
1579 const RenderPassPerfCounters &rpCounters = renderPassHelper->getPerfCounters();
1580
1581 counters.colorLoadOpClears += rpCounters.colorLoadOpClears;
1582 counters.colorLoadOpLoads += rpCounters.colorLoadOpLoads;
1583 counters.colorLoadOpNones += rpCounters.colorLoadOpNones;
1584 counters.colorStoreOpStores += rpCounters.colorStoreOpStores;
1585 counters.colorStoreOpNones += rpCounters.colorStoreOpNones;
1586 counters.depthLoadOpClears += rpCounters.depthLoadOpClears;
1587 counters.depthLoadOpLoads += rpCounters.depthLoadOpLoads;
1588 counters.depthLoadOpNones += rpCounters.depthLoadOpNones;
1589 counters.depthStoreOpStores += rpCounters.depthStoreOpStores;
1590 counters.depthStoreOpNones += rpCounters.depthStoreOpNones;
1591 counters.stencilLoadOpClears += rpCounters.stencilLoadOpClears;
1592 counters.stencilLoadOpLoads += rpCounters.stencilLoadOpLoads;
1593 counters.stencilLoadOpNones += rpCounters.stencilLoadOpNones;
1594 counters.stencilStoreOpStores += rpCounters.stencilStoreOpStores;
1595 counters.stencilStoreOpNones += rpCounters.stencilStoreOpNones;
1596 counters.colorAttachmentUnresolves += rpCounters.colorAttachmentUnresolves;
1597 counters.colorAttachmentResolves += rpCounters.colorAttachmentResolves;
1598 counters.depthAttachmentUnresolves += rpCounters.depthAttachmentUnresolves;
1599 counters.depthAttachmentResolves += rpCounters.depthAttachmentResolves;
1600 counters.stencilAttachmentUnresolves += rpCounters.stencilAttachmentUnresolves;
1601 counters.stencilAttachmentResolves += rpCounters.stencilAttachmentResolves;
1602 counters.readOnlyDepthStencilRenderPasses += rpCounters.readOnlyDepthStencil;
1603 }
1604 }
1605
InitializeSpecializationInfo(const SpecializationConstants & specConsts,SpecializationConstantMap<VkSpecializationMapEntry> * specializationEntriesOut,VkSpecializationInfo * specializationInfoOut)1606 void InitializeSpecializationInfo(
1607 const SpecializationConstants &specConsts,
1608 SpecializationConstantMap<VkSpecializationMapEntry> *specializationEntriesOut,
1609 VkSpecializationInfo *specializationInfoOut)
1610 {
1611 // Collect specialization constants.
1612 for (const sh::vk::SpecializationConstantId id :
1613 angle::AllEnums<sh::vk::SpecializationConstantId>())
1614 {
1615 (*specializationEntriesOut)[id].constantID = static_cast<uint32_t>(id);
1616 switch (id)
1617 {
1618 case sh::vk::SpecializationConstantId::SurfaceRotation:
1619 (*specializationEntriesOut)[id].offset =
1620 offsetof(SpecializationConstants, surfaceRotation);
1621 (*specializationEntriesOut)[id].size = sizeof(specConsts.surfaceRotation);
1622 break;
1623 case sh::vk::SpecializationConstantId::Dither:
1624 (*specializationEntriesOut)[id].offset =
1625 offsetof(vk::SpecializationConstants, dither);
1626 (*specializationEntriesOut)[id].size = sizeof(specConsts.dither);
1627 break;
1628 default:
1629 UNREACHABLE();
1630 break;
1631 }
1632 }
1633
1634 specializationInfoOut->mapEntryCount = static_cast<uint32_t>(specializationEntriesOut->size());
1635 specializationInfoOut->pMapEntries = specializationEntriesOut->data();
1636 specializationInfoOut->dataSize = sizeof(specConsts);
1637 specializationInfoOut->pData = &specConsts;
1638 }
1639
1640 // Utility for setting a value on a packed 4-bit integer array.
1641 template <typename SrcT>
Int4Array_Set(uint8_t * arrayBytes,uint32_t arrayIndex,SrcT value)1642 void Int4Array_Set(uint8_t *arrayBytes, uint32_t arrayIndex, SrcT value)
1643 {
1644 uint32_t byteIndex = arrayIndex >> 1;
1645 ASSERT(value < 16);
1646
1647 if ((arrayIndex & 1) == 0)
1648 {
1649 arrayBytes[byteIndex] &= 0xF0;
1650 arrayBytes[byteIndex] |= static_cast<uint8_t>(value);
1651 }
1652 else
1653 {
1654 arrayBytes[byteIndex] &= 0x0F;
1655 arrayBytes[byteIndex] |= static_cast<uint8_t>(value) << 4;
1656 }
1657 }
1658
1659 // Utility for getting a value from a packed 4-bit integer array.
1660 template <typename DestT>
Int4Array_Get(const uint8_t * arrayBytes,uint32_t arrayIndex)1661 DestT Int4Array_Get(const uint8_t *arrayBytes, uint32_t arrayIndex)
1662 {
1663 uint32_t byteIndex = arrayIndex >> 1;
1664
1665 if ((arrayIndex & 1) == 0)
1666 {
1667 return static_cast<DestT>(arrayBytes[byteIndex] & 0xF);
1668 }
1669 else
1670 {
1671 return static_cast<DestT>(arrayBytes[byteIndex] >> 4);
1672 }
1673 }
1674
1675 // When converting a byte number to a transition bit index we can shift instead of divide.
1676 constexpr size_t kTransitionByteShift = Log2(kGraphicsPipelineDirtyBitBytes);
1677
1678 // When converting a number of bits offset to a transition bit index we can also shift.
1679 constexpr size_t kBitsPerByte = 8;
1680 constexpr size_t kTransitionBitShift = kTransitionByteShift + Log2(kBitsPerByte);
1681
1682 // Helper macro to map from a PipelineDesc struct and field to a dirty bit index.
1683 // Uses the 'offsetof' macro to compute the offset 'Member' within the PipelineDesc.
1684 // We can optimize the dirty bit setting by computing the shifted dirty bit at compile time instead
1685 // of calling "set".
1686 #define ANGLE_GET_TRANSITION_BIT(Member) \
1687 (offsetof(GraphicsPipelineDesc, Member) >> kTransitionByteShift)
1688
1689 // Indexed dirty bits cannot be entirely computed at compile time since the index is passed to
1690 // the update function.
1691 #define ANGLE_GET_INDEXED_TRANSITION_BIT(Member, Index, BitWidth) \
1692 (((BitWidth * Index) >> kTransitionBitShift) + ANGLE_GET_TRANSITION_BIT(Member))
1693
1694 constexpr char kDescriptorTypeNameMap[][30] = {"sampler",
1695 "combined image sampler",
1696 "sampled image",
1697 "storage image",
1698 "uniform texel buffer",
1699 "storage texel buffer",
1700 "uniform buffer",
1701 "storage buffer",
1702 "uniform buffer dynamic",
1703 "storage buffer dynamic",
1704 "input attachment"};
1705
1706 // Helpers for creating a readable dump of the graphics pipeline graph. Each program generates a
1707 // group of nodes. The group's description is the common state among all nodes. Each node contains
1708 // the diff with the shared state. Arrows between nodes indicate the GraphicsPipelineTransitionBits
1709 // that have caused the transition. State that is 0 is not output for brevity.
1710 enum class PipelineState
1711 {
1712 VertexAttribFormat,
1713 VertexAttribDivisor = VertexAttribFormat + gl::MAX_VERTEX_ATTRIBS,
1714 VertexAttribOffset = VertexAttribDivisor + gl::MAX_VERTEX_ATTRIBS,
1715 VertexAttribStride = VertexAttribOffset + gl::MAX_VERTEX_ATTRIBS,
1716 VertexAttribCompressed = VertexAttribStride + gl::MAX_VERTEX_ATTRIBS,
1717 VertexAttribShaderComponentType = VertexAttribCompressed + gl::MAX_VERTEX_ATTRIBS,
1718 RenderPassSamples = VertexAttribShaderComponentType + gl::MAX_VERTEX_ATTRIBS,
1719 RenderPassColorAttachmentRange,
1720 RenderPassViewCount,
1721 RenderPassSrgbWriteControl,
1722 RenderPassHasColorFramebufferFetch,
1723 RenderPassHasDepthStencilFramebufferFetch,
1724 RenderPassIsRenderToTexture,
1725 RenderPassResolveDepth,
1726 RenderPassResolveStencil,
1727 RenderPassUnresolveDepth,
1728 RenderPassUnresolveStencil,
1729 RenderPassColorResolveMask,
1730 RenderPassColorUnresolveMask,
1731 RenderPassColorFormat,
1732 RenderPassDepthStencilFormat = RenderPassColorFormat + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1733 Subpass,
1734 Topology,
1735 PatchVertices,
1736 PrimitiveRestartEnable,
1737 PolygonMode,
1738 CullMode,
1739 FrontFace,
1740 SurfaceRotation,
1741 ViewportNegativeOneToOne,
1742 SampleShadingEnable,
1743 RasterizationSamples,
1744 MinSampleShading,
1745 SampleMask,
1746 AlphaToCoverageEnable,
1747 AlphaToOneEnable,
1748 LogicOpEnable,
1749 LogicOp,
1750 RasterizerDiscardEnable,
1751 ColorWriteMask,
1752 BlendEnableMask = ColorWriteMask + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1753 MissingOutputsMask,
1754 SrcColorBlendFactor,
1755 DstColorBlendFactor = SrcColorBlendFactor + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1756 ColorBlendOp = DstColorBlendFactor + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1757 SrcAlphaBlendFactor = ColorBlendOp + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1758 DstAlphaBlendFactor = SrcAlphaBlendFactor + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1759 AlphaBlendOp = DstAlphaBlendFactor + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1760 EmulatedDitherControl = AlphaBlendOp + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1761 DepthClampEnable,
1762 DepthBoundsTest,
1763 DepthCompareOp,
1764 DepthTest,
1765 DepthWrite,
1766 StencilTest,
1767 DepthBiasEnable,
1768 StencilOpFailFront,
1769 StencilOpPassFront,
1770 StencilOpDepthFailFront,
1771 StencilCompareFront,
1772 StencilOpFailBack,
1773 StencilOpPassBack,
1774 StencilOpDepthFailBack,
1775 StencilCompareBack,
1776
1777 InvalidEnum,
1778 EnumCount = InvalidEnum,
1779 };
1780
1781 using UnpackedPipelineState = angle::PackedEnumMap<PipelineState, uint32_t>;
1782 using PipelineStateBitSet = angle::BitSetArray<angle::EnumSize<PipelineState>()>;
1783
UnpackPipelineState(const GraphicsPipelineDesc & state,GraphicsPipelineSubset subset,UnpackedPipelineState * valuesOut)1784 [[maybe_unused]] void UnpackPipelineState(const GraphicsPipelineDesc &state,
1785 GraphicsPipelineSubset subset,
1786 UnpackedPipelineState *valuesOut)
1787 {
1788 const bool hasVertexInput = GraphicsPipelineHasVertexInput(subset);
1789 const bool hasShaders = GraphicsPipelineHasShaders(subset);
1790 const bool hasShadersOrFragmentOutput = GraphicsPipelineHasShadersOrFragmentOutput(subset);
1791 const bool hasFragmentOutput = GraphicsPipelineHasFragmentOutput(subset);
1792
1793 valuesOut->fill(0);
1794
1795 if (hasVertexInput)
1796 {
1797 const PipelineVertexInputState &vertexInputState = state.getVertexInputStateForLog();
1798
1799 const PackedVertexInputAttributes &vertex = vertexInputState.vertex;
1800 uint32_t *vaFormats = &(*valuesOut)[PipelineState::VertexAttribFormat];
1801 uint32_t *vaDivisors = &(*valuesOut)[PipelineState::VertexAttribDivisor];
1802 uint32_t *vaOffsets = &(*valuesOut)[PipelineState::VertexAttribOffset];
1803 uint32_t *vaStrides = &(*valuesOut)[PipelineState::VertexAttribStride];
1804 uint32_t *vaCompressed = &(*valuesOut)[PipelineState::VertexAttribCompressed];
1805 uint32_t *vaShaderComponentType =
1806 &(*valuesOut)[PipelineState::VertexAttribShaderComponentType];
1807 for (uint32_t attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
1808 {
1809 vaFormats[attribIndex] = vertex.attribs[attribIndex].format;
1810 vaDivisors[attribIndex] = vertex.attribs[attribIndex].divisor;
1811 vaOffsets[attribIndex] = vertex.attribs[attribIndex].offset;
1812 vaStrides[attribIndex] = vertex.strides[attribIndex];
1813 vaCompressed[attribIndex] = vertex.attribs[attribIndex].compressed;
1814
1815 gl::ComponentType componentType = gl::GetComponentTypeMask(
1816 gl::ComponentTypeMask(vertex.shaderAttribComponentType), attribIndex);
1817 vaShaderComponentType[attribIndex] = componentType == gl::ComponentType::InvalidEnum
1818 ? 0
1819 : static_cast<uint32_t>(componentType);
1820 }
1821
1822 const PackedInputAssemblyState &inputAssembly = vertexInputState.inputAssembly;
1823 (*valuesOut)[PipelineState::Topology] = inputAssembly.bits.topology;
1824 (*valuesOut)[PipelineState::PrimitiveRestartEnable] =
1825 inputAssembly.bits.primitiveRestartEnable;
1826 }
1827
1828 if (hasShaders)
1829 {
1830 const PipelineShadersState &shadersState = state.getShadersStateForLog();
1831
1832 const PackedPreRasterizationAndFragmentStates &shaders = shadersState.shaders;
1833 (*valuesOut)[PipelineState::ViewportNegativeOneToOne] =
1834 shaders.bits.viewportNegativeOneToOne;
1835 (*valuesOut)[PipelineState::DepthClampEnable] = shaders.bits.depthClampEnable;
1836 (*valuesOut)[PipelineState::PolygonMode] = shaders.bits.polygonMode;
1837 (*valuesOut)[PipelineState::CullMode] = shaders.bits.cullMode;
1838 (*valuesOut)[PipelineState::FrontFace] = shaders.bits.frontFace;
1839 (*valuesOut)[PipelineState::RasterizerDiscardEnable] = shaders.bits.rasterizerDiscardEnable;
1840 (*valuesOut)[PipelineState::DepthBiasEnable] = shaders.bits.depthBiasEnable;
1841 (*valuesOut)[PipelineState::PatchVertices] = shaders.bits.patchVertices;
1842 (*valuesOut)[PipelineState::DepthBoundsTest] = shaders.bits.depthBoundsTest;
1843 (*valuesOut)[PipelineState::DepthTest] = shaders.bits.depthTest;
1844 (*valuesOut)[PipelineState::DepthWrite] = shaders.bits.depthWrite;
1845 (*valuesOut)[PipelineState::StencilTest] = shaders.bits.stencilTest;
1846 (*valuesOut)[PipelineState::DepthCompareOp] = shaders.bits.depthCompareOp;
1847 (*valuesOut)[PipelineState::SurfaceRotation] = shaders.bits.surfaceRotation;
1848 (*valuesOut)[PipelineState::EmulatedDitherControl] = shaders.emulatedDitherControl;
1849 (*valuesOut)[PipelineState::StencilOpFailFront] = shaders.front.fail;
1850 (*valuesOut)[PipelineState::StencilOpPassFront] = shaders.front.pass;
1851 (*valuesOut)[PipelineState::StencilOpDepthFailFront] = shaders.front.depthFail;
1852 (*valuesOut)[PipelineState::StencilCompareFront] = shaders.front.compare;
1853 (*valuesOut)[PipelineState::StencilOpFailBack] = shaders.back.fail;
1854 (*valuesOut)[PipelineState::StencilOpPassBack] = shaders.back.pass;
1855 (*valuesOut)[PipelineState::StencilOpDepthFailBack] = shaders.back.depthFail;
1856 (*valuesOut)[PipelineState::StencilCompareBack] = shaders.back.compare;
1857 }
1858
1859 if (hasShadersOrFragmentOutput)
1860 {
1861 const PipelineSharedNonVertexInputState &sharedNonVertexInputState =
1862 state.getSharedNonVertexInputStateForLog();
1863
1864 const PackedMultisampleAndSubpassState &multisample = sharedNonVertexInputState.multisample;
1865 (*valuesOut)[PipelineState::SampleMask] = multisample.bits.sampleMask;
1866 (*valuesOut)[PipelineState::RasterizationSamples] =
1867 multisample.bits.rasterizationSamplesMinusOne + 1;
1868 (*valuesOut)[PipelineState::SampleShadingEnable] = multisample.bits.sampleShadingEnable;
1869 (*valuesOut)[PipelineState::AlphaToCoverageEnable] = multisample.bits.alphaToCoverageEnable;
1870 (*valuesOut)[PipelineState::AlphaToOneEnable] = multisample.bits.alphaToOneEnable;
1871 (*valuesOut)[PipelineState::Subpass] = multisample.bits.subpass;
1872 (*valuesOut)[PipelineState::MinSampleShading] = multisample.bits.minSampleShading;
1873
1874 const RenderPassDesc renderPass = sharedNonVertexInputState.renderPass;
1875 (*valuesOut)[PipelineState::RenderPassSamples] = renderPass.samples();
1876 (*valuesOut)[PipelineState::RenderPassColorAttachmentRange] =
1877 static_cast<uint32_t>(renderPass.colorAttachmentRange());
1878 (*valuesOut)[PipelineState::RenderPassViewCount] = renderPass.viewCount();
1879 (*valuesOut)[PipelineState::RenderPassSrgbWriteControl] =
1880 static_cast<uint32_t>(renderPass.getSRGBWriteControlMode());
1881 (*valuesOut)[PipelineState::RenderPassHasColorFramebufferFetch] =
1882 renderPass.hasColorFramebufferFetch();
1883 (*valuesOut)[PipelineState::RenderPassHasDepthStencilFramebufferFetch] =
1884 renderPass.hasDepthStencilFramebufferFetch();
1885 (*valuesOut)[PipelineState::RenderPassIsRenderToTexture] = renderPass.isRenderToTexture();
1886 (*valuesOut)[PipelineState::RenderPassResolveDepth] =
1887 renderPass.hasDepthResolveAttachment();
1888 (*valuesOut)[PipelineState::RenderPassResolveStencil] =
1889 renderPass.hasStencilResolveAttachment();
1890 (*valuesOut)[PipelineState::RenderPassUnresolveDepth] =
1891 renderPass.hasDepthUnresolveAttachment();
1892 (*valuesOut)[PipelineState::RenderPassUnresolveStencil] =
1893 renderPass.hasStencilUnresolveAttachment();
1894 (*valuesOut)[PipelineState::RenderPassColorResolveMask] =
1895 renderPass.getColorResolveAttachmentMask().bits();
1896 (*valuesOut)[PipelineState::RenderPassColorUnresolveMask] =
1897 renderPass.getColorUnresolveAttachmentMask().bits();
1898
1899 uint32_t *colorFormats = &(*valuesOut)[PipelineState::RenderPassColorFormat];
1900 for (uint32_t colorIndex = 0; colorIndex < renderPass.colorAttachmentRange(); ++colorIndex)
1901 {
1902 colorFormats[colorIndex] = static_cast<uint32_t>(renderPass[colorIndex]);
1903 }
1904 (*valuesOut)[PipelineState::RenderPassDepthStencilFormat] =
1905 static_cast<uint32_t>(renderPass[renderPass.depthStencilAttachmentIndex()]);
1906 }
1907
1908 if (hasFragmentOutput)
1909 {
1910 const PipelineFragmentOutputState &fragmentOutputState =
1911 state.getFragmentOutputStateForLog();
1912
1913 const PackedColorBlendState &blend = fragmentOutputState.blend;
1914 uint32_t *colorWriteMasks = &(*valuesOut)[PipelineState::ColorWriteMask];
1915 uint32_t *srcColorBlendFactors = &(*valuesOut)[PipelineState::SrcColorBlendFactor];
1916 uint32_t *dstColorBlendFactors = &(*valuesOut)[PipelineState::DstColorBlendFactor];
1917 uint32_t *colorBlendOps = &(*valuesOut)[PipelineState::ColorBlendOp];
1918 uint32_t *srcAlphaBlendFactors = &(*valuesOut)[PipelineState::SrcAlphaBlendFactor];
1919 uint32_t *dstAlphaBlendFactors = &(*valuesOut)[PipelineState::DstAlphaBlendFactor];
1920 uint32_t *alphaBlendOps = &(*valuesOut)[PipelineState::AlphaBlendOp];
1921 for (uint32_t colorIndex = 0; colorIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
1922 ++colorIndex)
1923 {
1924 colorWriteMasks[colorIndex] =
1925 Int4Array_Get<VkColorComponentFlags>(blend.colorWriteMaskBits, colorIndex);
1926
1927 srcColorBlendFactors[colorIndex] = blend.attachments[colorIndex].srcColorBlendFactor;
1928 dstColorBlendFactors[colorIndex] = blend.attachments[colorIndex].dstColorBlendFactor;
1929 colorBlendOps[colorIndex] = blend.attachments[colorIndex].colorBlendOp;
1930 srcAlphaBlendFactors[colorIndex] = blend.attachments[colorIndex].srcAlphaBlendFactor;
1931 dstAlphaBlendFactors[colorIndex] = blend.attachments[colorIndex].dstAlphaBlendFactor;
1932 alphaBlendOps[colorIndex] = blend.attachments[colorIndex].alphaBlendOp;
1933 }
1934
1935 const PackedBlendMaskAndLogicOpState &blendMaskAndLogic =
1936 fragmentOutputState.blendMaskAndLogic;
1937 (*valuesOut)[PipelineState::BlendEnableMask] = blendMaskAndLogic.bits.blendEnableMask;
1938 (*valuesOut)[PipelineState::LogicOpEnable] = blendMaskAndLogic.bits.logicOpEnable;
1939 (*valuesOut)[PipelineState::LogicOp] = blendMaskAndLogic.bits.logicOp;
1940 (*valuesOut)[PipelineState::MissingOutputsMask] = blendMaskAndLogic.bits.missingOutputsMask;
1941 }
1942 }
1943
GetCommonPipelineState(const std::vector<UnpackedPipelineState> & pipelines)1944 [[maybe_unused]] PipelineStateBitSet GetCommonPipelineState(
1945 const std::vector<UnpackedPipelineState> &pipelines)
1946 {
1947 PipelineStateBitSet commonState;
1948 commonState.set();
1949
1950 ASSERT(!pipelines.empty());
1951 const UnpackedPipelineState &firstPipeline = pipelines[0];
1952
1953 for (const UnpackedPipelineState &pipeline : pipelines)
1954 {
1955 for (size_t stateIndex = 0; stateIndex < firstPipeline.size(); ++stateIndex)
1956 {
1957 if (pipeline.data()[stateIndex] != firstPipeline.data()[stateIndex])
1958 {
1959 commonState.reset(stateIndex);
1960 }
1961 }
1962 }
1963
1964 return commonState;
1965 }
1966
IsPipelineState(size_t stateIndex,PipelineState pipelineState,size_t range)1967 bool IsPipelineState(size_t stateIndex, PipelineState pipelineState, size_t range)
1968 {
1969 size_t pipelineStateAsInt = static_cast<size_t>(pipelineState);
1970
1971 return stateIndex >= pipelineStateAsInt && stateIndex < pipelineStateAsInt + range;
1972 }
1973
GetPipelineStateSubIndex(size_t stateIndex,PipelineState pipelineState)1974 size_t GetPipelineStateSubIndex(size_t stateIndex, PipelineState pipelineState)
1975 {
1976 return stateIndex - static_cast<size_t>(pipelineState);
1977 }
1978
GetPipelineState(size_t stateIndex,bool * isRangedOut,size_t * subIndexOut)1979 PipelineState GetPipelineState(size_t stateIndex, bool *isRangedOut, size_t *subIndexOut)
1980 {
1981 constexpr PipelineState kRangedStates[] = {
1982 PipelineState::VertexAttribFormat, PipelineState::VertexAttribDivisor,
1983 PipelineState::VertexAttribOffset, PipelineState::VertexAttribStride,
1984 PipelineState::VertexAttribCompressed, PipelineState::VertexAttribShaderComponentType,
1985 PipelineState::RenderPassColorFormat, PipelineState::ColorWriteMask,
1986 PipelineState::SrcColorBlendFactor, PipelineState::DstColorBlendFactor,
1987 PipelineState::ColorBlendOp, PipelineState::SrcAlphaBlendFactor,
1988 PipelineState::DstAlphaBlendFactor, PipelineState::AlphaBlendOp,
1989 };
1990
1991 for (PipelineState ps : kRangedStates)
1992 {
1993 size_t range;
1994 switch (ps)
1995 {
1996 case PipelineState::VertexAttribFormat:
1997 case PipelineState::VertexAttribDivisor:
1998 case PipelineState::VertexAttribOffset:
1999 case PipelineState::VertexAttribStride:
2000 case PipelineState::VertexAttribCompressed:
2001 case PipelineState::VertexAttribShaderComponentType:
2002 range = gl::MAX_VERTEX_ATTRIBS;
2003 break;
2004 default:
2005 range = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
2006 break;
2007 }
2008
2009 if (IsPipelineState(stateIndex, ps, range))
2010 {
2011 *subIndexOut = GetPipelineStateSubIndex(stateIndex, ps);
2012 *isRangedOut = true;
2013 return ps;
2014 }
2015 }
2016
2017 *isRangedOut = false;
2018 return static_cast<PipelineState>(stateIndex);
2019 }
2020
OutputPipelineState(std::ostream & out,size_t stateIndex,uint32_t state)2021 [[maybe_unused]] void OutputPipelineState(std::ostream &out, size_t stateIndex, uint32_t state)
2022 {
2023 size_t subIndex = 0;
2024 bool isRanged = false;
2025 PipelineState pipelineState = GetPipelineState(stateIndex, &isRanged, &subIndex);
2026
2027 constexpr angle::PackedEnumMap<PipelineState, const char *> kStateNames = {{
2028 {PipelineState::VertexAttribFormat, "va_format"},
2029 {PipelineState::VertexAttribDivisor, "va_divisor"},
2030 {PipelineState::VertexAttribOffset, "va_offset"},
2031 {PipelineState::VertexAttribStride, "va_stride"},
2032 {PipelineState::VertexAttribCompressed, "va_compressed"},
2033 {PipelineState::VertexAttribShaderComponentType, "va_shader_component_type"},
2034 {PipelineState::RenderPassSamples, "rp_samples"},
2035 {PipelineState::RenderPassColorAttachmentRange, "rp_color_range"},
2036 {PipelineState::RenderPassViewCount, "rp_views"},
2037 {PipelineState::RenderPassSrgbWriteControl, "rp_srgb"},
2038 {PipelineState::RenderPassHasColorFramebufferFetch, "rp_has_color_framebuffer_fetch"},
2039 {PipelineState::RenderPassHasDepthStencilFramebufferFetch,
2040 "rp_has_depth_stencil_framebuffer_fetch"},
2041 {PipelineState::RenderPassIsRenderToTexture, "rp_is_msrtt"},
2042 {PipelineState::RenderPassResolveDepth, "rp_resolve_depth"},
2043 {PipelineState::RenderPassResolveStencil, "rp_resolve_stencil"},
2044 {PipelineState::RenderPassUnresolveDepth, "rp_unresolve_depth"},
2045 {PipelineState::RenderPassUnresolveStencil, "rp_unresolve_stencil"},
2046 {PipelineState::RenderPassColorResolveMask, "rp_resolve_color"},
2047 {PipelineState::RenderPassColorUnresolveMask, "rp_unresolve_color"},
2048 {PipelineState::RenderPassColorFormat, "rp_color"},
2049 {PipelineState::RenderPassDepthStencilFormat, "rp_depth_stencil"},
2050 {PipelineState::Subpass, "subpass"},
2051 {PipelineState::Topology, "topology"},
2052 {PipelineState::PatchVertices, "patch_vertices"},
2053 {PipelineState::PrimitiveRestartEnable, "primitive_restart"},
2054 {PipelineState::PolygonMode, "polygon_mode"},
2055 {PipelineState::CullMode, "cull_mode"},
2056 {PipelineState::FrontFace, "front_face"},
2057 {PipelineState::SurfaceRotation, "rotated_surface"},
2058 {PipelineState::ViewportNegativeOneToOne, "viewport_depth_[-1,1]"},
2059 {PipelineState::SampleShadingEnable, "sample_shading"},
2060 {PipelineState::RasterizationSamples, "rasterization_samples"},
2061 {PipelineState::MinSampleShading, "min_sample_shading"},
2062 {PipelineState::SampleMask, "sample_mask"},
2063 {PipelineState::AlphaToCoverageEnable, "alpha_to_coverage"},
2064 {PipelineState::AlphaToOneEnable, "alpha_to_one"},
2065 {PipelineState::LogicOpEnable, "logic_op_enable"},
2066 {PipelineState::LogicOp, "logic_op"},
2067 {PipelineState::RasterizerDiscardEnable, "rasterization_discard"},
2068 {PipelineState::ColorWriteMask, "color_write"},
2069 {PipelineState::BlendEnableMask, "blend_mask"},
2070 {PipelineState::MissingOutputsMask, "missing_outputs_mask"},
2071 {PipelineState::SrcColorBlendFactor, "src_color_blend"},
2072 {PipelineState::DstColorBlendFactor, "dst_color_blend"},
2073 {PipelineState::ColorBlendOp, "color_blend"},
2074 {PipelineState::SrcAlphaBlendFactor, "src_alpha_blend"},
2075 {PipelineState::DstAlphaBlendFactor, "dst_alpha_blend"},
2076 {PipelineState::AlphaBlendOp, "alpha_blend"},
2077 {PipelineState::EmulatedDitherControl, "dither"},
2078 {PipelineState::DepthClampEnable, "depth_clamp"},
2079 {PipelineState::DepthBoundsTest, "depth_bounds_test"},
2080 {PipelineState::DepthCompareOp, "depth_compare"},
2081 {PipelineState::DepthTest, "depth_test"},
2082 {PipelineState::DepthWrite, "depth_write"},
2083 {PipelineState::StencilTest, "stencil_test"},
2084 {PipelineState::DepthBiasEnable, "depth_bias"},
2085 {PipelineState::StencilOpFailFront, "stencil_front_fail"},
2086 {PipelineState::StencilOpPassFront, "stencil_front_pass"},
2087 {PipelineState::StencilOpDepthFailFront, "stencil_front_depth_fail"},
2088 {PipelineState::StencilCompareFront, "stencil_front_compare"},
2089 {PipelineState::StencilOpFailBack, "stencil_back_fail"},
2090 {PipelineState::StencilOpPassBack, "stencil_back_pass"},
2091 {PipelineState::StencilOpDepthFailBack, "stencil_back_depth_fail"},
2092 {PipelineState::StencilCompareBack, "stencil_back_compare"},
2093 }};
2094
2095 out << kStateNames[pipelineState];
2096 if (isRanged)
2097 {
2098 out << "_" << subIndex;
2099 }
2100
2101 switch (pipelineState)
2102 {
2103 // Given that state == 0 produces no output, binary state doesn't require anything but
2104 // its name specified, as it being enabled would be implied.
2105 case PipelineState::VertexAttribCompressed:
2106 case PipelineState::RenderPassSrgbWriteControl:
2107 case PipelineState::RenderPassHasColorFramebufferFetch:
2108 case PipelineState::RenderPassHasDepthStencilFramebufferFetch:
2109 case PipelineState::RenderPassIsRenderToTexture:
2110 case PipelineState::RenderPassResolveDepth:
2111 case PipelineState::RenderPassResolveStencil:
2112 case PipelineState::RenderPassUnresolveDepth:
2113 case PipelineState::RenderPassUnresolveStencil:
2114 case PipelineState::PrimitiveRestartEnable:
2115 case PipelineState::SurfaceRotation:
2116 case PipelineState::ViewportNegativeOneToOne:
2117 case PipelineState::SampleShadingEnable:
2118 case PipelineState::AlphaToCoverageEnable:
2119 case PipelineState::AlphaToOneEnable:
2120 case PipelineState::LogicOpEnable:
2121 case PipelineState::RasterizerDiscardEnable:
2122 case PipelineState::DepthClampEnable:
2123 case PipelineState::DepthBoundsTest:
2124 case PipelineState::DepthTest:
2125 case PipelineState::DepthWrite:
2126 case PipelineState::StencilTest:
2127 case PipelineState::DepthBiasEnable:
2128 break;
2129
2130 // Special formatting for some state
2131 case PipelineState::VertexAttribShaderComponentType:
2132 out << "=";
2133 switch (state)
2134 {
2135 case 0:
2136 static_assert(static_cast<uint32_t>(gl::ComponentType::Float) == 0);
2137 out << "float";
2138 break;
2139 case 1:
2140 static_assert(static_cast<uint32_t>(gl::ComponentType::Int) == 1);
2141 out << "int";
2142 break;
2143 case 2:
2144 static_assert(static_cast<uint32_t>(gl::ComponentType::UnsignedInt) == 2);
2145 out << "uint";
2146 break;
2147 case 3:
2148 static_assert(static_cast<uint32_t>(gl::ComponentType::NoType) == 3);
2149 out << "none";
2150 break;
2151 default:
2152 UNREACHABLE();
2153 }
2154 break;
2155 case PipelineState::Topology:
2156 out << "=";
2157 switch (state)
2158 {
2159 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
2160 out << "points";
2161 break;
2162 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
2163 out << "lines";
2164 break;
2165 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
2166 out << "line_strip";
2167 break;
2168 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
2169 out << "tris";
2170 break;
2171 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
2172 out << "tri_strip";
2173 break;
2174 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
2175 out << "tri_fan";
2176 break;
2177 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
2178 out << "lines_with_adj";
2179 break;
2180 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
2181 out << "line_strip_with_adj";
2182 break;
2183 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
2184 out << "tris_with_adj";
2185 break;
2186 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
2187 out << "tri_strip_with_adj";
2188 break;
2189 case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
2190 out << "patches";
2191 break;
2192 default:
2193 UNREACHABLE();
2194 }
2195 break;
2196 case PipelineState::PolygonMode:
2197 out << "=";
2198 switch (state)
2199 {
2200 case VK_POLYGON_MODE_FILL:
2201 out << "fill";
2202 break;
2203 case VK_POLYGON_MODE_LINE:
2204 out << "line";
2205 break;
2206 case VK_POLYGON_MODE_POINT:
2207 out << "point";
2208 break;
2209 default:
2210 UNREACHABLE();
2211 }
2212 break;
2213 case PipelineState::CullMode:
2214 out << "=";
2215 if ((state & VK_CULL_MODE_FRONT_BIT) != 0)
2216 {
2217 out << "front";
2218 }
2219 if (state == VK_CULL_MODE_FRONT_AND_BACK)
2220 {
2221 out << "+";
2222 }
2223 if ((state & VK_CULL_MODE_BACK_BIT) != 0)
2224 {
2225 out << "back";
2226 }
2227 break;
2228 case PipelineState::FrontFace:
2229 out << "=" << (state == VK_FRONT_FACE_COUNTER_CLOCKWISE ? "ccw" : "cw");
2230 break;
2231 case PipelineState::MinSampleShading:
2232 out << "=" << (static_cast<float>(state) / kMinSampleShadingScale);
2233 break;
2234 case PipelineState::SrcColorBlendFactor:
2235 case PipelineState::DstColorBlendFactor:
2236 case PipelineState::SrcAlphaBlendFactor:
2237 case PipelineState::DstAlphaBlendFactor:
2238 out << "=";
2239 switch (state)
2240 {
2241 case VK_BLEND_FACTOR_ZERO:
2242 out << "0";
2243 break;
2244 case VK_BLEND_FACTOR_ONE:
2245 out << "1";
2246 break;
2247 case VK_BLEND_FACTOR_SRC_COLOR:
2248 out << "sc";
2249 break;
2250 case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
2251 out << "1-sc";
2252 break;
2253 case VK_BLEND_FACTOR_DST_COLOR:
2254 out << "dc";
2255 break;
2256 case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
2257 out << "1-dc";
2258 break;
2259 case VK_BLEND_FACTOR_SRC_ALPHA:
2260 out << "sa";
2261 break;
2262 case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
2263 out << "1-sa";
2264 break;
2265 case VK_BLEND_FACTOR_DST_ALPHA:
2266 out << "da";
2267 break;
2268 case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
2269 out << "1-da";
2270 break;
2271 case VK_BLEND_FACTOR_CONSTANT_COLOR:
2272 out << "const_color";
2273 break;
2274 case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
2275 out << "1-const_color";
2276 break;
2277 case VK_BLEND_FACTOR_CONSTANT_ALPHA:
2278 out << "const_alpha";
2279 break;
2280 case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
2281 out << "1-const_alpha";
2282 break;
2283 case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE:
2284 out << "sat(sa)";
2285 break;
2286 case VK_BLEND_FACTOR_SRC1_COLOR:
2287 out << "sc1";
2288 break;
2289 case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
2290 out << "1-sc1";
2291 break;
2292 case VK_BLEND_FACTOR_SRC1_ALPHA:
2293 out << "sa1";
2294 break;
2295 case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
2296 out << "1-sa1";
2297 break;
2298 default:
2299 UNREACHABLE();
2300 }
2301 break;
2302 case PipelineState::ColorBlendOp:
2303 case PipelineState::AlphaBlendOp:
2304 out << "=";
2305 switch (UnpackBlendOp(static_cast<uint8_t>(state)))
2306 {
2307 case VK_BLEND_OP_ADD:
2308 out << "add";
2309 break;
2310 case VK_BLEND_OP_SUBTRACT:
2311 out << "sub";
2312 break;
2313 case VK_BLEND_OP_REVERSE_SUBTRACT:
2314 out << "reverse_sub";
2315 break;
2316 case VK_BLEND_OP_MIN:
2317 out << "min";
2318 break;
2319 case VK_BLEND_OP_MAX:
2320 out << "max";
2321 break;
2322 case VK_BLEND_OP_MULTIPLY_EXT:
2323 out << "multiply";
2324 break;
2325 case VK_BLEND_OP_SCREEN_EXT:
2326 out << "screen";
2327 break;
2328 case VK_BLEND_OP_OVERLAY_EXT:
2329 out << "overlay";
2330 break;
2331 case VK_BLEND_OP_DARKEN_EXT:
2332 out << "darken";
2333 break;
2334 case VK_BLEND_OP_LIGHTEN_EXT:
2335 out << "lighten";
2336 break;
2337 case VK_BLEND_OP_COLORDODGE_EXT:
2338 out << "dodge";
2339 break;
2340 case VK_BLEND_OP_COLORBURN_EXT:
2341 out << "burn";
2342 break;
2343 case VK_BLEND_OP_HARDLIGHT_EXT:
2344 out << "hardlight";
2345 break;
2346 case VK_BLEND_OP_SOFTLIGHT_EXT:
2347 out << "softlight";
2348 break;
2349 case VK_BLEND_OP_DIFFERENCE_EXT:
2350 out << "difference";
2351 break;
2352 case VK_BLEND_OP_EXCLUSION_EXT:
2353 out << "exclusion";
2354 break;
2355 case VK_BLEND_OP_HSL_HUE_EXT:
2356 out << "hsl_hue";
2357 break;
2358 case VK_BLEND_OP_HSL_SATURATION_EXT:
2359 out << "hsl_sat";
2360 break;
2361 case VK_BLEND_OP_HSL_COLOR_EXT:
2362 out << "hsl_color";
2363 break;
2364 case VK_BLEND_OP_HSL_LUMINOSITY_EXT:
2365 out << "hsl_lum";
2366 break;
2367 default:
2368 UNREACHABLE();
2369 }
2370 break;
2371 case PipelineState::DepthCompareOp:
2372 case PipelineState::StencilCompareFront:
2373 case PipelineState::StencilCompareBack:
2374 out << "=";
2375 switch (state)
2376 {
2377 case VK_COMPARE_OP_NEVER:
2378 out << "never";
2379 break;
2380 case VK_COMPARE_OP_LESS:
2381 out << "'<'";
2382 break;
2383 case VK_COMPARE_OP_EQUAL:
2384 out << "'='";
2385 break;
2386 case VK_COMPARE_OP_LESS_OR_EQUAL:
2387 out << "'<='";
2388 break;
2389 case VK_COMPARE_OP_GREATER:
2390 out << "'>'";
2391 break;
2392 case VK_COMPARE_OP_NOT_EQUAL:
2393 out << "'!='";
2394 break;
2395 case VK_COMPARE_OP_GREATER_OR_EQUAL:
2396 out << "'>='";
2397 break;
2398 case VK_COMPARE_OP_ALWAYS:
2399 out << "always";
2400 break;
2401 default:
2402 UNREACHABLE();
2403 }
2404 break;
2405 case PipelineState::StencilOpFailFront:
2406 case PipelineState::StencilOpPassFront:
2407 case PipelineState::StencilOpDepthFailFront:
2408 case PipelineState::StencilOpFailBack:
2409 case PipelineState::StencilOpPassBack:
2410 case PipelineState::StencilOpDepthFailBack:
2411 out << "=";
2412 switch (state)
2413 {
2414 case VK_STENCIL_OP_KEEP:
2415 out << "keep";
2416 break;
2417 case VK_STENCIL_OP_ZERO:
2418 out << "0";
2419 break;
2420 case VK_STENCIL_OP_REPLACE:
2421 out << "replace";
2422 break;
2423 case VK_STENCIL_OP_INCREMENT_AND_CLAMP:
2424 out << "clamp++";
2425 break;
2426 case VK_STENCIL_OP_DECREMENT_AND_CLAMP:
2427 out << "clamp--";
2428 break;
2429 case VK_STENCIL_OP_INVERT:
2430 out << "'~'";
2431 break;
2432 case VK_STENCIL_OP_INCREMENT_AND_WRAP:
2433 out << "wrap++";
2434 break;
2435 case VK_STENCIL_OP_DECREMENT_AND_WRAP:
2436 out << "wrap--";
2437 break;
2438 default:
2439 UNREACHABLE();
2440 }
2441 break;
2442
2443 // Some state output the value as hex because they are bitmasks
2444 case PipelineState::RenderPassColorResolveMask:
2445 case PipelineState::RenderPassColorUnresolveMask:
2446 case PipelineState::SampleMask:
2447 case PipelineState::ColorWriteMask:
2448 case PipelineState::BlendEnableMask:
2449 case PipelineState::MissingOutputsMask:
2450 case PipelineState::EmulatedDitherControl:
2451 out << "=0x" << std::hex << state << std::dec;
2452 break;
2453
2454 // The rest will simply output the state value
2455 default:
2456 out << "=" << state;
2457 break;
2458 }
2459
2460 out << "\\n";
2461 }
2462
OutputAllPipelineState(ErrorContext * context,std::ostream & out,const UnpackedPipelineState & pipeline,GraphicsPipelineSubset subset,const PipelineStateBitSet & include,bool isCommonState)2463 [[maybe_unused]] void OutputAllPipelineState(ErrorContext *context,
2464 std::ostream &out,
2465 const UnpackedPipelineState &pipeline,
2466 GraphicsPipelineSubset subset,
2467 const PipelineStateBitSet &include,
2468 bool isCommonState)
2469 {
2470 // Default non-existing state to 0, so they are automatically not output as
2471 // UnpackedPipelineState also sets them to 0.
2472 const bool hasVertexInput = GraphicsPipelineHasVertexInput(subset);
2473 const bool hasShaders = GraphicsPipelineHasShaders(subset);
2474 const bool hasShadersOrFragmentOutput = GraphicsPipelineHasShadersOrFragmentOutput(subset);
2475 const bool hasFragmentOutput = GraphicsPipelineHasFragmentOutput(subset);
2476
2477 const angle::PackedEnumMap<PipelineState, uint32_t> kDefaultState = {{
2478 // Vertex input state
2479 {PipelineState::VertexAttribFormat,
2480 hasVertexInput
2481 ? static_cast<uint32_t>(GetCurrentValueFormatID(gl::VertexAttribType::Float))
2482 : 0},
2483 {PipelineState::VertexAttribDivisor, 0},
2484 {PipelineState::VertexAttribOffset, 0},
2485 {PipelineState::VertexAttribStride, 0},
2486 {PipelineState::VertexAttribCompressed, 0},
2487 {PipelineState::VertexAttribShaderComponentType, 0},
2488 {PipelineState::Topology, hasVertexInput ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST : 0},
2489 {PipelineState::PrimitiveRestartEnable, 0},
2490
2491 // Shaders state
2492 {PipelineState::ViewportNegativeOneToOne,
2493 hasShaders && context->getFeatures().supportsDepthClipControl.enabled},
2494 {PipelineState::DepthClampEnable, 0},
2495 {PipelineState::PolygonMode, hasShaders ? VK_POLYGON_MODE_FILL : 0},
2496 {PipelineState::CullMode, hasShaders ? VK_CULL_MODE_NONE : 0},
2497 {PipelineState::FrontFace, hasShaders ? VK_FRONT_FACE_COUNTER_CLOCKWISE : 0},
2498 {PipelineState::RasterizerDiscardEnable, 0},
2499 {PipelineState::DepthBiasEnable, 0},
2500 {PipelineState::PatchVertices, hasShaders ? 3 : 0},
2501 {PipelineState::DepthBoundsTest, 0},
2502 {PipelineState::DepthTest, 0},
2503 {PipelineState::DepthWrite, 0},
2504 {PipelineState::StencilTest, 0},
2505 {PipelineState::DepthCompareOp, hasShaders ? VK_COMPARE_OP_LESS : 0},
2506 {PipelineState::SurfaceRotation, 0},
2507 {PipelineState::EmulatedDitherControl, 0},
2508 {PipelineState::StencilOpFailFront, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2509 {PipelineState::StencilOpPassFront, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2510 {PipelineState::StencilOpDepthFailFront, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2511 {PipelineState::StencilCompareFront, hasShaders ? VK_COMPARE_OP_ALWAYS : 0},
2512 {PipelineState::StencilOpFailBack, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2513 {PipelineState::StencilOpPassBack, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2514 {PipelineState::StencilOpDepthFailBack, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2515 {PipelineState::StencilCompareBack, hasShaders ? VK_COMPARE_OP_ALWAYS : 0},
2516
2517 // Shared shaders and fragment output state
2518 {PipelineState::SampleMask,
2519 hasShadersOrFragmentOutput ? std::numeric_limits<uint16_t>::max() : 0},
2520 {PipelineState::RasterizationSamples, hasShadersOrFragmentOutput ? 1 : 0},
2521 {PipelineState::SampleShadingEnable, 0},
2522 {PipelineState::MinSampleShading, hasShadersOrFragmentOutput ? kMinSampleShadingScale : 0},
2523 {PipelineState::AlphaToCoverageEnable, 0},
2524 {PipelineState::AlphaToOneEnable, 0},
2525 {PipelineState::RenderPassSamples, hasShadersOrFragmentOutput ? 1 : 0},
2526 {PipelineState::RenderPassColorAttachmentRange, 0},
2527 {PipelineState::RenderPassViewCount, 0},
2528 {PipelineState::RenderPassSrgbWriteControl, 0},
2529 {PipelineState::RenderPassHasColorFramebufferFetch, 0},
2530 {PipelineState::RenderPassHasDepthStencilFramebufferFetch, 0},
2531 {PipelineState::RenderPassIsRenderToTexture, 0},
2532 {PipelineState::RenderPassResolveDepth, 0},
2533 {PipelineState::RenderPassResolveStencil, 0},
2534 {PipelineState::RenderPassUnresolveDepth, 0},
2535 {PipelineState::RenderPassUnresolveStencil, 0},
2536 {PipelineState::RenderPassColorResolveMask, 0},
2537 {PipelineState::RenderPassColorUnresolveMask, 0},
2538 {PipelineState::RenderPassColorFormat, 0},
2539 {PipelineState::RenderPassDepthStencilFormat, 0},
2540 {PipelineState::Subpass, 0},
2541
2542 // Fragment output state
2543 {PipelineState::ColorWriteMask, 0},
2544 {PipelineState::SrcColorBlendFactor, hasFragmentOutput ? VK_BLEND_FACTOR_ONE : 0},
2545 {PipelineState::DstColorBlendFactor, hasFragmentOutput ? VK_BLEND_FACTOR_ZERO : 0},
2546 {PipelineState::ColorBlendOp, hasFragmentOutput ? VK_BLEND_OP_ADD : 0},
2547 {PipelineState::SrcAlphaBlendFactor, hasFragmentOutput ? VK_BLEND_FACTOR_ONE : 0},
2548 {PipelineState::DstAlphaBlendFactor, hasFragmentOutput ? VK_BLEND_FACTOR_ZERO : 0},
2549 {PipelineState::AlphaBlendOp, hasFragmentOutput ? VK_BLEND_OP_ADD : 0},
2550 {PipelineState::BlendEnableMask, 0},
2551 {PipelineState::LogicOpEnable, 0},
2552 {PipelineState::LogicOp, hasFragmentOutput ? VK_LOGIC_OP_COPY : 0},
2553 {PipelineState::MissingOutputsMask, 0},
2554 }};
2555
2556 bool anyStateOutput = false;
2557 for (size_t stateIndex : include)
2558 {
2559 size_t subIndex = 0;
2560 bool isRanged = false;
2561 PipelineState pipelineState = GetPipelineState(stateIndex, &isRanged, &subIndex);
2562
2563 const uint32_t state = pipeline.data()[stateIndex];
2564 if (state != kDefaultState[pipelineState])
2565 {
2566 OutputPipelineState(out, stateIndex, state);
2567 anyStateOutput = true;
2568 }
2569 }
2570
2571 if (!isCommonState)
2572 {
2573 out << "(" << (anyStateOutput ? "+" : "") << "common state)\\n";
2574 }
2575 }
2576
2577 template <typename Hash>
DumpPipelineCacheGraph(ErrorContext * context,const std::unordered_map<GraphicsPipelineDesc,PipelineHelper,Hash,typename GraphicsPipelineCacheTypeHelper<Hash>::KeyEqual> & cache)2578 void DumpPipelineCacheGraph(
2579 ErrorContext *context,
2580 const std::unordered_map<GraphicsPipelineDesc,
2581 PipelineHelper,
2582 Hash,
2583 typename GraphicsPipelineCacheTypeHelper<Hash>::KeyEqual> &cache)
2584 {
2585 constexpr GraphicsPipelineSubset kSubset = GraphicsPipelineCacheTypeHelper<Hash>::kSubset;
2586
2587 std::ostream &out = context->getRenderer()->getPipelineCacheGraphStream();
2588
2589 static std::atomic<uint32_t> sCacheSerial(0);
2590 angle::HashMap<GraphicsPipelineDesc, uint32_t, Hash,
2591 typename GraphicsPipelineCacheTypeHelper<Hash>::KeyEqual>
2592 descToId;
2593
2594 uint32_t cacheSerial = sCacheSerial.fetch_add(1);
2595 uint32_t descId = 0;
2596
2597 // Unpack pipeline states
2598 std::vector<UnpackedPipelineState> pipelines(cache.size());
2599 for (const auto &descAndPipeline : cache)
2600 {
2601 UnpackPipelineState(descAndPipeline.first, kSubset, &pipelines[descId++]);
2602 }
2603
2604 // Extract common state between all pipelines.
2605 PipelineStateBitSet commonState = GetCommonPipelineState(pipelines);
2606 PipelineStateBitSet nodeState = ~commonState;
2607
2608 const char *subsetDescription = "";
2609 const char *subsetTag = "";
2610 switch (kSubset)
2611 {
2612 case GraphicsPipelineSubset::Shaders:
2613 subsetDescription = "(shaders)\\n";
2614 subsetTag = "S_";
2615 break;
2616 default:
2617 break;
2618 }
2619
2620 out << " subgraph cluster_" << subsetTag << cacheSerial << "{\n";
2621 out << " label=\"Program " << cacheSerial << "\\n"
2622 << subsetDescription << "\\nCommon state:\\n";
2623 OutputAllPipelineState(context, out, pipelines[0], kSubset, commonState, true);
2624 out << "\";\n";
2625
2626 descId = 0;
2627 for (const auto &descAndPipeline : cache)
2628 {
2629 const GraphicsPipelineDesc &desc = descAndPipeline.first;
2630
2631 const char *style = "";
2632 const char *feedbackDesc = "";
2633 switch (descAndPipeline.second.getCacheLookUpFeedback())
2634 {
2635 case CacheLookUpFeedback::Hit:
2636 // Default is green already
2637 break;
2638 case CacheLookUpFeedback::Miss:
2639 style = "[color=red]";
2640 break;
2641 case CacheLookUpFeedback::LinkedDrawHit:
2642 // Default is green already
2643 style = "[style=dotted]";
2644 feedbackDesc = "(linked)\\n";
2645 break;
2646 case CacheLookUpFeedback::LinkedDrawMiss:
2647 style = "[style=dotted,color=red]";
2648 feedbackDesc = "(linked)\\n";
2649 break;
2650 case CacheLookUpFeedback::WarmUpHit:
2651 // Default is green already
2652 style = "[style=dashed]";
2653 feedbackDesc = "(warm up)\\n";
2654 break;
2655 case CacheLookUpFeedback::WarmUpMiss:
2656 style = "[style=dashed,color=red]";
2657 feedbackDesc = "(warm up)\\n";
2658 break;
2659 case CacheLookUpFeedback::UtilsHit:
2660 style = "[color=yellow]";
2661 feedbackDesc = "(utils)\\n";
2662 break;
2663 case CacheLookUpFeedback::UtilsMiss:
2664 style = "[color=purple]";
2665 feedbackDesc = "(utils)\\n";
2666 break;
2667 default:
2668 // No feedback available
2669 break;
2670 }
2671
2672 out << " p" << subsetTag << cacheSerial << "_" << descId << "[label=\"Pipeline " << descId
2673 << "\\n"
2674 << feedbackDesc << "\\n";
2675 OutputAllPipelineState(context, out, pipelines[descId], kSubset, nodeState, false);
2676 out << "\"]" << style << ";\n";
2677
2678 descToId[desc] = descId++;
2679 }
2680 for (const auto &descAndPipeline : cache)
2681 {
2682 const GraphicsPipelineDesc &desc = descAndPipeline.first;
2683 const PipelineHelper &pipelineHelper = descAndPipeline.second;
2684 const std::vector<GraphicsPipelineTransition> &transitions =
2685 pipelineHelper.getTransitions();
2686
2687 for (const GraphicsPipelineTransition &transition : transitions)
2688 {
2689 #if defined(ANGLE_IS_64_BIT_CPU)
2690 const uint64_t transitionBits = transition.bits.bits();
2691 #else
2692 const uint64_t transitionBits =
2693 static_cast<uint64_t>(transition.bits.bits(1)) << 32 | transition.bits.bits(0);
2694 #endif
2695 out << " p" << subsetTag << cacheSerial << "_" << descToId[desc] << " -> p"
2696 << subsetTag << cacheSerial << "_" << descToId[*transition.desc] << " [label=\"'0x"
2697 << std::hex << transitionBits << std::dec << "'\"];\n";
2698 }
2699 }
2700 out << " }\n";
2701 }
2702
2703 // Used by SharedCacheKeyManager
MakeInvalidCachedObject(SharedFramebufferCacheKey * cacheKeyOut)2704 void MakeInvalidCachedObject(SharedFramebufferCacheKey *cacheKeyOut)
2705 {
2706 *cacheKeyOut = SharedFramebufferCacheKey::MakeShared(VK_NULL_HANDLE);
2707 // So that it will mark as invalid.
2708 (*cacheKeyOut)->destroy(VK_NULL_HANDLE);
2709 }
2710
MakeInvalidCachedObject(SharedDescriptorSetCacheKey * cacheKeyOut)2711 void MakeInvalidCachedObject(SharedDescriptorSetCacheKey *cacheKeyOut)
2712 {
2713 *cacheKeyOut = SharedDescriptorSetCacheKey::MakeShared(VK_NULL_HANDLE);
2714 }
2715
ShouldDumpPipelineCacheGraph(ErrorContext * context)2716 bool ShouldDumpPipelineCacheGraph(ErrorContext *context)
2717 {
2718 return kDumpPipelineCacheGraph && context->getRenderer()->isPipelineCacheGraphDumpEnabled();
2719 }
2720 } // anonymous namespace
2721
GetProgramFramebufferFetchMode(const gl::ProgramExecutable * executable)2722 FramebufferFetchMode GetProgramFramebufferFetchMode(const gl::ProgramExecutable *executable)
2723 {
2724 if (executable == nullptr)
2725 {
2726 return FramebufferFetchMode::None;
2727 }
2728
2729 const bool hasColorFramebufferFetch = executable->usesColorFramebufferFetch();
2730 const bool hasDepthStencilFramebufferFetch =
2731 executable->usesDepthFramebufferFetch() || executable->usesStencilFramebufferFetch();
2732
2733 if (hasDepthStencilFramebufferFetch)
2734 {
2735 return hasColorFramebufferFetch ? FramebufferFetchMode::ColorAndDepthStencil
2736 : FramebufferFetchMode::DepthStencil;
2737 }
2738 else
2739 {
2740 return hasColorFramebufferFetch ? FramebufferFetchMode::Color : FramebufferFetchMode::None;
2741 }
2742 }
2743
GetGraphicsPipelineTransitionBitsMask(GraphicsPipelineSubset subset)2744 GraphicsPipelineTransitionBits GetGraphicsPipelineTransitionBitsMask(GraphicsPipelineSubset subset)
2745 {
2746 if (subset == GraphicsPipelineSubset::Shaders)
2747 {
2748 return kPipelineShadersTransitionBitsMask;
2749 }
2750
2751 ASSERT(subset == GraphicsPipelineSubset::Complete);
2752
2753 GraphicsPipelineTransitionBits allBits;
2754 allBits.set();
2755
2756 return allBits;
2757 }
2758
2759 // RenderPassDesc implementation.
RenderPassDesc()2760 RenderPassDesc::RenderPassDesc()
2761 {
2762 memset(this, 0, sizeof(RenderPassDesc));
2763 }
2764
2765 RenderPassDesc::~RenderPassDesc() = default;
2766
RenderPassDesc(const RenderPassDesc & other)2767 RenderPassDesc::RenderPassDesc(const RenderPassDesc &other)
2768 {
2769 memcpy(this, &other, sizeof(RenderPassDesc));
2770 }
2771
packColorAttachment(size_t colorIndexGL,angle::FormatID formatID)2772 void RenderPassDesc::packColorAttachment(size_t colorIndexGL, angle::FormatID formatID)
2773 {
2774 ASSERT(colorIndexGL < mAttachmentFormats.size());
2775 static_assert(angle::kNumANGLEFormats < std::numeric_limits<uint8_t>::max(),
2776 "Too many ANGLE formats to fit in uint8_t");
2777 // Force the user to pack the depth/stencil attachment last.
2778 ASSERT(!hasDepthStencilAttachment());
2779 // This function should only be called for enabled GL color attachments.
2780 ASSERT(formatID != angle::FormatID::NONE);
2781
2782 uint8_t &packedFormat = mAttachmentFormats[colorIndexGL];
2783 SetBitField(packedFormat, formatID);
2784
2785 // Set color attachment range such that it covers the range from index 0 through last active
2786 // index. This is the reasons why we need depth/stencil to be packed last.
2787 SetBitField(mColorAttachmentRange, std::max<size_t>(mColorAttachmentRange, colorIndexGL + 1));
2788 }
2789
packColorAttachmentGap(size_t colorIndexGL)2790 void RenderPassDesc::packColorAttachmentGap(size_t colorIndexGL)
2791 {
2792 ASSERT(colorIndexGL < mAttachmentFormats.size());
2793 static_assert(angle::kNumANGLEFormats < std::numeric_limits<uint8_t>::max(),
2794 "Too many ANGLE formats to fit in uint8_t");
2795 // Force the user to pack the depth/stencil attachment last.
2796 ASSERT(!hasDepthStencilAttachment());
2797
2798 // Use NONE as a flag for gaps in GL color attachments.
2799 uint8_t &packedFormat = mAttachmentFormats[colorIndexGL];
2800 SetBitField(packedFormat, angle::FormatID::NONE);
2801 }
2802
packDepthStencilAttachment(angle::FormatID formatID)2803 void RenderPassDesc::packDepthStencilAttachment(angle::FormatID formatID)
2804 {
2805 ASSERT(!hasDepthStencilAttachment());
2806
2807 size_t index = depthStencilAttachmentIndex();
2808 ASSERT(index < mAttachmentFormats.size());
2809
2810 uint8_t &packedFormat = mAttachmentFormats[index];
2811 SetBitField(packedFormat, formatID);
2812 }
2813
packColorResolveAttachment(size_t colorIndexGL)2814 void RenderPassDesc::packColorResolveAttachment(size_t colorIndexGL)
2815 {
2816 ASSERT(isColorAttachmentEnabled(colorIndexGL));
2817 ASSERT(!mColorResolveAttachmentMask.test(colorIndexGL));
2818 ASSERT(mSamples > 1);
2819 mColorResolveAttachmentMask.set(colorIndexGL);
2820 }
2821
packYUVResolveAttachment(size_t colorIndexGL)2822 void RenderPassDesc::packYUVResolveAttachment(size_t colorIndexGL)
2823 {
2824 ASSERT(isColorAttachmentEnabled(colorIndexGL));
2825 ASSERT(!mColorResolveAttachmentMask.test(colorIndexGL));
2826 mColorResolveAttachmentMask.set(colorIndexGL);
2827 SetBitField(mIsYUVResolve, 1);
2828 }
2829
removeColorResolveAttachment(size_t colorIndexGL)2830 void RenderPassDesc::removeColorResolveAttachment(size_t colorIndexGL)
2831 {
2832 ASSERT(mColorResolveAttachmentMask.test(colorIndexGL));
2833 mColorResolveAttachmentMask.reset(colorIndexGL);
2834 }
2835
packColorUnresolveAttachment(size_t colorIndexGL)2836 void RenderPassDesc::packColorUnresolveAttachment(size_t colorIndexGL)
2837 {
2838 mColorUnresolveAttachmentMask.set(colorIndexGL);
2839 }
2840
removeColorUnresolveAttachment(size_t colorIndexGL)2841 void RenderPassDesc::removeColorUnresolveAttachment(size_t colorIndexGL)
2842 {
2843 mColorUnresolveAttachmentMask.reset(colorIndexGL);
2844 }
2845
packDepthResolveAttachment()2846 void RenderPassDesc::packDepthResolveAttachment()
2847 {
2848 ASSERT(hasDepthStencilAttachment());
2849 ASSERT(!hasDepthResolveAttachment());
2850
2851 mResolveDepth = true;
2852 }
2853
packStencilResolveAttachment()2854 void RenderPassDesc::packStencilResolveAttachment()
2855 {
2856 ASSERT(hasDepthStencilAttachment());
2857 ASSERT(!hasStencilResolveAttachment());
2858
2859 mResolveStencil = true;
2860 }
2861
packDepthUnresolveAttachment()2862 void RenderPassDesc::packDepthUnresolveAttachment()
2863 {
2864 ASSERT(hasDepthStencilAttachment());
2865
2866 mUnresolveDepth = true;
2867 }
2868
packStencilUnresolveAttachment()2869 void RenderPassDesc::packStencilUnresolveAttachment()
2870 {
2871 ASSERT(hasDepthStencilAttachment());
2872
2873 mUnresolveStencil = true;
2874 }
2875
removeDepthStencilUnresolveAttachment()2876 void RenderPassDesc::removeDepthStencilUnresolveAttachment()
2877 {
2878 mUnresolveDepth = false;
2879 mUnresolveStencil = false;
2880 }
2881
getPackedColorAttachmentIndex(size_t colorIndexGL)2882 PackedAttachmentIndex RenderPassDesc::getPackedColorAttachmentIndex(size_t colorIndexGL)
2883 {
2884 ASSERT(colorIndexGL < colorAttachmentRange());
2885 ASSERT(isColorAttachmentEnabled(colorIndexGL));
2886
2887 vk::PackedAttachmentIndex colorIndexVk(0);
2888 for (uint32_t index = 0; index < colorIndexGL; ++index)
2889 {
2890 if (isColorAttachmentEnabled(index))
2891 {
2892 ++colorIndexVk;
2893 }
2894 }
2895
2896 return colorIndexVk;
2897 }
2898
operator =(const RenderPassDesc & other)2899 RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other)
2900 {
2901 memcpy(this, &other, sizeof(RenderPassDesc));
2902 return *this;
2903 }
2904
setWriteControlMode(gl::SrgbWriteControlMode mode)2905 void RenderPassDesc::setWriteControlMode(gl::SrgbWriteControlMode mode)
2906 {
2907 SetBitField(mSrgbWriteControl, mode);
2908 }
2909
hash() const2910 size_t RenderPassDesc::hash() const
2911 {
2912 return angle::ComputeGenericHash(*this);
2913 }
2914
isColorAttachmentEnabled(size_t colorIndexGL) const2915 bool RenderPassDesc::isColorAttachmentEnabled(size_t colorIndexGL) const
2916 {
2917 angle::FormatID formatID = operator[](colorIndexGL);
2918 return formatID != angle::FormatID::NONE;
2919 }
2920
hasDepthStencilAttachment() const2921 bool RenderPassDesc::hasDepthStencilAttachment() const
2922 {
2923 angle::FormatID formatID = operator[](depthStencilAttachmentIndex());
2924 return formatID != angle::FormatID::NONE;
2925 }
2926
clearableAttachmentCount() const2927 size_t RenderPassDesc::clearableAttachmentCount() const
2928 {
2929 size_t colorAttachmentCount = 0;
2930 for (size_t i = 0; i < mColorAttachmentRange; ++i)
2931 {
2932 colorAttachmentCount += isColorAttachmentEnabled(i);
2933 }
2934
2935 // Note that there are no gaps in depth/stencil attachments. In fact there is a maximum of 1 of
2936 // it + 1 for its resolve attachment.
2937 size_t depthStencilCount = hasDepthStencilAttachment() ? 1 : 0;
2938 size_t depthStencilResolveCount = hasDepthStencilResolveAttachment() ? 1 : 0;
2939 return colorAttachmentCount + mColorResolveAttachmentMask.count() + depthStencilCount +
2940 depthStencilResolveCount;
2941 }
2942
attachmentCount() const2943 size_t RenderPassDesc::attachmentCount() const
2944 {
2945 return clearableAttachmentCount() + (hasFragmentShadingAttachment() ? 1 : 0);
2946 }
2947
setLegacyDither(bool enabled)2948 void RenderPassDesc::setLegacyDither(bool enabled)
2949 {
2950 SetBitField(mLegacyDitherEnabled, enabled ? 1 : 0);
2951 }
2952
beginRenderPass(ErrorContext * context,PrimaryCommandBuffer * primary,const RenderPass & renderPass,VkFramebuffer framebuffer,const gl::Rectangle & renderArea,VkSubpassContents subpassContents,PackedClearValuesArray & clearValues,const VkRenderPassAttachmentBeginInfo * attachmentBeginInfo) const2953 void RenderPassDesc::beginRenderPass(
2954 ErrorContext *context,
2955 PrimaryCommandBuffer *primary,
2956 const RenderPass &renderPass,
2957 VkFramebuffer framebuffer,
2958 const gl::Rectangle &renderArea,
2959 VkSubpassContents subpassContents,
2960 PackedClearValuesArray &clearValues,
2961 const VkRenderPassAttachmentBeginInfo *attachmentBeginInfo) const
2962 {
2963 VkRenderPassBeginInfo beginInfo = {};
2964 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
2965 beginInfo.pNext = attachmentBeginInfo;
2966 beginInfo.renderPass = renderPass.getHandle();
2967 beginInfo.framebuffer = framebuffer;
2968 beginInfo.renderArea.offset.x = static_cast<uint32_t>(renderArea.x);
2969 beginInfo.renderArea.offset.y = static_cast<uint32_t>(renderArea.y);
2970 beginInfo.renderArea.extent.width = static_cast<uint32_t>(renderArea.width);
2971 beginInfo.renderArea.extent.height = static_cast<uint32_t>(renderArea.height);
2972 beginInfo.clearValueCount = static_cast<uint32_t>(clearableAttachmentCount());
2973 beginInfo.pClearValues = clearValues.data();
2974
2975 primary->beginRenderPass(beginInfo, subpassContents);
2976 }
2977
beginRendering(ErrorContext * context,PrimaryCommandBuffer * primary,const gl::Rectangle & renderArea,VkSubpassContents subpassContents,const FramebufferAttachmentsVector<VkImageView> & attachmentViews,const AttachmentOpsArray & ops,PackedClearValuesArray & clearValues,uint32_t layerCount) const2978 void RenderPassDesc::beginRendering(
2979 ErrorContext *context,
2980 PrimaryCommandBuffer *primary,
2981 const gl::Rectangle &renderArea,
2982 VkSubpassContents subpassContents,
2983 const FramebufferAttachmentsVector<VkImageView> &attachmentViews,
2984 const AttachmentOpsArray &ops,
2985 PackedClearValuesArray &clearValues,
2986 uint32_t layerCount) const
2987 {
2988 DynamicRenderingInfo info;
2989 DeriveRenderingInfo(context->getRenderer(), *this, DynamicRenderingInfoSubset::Full, renderArea,
2990 subpassContents, attachmentViews, ops, clearValues, layerCount, &info);
2991
2992 primary->beginRendering(info.renderingInfo);
2993
2994 VkRenderingAttachmentLocationInfoKHR attachmentLocations = {};
2995 attachmentLocations.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR;
2996 attachmentLocations.colorAttachmentCount = info.renderingInfo.colorAttachmentCount;
2997 attachmentLocations.pColorAttachmentLocations = info.colorAttachmentLocations.data();
2998
2999 primary->setRenderingAttachmentLocations(&attachmentLocations);
3000
3001 if (hasColorFramebufferFetch())
3002 {
3003 VkRenderingInputAttachmentIndexInfoKHR inputLocations = {};
3004 inputLocations.sType = VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR;
3005 inputLocations.colorAttachmentCount = info.renderingInfo.colorAttachmentCount;
3006 inputLocations.pColorAttachmentInputIndices = info.colorAttachmentLocations.data();
3007
3008 primary->setRenderingInputAttachmentIndicates(&inputLocations);
3009 }
3010 }
3011
populateRenderingInheritanceInfo(Renderer * renderer,VkCommandBufferInheritanceRenderingInfo * infoOut,gl::DrawBuffersArray<VkFormat> * colorFormatStorageOut) const3012 void RenderPassDesc::populateRenderingInheritanceInfo(
3013 Renderer *renderer,
3014 VkCommandBufferInheritanceRenderingInfo *infoOut,
3015 gl::DrawBuffersArray<VkFormat> *colorFormatStorageOut) const
3016 {
3017 DynamicRenderingInfo renderingInfo;
3018 DeriveRenderingInfo(renderer, *this, DynamicRenderingInfoSubset::Pipeline, {},
3019 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, {}, {}, {}, 0,
3020 &renderingInfo);
3021 *colorFormatStorageOut = renderingInfo.colorAttachmentFormats;
3022
3023 *infoOut = {};
3024 infoOut->sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO;
3025 infoOut->flags = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT;
3026 if (isLegacyDitherEnabled())
3027 {
3028 ASSERT(renderer->getFeatures().supportsLegacyDithering.enabled);
3029 infoOut->flags |= VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT;
3030 }
3031 infoOut->viewMask = renderingInfo.renderingInfo.viewMask;
3032 infoOut->colorAttachmentCount = renderingInfo.renderingInfo.colorAttachmentCount;
3033 infoOut->pColorAttachmentFormats = colorFormatStorageOut->data();
3034 infoOut->depthAttachmentFormat = renderingInfo.depthAttachmentFormat;
3035 infoOut->stencilAttachmentFormat = renderingInfo.stencilAttachmentFormat;
3036 infoOut->rasterizationSamples =
3037 gl_vk::GetSamples(samples(), renderer->getFeatures().limitSampleCountTo2.enabled);
3038 }
3039
updatePerfCounters(ErrorContext * context,const FramebufferAttachmentsVector<VkImageView> & attachmentViews,const AttachmentOpsArray & ops,angle::VulkanPerfCounters * countersOut)3040 void RenderPassDesc::updatePerfCounters(
3041 ErrorContext *context,
3042 const FramebufferAttachmentsVector<VkImageView> &attachmentViews,
3043 const AttachmentOpsArray &ops,
3044 angle::VulkanPerfCounters *countersOut)
3045 {
3046 DynamicRenderingInfo info;
3047 DeriveRenderingInfo(context->getRenderer(), *this, DynamicRenderingInfoSubset::Full, {},
3048 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS, attachmentViews, ops, {}, 0,
3049 &info);
3050
3051 // Note: resolve attachments don't have ops with dynamic rendering and they are implicit.
3052 // Counter-tests should take the |preferDynamicRendering| flag into account. For color, it's
3053 // trivial to assume DONT_CARE/STORE, but it gets more complicated with depth/stencil when only
3054 // one aspect is resolved.
3055
3056 for (uint32_t index = 0; index < info.renderingInfo.colorAttachmentCount; ++index)
3057 {
3058 const VkRenderingAttachmentInfo &colorInfo = info.renderingInfo.pColorAttachments[index];
3059 ASSERT(colorInfo.imageView != VK_NULL_HANDLE);
3060
3061 countersOut->colorLoadOpClears += colorInfo.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
3062 countersOut->colorLoadOpLoads += colorInfo.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
3063 countersOut->colorLoadOpNones += colorInfo.loadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT ? 1 : 0;
3064 countersOut->colorStoreOpStores +=
3065 colorInfo.storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
3066 countersOut->colorStoreOpNones +=
3067 colorInfo.storeOp == VK_ATTACHMENT_STORE_OP_NONE_EXT ? 1 : 0;
3068
3069 if (colorInfo.resolveMode != VK_RESOLVE_MODE_NONE)
3070 {
3071 countersOut->colorStoreOpStores += 1;
3072 countersOut->colorAttachmentResolves += 1;
3073 }
3074 }
3075
3076 if (info.renderingInfo.pDepthAttachment != nullptr)
3077 {
3078 ASSERT(info.renderingInfo.pDepthAttachment->imageView != VK_NULL_HANDLE);
3079
3080 const VkRenderingAttachmentInfo &depthInfo = *info.renderingInfo.pDepthAttachment;
3081
3082 countersOut->depthLoadOpClears += depthInfo.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
3083 countersOut->depthLoadOpLoads += depthInfo.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
3084 countersOut->depthLoadOpNones += depthInfo.loadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT ? 1 : 0;
3085 countersOut->depthStoreOpStores +=
3086 depthInfo.storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
3087 countersOut->depthStoreOpNones +=
3088 depthInfo.storeOp == VK_ATTACHMENT_STORE_OP_NONE_EXT ? 1 : 0;
3089
3090 if (depthInfo.resolveMode != VK_RESOLVE_MODE_NONE)
3091 {
3092 countersOut->depthStoreOpStores += 1;
3093 countersOut->depthAttachmentResolves += 1;
3094 }
3095 }
3096
3097 if (info.renderingInfo.pStencilAttachment != nullptr)
3098 {
3099 ASSERT(info.renderingInfo.pStencilAttachment->imageView != VK_NULL_HANDLE);
3100
3101 const VkRenderingAttachmentInfo &stencilInfo = *info.renderingInfo.pStencilAttachment;
3102
3103 countersOut->stencilLoadOpClears +=
3104 stencilInfo.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
3105 countersOut->stencilLoadOpLoads += stencilInfo.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
3106 countersOut->stencilLoadOpNones +=
3107 stencilInfo.loadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT ? 1 : 0;
3108 countersOut->stencilStoreOpStores +=
3109 stencilInfo.storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
3110 countersOut->stencilStoreOpNones +=
3111 stencilInfo.storeOp == VK_ATTACHMENT_STORE_OP_NONE_EXT ? 1 : 0;
3112
3113 if (stencilInfo.resolveMode != VK_RESOLVE_MODE_NONE)
3114 {
3115 countersOut->stencilStoreOpStores += 1;
3116 countersOut->stencilAttachmentResolves += 1;
3117 }
3118 }
3119
3120 if (info.renderingInfo.pDepthAttachment != nullptr ||
3121 info.renderingInfo.pStencilAttachment != nullptr)
3122 {
3123 ASSERT(info.renderingInfo.pDepthAttachment == nullptr ||
3124 info.renderingInfo.pStencilAttachment == nullptr ||
3125 info.renderingInfo.pDepthAttachment->imageLayout ==
3126 info.renderingInfo.pStencilAttachment->imageLayout);
3127
3128 const VkImageLayout layout = info.renderingInfo.pDepthAttachment != nullptr
3129 ? info.renderingInfo.pDepthAttachment->imageLayout
3130 : info.renderingInfo.pStencilAttachment->imageLayout;
3131
3132 countersOut->readOnlyDepthStencilRenderPasses +=
3133 layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL ? 1 : 0;
3134 }
3135 }
3136
operator ==(const RenderPassDesc & lhs,const RenderPassDesc & rhs)3137 bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs)
3138 {
3139 return memcmp(&lhs, &rhs, sizeof(RenderPassDesc)) == 0;
3140 }
3141
3142 // Compute Pipeline Description implementation.
3143 // Use aligned allocation and free so we can use the alignas keyword.
operator new(std::size_t size)3144 void *ComputePipelineDesc::operator new(std::size_t size)
3145 {
3146 return angle::AlignedAlloc(size, 32);
3147 }
3148
operator delete(void * ptr)3149 void ComputePipelineDesc::operator delete(void *ptr)
3150 {
3151 return angle::AlignedFree(ptr);
3152 }
3153
ComputePipelineDesc()3154 ComputePipelineDesc::ComputePipelineDesc()
3155 {
3156 ASSERT(mPipelineOptions.permutationIndex == 0);
3157 ASSERT(std::all_of(mPadding, mPadding + sizeof(mPadding), [](char c) { return c == 0; }));
3158 }
3159
ComputePipelineDesc(const ComputePipelineDesc & other)3160 ComputePipelineDesc::ComputePipelineDesc(const ComputePipelineDesc &other)
3161 : mConstantIds{other.getConstantIds()},
3162 mConstants{other.getConstants()},
3163 mPipelineOptions{other.getPipelineOptions()}
3164 {}
3165
operator =(const ComputePipelineDesc & other)3166 ComputePipelineDesc &ComputePipelineDesc::operator=(const ComputePipelineDesc &other)
3167 {
3168 mPipelineOptions = other.getPipelineOptions();
3169 mConstantIds = other.getConstantIds();
3170 mConstants = other.getConstants();
3171 return *this;
3172 }
3173
ComputePipelineDesc(VkSpecializationInfo * specializationInfo,ComputePipelineOptions pipelineOptions)3174 ComputePipelineDesc::ComputePipelineDesc(VkSpecializationInfo *specializationInfo,
3175 ComputePipelineOptions pipelineOptions)
3176 : mConstantIds{}, mConstants{}, mPipelineOptions{pipelineOptions}
3177 {
3178 if (specializationInfo != nullptr && specializationInfo->pMapEntries &&
3179 specializationInfo->mapEntryCount != 0)
3180 {
3181 const VkSpecializationMapEntry *mapEntries = specializationInfo->pMapEntries;
3182 mConstantIds.resize(specializationInfo->mapEntryCount);
3183 for (size_t mapEntryCount = 0; mapEntryCount < mConstantIds.size(); mapEntryCount++)
3184 mConstantIds[mapEntryCount] = mapEntries[mapEntryCount].constantID;
3185 }
3186 if (specializationInfo != nullptr && specializationInfo->pData &&
3187 specializationInfo->dataSize != 0)
3188 {
3189 const uint32_t *constDataEntries = (const uint32_t *)specializationInfo->pData;
3190 mConstants.resize(specializationInfo->dataSize / sizeof(uint32_t));
3191 for (size_t constantEntryCount = 0; constantEntryCount < mConstants.size();
3192 constantEntryCount++)
3193 mConstants[constantEntryCount] = constDataEntries[constantEntryCount];
3194 }
3195 }
3196
hash() const3197 size_t ComputePipelineDesc::hash() const
3198 {
3199 // Union is static-asserted, just another sanity check here
3200 ASSERT(sizeof(ComputePipelineOptions) == 1);
3201
3202 size_t paddedPipelineOptions = mPipelineOptions.permutationIndex;
3203 size_t pipelineOptionsHash =
3204 angle::ComputeGenericHash(&paddedPipelineOptions, sizeof(paddedPipelineOptions));
3205
3206 size_t specializationConstantIDsHash = 0;
3207 if (!mConstantIds.empty())
3208 {
3209 specializationConstantIDsHash =
3210 angle::ComputeGenericHash(mConstantIds.data(), mConstantIds.size() * sizeof(uint32_t));
3211 }
3212
3213 size_t specializationConstantsHash = 0;
3214 if (!mConstants.empty())
3215 {
3216 specializationConstantsHash =
3217 angle::ComputeGenericHash(mConstants.data(), mConstants.size() * sizeof(uint32_t));
3218 }
3219
3220 return pipelineOptionsHash ^ specializationConstantIDsHash ^ specializationConstantsHash;
3221 }
3222
keyEqual(const ComputePipelineDesc & other) const3223 bool ComputePipelineDesc::keyEqual(const ComputePipelineDesc &other) const
3224 {
3225 return mPipelineOptions.permutationIndex == other.getPipelineOptions().permutationIndex &&
3226 mConstantIds == other.getConstantIds() && mConstants == other.getConstants();
3227 }
3228
3229 // GraphicsPipelineDesc implementation.
3230 // Use aligned allocation and free so we can use the alignas keyword.
operator new(std::size_t size)3231 void *GraphicsPipelineDesc::operator new(std::size_t size)
3232 {
3233 return angle::AlignedAlloc(size, 32);
3234 }
3235
operator delete(void * ptr)3236 void GraphicsPipelineDesc::operator delete(void *ptr)
3237 {
3238 return angle::AlignedFree(ptr);
3239 }
3240
GraphicsPipelineDesc()3241 GraphicsPipelineDesc::GraphicsPipelineDesc()
3242 {
3243 memset(this, 0, sizeof(GraphicsPipelineDesc));
3244 }
3245
3246 GraphicsPipelineDesc::~GraphicsPipelineDesc() = default;
3247
GraphicsPipelineDesc(const GraphicsPipelineDesc & other)3248 GraphicsPipelineDesc::GraphicsPipelineDesc(const GraphicsPipelineDesc &other)
3249 {
3250 *this = other;
3251 }
3252
operator =(const GraphicsPipelineDesc & other)3253 GraphicsPipelineDesc &GraphicsPipelineDesc::operator=(const GraphicsPipelineDesc &other)
3254 {
3255 memcpy(this, &other, sizeof(*this));
3256 return *this;
3257 }
3258
getPipelineSubsetMemory(GraphicsPipelineSubset subset,size_t * sizeOut) const3259 const void *GraphicsPipelineDesc::getPipelineSubsetMemory(GraphicsPipelineSubset subset,
3260 size_t *sizeOut) const
3261 {
3262 // GraphicsPipelineDesc must be laid out such that the three subsets are contiguous. The layout
3263 // is:
3264 //
3265 // Shaders State \
3266 // )--> Pre-rasterization + fragment subset
3267 // Shared Non-Vertex-Input State / \
3268 // )--> fragment output subset
3269 // Fragment Output State /
3270 //
3271 // Vertex Input State ----> Vertex input subset
3272 static_assert(offsetof(GraphicsPipelineDesc, mShaders) == kPipelineShadersDescOffset);
3273 static_assert(offsetof(GraphicsPipelineDesc, mSharedNonVertexInput) ==
3274 kPipelineShadersDescOffset + kGraphicsPipelineShadersStateSize);
3275 static_assert(offsetof(GraphicsPipelineDesc, mSharedNonVertexInput) ==
3276 kPipelineFragmentOutputDescOffset);
3277 static_assert(offsetof(GraphicsPipelineDesc, mFragmentOutput) ==
3278 kPipelineFragmentOutputDescOffset +
3279 kGraphicsPipelineSharedNonVertexInputStateSize);
3280 static_assert(offsetof(GraphicsPipelineDesc, mVertexInput) == kPipelineVertexInputDescOffset);
3281
3282 // Exclude the full vertex or only vertex strides from the hash. It's conveniently placed last,
3283 // so it would be easy to exclude it from hash.
3284 static_assert(offsetof(GraphicsPipelineDesc, mVertexInput.vertex.strides) +
3285 sizeof(PackedVertexInputAttributes::strides) ==
3286 sizeof(GraphicsPipelineDesc));
3287 static_assert(offsetof(GraphicsPipelineDesc, mVertexInput.vertex) +
3288 sizeof(PackedVertexInputAttributes) ==
3289 sizeof(GraphicsPipelineDesc));
3290
3291 size_t vertexInputReduceSize = 0;
3292 if (mVertexInput.inputAssembly.bits.useVertexInputBindingStrideDynamicState)
3293 {
3294 vertexInputReduceSize = sizeof(PackedVertexInputAttributes::strides);
3295 }
3296 else if (mVertexInput.inputAssembly.bits.useVertexInputDynamicState)
3297 {
3298 vertexInputReduceSize = sizeof(PackedVertexInputAttributes);
3299 }
3300
3301 switch (subset)
3302 {
3303 case GraphicsPipelineSubset::Shaders:
3304 *sizeOut = kPipelineShadersDescSize;
3305 return &mShaders;
3306
3307 case GraphicsPipelineSubset::Complete:
3308 default:
3309 *sizeOut = sizeof(*this) - vertexInputReduceSize;
3310 return this;
3311 }
3312 }
3313
hash(GraphicsPipelineSubset subset) const3314 size_t GraphicsPipelineDesc::hash(GraphicsPipelineSubset subset) const
3315 {
3316 size_t keySize = 0;
3317 const void *key = getPipelineSubsetMemory(subset, &keySize);
3318
3319 return angle::ComputeGenericHash(key, keySize);
3320 }
3321
keyEqual(const GraphicsPipelineDesc & other,GraphicsPipelineSubset subset) const3322 bool GraphicsPipelineDesc::keyEqual(const GraphicsPipelineDesc &other,
3323 GraphicsPipelineSubset subset) const
3324 {
3325 size_t keySize = 0;
3326 const void *key = getPipelineSubsetMemory(subset, &keySize);
3327
3328 size_t otherKeySize = 0;
3329 const void *otherKey = other.getPipelineSubsetMemory(subset, &otherKeySize);
3330
3331 // Compare the relevant part of the desc memory. Note that due to workarounds (e.g.
3332 // useVertexInputBindingStrideDynamicState), |this| or |other| may produce different key sizes.
3333 // In that case, comparing the minimum of the two is sufficient; if the workarounds are
3334 // different, the comparison would fail anyway.
3335 return memcmp(key, otherKey, std::min(keySize, otherKeySize)) == 0;
3336 }
3337
3338 // Initialize PSO states, it is consistent with initial value of gl::State.
3339 //
3340 // Some states affect the pipeline, but they are not derived from the GL state, but rather the
3341 // properties of the Vulkan device or the context itself; such as whether a workaround is in
3342 // effect, or the context is robust. For VK_EXT_graphics_pipeline_library, such state that affects
3343 // multiple subsets of the pipeline is duplicated in each subset (for example, there are two
3344 // copies of isRobustContext, one for vertex input and one for shader stages).
initDefaults(const ErrorContext * context,GraphicsPipelineSubset subset,PipelineRobustness pipelineRobustness,PipelineProtectedAccess pipelineProtectedAccess)3345 void GraphicsPipelineDesc::initDefaults(const ErrorContext *context,
3346 GraphicsPipelineSubset subset,
3347 PipelineRobustness pipelineRobustness,
3348 PipelineProtectedAccess pipelineProtectedAccess)
3349 {
3350 if (GraphicsPipelineHasVertexInput(subset))
3351 {
3352 // Set all vertex input attributes to default, the default format is Float
3353 angle::FormatID defaultFormat = GetCurrentValueFormatID(gl::VertexAttribType::Float);
3354 for (PackedAttribDesc &packedAttrib : mVertexInput.vertex.attribs)
3355 {
3356 SetBitField(packedAttrib.divisor, 0);
3357 SetBitField(packedAttrib.format, defaultFormat);
3358 SetBitField(packedAttrib.compressed, 0);
3359 SetBitField(packedAttrib.offset, 0);
3360 }
3361 mVertexInput.vertex.shaderAttribComponentType = 0;
3362 memset(mVertexInput.vertex.strides, 0, sizeof(mVertexInput.vertex.strides));
3363
3364 SetBitField(mVertexInput.inputAssembly.bits.topology, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
3365 mVertexInput.inputAssembly.bits.primitiveRestartEnable = 0;
3366 mVertexInput.inputAssembly.bits.useVertexInputBindingStrideDynamicState =
3367 context->getFeatures().useVertexInputBindingStrideDynamicState.enabled;
3368 mVertexInput.inputAssembly.bits.useVertexInputDynamicState =
3369 context->getFeatures().supportsVertexInputDynamicState.enabled;
3370 mVertexInput.inputAssembly.bits.padding = 0;
3371 }
3372
3373 if (GraphicsPipelineHasShaders(subset))
3374 {
3375 mShaders.shaders.bits.viewportNegativeOneToOne =
3376 context->getFeatures().supportsDepthClipControl.enabled;
3377 mShaders.shaders.bits.depthClampEnable = 0;
3378 SetBitField(mShaders.shaders.bits.polygonMode, VK_POLYGON_MODE_FILL);
3379 SetBitField(mShaders.shaders.bits.cullMode, VK_CULL_MODE_NONE);
3380 SetBitField(mShaders.shaders.bits.frontFace, VK_FRONT_FACE_COUNTER_CLOCKWISE);
3381 mShaders.shaders.bits.rasterizerDiscardEnable = 0;
3382 mShaders.shaders.bits.depthBiasEnable = 0;
3383 SetBitField(mShaders.shaders.bits.patchVertices, 3);
3384 mShaders.shaders.bits.depthBoundsTest = 0;
3385 mShaders.shaders.bits.depthTest = 0;
3386 mShaders.shaders.bits.depthWrite = 0;
3387 mShaders.shaders.bits.stencilTest = 0;
3388 mShaders.shaders.bits.nonZeroStencilWriteMaskWorkaround = 0;
3389 SetBitField(mShaders.shaders.bits.depthCompareOp, VK_COMPARE_OP_LESS);
3390 mShaders.shaders.bits.surfaceRotation = 0;
3391 mShaders.shaders.emulatedDitherControl = 0;
3392 mShaders.shaders.padding = 0;
3393 SetBitField(mShaders.shaders.front.fail, VK_STENCIL_OP_KEEP);
3394 SetBitField(mShaders.shaders.front.pass, VK_STENCIL_OP_KEEP);
3395 SetBitField(mShaders.shaders.front.depthFail, VK_STENCIL_OP_KEEP);
3396 SetBitField(mShaders.shaders.front.compare, VK_COMPARE_OP_ALWAYS);
3397 SetBitField(mShaders.shaders.back.fail, VK_STENCIL_OP_KEEP);
3398 SetBitField(mShaders.shaders.back.pass, VK_STENCIL_OP_KEEP);
3399 SetBitField(mShaders.shaders.back.depthFail, VK_STENCIL_OP_KEEP);
3400 SetBitField(mShaders.shaders.back.compare, VK_COMPARE_OP_ALWAYS);
3401 }
3402
3403 if (GraphicsPipelineHasShadersOrFragmentOutput(subset))
3404 {
3405 mSharedNonVertexInput.multisample.bits.sampleMask = std::numeric_limits<uint16_t>::max();
3406 mSharedNonVertexInput.multisample.bits.rasterizationSamplesMinusOne = 0;
3407 mSharedNonVertexInput.multisample.bits.sampleShadingEnable = 0;
3408 mSharedNonVertexInput.multisample.bits.alphaToCoverageEnable = 0;
3409 mSharedNonVertexInput.multisample.bits.alphaToOneEnable = 0;
3410 mSharedNonVertexInput.multisample.bits.subpass = 0;
3411 mSharedNonVertexInput.multisample.bits.minSampleShading = kMinSampleShadingScale;
3412 }
3413
3414 if (GraphicsPipelineHasFragmentOutput(subset))
3415 {
3416 constexpr VkFlags kAllColorBits = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
3417 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
3418
3419 for (uint32_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
3420 ++colorIndexGL)
3421 {
3422 Int4Array_Set(mFragmentOutput.blend.colorWriteMaskBits, colorIndexGL, kAllColorBits);
3423 }
3424
3425 PackedColorBlendAttachmentState blendAttachmentState;
3426 SetBitField(blendAttachmentState.srcColorBlendFactor, VK_BLEND_FACTOR_ONE);
3427 SetBitField(blendAttachmentState.dstColorBlendFactor, VK_BLEND_FACTOR_ZERO);
3428 SetBitField(blendAttachmentState.colorBlendOp, VK_BLEND_OP_ADD);
3429 SetBitField(blendAttachmentState.srcAlphaBlendFactor, VK_BLEND_FACTOR_ONE);
3430 SetBitField(blendAttachmentState.dstAlphaBlendFactor, VK_BLEND_FACTOR_ZERO);
3431 SetBitField(blendAttachmentState.alphaBlendOp, VK_BLEND_OP_ADD);
3432
3433 std::fill(&mFragmentOutput.blend.attachments[0],
3434 &mFragmentOutput.blend.attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS],
3435 blendAttachmentState);
3436
3437 mFragmentOutput.blendMaskAndLogic.bits.blendEnableMask = 0;
3438 mFragmentOutput.blendMaskAndLogic.bits.logicOpEnable = 0;
3439 SetBitField(mFragmentOutput.blendMaskAndLogic.bits.logicOp, VK_LOGIC_OP_COPY);
3440 mFragmentOutput.blendMaskAndLogic.bits.padding = 0;
3441 }
3442
3443 // Context robustness affects vertex input and shader stages.
3444 mVertexInput.inputAssembly.bits.isRobustContext = mShaders.shaders.bits.isRobustContext =
3445 pipelineRobustness == PipelineRobustness::Robust;
3446
3447 // Context protected-ness affects all subsets.
3448 mVertexInput.inputAssembly.bits.isProtectedContext = mShaders.shaders.bits.isProtectedContext =
3449 mFragmentOutput.blendMaskAndLogic.bits.isProtectedContext =
3450 pipelineProtectedAccess == PipelineProtectedAccess::Protected;
3451 }
3452
initializePipeline(ErrorContext * context,PipelineCacheAccess * pipelineCache,GraphicsPipelineSubset subset,const RenderPass & compatibleRenderPass,const PipelineLayout & pipelineLayout,const GraphicsPipelineShadersInfo & shaders,Pipeline * pipelineOut,CacheLookUpFeedback * feedbackOut) const3453 VkResult GraphicsPipelineDesc::initializePipeline(ErrorContext *context,
3454 PipelineCacheAccess *pipelineCache,
3455 GraphicsPipelineSubset subset,
3456 const RenderPass &compatibleRenderPass,
3457 const PipelineLayout &pipelineLayout,
3458 const GraphicsPipelineShadersInfo &shaders,
3459 Pipeline *pipelineOut,
3460 CacheLookUpFeedback *feedbackOut) const
3461 {
3462 GraphicsPipelineVertexInputVulkanStructs vertexInputState;
3463 GraphicsPipelineShadersVulkanStructs shadersState;
3464 GraphicsPipelineSharedNonVertexInputVulkanStructs sharedNonVertexInputState;
3465 GraphicsPipelineFragmentOutputVulkanStructs fragmentOutputState;
3466 GraphicsPipelineDynamicStateList dynamicStateList;
3467
3468 // With dynamic rendering, there are no render pass objects.
3469 ASSERT(!compatibleRenderPass.valid() || !context->getFeatures().preferDynamicRendering.enabled);
3470
3471 VkGraphicsPipelineCreateInfo createInfo = {};
3472 createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
3473 createInfo.flags = 0;
3474 createInfo.renderPass = compatibleRenderPass.getHandle();
3475 createInfo.subpass = mSharedNonVertexInput.multisample.bits.subpass;
3476
3477 const bool hasVertexInput = GraphicsPipelineHasVertexInput(subset);
3478 const bool hasShaders = GraphicsPipelineHasShaders(subset);
3479 const bool hasShadersOrFragmentOutput = GraphicsPipelineHasShadersOrFragmentOutput(subset);
3480 const bool hasFragmentOutput = GraphicsPipelineHasFragmentOutput(subset);
3481
3482 if (hasVertexInput)
3483 {
3484 initializePipelineVertexInputState(context, &vertexInputState, &dynamicStateList);
3485
3486 createInfo.pVertexInputState = &vertexInputState.vertexInputState;
3487 createInfo.pInputAssemblyState = &vertexInputState.inputAssemblyState;
3488 }
3489
3490 VkPipeline shadersPipeline = VK_NULL_HANDLE;
3491 VkPipelineLibraryCreateInfoKHR shadersLibraryInfo = {};
3492 shadersLibraryInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR;
3493
3494 if (hasShaders)
3495 {
3496 // If the shaders state comes from a library, use the library instead.
3497 if (shaders.usePipelineLibrary())
3498 {
3499 shadersPipeline = shaders.mPipelineLibrary->getPipeline().getHandle();
3500
3501 shadersLibraryInfo.libraryCount = 1;
3502 shadersLibraryInfo.pLibraries = &shadersPipeline;
3503
3504 AddToPNextChain(&createInfo, &shadersLibraryInfo);
3505 }
3506 else
3507 {
3508 initializePipelineShadersState(context, *shaders.mShaders, *shaders.mSpecConsts,
3509 &shadersState, &dynamicStateList);
3510
3511 createInfo.stageCount = static_cast<uint32_t>(shadersState.shaderStages.size());
3512 createInfo.pStages = shadersState.shaderStages.data();
3513 createInfo.pTessellationState = &shadersState.tessellationState;
3514 createInfo.pViewportState = &shadersState.viewportState;
3515 createInfo.pRasterizationState = &shadersState.rasterState;
3516 createInfo.pDepthStencilState = &shadersState.depthStencilState;
3517 }
3518
3519 createInfo.layout = pipelineLayout.getHandle();
3520 }
3521
3522 if (hasShadersOrFragmentOutput)
3523 {
3524 initializePipelineSharedNonVertexInputState(context, &sharedNonVertexInputState,
3525 &dynamicStateList);
3526
3527 createInfo.pMultisampleState = &sharedNonVertexInputState.multisampleState;
3528 }
3529
3530 if (hasFragmentOutput)
3531 {
3532 initializePipelineFragmentOutputState(context, &fragmentOutputState, &dynamicStateList);
3533
3534 createInfo.pColorBlendState = &fragmentOutputState.blendState;
3535 }
3536
3537 VkPipelineDynamicStateCreateInfo dynamicState = {};
3538 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
3539 dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStateList.size());
3540 dynamicState.pDynamicStates = dynamicStateList.data();
3541 createInfo.pDynamicState = dynamicStateList.empty() ? nullptr : &dynamicState;
3542
3543 // If not a complete pipeline, specify which subset is being created
3544 VkGraphicsPipelineLibraryCreateInfoEXT libraryInfo = {};
3545 libraryInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT;
3546
3547 if (subset == GraphicsPipelineSubset::Shaders)
3548 {
3549 libraryInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
3550 VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
3551
3552 createInfo.flags |= VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
3553
3554 AddToPNextChain(&createInfo, &libraryInfo);
3555 }
3556 else if (hasShaders && shaders.usePipelineLibrary())
3557 {
3558 libraryInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT |
3559 VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT;
3560
3561 AddToPNextChain(&createInfo, &libraryInfo);
3562 }
3563
3564 VkPipelineRobustnessCreateInfoEXT robustness = {};
3565 robustness.sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT;
3566
3567 // Enable robustness on the pipeline if needed. Note that the global robustBufferAccess feature
3568 // must be disabled by default.
3569 if ((hasVertexInput && mVertexInput.inputAssembly.bits.isRobustContext) ||
3570 (hasShaders && mShaders.shaders.bits.isRobustContext))
3571 {
3572 ASSERT(context->getFeatures().supportsPipelineRobustness.enabled);
3573
3574 robustness.storageBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
3575 robustness.uniformBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
3576 robustness.vertexInputs = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
3577 robustness.images = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT;
3578
3579 AddToPNextChain(&createInfo, &robustness);
3580 }
3581
3582 if ((hasVertexInput && mVertexInput.inputAssembly.bits.isProtectedContext) ||
3583 (hasShaders && mShaders.shaders.bits.isProtectedContext) ||
3584 (hasFragmentOutput && mFragmentOutput.blendMaskAndLogic.bits.isProtectedContext))
3585 {
3586 ASSERT(context->getFeatures().supportsPipelineProtectedAccess.enabled);
3587 createInfo.flags |= VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT;
3588 }
3589 else if (context->getFeatures().supportsPipelineProtectedAccess.enabled)
3590 {
3591 createInfo.flags |= VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT;
3592 }
3593
3594 VkPipelineCreationFeedback feedback = {};
3595 gl::ShaderMap<VkPipelineCreationFeedback> perStageFeedback;
3596
3597 VkPipelineCreationFeedbackCreateInfo feedbackInfo = {};
3598 feedbackInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO;
3599
3600 const bool supportsFeedback = context->getFeatures().supportsPipelineCreationFeedback.enabled;
3601 if (supportsFeedback)
3602 {
3603 feedbackInfo.pPipelineCreationFeedback = &feedback;
3604 // Provide some storage for per-stage data, even though it's not used. This first works
3605 // around a VVL bug that doesn't allow `pipelineStageCreationFeedbackCount=0` despite the
3606 // spec (See https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/4161). Even
3607 // with fixed VVL, several drivers crash when this storage is missing too.
3608 feedbackInfo.pipelineStageCreationFeedbackCount = createInfo.stageCount;
3609 feedbackInfo.pPipelineStageCreationFeedbacks = perStageFeedback.data();
3610
3611 AddToPNextChain(&createInfo, &feedbackInfo);
3612 }
3613
3614 // Attach dynamic rendering info if needed. This is done last because the flags may need to
3615 // be transfered to |VkPipelineCreateFlags2CreateInfoKHR|, so it must be done after every
3616 // other flag is set.
3617 DynamicRenderingInfo renderingInfo;
3618 VkPipelineRenderingCreateInfoKHR pipelineRenderingInfo;
3619 VkRenderingAttachmentLocationInfoKHR attachmentLocations;
3620 VkRenderingInputAttachmentIndexInfoKHR inputLocations;
3621 VkPipelineCreateFlags2CreateInfoKHR createFlags2;
3622 if (hasShadersOrFragmentOutput && context->getFeatures().preferDynamicRendering.enabled)
3623 {
3624 DeriveRenderingInfo(context->getRenderer(), getRenderPassDesc(),
3625 DynamicRenderingInfoSubset::Pipeline, {}, VK_SUBPASS_CONTENTS_INLINE,
3626 {}, {}, {}, 0, &renderingInfo);
3627 AttachPipelineRenderingInfo(context, getRenderPassDesc(), renderingInfo, subset,
3628 shaders.usePipelineLibrary()
3629 ? ShadersStateSource::PipelineLibrary
3630 : ShadersStateSource::ThisPipeline,
3631 &pipelineRenderingInfo, &attachmentLocations, &inputLocations,
3632 &createFlags2, &createInfo);
3633 }
3634
3635 VkResult result = pipelineCache->createGraphicsPipeline(context, createInfo, pipelineOut);
3636
3637 if (supportsFeedback)
3638 {
3639 const bool cacheHit =
3640 (feedback.flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT) !=
3641 0;
3642
3643 *feedbackOut = cacheHit ? CacheLookUpFeedback::Hit : CacheLookUpFeedback::Miss;
3644 ApplyPipelineCreationFeedback(context, feedback);
3645 }
3646
3647 return result;
3648 }
3649
patchVertexAttribComponentType(angle::FormatID format,gl::ComponentType vsInputType)3650 angle::FormatID patchVertexAttribComponentType(angle::FormatID format,
3651 gl::ComponentType vsInputType)
3652 {
3653 const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromID(format);
3654 // For normalized format, keep the same ?
3655 EGLBoolean normalized = vertexFormat.normalized;
3656 if (normalized)
3657 {
3658 return format;
3659 }
3660 gl::VertexAttribType attribType = gl::FromGLenum<gl::VertexAttribType>(vertexFormat.type);
3661 if (vsInputType != gl::ComponentType::Float)
3662 {
3663 ASSERT(vsInputType == gl::ComponentType::Int ||
3664 vsInputType == gl::ComponentType::UnsignedInt);
3665 switch (attribType)
3666 {
3667 case gl::VertexAttribType::Float:
3668 case gl::VertexAttribType::Fixed:
3669 case gl::VertexAttribType::UnsignedInt:
3670 case gl::VertexAttribType::Int:
3671 attribType = vsInputType == gl::ComponentType::Int
3672 ? gl::VertexAttribType::Int
3673 : gl::VertexAttribType::UnsignedInt;
3674 break;
3675 case gl::VertexAttribType::HalfFloat:
3676 case gl::VertexAttribType::HalfFloatOES:
3677 case gl::VertexAttribType::Short:
3678 case gl::VertexAttribType::UnsignedShort:
3679 attribType = vsInputType == gl::ComponentType::Int
3680 ? gl::VertexAttribType::Short
3681 : gl::VertexAttribType::UnsignedShort;
3682 break;
3683 case gl::VertexAttribType::Byte:
3684 case gl::VertexAttribType::UnsignedByte:
3685 attribType = vsInputType == gl::ComponentType::Int
3686 ? gl::VertexAttribType::Byte
3687 : gl::VertexAttribType::UnsignedByte;
3688 break;
3689 case gl::VertexAttribType::UnsignedInt2101010:
3690 case gl::VertexAttribType::Int2101010:
3691 attribType = vsInputType == gl::ComponentType::Int
3692 ? gl::VertexAttribType::Int2101010
3693 : gl::VertexAttribType::UnsignedInt2101010;
3694 break;
3695 case gl::VertexAttribType::UnsignedInt1010102:
3696 case gl::VertexAttribType::Int1010102:
3697 attribType = vsInputType == gl::ComponentType::Int
3698 ? gl::VertexAttribType::Int1010102
3699 : gl::VertexAttribType::UnsignedInt1010102;
3700 break;
3701 default:
3702 ASSERT(0);
3703 break;
3704 }
3705 }
3706 return gl::GetVertexFormatID(attribType, vertexFormat.normalized, vertexFormat.components,
3707 !vertexFormat.pureInteger);
3708 }
3709
getPipelineVertexInputStateFormat(ErrorContext * context,angle::FormatID formatID,bool compressed,const gl::ComponentType programAttribType,uint32_t attribIndex)3710 VkFormat GraphicsPipelineDesc::getPipelineVertexInputStateFormat(
3711 ErrorContext *context,
3712 angle::FormatID formatID,
3713 bool compressed,
3714 const gl::ComponentType programAttribType,
3715 uint32_t attribIndex)
3716 {
3717 vk::Renderer *renderer = context->getRenderer();
3718 // Get the corresponding VkFormat for the attrib's format.
3719 const Format &format = renderer->getFormat(formatID);
3720 const angle::Format &intendedFormat = format.getIntendedFormat();
3721 VkFormat vkFormat = format.getActualBufferVkFormat(renderer, compressed);
3722
3723 const gl::ComponentType attribType = GetVertexAttributeComponentType(
3724 intendedFormat.isPureInt(), intendedFormat.vertexAttribType);
3725
3726 if (attribType != programAttribType)
3727 {
3728 VkFormat origVkFormat = vkFormat;
3729 if (attribType == gl::ComponentType::Float || programAttribType == gl::ComponentType::Float)
3730 {
3731 angle::FormatID patchFormatID =
3732 patchVertexAttribComponentType(formatID, programAttribType);
3733 vkFormat =
3734 renderer->getFormat(patchFormatID).getActualBufferVkFormat(renderer, compressed);
3735 }
3736 else
3737 {
3738 // When converting from an unsigned to a signed format or vice versa, attempt to
3739 // match the bit width.
3740 angle::FormatID convertedFormatID = gl::ConvertFormatSignedness(intendedFormat);
3741 const Format &convertedFormat = renderer->getFormat(convertedFormatID);
3742 ASSERT(intendedFormat.channelCount == convertedFormat.getIntendedFormat().channelCount);
3743 ASSERT(intendedFormat.redBits == convertedFormat.getIntendedFormat().redBits);
3744 ASSERT(intendedFormat.greenBits == convertedFormat.getIntendedFormat().greenBits);
3745 ASSERT(intendedFormat.blueBits == convertedFormat.getIntendedFormat().blueBits);
3746 ASSERT(intendedFormat.alphaBits == convertedFormat.getIntendedFormat().alphaBits);
3747
3748 vkFormat = convertedFormat.getActualBufferVkFormat(renderer, compressed);
3749 }
3750 const Format &origFormat = renderer->getFormat(GetFormatIDFromVkFormat(origVkFormat));
3751 const Format &patchFormat = renderer->getFormat(GetFormatIDFromVkFormat(vkFormat));
3752 ASSERT(origFormat.getIntendedFormat().pixelBytes ==
3753 patchFormat.getIntendedFormat().pixelBytes);
3754 ASSERT(renderer->getNativeExtensions().relaxedVertexAttributeTypeANGLE);
3755 }
3756
3757 return vkFormat;
3758 }
3759
initializePipelineVertexInputState(ErrorContext * context,GraphicsPipelineVertexInputVulkanStructs * stateOut,GraphicsPipelineDynamicStateList * dynamicStateListOut) const3760 void GraphicsPipelineDesc::initializePipelineVertexInputState(
3761 ErrorContext *context,
3762 GraphicsPipelineVertexInputVulkanStructs *stateOut,
3763 GraphicsPipelineDynamicStateList *dynamicStateListOut) const
3764 {
3765 // TODO(jmadill): Possibly use different path for ES 3.1 split bindings/attribs.
3766 uint32_t vertexAttribCount = 0;
3767
3768 stateOut->divisorState.sType =
3769 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
3770 stateOut->divisorState.pVertexBindingDivisors = stateOut->divisorDesc.data();
3771 for (size_t attribIndexSizeT :
3772 gl::AttributesMask(mVertexInput.inputAssembly.bits.programActiveAttributeLocations))
3773 {
3774 const uint32_t attribIndex = static_cast<uint32_t>(attribIndexSizeT);
3775
3776 VkVertexInputBindingDescription &bindingDesc = stateOut->bindingDescs[vertexAttribCount];
3777 VkVertexInputAttributeDescription &attribDesc = stateOut->attributeDescs[vertexAttribCount];
3778 const PackedAttribDesc &packedAttrib = mVertexInput.vertex.attribs[attribIndex];
3779
3780 bindingDesc.binding = attribIndex;
3781 bindingDesc.stride = static_cast<uint32_t>(mVertexInput.vertex.strides[attribIndex]);
3782 if (packedAttrib.divisor != 0)
3783 {
3784 bindingDesc.inputRate = static_cast<VkVertexInputRate>(VK_VERTEX_INPUT_RATE_INSTANCE);
3785 stateOut->divisorDesc[stateOut->divisorState.vertexBindingDivisorCount].binding =
3786 bindingDesc.binding;
3787 stateOut->divisorDesc[stateOut->divisorState.vertexBindingDivisorCount].divisor =
3788 packedAttrib.divisor;
3789 ++stateOut->divisorState.vertexBindingDivisorCount;
3790 }
3791 else
3792 {
3793 bindingDesc.inputRate = static_cast<VkVertexInputRate>(VK_VERTEX_INPUT_RATE_VERTEX);
3794 }
3795
3796 // If using dynamic state for stride, the value for stride is unconditionally 0 here.
3797 // |ContextVk::handleDirtyGraphicsVertexBuffers| implements the same fix when setting stride
3798 // dynamically.
3799 ASSERT(!context->getFeatures().useVertexInputBindingStrideDynamicState.enabled ||
3800 bindingDesc.stride == 0);
3801
3802 // Get the corresponding VkFormat for the attrib's format.
3803 angle::FormatID formatID = static_cast<angle::FormatID>(packedAttrib.format);
3804 const gl::ComponentType programAttribType = gl::GetComponentTypeMask(
3805 gl::ComponentTypeMask(mVertexInput.vertex.shaderAttribComponentType), attribIndex);
3806
3807 attribDesc.binding = attribIndex;
3808 attribDesc.format = getPipelineVertexInputStateFormat(
3809 context, formatID, packedAttrib.compressed, programAttribType, attribIndex);
3810 attribDesc.location = static_cast<uint32_t>(attribIndex);
3811 attribDesc.offset = packedAttrib.offset;
3812
3813 vertexAttribCount++;
3814 }
3815
3816 // The binding descriptions are filled in at draw time.
3817 stateOut->vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
3818 stateOut->vertexInputState.flags = 0;
3819 stateOut->vertexInputState.vertexBindingDescriptionCount = vertexAttribCount;
3820 stateOut->vertexInputState.pVertexBindingDescriptions = stateOut->bindingDescs.data();
3821 stateOut->vertexInputState.vertexAttributeDescriptionCount = vertexAttribCount;
3822 stateOut->vertexInputState.pVertexAttributeDescriptions = stateOut->attributeDescs.data();
3823 if (stateOut->divisorState.vertexBindingDivisorCount)
3824 {
3825 stateOut->vertexInputState.pNext = &stateOut->divisorState;
3826 }
3827
3828 const PackedInputAssemblyState &inputAssembly = mVertexInput.inputAssembly;
3829
3830 // Primitive topology is filled in at draw time.
3831 stateOut->inputAssemblyState.sType =
3832 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
3833 stateOut->inputAssemblyState.flags = 0;
3834 stateOut->inputAssemblyState.topology =
3835 static_cast<VkPrimitiveTopology>(inputAssembly.bits.topology);
3836 stateOut->inputAssemblyState.primitiveRestartEnable =
3837 static_cast<VkBool32>(inputAssembly.bits.primitiveRestartEnable);
3838
3839 // Dynamic state
3840 if (context->getFeatures().useVertexInputBindingStrideDynamicState.enabled &&
3841 vertexAttribCount > 0)
3842 {
3843 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE);
3844 }
3845 if (context->getFeatures().usePrimitiveRestartEnableDynamicState.enabled)
3846 {
3847 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE);
3848 }
3849 if (context->getFeatures().supportsVertexInputDynamicState.enabled)
3850 {
3851 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
3852 }
3853 }
3854
initializePipelineShadersState(ErrorContext * context,const ShaderModuleMap & shaders,const SpecializationConstants & specConsts,GraphicsPipelineShadersVulkanStructs * stateOut,GraphicsPipelineDynamicStateList * dynamicStateListOut) const3855 void GraphicsPipelineDesc::initializePipelineShadersState(
3856 ErrorContext *context,
3857 const ShaderModuleMap &shaders,
3858 const SpecializationConstants &specConsts,
3859 GraphicsPipelineShadersVulkanStructs *stateOut,
3860 GraphicsPipelineDynamicStateList *dynamicStateListOut) const
3861 {
3862 InitializeSpecializationInfo(specConsts, &stateOut->specializationEntries,
3863 &stateOut->specializationInfo);
3864
3865 // Vertex shader is always expected to be present.
3866 const ShaderModule &vertexModule = *shaders[gl::ShaderType::Vertex];
3867 ASSERT(vertexModule.valid());
3868 VkPipelineShaderStageCreateInfo vertexStage = {};
3869 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3870 VK_SHADER_STAGE_VERTEX_BIT, vertexModule.getHandle(),
3871 stateOut->specializationInfo, &vertexStage);
3872 stateOut->shaderStages.push_back(vertexStage);
3873
3874 const ShaderModulePtr &tessControlPointer = shaders[gl::ShaderType::TessControl];
3875 if (tessControlPointer)
3876 {
3877 const ShaderModule &tessControlModule = *tessControlPointer;
3878 VkPipelineShaderStageCreateInfo tessControlStage = {};
3879 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3880 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
3881 tessControlModule.getHandle(), stateOut->specializationInfo,
3882 &tessControlStage);
3883 stateOut->shaderStages.push_back(tessControlStage);
3884 }
3885
3886 const ShaderModulePtr &tessEvaluationPointer = shaders[gl::ShaderType::TessEvaluation];
3887 if (tessEvaluationPointer)
3888 {
3889 const ShaderModule &tessEvaluationModule = *tessEvaluationPointer;
3890 VkPipelineShaderStageCreateInfo tessEvaluationStage = {};
3891 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3892 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
3893 tessEvaluationModule.getHandle(), stateOut->specializationInfo,
3894 &tessEvaluationStage);
3895 stateOut->shaderStages.push_back(tessEvaluationStage);
3896 }
3897
3898 const ShaderModulePtr &geometryPointer = shaders[gl::ShaderType::Geometry];
3899 if (geometryPointer)
3900 {
3901 const ShaderModule &geometryModule = *geometryPointer;
3902 VkPipelineShaderStageCreateInfo geometryStage = {};
3903 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3904 VK_SHADER_STAGE_GEOMETRY_BIT, geometryModule.getHandle(),
3905 stateOut->specializationInfo, &geometryStage);
3906 stateOut->shaderStages.push_back(geometryStage);
3907 }
3908
3909 // Fragment shader is optional.
3910 const ShaderModulePtr &fragmentPointer = shaders[gl::ShaderType::Fragment];
3911 if (fragmentPointer && !mShaders.shaders.bits.rasterizerDiscardEnable)
3912 {
3913 const ShaderModule &fragmentModule = *fragmentPointer;
3914 VkPipelineShaderStageCreateInfo fragmentStage = {};
3915 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3916 VK_SHADER_STAGE_FRAGMENT_BIT, fragmentModule.getHandle(),
3917 stateOut->specializationInfo, &fragmentStage);
3918 stateOut->shaderStages.push_back(fragmentStage);
3919 }
3920
3921 // Set initial viewport and scissor state.
3922 stateOut->viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
3923 stateOut->viewportState.flags = 0;
3924 stateOut->viewportState.viewportCount = 1;
3925 stateOut->viewportState.pViewports = nullptr;
3926 stateOut->viewportState.scissorCount = 1;
3927 stateOut->viewportState.pScissors = nullptr;
3928
3929 if (context->getFeatures().supportsDepthClipControl.enabled)
3930 {
3931 stateOut->depthClipControl.sType =
3932 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT;
3933 stateOut->depthClipControl.negativeOneToOne =
3934 static_cast<VkBool32>(mShaders.shaders.bits.viewportNegativeOneToOne);
3935
3936 stateOut->viewportState.pNext = &stateOut->depthClipControl;
3937 }
3938
3939 // Rasterizer state.
3940 stateOut->rasterState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
3941 stateOut->rasterState.flags = 0;
3942 stateOut->rasterState.depthClampEnable =
3943 static_cast<VkBool32>(mShaders.shaders.bits.depthClampEnable);
3944 stateOut->rasterState.rasterizerDiscardEnable =
3945 static_cast<VkBool32>(mShaders.shaders.bits.rasterizerDiscardEnable);
3946 stateOut->rasterState.polygonMode =
3947 static_cast<VkPolygonMode>(mShaders.shaders.bits.polygonMode);
3948 stateOut->rasterState.cullMode = static_cast<VkCullModeFlags>(mShaders.shaders.bits.cullMode);
3949 stateOut->rasterState.frontFace = static_cast<VkFrontFace>(mShaders.shaders.bits.frontFace);
3950 stateOut->rasterState.depthBiasEnable =
3951 static_cast<VkBool32>(mShaders.shaders.bits.depthBiasEnable);
3952 stateOut->rasterState.lineWidth = 0;
3953 const void **pNextPtr = &stateOut->rasterState.pNext;
3954
3955 const PackedMultisampleAndSubpassState &multisample = mSharedNonVertexInput.multisample;
3956
3957 stateOut->rasterLineState.sType =
3958 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
3959 // Enable Bresenham line rasterization if available and the following conditions are met:
3960 // 1.) not multisampling
3961 // 2.) VUID-VkGraphicsPipelineCreateInfo-lineRasterizationMode-02766:
3962 // The Vulkan spec states: If the lineRasterizationMode member of a
3963 // VkPipelineRasterizationLineStateCreateInfoEXT structure included in the pNext chain of
3964 // pRasterizationState is VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT or
3965 // VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT and if rasterization is enabled, then the
3966 // alphaToCoverageEnable, alphaToOneEnable, and sampleShadingEnable members of pMultisampleState
3967 // must all be VK_FALSE.
3968 if (multisample.bits.rasterizationSamplesMinusOne == 0 &&
3969 !mShaders.shaders.bits.rasterizerDiscardEnable && !multisample.bits.alphaToCoverageEnable &&
3970 !multisample.bits.alphaToOneEnable && !multisample.bits.sampleShadingEnable &&
3971 context->getFeatures().bresenhamLineRasterization.enabled)
3972 {
3973 stateOut->rasterLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
3974 *pNextPtr = &stateOut->rasterLineState;
3975 pNextPtr = &stateOut->rasterLineState.pNext;
3976 }
3977
3978 // Always set provoking vertex mode to last if available.
3979 if (context->getFeatures().provokingVertex.enabled)
3980 {
3981 stateOut->provokingVertexState.sType =
3982 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT;
3983 stateOut->provokingVertexState.provokingVertexMode =
3984 VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
3985 *pNextPtr = &stateOut->provokingVertexState;
3986 pNextPtr = &stateOut->provokingVertexState.pNext;
3987 }
3988
3989 if (context->getFeatures().supportsGeometryStreamsCapability.enabled)
3990 {
3991 stateOut->rasterStreamState.sType =
3992 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT;
3993 stateOut->rasterStreamState.rasterizationStream = 0;
3994 *pNextPtr = &stateOut->rasterStreamState;
3995 pNextPtr = &stateOut->rasterStreamState.pNext;
3996 }
3997
3998 // Depth/stencil state.
3999 stateOut->depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
4000 stateOut->depthStencilState.flags = 0;
4001 stateOut->depthStencilState.depthTestEnable =
4002 static_cast<VkBool32>(mShaders.shaders.bits.depthTest);
4003 stateOut->depthStencilState.depthWriteEnable =
4004 static_cast<VkBool32>(mShaders.shaders.bits.depthWrite);
4005 stateOut->depthStencilState.depthCompareOp =
4006 static_cast<VkCompareOp>(mShaders.shaders.bits.depthCompareOp);
4007 stateOut->depthStencilState.depthBoundsTestEnable =
4008 static_cast<VkBool32>(mShaders.shaders.bits.depthBoundsTest);
4009 stateOut->depthStencilState.stencilTestEnable =
4010 static_cast<VkBool32>(mShaders.shaders.bits.stencilTest);
4011 UnpackStencilState(mShaders.shaders.front, &stateOut->depthStencilState.front,
4012 mShaders.shaders.bits.nonZeroStencilWriteMaskWorkaround);
4013 UnpackStencilState(mShaders.shaders.back, &stateOut->depthStencilState.back,
4014 mShaders.shaders.bits.nonZeroStencilWriteMaskWorkaround);
4015 stateOut->depthStencilState.minDepthBounds = 0;
4016 stateOut->depthStencilState.maxDepthBounds = 0;
4017
4018 if (getRenderPassDepthStencilFramebufferFetchMode())
4019 {
4020 stateOut->depthStencilState.flags |=
4021 VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT |
4022 VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT;
4023 }
4024
4025 // tessellation State
4026 if (tessControlPointer && tessEvaluationPointer)
4027 {
4028 stateOut->domainOriginState.sType =
4029 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
4030 stateOut->domainOriginState.pNext = NULL;
4031 stateOut->domainOriginState.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
4032
4033 stateOut->tessellationState.sType =
4034 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
4035 stateOut->tessellationState.flags = 0;
4036 stateOut->tessellationState.pNext = &stateOut->domainOriginState;
4037 stateOut->tessellationState.patchControlPoints =
4038 static_cast<uint32_t>(mShaders.shaders.bits.patchVertices);
4039 }
4040
4041 // Dynamic state
4042 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_VIEWPORT);
4043 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_SCISSOR);
4044 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_LINE_WIDTH);
4045 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
4046 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
4047 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
4048 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
4049 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
4050 if (context->getFeatures().useCullModeDynamicState.enabled)
4051 {
4052 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_CULL_MODE_EXT);
4053 }
4054 if (context->getFeatures().useFrontFaceDynamicState.enabled)
4055 {
4056 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_FRONT_FACE_EXT);
4057 }
4058 if (context->getFeatures().useDepthTestEnableDynamicState.enabled)
4059 {
4060 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE);
4061 }
4062 if (context->getFeatures().useDepthWriteEnableDynamicState.enabled)
4063 {
4064 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE);
4065 }
4066 if (context->getFeatures().useDepthCompareOpDynamicState.enabled)
4067 {
4068 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_COMPARE_OP);
4069 }
4070 if (context->getFeatures().useStencilTestEnableDynamicState.enabled)
4071 {
4072 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE);
4073 }
4074 if (context->getFeatures().useStencilOpDynamicState.enabled)
4075 {
4076 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_OP);
4077 }
4078 if (context->getFeatures().useRasterizerDiscardEnableDynamicState.enabled)
4079 {
4080 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE);
4081 }
4082 if (context->getFeatures().useDepthBiasEnableDynamicState.enabled)
4083 {
4084 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE);
4085 }
4086 if (context->getFeatures().supportsFragmentShadingRate.enabled)
4087 {
4088 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR);
4089 }
4090 }
4091
initializePipelineSharedNonVertexInputState(ErrorContext * context,GraphicsPipelineSharedNonVertexInputVulkanStructs * stateOut,GraphicsPipelineDynamicStateList * dynamicStateListOut) const4092 void GraphicsPipelineDesc::initializePipelineSharedNonVertexInputState(
4093 ErrorContext *context,
4094 GraphicsPipelineSharedNonVertexInputVulkanStructs *stateOut,
4095 GraphicsPipelineDynamicStateList *dynamicStateListOut) const
4096 {
4097 const PackedMultisampleAndSubpassState &multisample = mSharedNonVertexInput.multisample;
4098
4099 stateOut->sampleMask = multisample.bits.sampleMask;
4100
4101 // Multisample state.
4102 stateOut->multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
4103 stateOut->multisampleState.flags = 0;
4104 stateOut->multisampleState.rasterizationSamples =
4105 gl_vk::GetSamples(multisample.bits.rasterizationSamplesMinusOne + 1,
4106 context->getFeatures().limitSampleCountTo2.enabled);
4107 stateOut->multisampleState.sampleShadingEnable =
4108 static_cast<VkBool32>(multisample.bits.sampleShadingEnable);
4109 stateOut->multisampleState.minSampleShading =
4110 static_cast<float>(multisample.bits.minSampleShading) / kMinSampleShadingScale;
4111 stateOut->multisampleState.pSampleMask = &stateOut->sampleMask;
4112 stateOut->multisampleState.alphaToCoverageEnable =
4113 static_cast<VkBool32>(multisample.bits.alphaToCoverageEnable);
4114 stateOut->multisampleState.alphaToOneEnable =
4115 static_cast<VkBool32>(multisample.bits.alphaToOneEnable);
4116 }
4117
initializePipelineFragmentOutputState(ErrorContext * context,GraphicsPipelineFragmentOutputVulkanStructs * stateOut,GraphicsPipelineDynamicStateList * dynamicStateListOut) const4118 void GraphicsPipelineDesc::initializePipelineFragmentOutputState(
4119 ErrorContext *context,
4120 GraphicsPipelineFragmentOutputVulkanStructs *stateOut,
4121 GraphicsPipelineDynamicStateList *dynamicStateListOut) const
4122 {
4123 stateOut->blendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
4124 stateOut->blendState.flags = 0;
4125 stateOut->blendState.logicOpEnable =
4126 static_cast<VkBool32>(mFragmentOutput.blendMaskAndLogic.bits.logicOpEnable);
4127 stateOut->blendState.logicOp =
4128 static_cast<VkLogicOp>(mFragmentOutput.blendMaskAndLogic.bits.logicOp);
4129 stateOut->blendState.attachmentCount =
4130 static_cast<uint32_t>(mSharedNonVertexInput.renderPass.colorAttachmentRange());
4131 stateOut->blendState.pAttachments = stateOut->blendAttachmentState.data();
4132
4133 // If this graphics pipeline is for the unresolve operation, correct the color attachment count
4134 // for that subpass.
4135 if ((mSharedNonVertexInput.renderPass.getColorUnresolveAttachmentMask().any() ||
4136 mSharedNonVertexInput.renderPass.hasDepthStencilUnresolveAttachment()) &&
4137 mSharedNonVertexInput.multisample.bits.subpass == 0)
4138 {
4139 stateOut->blendState.attachmentCount = static_cast<uint32_t>(
4140 mSharedNonVertexInput.renderPass.getColorUnresolveAttachmentMask().count());
4141 }
4142
4143 // Specify rasterization order for color when available and there is framebuffer fetch. This
4144 // allows implementation of coherent framebuffer fetch / advanced blend.
4145 if (context->getFeatures().supportsRasterizationOrderAttachmentAccess.enabled &&
4146 getRenderPassColorFramebufferFetchMode())
4147 {
4148 stateOut->blendState.flags |=
4149 VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT;
4150 }
4151
4152 const gl::DrawBufferMask blendEnableMask(
4153 mFragmentOutput.blendMaskAndLogic.bits.blendEnableMask);
4154
4155 // Zero-init all states.
4156 stateOut->blendAttachmentState = {};
4157
4158 const PackedColorBlendState &colorBlend = mFragmentOutput.blend;
4159
4160 // With render pass objects, the blend state is indexed by the subpass-mapped locations.
4161 // With dynamic rendering, it is indexed by the actual attachment index.
4162 uint32_t colorAttachmentIndex = 0;
4163 for (uint32_t colorIndexGL = 0; colorIndexGL < stateOut->blendState.attachmentCount;
4164 ++colorIndexGL)
4165 {
4166 if (context->getFeatures().preferDynamicRendering.enabled &&
4167 !mSharedNonVertexInput.renderPass.isColorAttachmentEnabled(colorIndexGL))
4168 {
4169 continue;
4170 }
4171
4172 VkPipelineColorBlendAttachmentState &state =
4173 stateOut->blendAttachmentState[colorAttachmentIndex++];
4174
4175 if (blendEnableMask[colorIndexGL])
4176 {
4177 // To avoid triggering valid usage error, blending must be disabled for formats that do
4178 // not have VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT feature bit set.
4179 // From OpenGL ES clients, this means disabling blending for integer formats.
4180 if (!angle::Format::Get(mSharedNonVertexInput.renderPass[colorIndexGL]).isInt())
4181 {
4182 ASSERT(!context->getRenderer()
4183 ->getFormat(mSharedNonVertexInput.renderPass[colorIndexGL])
4184 .getActualRenderableImageFormat()
4185 .isInt());
4186
4187 // The blend fixed-function is enabled with normal blend as well as advanced blend
4188 // when the Vulkan extension is present. When emulating advanced blend in the
4189 // shader, the blend fixed-function must be disabled.
4190 const PackedColorBlendAttachmentState &packedBlendState =
4191 colorBlend.attachments[colorIndexGL];
4192 if (packedBlendState.colorBlendOp <= static_cast<uint8_t>(VK_BLEND_OP_MAX) ||
4193 context->getFeatures().supportsBlendOperationAdvanced.enabled)
4194 {
4195 state.blendEnable = VK_TRUE;
4196 UnpackBlendAttachmentState(packedBlendState, &state);
4197 }
4198 }
4199 }
4200
4201 ASSERT(context->getRenderer()->getNativeExtensions().robustFragmentShaderOutputANGLE);
4202 if ((mFragmentOutput.blendMaskAndLogic.bits.missingOutputsMask >> colorIndexGL & 1) != 0)
4203 {
4204 state.colorWriteMask = 0;
4205 }
4206 else
4207 {
4208 state.colorWriteMask =
4209 Int4Array_Get<VkColorComponentFlags>(colorBlend.colorWriteMaskBits, colorIndexGL);
4210 }
4211 }
4212
4213 if (context->getFeatures().preferDynamicRendering.enabled)
4214 {
4215 stateOut->blendState.attachmentCount = colorAttachmentIndex;
4216 }
4217
4218 // Dynamic state
4219 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
4220 if (context->getFeatures().supportsLogicOpDynamicState.enabled)
4221 {
4222 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_LOGIC_OP_EXT);
4223 }
4224 }
4225
updateVertexInput(ContextVk * contextVk,GraphicsPipelineTransitionBits * transition,uint32_t attribIndex,GLuint stride,GLuint divisor,angle::FormatID format,bool compressed,GLuint relativeOffset)4226 void GraphicsPipelineDesc::updateVertexInput(ContextVk *contextVk,
4227 GraphicsPipelineTransitionBits *transition,
4228 uint32_t attribIndex,
4229 GLuint stride,
4230 GLuint divisor,
4231 angle::FormatID format,
4232 bool compressed,
4233 GLuint relativeOffset)
4234 {
4235 PackedAttribDesc &packedAttrib = mVertexInput.vertex.attribs[attribIndex];
4236
4237 SetBitField(packedAttrib.divisor, divisor);
4238
4239 if (format == angle::FormatID::NONE)
4240 {
4241 UNIMPLEMENTED();
4242 }
4243
4244 SetBitField(packedAttrib.format, format);
4245 SetBitField(packedAttrib.compressed, compressed);
4246 SetBitField(packedAttrib.offset, relativeOffset);
4247
4248 constexpr size_t kAttribBits = kPackedAttribDescSize * kBitsPerByte;
4249 const size_t kBit =
4250 ANGLE_GET_INDEXED_TRANSITION_BIT(mVertexInput.vertex.attribs, attribIndex, kAttribBits);
4251
4252 // Each attribute is 4 bytes, so only one transition bit needs to be set.
4253 static_assert(kPackedAttribDescSize == kGraphicsPipelineDirtyBitBytes,
4254 "Adjust transition bits");
4255 transition->set(kBit);
4256
4257 if (!contextVk->getFeatures().useVertexInputBindingStrideDynamicState.enabled)
4258 {
4259 SetBitField(mVertexInput.vertex.strides[attribIndex], stride);
4260 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(
4261 mVertexInput.vertex.strides, attribIndex,
4262 sizeof(mVertexInput.vertex.strides[0]) * kBitsPerByte));
4263 }
4264 }
4265
setVertexShaderComponentTypes(gl::AttributesMask activeAttribLocations,gl::ComponentTypeMask componentTypeMask)4266 void GraphicsPipelineDesc::setVertexShaderComponentTypes(gl::AttributesMask activeAttribLocations,
4267 gl::ComponentTypeMask componentTypeMask)
4268 {
4269 SetBitField(mVertexInput.inputAssembly.bits.programActiveAttributeLocations,
4270 activeAttribLocations.bits());
4271
4272 const gl::ComponentTypeMask activeComponentTypeMask =
4273 componentTypeMask & gl::GetActiveComponentTypeMask(activeAttribLocations);
4274
4275 SetBitField(mVertexInput.vertex.shaderAttribComponentType, activeComponentTypeMask.bits());
4276 }
4277
updateVertexShaderComponentTypes(GraphicsPipelineTransitionBits * transition,gl::AttributesMask activeAttribLocations,gl::ComponentTypeMask componentTypeMask)4278 void GraphicsPipelineDesc::updateVertexShaderComponentTypes(
4279 GraphicsPipelineTransitionBits *transition,
4280 gl::AttributesMask activeAttribLocations,
4281 gl::ComponentTypeMask componentTypeMask)
4282 {
4283 if (mVertexInput.inputAssembly.bits.programActiveAttributeLocations !=
4284 activeAttribLocations.bits())
4285 {
4286 SetBitField(mVertexInput.inputAssembly.bits.programActiveAttributeLocations,
4287 activeAttribLocations.bits());
4288 transition->set(ANGLE_GET_TRANSITION_BIT(mVertexInput.inputAssembly.bits));
4289 }
4290
4291 const gl::ComponentTypeMask activeComponentTypeMask =
4292 componentTypeMask & gl::GetActiveComponentTypeMask(activeAttribLocations);
4293
4294 if (mVertexInput.vertex.shaderAttribComponentType != activeComponentTypeMask.bits())
4295 {
4296 SetBitField(mVertexInput.vertex.shaderAttribComponentType, activeComponentTypeMask.bits());
4297 transition->set(ANGLE_GET_TRANSITION_BIT(mVertexInput.vertex.shaderAttribComponentType));
4298 }
4299 }
4300
setTopology(gl::PrimitiveMode drawMode)4301 void GraphicsPipelineDesc::setTopology(gl::PrimitiveMode drawMode)
4302 {
4303 VkPrimitiveTopology vkTopology = gl_vk::GetPrimitiveTopology(drawMode);
4304 SetBitField(mVertexInput.inputAssembly.bits.topology, vkTopology);
4305 }
4306
updateTopology(GraphicsPipelineTransitionBits * transition,gl::PrimitiveMode drawMode)4307 void GraphicsPipelineDesc::updateTopology(GraphicsPipelineTransitionBits *transition,
4308 gl::PrimitiveMode drawMode)
4309 {
4310 setTopology(drawMode);
4311 transition->set(ANGLE_GET_TRANSITION_BIT(mVertexInput.inputAssembly.bits));
4312 }
4313
updateDepthClipControl(GraphicsPipelineTransitionBits * transition,bool negativeOneToOne)4314 void GraphicsPipelineDesc::updateDepthClipControl(GraphicsPipelineTransitionBits *transition,
4315 bool negativeOneToOne)
4316 {
4317 SetBitField(mShaders.shaders.bits.viewportNegativeOneToOne, negativeOneToOne);
4318 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4319 }
4320
updatePrimitiveRestartEnabled(GraphicsPipelineTransitionBits * transition,bool primitiveRestartEnabled)4321 void GraphicsPipelineDesc::updatePrimitiveRestartEnabled(GraphicsPipelineTransitionBits *transition,
4322 bool primitiveRestartEnabled)
4323 {
4324 mVertexInput.inputAssembly.bits.primitiveRestartEnable =
4325 static_cast<uint16_t>(primitiveRestartEnabled);
4326 transition->set(ANGLE_GET_TRANSITION_BIT(mVertexInput.inputAssembly.bits));
4327 }
4328
updatePolygonMode(GraphicsPipelineTransitionBits * transition,gl::PolygonMode polygonMode)4329 void GraphicsPipelineDesc::updatePolygonMode(GraphicsPipelineTransitionBits *transition,
4330 gl::PolygonMode polygonMode)
4331 {
4332 mShaders.shaders.bits.polygonMode = gl_vk::GetPolygonMode(polygonMode);
4333 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4334 }
4335
updateCullMode(GraphicsPipelineTransitionBits * transition,const gl::RasterizerState & rasterState)4336 void GraphicsPipelineDesc::updateCullMode(GraphicsPipelineTransitionBits *transition,
4337 const gl::RasterizerState &rasterState)
4338 {
4339 SetBitField(mShaders.shaders.bits.cullMode, gl_vk::GetCullMode(rasterState));
4340 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4341 }
4342
updateFrontFace(GraphicsPipelineTransitionBits * transition,const gl::RasterizerState & rasterState,bool invertFrontFace)4343 void GraphicsPipelineDesc::updateFrontFace(GraphicsPipelineTransitionBits *transition,
4344 const gl::RasterizerState &rasterState,
4345 bool invertFrontFace)
4346 {
4347 SetBitField(mShaders.shaders.bits.frontFace,
4348 gl_vk::GetFrontFace(rasterState.frontFace, invertFrontFace));
4349 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4350 }
4351
updateRasterizerDiscardEnabled(GraphicsPipelineTransitionBits * transition,bool rasterizerDiscardEnabled)4352 void GraphicsPipelineDesc::updateRasterizerDiscardEnabled(
4353 GraphicsPipelineTransitionBits *transition,
4354 bool rasterizerDiscardEnabled)
4355 {
4356 mShaders.shaders.bits.rasterizerDiscardEnable = static_cast<uint32_t>(rasterizerDiscardEnabled);
4357 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4358 }
4359
getRasterizationSamples() const4360 uint32_t GraphicsPipelineDesc::getRasterizationSamples() const
4361 {
4362 return mSharedNonVertexInput.multisample.bits.rasterizationSamplesMinusOne + 1;
4363 }
4364
setRasterizationSamples(uint32_t rasterizationSamples)4365 void GraphicsPipelineDesc::setRasterizationSamples(uint32_t rasterizationSamples)
4366 {
4367 ASSERT(rasterizationSamples > 0);
4368 mSharedNonVertexInput.multisample.bits.rasterizationSamplesMinusOne = rasterizationSamples - 1;
4369 }
4370
updateRasterizationSamples(GraphicsPipelineTransitionBits * transition,uint32_t rasterizationSamples)4371 void GraphicsPipelineDesc::updateRasterizationSamples(GraphicsPipelineTransitionBits *transition,
4372 uint32_t rasterizationSamples)
4373 {
4374 setRasterizationSamples(rasterizationSamples);
4375 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
4376 }
4377
updateAlphaToCoverageEnable(GraphicsPipelineTransitionBits * transition,bool enable)4378 void GraphicsPipelineDesc::updateAlphaToCoverageEnable(GraphicsPipelineTransitionBits *transition,
4379 bool enable)
4380 {
4381 mSharedNonVertexInput.multisample.bits.alphaToCoverageEnable = enable;
4382 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
4383 }
4384
updateAlphaToOneEnable(GraphicsPipelineTransitionBits * transition,bool enable)4385 void GraphicsPipelineDesc::updateAlphaToOneEnable(GraphicsPipelineTransitionBits *transition,
4386 bool enable)
4387 {
4388 mSharedNonVertexInput.multisample.bits.alphaToOneEnable = enable;
4389 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
4390 }
4391
updateSampleMask(GraphicsPipelineTransitionBits * transition,uint32_t maskNumber,uint32_t mask)4392 void GraphicsPipelineDesc::updateSampleMask(GraphicsPipelineTransitionBits *transition,
4393 uint32_t maskNumber,
4394 uint32_t mask)
4395 {
4396 ASSERT(maskNumber == 0);
4397 SetBitField(mSharedNonVertexInput.multisample.bits.sampleMask, mask);
4398
4399 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
4400 }
4401
updateSampleShading(GraphicsPipelineTransitionBits * transition,bool enable,float value)4402 void GraphicsPipelineDesc::updateSampleShading(GraphicsPipelineTransitionBits *transition,
4403 bool enable,
4404 float value)
4405 {
4406 mSharedNonVertexInput.multisample.bits.sampleShadingEnable = enable;
4407 if (enable)
4408 {
4409 SetBitField(mSharedNonVertexInput.multisample.bits.minSampleShading,
4410 static_cast<uint16_t>(value * kMinSampleShadingScale));
4411 }
4412 else
4413 {
4414 mSharedNonVertexInput.multisample.bits.minSampleShading = kMinSampleShadingScale;
4415 }
4416
4417 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
4418 }
4419
setSingleBlend(uint32_t colorIndexGL,bool enabled,VkBlendOp op,VkBlendFactor srcFactor,VkBlendFactor dstFactor)4420 void GraphicsPipelineDesc::setSingleBlend(uint32_t colorIndexGL,
4421 bool enabled,
4422 VkBlendOp op,
4423 VkBlendFactor srcFactor,
4424 VkBlendFactor dstFactor)
4425 {
4426 mFragmentOutput.blendMaskAndLogic.bits.blendEnableMask |=
4427 static_cast<uint8_t>(1 << colorIndexGL);
4428
4429 PackedColorBlendAttachmentState &blendAttachmentState =
4430 mFragmentOutput.blend.attachments[colorIndexGL];
4431
4432 SetBitField(blendAttachmentState.colorBlendOp, op);
4433 SetBitField(blendAttachmentState.alphaBlendOp, op);
4434
4435 SetBitField(blendAttachmentState.srcColorBlendFactor, srcFactor);
4436 SetBitField(blendAttachmentState.dstColorBlendFactor, dstFactor);
4437 SetBitField(blendAttachmentState.srcAlphaBlendFactor, VK_BLEND_FACTOR_ZERO);
4438 SetBitField(blendAttachmentState.dstAlphaBlendFactor, VK_BLEND_FACTOR_ONE);
4439 }
4440
updateBlendEnabled(GraphicsPipelineTransitionBits * transition,gl::DrawBufferMask blendEnabledMask)4441 void GraphicsPipelineDesc::updateBlendEnabled(GraphicsPipelineTransitionBits *transition,
4442 gl::DrawBufferMask blendEnabledMask)
4443 {
4444 SetBitField(mFragmentOutput.blendMaskAndLogic.bits.blendEnableMask, blendEnabledMask.bits());
4445 transition->set(ANGLE_GET_TRANSITION_BIT(mFragmentOutput.blendMaskAndLogic.bits));
4446 }
4447
updateBlendEquations(GraphicsPipelineTransitionBits * transition,const gl::BlendStateExt & blendStateExt,gl::DrawBufferMask attachmentMask)4448 void GraphicsPipelineDesc::updateBlendEquations(GraphicsPipelineTransitionBits *transition,
4449 const gl::BlendStateExt &blendStateExt,
4450 gl::DrawBufferMask attachmentMask)
4451 {
4452 constexpr size_t kSizeBits = sizeof(PackedColorBlendAttachmentState) * 8;
4453
4454 for (size_t attachmentIndex : attachmentMask)
4455 {
4456 PackedColorBlendAttachmentState &blendAttachmentState =
4457 mFragmentOutput.blend.attachments[attachmentIndex];
4458 blendAttachmentState.colorBlendOp =
4459 PackGLBlendOp(blendStateExt.getEquationColorIndexed(attachmentIndex));
4460 blendAttachmentState.alphaBlendOp =
4461 PackGLBlendOp(blendStateExt.getEquationAlphaIndexed(attachmentIndex));
4462 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mFragmentOutput.blend.attachments,
4463 attachmentIndex, kSizeBits));
4464 }
4465 }
4466
updateBlendFuncs(GraphicsPipelineTransitionBits * transition,const gl::BlendStateExt & blendStateExt,gl::DrawBufferMask attachmentMask)4467 void GraphicsPipelineDesc::updateBlendFuncs(GraphicsPipelineTransitionBits *transition,
4468 const gl::BlendStateExt &blendStateExt,
4469 gl::DrawBufferMask attachmentMask)
4470 {
4471 constexpr size_t kSizeBits = sizeof(PackedColorBlendAttachmentState) * 8;
4472 for (size_t attachmentIndex : attachmentMask)
4473 {
4474 PackedColorBlendAttachmentState &blendAttachmentState =
4475 mFragmentOutput.blend.attachments[attachmentIndex];
4476 blendAttachmentState.srcColorBlendFactor =
4477 PackGLBlendFactor(blendStateExt.getSrcColorIndexed(attachmentIndex));
4478 blendAttachmentState.dstColorBlendFactor =
4479 PackGLBlendFactor(blendStateExt.getDstColorIndexed(attachmentIndex));
4480 blendAttachmentState.srcAlphaBlendFactor =
4481 PackGLBlendFactor(blendStateExt.getSrcAlphaIndexed(attachmentIndex));
4482 blendAttachmentState.dstAlphaBlendFactor =
4483 PackGLBlendFactor(blendStateExt.getDstAlphaIndexed(attachmentIndex));
4484 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mFragmentOutput.blend.attachments,
4485 attachmentIndex, kSizeBits));
4486 }
4487 }
4488
resetBlendFuncsAndEquations(GraphicsPipelineTransitionBits * transition,const gl::BlendStateExt & blendStateExt,gl::DrawBufferMask previousAttachmentsMask,gl::DrawBufferMask newAttachmentsMask)4489 void GraphicsPipelineDesc::resetBlendFuncsAndEquations(GraphicsPipelineTransitionBits *transition,
4490 const gl::BlendStateExt &blendStateExt,
4491 gl::DrawBufferMask previousAttachmentsMask,
4492 gl::DrawBufferMask newAttachmentsMask)
4493 {
4494 // A framebuffer with attachments in P was bound, and now one with attachments in N is bound.
4495 // We need to clear blend funcs and equations for attachments in P that are not in N. That is
4496 // attachments in P&~N.
4497 const gl::DrawBufferMask attachmentsToClear = previousAttachmentsMask & ~newAttachmentsMask;
4498 // We also need to restore blend funcs and equations for attachments in N that are not in P.
4499 const gl::DrawBufferMask attachmentsToAdd = newAttachmentsMask & ~previousAttachmentsMask;
4500 constexpr size_t kSizeBits = sizeof(PackedColorBlendAttachmentState) * 8;
4501
4502 for (size_t attachmentIndex : attachmentsToClear)
4503 {
4504 PackedColorBlendAttachmentState &blendAttachmentState =
4505 mFragmentOutput.blend.attachments[attachmentIndex];
4506
4507 blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
4508 blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
4509 blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
4510 blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
4511 blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
4512 blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
4513
4514 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mFragmentOutput.blend.attachments,
4515 attachmentIndex, kSizeBits));
4516 }
4517
4518 if (attachmentsToAdd.any())
4519 {
4520 updateBlendFuncs(transition, blendStateExt, attachmentsToAdd);
4521 updateBlendEquations(transition, blendStateExt, attachmentsToAdd);
4522 }
4523 }
4524
setColorWriteMasks(gl::BlendStateExt::ColorMaskStorage::Type colorMasks,const gl::DrawBufferMask & alphaMask,const gl::DrawBufferMask & enabledDrawBuffers)4525 void GraphicsPipelineDesc::setColorWriteMasks(gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
4526 const gl::DrawBufferMask &alphaMask,
4527 const gl::DrawBufferMask &enabledDrawBuffers)
4528 {
4529 for (uint32_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
4530 colorIndexGL++)
4531 {
4532 uint8_t colorMask =
4533 gl::BlendStateExt::ColorMaskStorage::GetValueIndexed(colorIndexGL, colorMasks);
4534
4535 uint8_t mask = 0;
4536 if (enabledDrawBuffers.test(colorIndexGL))
4537 {
4538 mask = alphaMask[colorIndexGL] ? (colorMask & ~VK_COLOR_COMPONENT_A_BIT) : colorMask;
4539 }
4540 Int4Array_Set(mFragmentOutput.blend.colorWriteMaskBits, colorIndexGL, mask);
4541 }
4542 }
4543
setSingleColorWriteMask(uint32_t colorIndexGL,VkColorComponentFlags colorComponentFlags)4544 void GraphicsPipelineDesc::setSingleColorWriteMask(uint32_t colorIndexGL,
4545 VkColorComponentFlags colorComponentFlags)
4546 {
4547 uint8_t colorMask = static_cast<uint8_t>(colorComponentFlags);
4548 Int4Array_Set(mFragmentOutput.blend.colorWriteMaskBits, colorIndexGL, colorMask);
4549 }
4550
updateColorWriteMasks(GraphicsPipelineTransitionBits * transition,gl::BlendStateExt::ColorMaskStorage::Type colorMasks,const gl::DrawBufferMask & alphaMask,const gl::DrawBufferMask & enabledDrawBuffers)4551 void GraphicsPipelineDesc::updateColorWriteMasks(
4552 GraphicsPipelineTransitionBits *transition,
4553 gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
4554 const gl::DrawBufferMask &alphaMask,
4555 const gl::DrawBufferMask &enabledDrawBuffers)
4556 {
4557 setColorWriteMasks(colorMasks, alphaMask, enabledDrawBuffers);
4558
4559 for (size_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
4560 colorIndexGL++)
4561 {
4562 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mFragmentOutput.blend.colorWriteMaskBits,
4563 colorIndexGL, 4));
4564 }
4565 }
4566
updateMissingOutputsMask(GraphicsPipelineTransitionBits * transition,gl::DrawBufferMask missingOutputsMask)4567 void GraphicsPipelineDesc::updateMissingOutputsMask(GraphicsPipelineTransitionBits *transition,
4568 gl::DrawBufferMask missingOutputsMask)
4569 {
4570 if (mFragmentOutput.blendMaskAndLogic.bits.missingOutputsMask != missingOutputsMask.bits())
4571 {
4572 SetBitField(mFragmentOutput.blendMaskAndLogic.bits.missingOutputsMask,
4573 missingOutputsMask.bits());
4574 transition->set(ANGLE_GET_TRANSITION_BIT(mFragmentOutput.blendMaskAndLogic.bits));
4575 }
4576 }
4577
updateLogicOpEnabled(GraphicsPipelineTransitionBits * transition,bool enable)4578 void GraphicsPipelineDesc::updateLogicOpEnabled(GraphicsPipelineTransitionBits *transition,
4579 bool enable)
4580 {
4581 mFragmentOutput.blendMaskAndLogic.bits.logicOpEnable = enable;
4582 transition->set(ANGLE_GET_TRANSITION_BIT(mFragmentOutput.blendMaskAndLogic.bits));
4583 }
4584
updateLogicOp(GraphicsPipelineTransitionBits * transition,VkLogicOp logicOp)4585 void GraphicsPipelineDesc::updateLogicOp(GraphicsPipelineTransitionBits *transition,
4586 VkLogicOp logicOp)
4587 {
4588 SetBitField(mFragmentOutput.blendMaskAndLogic.bits.logicOp, logicOp);
4589 transition->set(ANGLE_GET_TRANSITION_BIT(mFragmentOutput.blendMaskAndLogic.bits));
4590 }
4591
setDepthTestEnabled(bool enabled)4592 void GraphicsPipelineDesc::setDepthTestEnabled(bool enabled)
4593 {
4594 mShaders.shaders.bits.depthTest = enabled;
4595 }
4596
setDepthWriteEnabled(bool enabled)4597 void GraphicsPipelineDesc::setDepthWriteEnabled(bool enabled)
4598 {
4599 mShaders.shaders.bits.depthWrite = enabled;
4600 }
4601
setDepthFunc(VkCompareOp op)4602 void GraphicsPipelineDesc::setDepthFunc(VkCompareOp op)
4603 {
4604 SetBitField(mShaders.shaders.bits.depthCompareOp, op);
4605 }
4606
setDepthClampEnabled(bool enabled)4607 void GraphicsPipelineDesc::setDepthClampEnabled(bool enabled)
4608 {
4609 mShaders.shaders.bits.depthClampEnable = enabled;
4610 }
4611
setStencilTestEnabled(bool enabled)4612 void GraphicsPipelineDesc::setStencilTestEnabled(bool enabled)
4613 {
4614 mShaders.shaders.bits.stencilTest = enabled;
4615 }
4616
setStencilFrontFuncs(VkCompareOp compareOp)4617 void GraphicsPipelineDesc::setStencilFrontFuncs(VkCompareOp compareOp)
4618 {
4619 SetBitField(mShaders.shaders.front.compare, compareOp);
4620 }
4621
setStencilBackFuncs(VkCompareOp compareOp)4622 void GraphicsPipelineDesc::setStencilBackFuncs(VkCompareOp compareOp)
4623 {
4624 SetBitField(mShaders.shaders.back.compare, compareOp);
4625 }
4626
setStencilFrontOps(VkStencilOp failOp,VkStencilOp passOp,VkStencilOp depthFailOp)4627 void GraphicsPipelineDesc::setStencilFrontOps(VkStencilOp failOp,
4628 VkStencilOp passOp,
4629 VkStencilOp depthFailOp)
4630 {
4631 SetBitField(mShaders.shaders.front.fail, failOp);
4632 SetBitField(mShaders.shaders.front.pass, passOp);
4633 SetBitField(mShaders.shaders.front.depthFail, depthFailOp);
4634 }
4635
setStencilBackOps(VkStencilOp failOp,VkStencilOp passOp,VkStencilOp depthFailOp)4636 void GraphicsPipelineDesc::setStencilBackOps(VkStencilOp failOp,
4637 VkStencilOp passOp,
4638 VkStencilOp depthFailOp)
4639 {
4640 SetBitField(mShaders.shaders.back.fail, failOp);
4641 SetBitField(mShaders.shaders.back.pass, passOp);
4642 SetBitField(mShaders.shaders.back.depthFail, depthFailOp);
4643 }
4644
updateDepthTestEnabled(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState,const gl::Framebuffer * drawFramebuffer)4645 void GraphicsPipelineDesc::updateDepthTestEnabled(GraphicsPipelineTransitionBits *transition,
4646 const gl::DepthStencilState &depthStencilState,
4647 const gl::Framebuffer *drawFramebuffer)
4648 {
4649 // Only enable the depth test if the draw framebuffer has a depth buffer. It's possible that
4650 // we're emulating a stencil-only buffer with a depth-stencil buffer
4651 setDepthTestEnabled(depthStencilState.depthTest && drawFramebuffer->hasDepth());
4652 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4653 }
4654
updateDepthFunc(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4655 void GraphicsPipelineDesc::updateDepthFunc(GraphicsPipelineTransitionBits *transition,
4656 const gl::DepthStencilState &depthStencilState)
4657 {
4658 setDepthFunc(gl_vk::GetCompareOp(depthStencilState.depthFunc));
4659 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4660 }
4661
updateDepthClampEnabled(GraphicsPipelineTransitionBits * transition,bool enabled)4662 void GraphicsPipelineDesc::updateDepthClampEnabled(GraphicsPipelineTransitionBits *transition,
4663 bool enabled)
4664 {
4665 setDepthClampEnabled(enabled);
4666 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4667 }
4668
updateSurfaceRotation(GraphicsPipelineTransitionBits * transition,bool isRotatedAspectRatio)4669 void GraphicsPipelineDesc::updateSurfaceRotation(GraphicsPipelineTransitionBits *transition,
4670 bool isRotatedAspectRatio)
4671 {
4672 SetBitField(mShaders.shaders.bits.surfaceRotation, isRotatedAspectRatio);
4673 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4674 }
4675
updateDepthWriteEnabled(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState,const gl::Framebuffer * drawFramebuffer)4676 void GraphicsPipelineDesc::updateDepthWriteEnabled(GraphicsPipelineTransitionBits *transition,
4677 const gl::DepthStencilState &depthStencilState,
4678 const gl::Framebuffer *drawFramebuffer)
4679 {
4680 // Don't write to depth buffers that should not exist
4681 const bool depthWriteEnabled =
4682 drawFramebuffer->hasDepth() && depthStencilState.depthTest && depthStencilState.depthMask;
4683 if (static_cast<bool>(mShaders.shaders.bits.depthWrite) != depthWriteEnabled)
4684 {
4685 setDepthWriteEnabled(depthWriteEnabled);
4686 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4687 }
4688 }
4689
updateStencilTestEnabled(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState,const gl::Framebuffer * drawFramebuffer)4690 void GraphicsPipelineDesc::updateStencilTestEnabled(GraphicsPipelineTransitionBits *transition,
4691 const gl::DepthStencilState &depthStencilState,
4692 const gl::Framebuffer *drawFramebuffer)
4693 {
4694 // Only enable the stencil test if the draw framebuffer has a stencil buffer. It's possible
4695 // that we're emulating a depth-only buffer with a depth-stencil buffer
4696 setStencilTestEnabled(depthStencilState.stencilTest && drawFramebuffer->hasStencil());
4697 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4698 }
4699
updateStencilFrontFuncs(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4700 void GraphicsPipelineDesc::updateStencilFrontFuncs(GraphicsPipelineTransitionBits *transition,
4701 const gl::DepthStencilState &depthStencilState)
4702 {
4703 setStencilFrontFuncs(gl_vk::GetCompareOp(depthStencilState.stencilFunc));
4704 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.front));
4705 }
4706
updateStencilBackFuncs(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4707 void GraphicsPipelineDesc::updateStencilBackFuncs(GraphicsPipelineTransitionBits *transition,
4708 const gl::DepthStencilState &depthStencilState)
4709 {
4710 setStencilBackFuncs(gl_vk::GetCompareOp(depthStencilState.stencilBackFunc));
4711 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.back));
4712 }
4713
updateStencilFrontOps(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4714 void GraphicsPipelineDesc::updateStencilFrontOps(GraphicsPipelineTransitionBits *transition,
4715 const gl::DepthStencilState &depthStencilState)
4716 {
4717 setStencilFrontOps(gl_vk::GetStencilOp(depthStencilState.stencilFail),
4718 gl_vk::GetStencilOp(depthStencilState.stencilPassDepthPass),
4719 gl_vk::GetStencilOp(depthStencilState.stencilPassDepthFail));
4720 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.front));
4721 }
4722
updateStencilBackOps(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4723 void GraphicsPipelineDesc::updateStencilBackOps(GraphicsPipelineTransitionBits *transition,
4724 const gl::DepthStencilState &depthStencilState)
4725 {
4726 setStencilBackOps(gl_vk::GetStencilOp(depthStencilState.stencilBackFail),
4727 gl_vk::GetStencilOp(depthStencilState.stencilBackPassDepthPass),
4728 gl_vk::GetStencilOp(depthStencilState.stencilBackPassDepthFail));
4729 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.back));
4730 }
4731
updatePolygonOffsetEnabled(GraphicsPipelineTransitionBits * transition,bool enabled)4732 void GraphicsPipelineDesc::updatePolygonOffsetEnabled(GraphicsPipelineTransitionBits *transition,
4733 bool enabled)
4734 {
4735 mShaders.shaders.bits.depthBiasEnable = enabled;
4736 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4737 }
4738
setRenderPassDesc(const RenderPassDesc & renderPassDesc)4739 void GraphicsPipelineDesc::setRenderPassDesc(const RenderPassDesc &renderPassDesc)
4740 {
4741 mSharedNonVertexInput.renderPass = renderPassDesc;
4742 }
4743
updateSubpass(GraphicsPipelineTransitionBits * transition,uint32_t subpass)4744 void GraphicsPipelineDesc::updateSubpass(GraphicsPipelineTransitionBits *transition,
4745 uint32_t subpass)
4746 {
4747 if (mSharedNonVertexInput.multisample.bits.subpass != subpass)
4748 {
4749 SetBitField(mSharedNonVertexInput.multisample.bits.subpass, subpass);
4750 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
4751 }
4752 }
4753
updatePatchVertices(GraphicsPipelineTransitionBits * transition,GLuint value)4754 void GraphicsPipelineDesc::updatePatchVertices(GraphicsPipelineTransitionBits *transition,
4755 GLuint value)
4756 {
4757 SetBitField(mShaders.shaders.bits.patchVertices, value);
4758 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4759 }
4760
resetSubpass(GraphicsPipelineTransitionBits * transition)4761 void GraphicsPipelineDesc::resetSubpass(GraphicsPipelineTransitionBits *transition)
4762 {
4763 updateSubpass(transition, 0);
4764 }
4765
nextSubpass(GraphicsPipelineTransitionBits * transition)4766 void GraphicsPipelineDesc::nextSubpass(GraphicsPipelineTransitionBits *transition)
4767 {
4768 updateSubpass(transition, mSharedNonVertexInput.multisample.bits.subpass + 1);
4769 }
4770
setSubpass(uint32_t subpass)4771 void GraphicsPipelineDesc::setSubpass(uint32_t subpass)
4772 {
4773 SetBitField(mSharedNonVertexInput.multisample.bits.subpass, subpass);
4774 }
4775
getSubpass() const4776 uint32_t GraphicsPipelineDesc::getSubpass() const
4777 {
4778 return mSharedNonVertexInput.multisample.bits.subpass;
4779 }
4780
updateEmulatedDitherControl(GraphicsPipelineTransitionBits * transition,uint16_t value)4781 void GraphicsPipelineDesc::updateEmulatedDitherControl(GraphicsPipelineTransitionBits *transition,
4782 uint16_t value)
4783 {
4784 // Make sure we don't waste time resetting this to zero in the common no-dither case.
4785 ASSERT(value != 0 || mShaders.shaders.emulatedDitherControl != 0);
4786
4787 mShaders.shaders.emulatedDitherControl = value;
4788 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.emulatedDitherControl));
4789 }
4790
updateNonZeroStencilWriteMaskWorkaround(GraphicsPipelineTransitionBits * transition,bool enabled)4791 void GraphicsPipelineDesc::updateNonZeroStencilWriteMaskWorkaround(
4792 GraphicsPipelineTransitionBits *transition,
4793 bool enabled)
4794 {
4795 mShaders.shaders.bits.nonZeroStencilWriteMaskWorkaround = enabled;
4796 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4797 }
4798
updateRenderPassDesc(GraphicsPipelineTransitionBits * transition,const angle::FeaturesVk & features,const RenderPassDesc & renderPassDesc,FramebufferFetchMode framebufferFetchMode)4799 void GraphicsPipelineDesc::updateRenderPassDesc(GraphicsPipelineTransitionBits *transition,
4800 const angle::FeaturesVk &features,
4801 const RenderPassDesc &renderPassDesc,
4802 FramebufferFetchMode framebufferFetchMode)
4803 {
4804 setRenderPassDesc(renderPassDesc);
4805
4806 // Framebuffer fetch mode is an inherent property of the executable. With dynamic rendering, it
4807 // is not tracked in the framebuffer's render pass desc (the source of |renderPassDesc|), and is
4808 // overriden at this point.
4809 if (features.preferDynamicRendering.enabled)
4810 {
4811 setRenderPassFramebufferFetchMode(framebufferFetchMode);
4812 }
4813
4814 // The RenderPass is a special case where it spans multiple bits but has no member.
4815 constexpr size_t kFirstBit =
4816 offsetof(GraphicsPipelineDesc, mSharedNonVertexInput.renderPass) >> kTransitionByteShift;
4817 constexpr size_t kBitCount = kRenderPassDescSize >> kTransitionByteShift;
4818 for (size_t bit = 0; bit < kBitCount; ++bit)
4819 {
4820 transition->set(kFirstBit + bit);
4821 }
4822 }
4823
setRenderPassSampleCount(GLint samples)4824 void GraphicsPipelineDesc::setRenderPassSampleCount(GLint samples)
4825 {
4826 mSharedNonVertexInput.renderPass.setSamples(samples);
4827 }
4828
setRenderPassFramebufferFetchMode(FramebufferFetchMode framebufferFetchMode)4829 void GraphicsPipelineDesc::setRenderPassFramebufferFetchMode(
4830 FramebufferFetchMode framebufferFetchMode)
4831 {
4832 mSharedNonVertexInput.renderPass.setFramebufferFetchMode(framebufferFetchMode);
4833 }
4834
setRenderPassColorAttachmentFormat(size_t colorIndexGL,angle::FormatID formatID)4835 void GraphicsPipelineDesc::setRenderPassColorAttachmentFormat(size_t colorIndexGL,
4836 angle::FormatID formatID)
4837 {
4838 mSharedNonVertexInput.renderPass.packColorAttachment(colorIndexGL, formatID);
4839 }
4840
setRenderPassFoveation(bool isFoveated)4841 void GraphicsPipelineDesc::setRenderPassFoveation(bool isFoveated)
4842 {
4843 mSharedNonVertexInput.renderPass.setFragmentShadingAttachment(isFoveated);
4844 }
4845
4846 // AttachmentOpsArray implementation.
AttachmentOpsArray()4847 AttachmentOpsArray::AttachmentOpsArray()
4848 {
4849 memset(&mOps, 0, sizeof(PackedAttachmentOpsDesc) * mOps.size());
4850 }
4851
4852 AttachmentOpsArray::~AttachmentOpsArray() = default;
4853
AttachmentOpsArray(const AttachmentOpsArray & other)4854 AttachmentOpsArray::AttachmentOpsArray(const AttachmentOpsArray &other)
4855 {
4856 memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
4857 }
4858
operator =(const AttachmentOpsArray & other)4859 AttachmentOpsArray &AttachmentOpsArray::operator=(const AttachmentOpsArray &other)
4860 {
4861 memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
4862 return *this;
4863 }
4864
initWithLoadStore(PackedAttachmentIndex index,ImageLayout initialLayout,ImageLayout finalLayout)4865 void AttachmentOpsArray::initWithLoadStore(PackedAttachmentIndex index,
4866 ImageLayout initialLayout,
4867 ImageLayout finalLayout)
4868 {
4869 setLayouts(index, initialLayout, finalLayout);
4870 setOps(index, RenderPassLoadOp::Load, RenderPassStoreOp::Store);
4871 setStencilOps(index, RenderPassLoadOp::Load, RenderPassStoreOp::Store);
4872 }
4873
setLayouts(PackedAttachmentIndex index,ImageLayout initialLayout,ImageLayout finalLayout)4874 void AttachmentOpsArray::setLayouts(PackedAttachmentIndex index,
4875 ImageLayout initialLayout,
4876 ImageLayout finalLayout)
4877 {
4878 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4879 SetBitField(ops.initialLayout, initialLayout);
4880 SetBitField(ops.finalLayout, finalLayout);
4881 SetBitField(ops.finalResolveLayout, finalLayout);
4882 }
4883
setOps(PackedAttachmentIndex index,RenderPassLoadOp loadOp,RenderPassStoreOp storeOp)4884 void AttachmentOpsArray::setOps(PackedAttachmentIndex index,
4885 RenderPassLoadOp loadOp,
4886 RenderPassStoreOp storeOp)
4887 {
4888 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4889 SetBitField(ops.loadOp, loadOp);
4890 SetBitField(ops.storeOp, storeOp);
4891 ops.isInvalidated = false;
4892 }
4893
setStencilOps(PackedAttachmentIndex index,RenderPassLoadOp loadOp,RenderPassStoreOp storeOp)4894 void AttachmentOpsArray::setStencilOps(PackedAttachmentIndex index,
4895 RenderPassLoadOp loadOp,
4896 RenderPassStoreOp storeOp)
4897 {
4898 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4899 SetBitField(ops.stencilLoadOp, loadOp);
4900 SetBitField(ops.stencilStoreOp, storeOp);
4901 ops.isStencilInvalidated = false;
4902 }
4903
setClearOp(PackedAttachmentIndex index)4904 void AttachmentOpsArray::setClearOp(PackedAttachmentIndex index)
4905 {
4906 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4907 SetBitField(ops.loadOp, RenderPassLoadOp::Clear);
4908 }
4909
setClearStencilOp(PackedAttachmentIndex index)4910 void AttachmentOpsArray::setClearStencilOp(PackedAttachmentIndex index)
4911 {
4912 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4913 SetBitField(ops.stencilLoadOp, RenderPassLoadOp::Clear);
4914 }
4915
hash() const4916 size_t AttachmentOpsArray::hash() const
4917 {
4918 return angle::ComputeGenericHash(mOps);
4919 }
4920
operator ==(const AttachmentOpsArray & lhs,const AttachmentOpsArray & rhs)4921 bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs)
4922 {
4923 return memcmp(&lhs, &rhs, sizeof(AttachmentOpsArray)) == 0;
4924 }
4925
4926 // DescriptorSetLayoutDesc implementation.
DescriptorSetLayoutDesc()4927 DescriptorSetLayoutDesc::DescriptorSetLayoutDesc()
4928 : mImmutableSamplers{}, mDescriptorSetLayoutBindings{}
4929 {}
4930
4931 DescriptorSetLayoutDesc::~DescriptorSetLayoutDesc() = default;
4932
4933 DescriptorSetLayoutDesc::DescriptorSetLayoutDesc(const DescriptorSetLayoutDesc &other) = default;
4934
4935 DescriptorSetLayoutDesc &DescriptorSetLayoutDesc::operator=(const DescriptorSetLayoutDesc &other) =
4936 default;
4937
hash() const4938 size_t DescriptorSetLayoutDesc::hash() const
4939 {
4940 size_t validDescriptorSetLayoutBindingsCount = mDescriptorSetLayoutBindings.size();
4941 size_t validImmutableSamplersCount = mImmutableSamplers.size();
4942
4943 ASSERT(validDescriptorSetLayoutBindingsCount != 0 || validImmutableSamplersCount == 0);
4944
4945 size_t genericHash = 0;
4946 if (validDescriptorSetLayoutBindingsCount > 0)
4947 {
4948 genericHash = angle::ComputeGenericHash(
4949 mDescriptorSetLayoutBindings.data(),
4950 validDescriptorSetLayoutBindingsCount * sizeof(PackedDescriptorSetBinding));
4951 }
4952
4953 if (validImmutableSamplersCount > 0)
4954 {
4955 genericHash ^= angle::ComputeGenericHash(mImmutableSamplers.data(),
4956 validImmutableSamplersCount * sizeof(VkSampler));
4957 }
4958
4959 return genericHash;
4960 }
4961
operator ==(const DescriptorSetLayoutDesc & other) const4962 bool DescriptorSetLayoutDesc::operator==(const DescriptorSetLayoutDesc &other) const
4963 {
4964 return mDescriptorSetLayoutBindings == other.mDescriptorSetLayoutBindings &&
4965 mImmutableSamplers == other.mImmutableSamplers;
4966 }
4967
addBinding(uint32_t bindingIndex,VkDescriptorType descriptorType,uint32_t count,VkShaderStageFlags stages,const Sampler * immutableSampler)4968 void DescriptorSetLayoutDesc::addBinding(uint32_t bindingIndex,
4969 VkDescriptorType descriptorType,
4970 uint32_t count,
4971 VkShaderStageFlags stages,
4972 const Sampler *immutableSampler)
4973 {
4974 ASSERT(static_cast<uint8_t>(descriptorType) != PackedDescriptorSetBinding::kInvalidType);
4975 ASSERT(static_cast<size_t>(descriptorType) < std::numeric_limits<uint8_t>::max());
4976 ASSERT(count < std::numeric_limits<uint16_t>::max());
4977 ASSERT(bindingIndex < std::numeric_limits<uint16_t>::max());
4978
4979 if (bindingIndex >= mDescriptorSetLayoutBindings.size())
4980 {
4981 PackedDescriptorSetBinding invalid = {};
4982 invalid.type = PackedDescriptorSetBinding::kInvalidType;
4983 mDescriptorSetLayoutBindings.resize(bindingIndex + 1, invalid);
4984 }
4985
4986 PackedDescriptorSetBinding &packedBinding = mDescriptorSetLayoutBindings[bindingIndex];
4987 ASSERT(packedBinding.type == PackedDescriptorSetBinding::kInvalidType);
4988 SetBitField(packedBinding.type, descriptorType);
4989 SetBitField(packedBinding.count, count);
4990 SetBitField(packedBinding.stages, stages);
4991 SetBitField(packedBinding.hasImmutableSampler, 0);
4992
4993 if (immutableSampler)
4994 {
4995 if (bindingIndex >= mImmutableSamplers.size())
4996 {
4997 mImmutableSamplers.resize(bindingIndex + 1);
4998 }
4999
5000 ASSERT(count == 1);
5001 SetBitField(packedBinding.hasImmutableSampler, 1);
5002 mImmutableSamplers[bindingIndex] = immutableSampler->getHandle();
5003 }
5004 }
5005
unpackBindings(DescriptorSetLayoutBindingVector * bindings) const5006 void DescriptorSetLayoutDesc::unpackBindings(DescriptorSetLayoutBindingVector *bindings) const
5007 {
5008 // Unpack all valid descriptor set layout bindings
5009 for (size_t bindingIndex = 0; bindingIndex < mDescriptorSetLayoutBindings.size();
5010 ++bindingIndex)
5011 {
5012 const PackedDescriptorSetBinding &packedBinding =
5013 mDescriptorSetLayoutBindings[bindingIndex];
5014 if (packedBinding.type == PackedDescriptorSetBinding::kInvalidType)
5015 {
5016 continue;
5017 }
5018
5019 ASSERT(packedBinding.count != 0);
5020
5021 VkDescriptorSetLayoutBinding binding = {};
5022 binding.binding = static_cast<uint32_t>(bindingIndex);
5023 binding.descriptorCount = packedBinding.count;
5024 binding.descriptorType = static_cast<VkDescriptorType>(packedBinding.type);
5025 binding.stageFlags = static_cast<VkShaderStageFlags>(packedBinding.stages);
5026
5027 if (packedBinding.hasImmutableSampler)
5028 {
5029 ASSERT(packedBinding.count == 1);
5030 binding.pImmutableSamplers = &mImmutableSamplers[bindingIndex];
5031 }
5032
5033 bindings->push_back(binding);
5034 }
5035 }
5036
5037 // PipelineLayoutDesc implementation.
PipelineLayoutDesc()5038 PipelineLayoutDesc::PipelineLayoutDesc()
5039 : mDescriptorSetLayouts{}, mPushConstantRange{}, mPadding(0)
5040 {}
5041
5042 PipelineLayoutDesc::~PipelineLayoutDesc() = default;
5043
5044 PipelineLayoutDesc::PipelineLayoutDesc(const PipelineLayoutDesc &other) = default;
5045
operator =(const PipelineLayoutDesc & rhs)5046 PipelineLayoutDesc &PipelineLayoutDesc::operator=(const PipelineLayoutDesc &rhs)
5047 {
5048 mDescriptorSetLayouts = rhs.mDescriptorSetLayouts;
5049 mPushConstantRange = rhs.mPushConstantRange;
5050 return *this;
5051 }
5052
hash() const5053 size_t PipelineLayoutDesc::hash() const
5054 {
5055 size_t genericHash = angle::ComputeGenericHash(mPushConstantRange);
5056 for (const DescriptorSetLayoutDesc &descriptorSetLayoutDesc : mDescriptorSetLayouts)
5057 {
5058 genericHash ^= descriptorSetLayoutDesc.hash();
5059 }
5060 return genericHash;
5061 }
5062
operator ==(const PipelineLayoutDesc & other) const5063 bool PipelineLayoutDesc::operator==(const PipelineLayoutDesc &other) const
5064 {
5065 return mPushConstantRange == other.mPushConstantRange &&
5066 mDescriptorSetLayouts == other.mDescriptorSetLayouts;
5067 }
5068
updateDescriptorSetLayout(DescriptorSetIndex setIndex,const DescriptorSetLayoutDesc & desc)5069 void PipelineLayoutDesc::updateDescriptorSetLayout(DescriptorSetIndex setIndex,
5070 const DescriptorSetLayoutDesc &desc)
5071 {
5072 mDescriptorSetLayouts[setIndex] = desc;
5073 }
5074
updatePushConstantRange(VkShaderStageFlags stageMask,uint32_t offset,uint32_t size)5075 void PipelineLayoutDesc::updatePushConstantRange(VkShaderStageFlags stageMask,
5076 uint32_t offset,
5077 uint32_t size)
5078 {
5079 SetBitField(mPushConstantRange.offset, offset);
5080 SetBitField(mPushConstantRange.size, size);
5081 SetBitField(mPushConstantRange.stageMask, stageMask);
5082 }
5083
5084 // CreateMonolithicPipelineTask implementation.
CreateMonolithicPipelineTask(Renderer * renderer,const PipelineCacheAccess & pipelineCache,const PipelineLayout & pipelineLayout,const ShaderModuleMap & shaders,const SpecializationConstants & specConsts,const GraphicsPipelineDesc & desc)5085 CreateMonolithicPipelineTask::CreateMonolithicPipelineTask(
5086 Renderer *renderer,
5087 const PipelineCacheAccess &pipelineCache,
5088 const PipelineLayout &pipelineLayout,
5089 const ShaderModuleMap &shaders,
5090 const SpecializationConstants &specConsts,
5091 const GraphicsPipelineDesc &desc)
5092 : ErrorContext(renderer),
5093 mPipelineCache(pipelineCache),
5094 mCompatibleRenderPass(nullptr),
5095 mPipelineLayout(pipelineLayout),
5096 mShaders(shaders),
5097 mSpecConsts(specConsts),
5098 mDesc(desc),
5099 mResult(VK_NOT_READY),
5100 mFeedback(CacheLookUpFeedback::None)
5101 {}
5102
setCompatibleRenderPass(const RenderPass * compatibleRenderPass)5103 void CreateMonolithicPipelineTask::setCompatibleRenderPass(const RenderPass *compatibleRenderPass)
5104 {
5105 mCompatibleRenderPass = compatibleRenderPass;
5106 }
5107
operator ()()5108 void CreateMonolithicPipelineTask::operator()()
5109 {
5110 const RenderPass unusedRenderPass;
5111 const RenderPass *compatibleRenderPass =
5112 mCompatibleRenderPass ? mCompatibleRenderPass : &unusedRenderPass;
5113
5114 ANGLE_TRACE_EVENT0("gpu.angle", "CreateMonolithicPipelineTask");
5115 mResult = mDesc.initializePipeline(this, &mPipelineCache, vk::GraphicsPipelineSubset::Complete,
5116 *compatibleRenderPass, mPipelineLayout,
5117 {&mShaders, &mSpecConsts}, &mPipeline, &mFeedback);
5118
5119 if (mRenderer->getFeatures().slowDownMonolithicPipelineCreationForTesting.enabled)
5120 {
5121 constexpr double kSlowdownTime = 0.05;
5122
5123 double startTime = angle::GetCurrentSystemTime();
5124 while (angle::GetCurrentSystemTime() - startTime < kSlowdownTime)
5125 {
5126 // Busy waiting
5127 }
5128 }
5129 }
5130
handleError(VkResult result,const char * file,const char * function,unsigned int line)5131 void CreateMonolithicPipelineTask::handleError(VkResult result,
5132 const char *file,
5133 const char *function,
5134 unsigned int line)
5135 {
5136 UNREACHABLE();
5137 }
5138
5139 // WaitableMonolithicPipelineCreationTask implementation
~WaitableMonolithicPipelineCreationTask()5140 WaitableMonolithicPipelineCreationTask::~WaitableMonolithicPipelineCreationTask()
5141 {
5142 ASSERT(!mWaitableEvent);
5143 ASSERT(!mTask);
5144 }
5145
5146 // PipelineHelper implementation.
PipelineHelper()5147 PipelineHelper::PipelineHelper()
5148 {
5149 mTransitions.reserve(8);
5150 }
5151
5152 PipelineHelper::~PipelineHelper() = default;
5153
destroy(VkDevice device)5154 void PipelineHelper::destroy(VkDevice device)
5155 {
5156 mPipeline.destroy(device);
5157 mLinkedPipelineToRelease.destroy(device);
5158
5159 // If there is a pending task, wait for it before destruction.
5160 if (mMonolithicPipelineCreationTask.isValid())
5161 {
5162 if (mMonolithicPipelineCreationTask.isPosted())
5163 {
5164 mMonolithicPipelineCreationTask.wait();
5165 mMonolithicPipelineCreationTask.getTask()->getPipeline().destroy(device);
5166 }
5167 mMonolithicPipelineCreationTask.reset();
5168 }
5169
5170 reset();
5171 }
5172
release(ErrorContext * context)5173 void PipelineHelper::release(ErrorContext *context)
5174 {
5175 Renderer *renderer = context->getRenderer();
5176
5177 renderer->collectGarbage(mUse, &mPipeline);
5178 renderer->collectGarbage(mUse, &mLinkedPipelineToRelease);
5179
5180 // If there is a pending task, wait for it before release.
5181 if (mMonolithicPipelineCreationTask.isValid())
5182 {
5183 if (mMonolithicPipelineCreationTask.isPosted())
5184 {
5185 mMonolithicPipelineCreationTask.wait();
5186 renderer->collectGarbage(mUse,
5187 &mMonolithicPipelineCreationTask.getTask()->getPipeline());
5188 }
5189 mMonolithicPipelineCreationTask.reset();
5190 }
5191
5192 reset();
5193 }
5194
reset()5195 void PipelineHelper::reset()
5196 {
5197 mCacheLookUpFeedback = CacheLookUpFeedback::None;
5198 mMonolithicCacheLookUpFeedback = CacheLookUpFeedback::None;
5199
5200 mLinkedShaders = nullptr;
5201 }
5202
getPreferredPipeline(ContextVk * contextVk,const Pipeline ** pipelineOut)5203 angle::Result PipelineHelper::getPreferredPipeline(ContextVk *contextVk,
5204 const Pipeline **pipelineOut)
5205 {
5206 if (mMonolithicPipelineCreationTask.isValid())
5207 {
5208 // If there is a monolithic task pending, attempt to post it if not already. Once the task
5209 // is done, retrieve the results and replace the pipeline.
5210 if (!mMonolithicPipelineCreationTask.isPosted())
5211 {
5212 ANGLE_TRY(contextVk->getShareGroup()->scheduleMonolithicPipelineCreationTask(
5213 contextVk, &mMonolithicPipelineCreationTask));
5214 }
5215 else if (mMonolithicPipelineCreationTask.isReady())
5216 {
5217 CreateMonolithicPipelineTask *task = &*mMonolithicPipelineCreationTask.getTask();
5218 ANGLE_VK_TRY(contextVk, task->getResult());
5219
5220 mMonolithicCacheLookUpFeedback = task->getFeedback();
5221
5222 // The pipeline will not be used anymore. Every context that has used this pipeline has
5223 // already updated the serial.
5224 mLinkedPipelineToRelease = std::move(mPipeline);
5225
5226 // Replace it with the monolithic one.
5227 mPipeline = std::move(task->getPipeline());
5228
5229 mLinkedShaders = nullptr;
5230
5231 mMonolithicPipelineCreationTask.reset();
5232
5233 ++contextVk->getPerfCounters().monolithicPipelineCreation;
5234 }
5235 }
5236
5237 *pipelineOut = &mPipeline;
5238
5239 return angle::Result::Continue;
5240 }
5241
addTransition(GraphicsPipelineTransitionBits bits,const GraphicsPipelineDesc * desc,PipelineHelper * pipeline)5242 void PipelineHelper::addTransition(GraphicsPipelineTransitionBits bits,
5243 const GraphicsPipelineDesc *desc,
5244 PipelineHelper *pipeline)
5245 {
5246 mTransitions.emplace_back(bits, desc, pipeline);
5247 }
5248
setLinkedLibraryReferences(vk::PipelineHelper * shadersPipeline)5249 void PipelineHelper::setLinkedLibraryReferences(vk::PipelineHelper *shadersPipeline)
5250 {
5251 mLinkedShaders = shadersPipeline;
5252 }
5253
retainInRenderPass(RenderPassCommandBufferHelper * renderPassCommands)5254 void PipelineHelper::retainInRenderPass(RenderPassCommandBufferHelper *renderPassCommands)
5255 {
5256 renderPassCommands->retainResource(this);
5257
5258 // Keep references to the linked libraries alive. Note that currently only need to do this for
5259 // the shaders library, as the vertex and fragment libraries live in the context until
5260 // destruction.
5261 if (mLinkedShaders != nullptr)
5262 {
5263 renderPassCommands->retainResource(mLinkedShaders);
5264 }
5265 }
5266
5267 // FramebufferHelper implementation.
5268 FramebufferHelper::FramebufferHelper() = default;
5269
5270 FramebufferHelper::~FramebufferHelper() = default;
5271
FramebufferHelper(FramebufferHelper && other)5272 FramebufferHelper::FramebufferHelper(FramebufferHelper &&other) : Resource(std::move(other))
5273 {
5274 mFramebuffer = std::move(other.mFramebuffer);
5275 }
5276
operator =(FramebufferHelper && other)5277 FramebufferHelper &FramebufferHelper::operator=(FramebufferHelper &&other)
5278 {
5279 Resource::operator=(std::move(other));
5280 std::swap(mFramebuffer, other.mFramebuffer);
5281 return *this;
5282 }
5283
init(ErrorContext * context,const VkFramebufferCreateInfo & createInfo)5284 angle::Result FramebufferHelper::init(ErrorContext *context,
5285 const VkFramebufferCreateInfo &createInfo)
5286 {
5287 ANGLE_VK_TRY(context, mFramebuffer.init(context->getDevice(), createInfo));
5288 return angle::Result::Continue;
5289 }
5290
destroy(Renderer * renderer)5291 void FramebufferHelper::destroy(Renderer *renderer)
5292 {
5293 mFramebuffer.destroy(renderer->getDevice());
5294 }
5295
release(ContextVk * contextVk)5296 void FramebufferHelper::release(ContextVk *contextVk)
5297 {
5298 contextVk->addGarbage(&mFramebuffer);
5299 }
5300
5301 // DescriptorSetDesc implementation.
hash() const5302 size_t DescriptorSetDesc::hash() const
5303 {
5304 if (mDescriptorInfos.empty())
5305 {
5306 return 0;
5307 }
5308
5309 return angle::ComputeGenericHash(mDescriptorInfos.data(),
5310 sizeof(mDescriptorInfos[0]) * mDescriptorInfos.size());
5311 }
5312
5313 // FramebufferDesc implementation.
5314
FramebufferDesc()5315 FramebufferDesc::FramebufferDesc()
5316 {
5317 reset();
5318 }
5319
5320 FramebufferDesc::~FramebufferDesc() = default;
5321 FramebufferDesc::FramebufferDesc(const FramebufferDesc &other) = default;
5322 FramebufferDesc &FramebufferDesc::operator=(const FramebufferDesc &other) = default;
5323
update(uint32_t index,ImageOrBufferViewSubresourceSerial serial)5324 void FramebufferDesc::update(uint32_t index, ImageOrBufferViewSubresourceSerial serial)
5325 {
5326 static_assert(kMaxFramebufferAttachments + 1 < std::numeric_limits<uint8_t>::max(),
5327 "mMaxIndex size is too small");
5328 ASSERT(index < kMaxFramebufferAttachments);
5329 mSerials[index] = serial;
5330 if (serial.viewSerial.valid())
5331 {
5332 SetBitField(mMaxIndex, std::max(mMaxIndex, static_cast<uint16_t>(index + 1)));
5333 }
5334 }
5335
updateColor(uint32_t index,ImageOrBufferViewSubresourceSerial serial)5336 void FramebufferDesc::updateColor(uint32_t index, ImageOrBufferViewSubresourceSerial serial)
5337 {
5338 update(kFramebufferDescColorIndexOffset + index, serial);
5339 }
5340
updateColorResolve(uint32_t index,ImageOrBufferViewSubresourceSerial serial)5341 void FramebufferDesc::updateColorResolve(uint32_t index, ImageOrBufferViewSubresourceSerial serial)
5342 {
5343 update(kFramebufferDescColorResolveIndexOffset + index, serial);
5344 }
5345
updateUnresolveMask(FramebufferNonResolveAttachmentMask unresolveMask)5346 void FramebufferDesc::updateUnresolveMask(FramebufferNonResolveAttachmentMask unresolveMask)
5347 {
5348 SetBitField(mUnresolveAttachmentMask, unresolveMask.bits());
5349 }
5350
updateDepthStencil(ImageOrBufferViewSubresourceSerial serial)5351 void FramebufferDesc::updateDepthStencil(ImageOrBufferViewSubresourceSerial serial)
5352 {
5353 update(kFramebufferDescDepthStencilIndex, serial);
5354 }
5355
updateDepthStencilResolve(ImageOrBufferViewSubresourceSerial serial)5356 void FramebufferDesc::updateDepthStencilResolve(ImageOrBufferViewSubresourceSerial serial)
5357 {
5358 update(kFramebufferDescDepthStencilResolveIndexOffset, serial);
5359 }
5360
updateFragmentShadingRate(ImageOrBufferViewSubresourceSerial serial)5361 void FramebufferDesc::updateFragmentShadingRate(ImageOrBufferViewSubresourceSerial serial)
5362 {
5363 update(kFramebufferDescFragmentShadingRateAttachmentIndexOffset, serial);
5364 }
5365
hasFragmentShadingRateAttachment() const5366 bool FramebufferDesc::hasFragmentShadingRateAttachment() const
5367 {
5368 return mSerials[kFramebufferDescFragmentShadingRateAttachmentIndexOffset].viewSerial.valid();
5369 }
5370
hash() const5371 size_t FramebufferDesc::hash() const
5372 {
5373 return angle::ComputeGenericHash(&mSerials, sizeof(mSerials[0]) * mMaxIndex) ^
5374 mHasColorFramebufferFetch << 26 ^ mIsRenderToTexture << 25 ^ mLayerCount << 16 ^
5375 mUnresolveAttachmentMask;
5376 }
5377
reset()5378 void FramebufferDesc::reset()
5379 {
5380 mMaxIndex = 0;
5381 mHasColorFramebufferFetch = false;
5382 mLayerCount = 0;
5383 mSrgbWriteControlMode = 0;
5384 mUnresolveAttachmentMask = 0;
5385 mIsRenderToTexture = 0;
5386 // An empty FramebufferDesc is still a valid desc. It becomes invalid when it is explicitly
5387 // destroyed or released by SharedFramebufferCacheKey.
5388 mIsValid = 1;
5389 memset(&mSerials, 0, sizeof(mSerials));
5390 }
5391
operator ==(const FramebufferDesc & other) const5392 bool FramebufferDesc::operator==(const FramebufferDesc &other) const
5393 {
5394 if (mMaxIndex != other.mMaxIndex || mLayerCount != other.mLayerCount ||
5395 mUnresolveAttachmentMask != other.mUnresolveAttachmentMask ||
5396 mHasColorFramebufferFetch != other.mHasColorFramebufferFetch ||
5397 mSrgbWriteControlMode != other.mSrgbWriteControlMode ||
5398 mIsRenderToTexture != other.mIsRenderToTexture)
5399 {
5400 return false;
5401 }
5402
5403 size_t validRegionSize = sizeof(mSerials[0]) * mMaxIndex;
5404 return memcmp(&mSerials, &other.mSerials, validRegionSize) == 0;
5405 }
5406
attachmentCount() const5407 uint32_t FramebufferDesc::attachmentCount() const
5408 {
5409 uint32_t count = 0;
5410 for (const ImageOrBufferViewSubresourceSerial &serial : mSerials)
5411 {
5412 if (serial.viewSerial.valid())
5413 {
5414 count++;
5415 }
5416 }
5417 return count;
5418 }
5419
getUnresolveAttachmentMask() const5420 FramebufferNonResolveAttachmentMask FramebufferDesc::getUnresolveAttachmentMask() const
5421 {
5422 return FramebufferNonResolveAttachmentMask(mUnresolveAttachmentMask);
5423 }
5424
updateLayerCount(uint32_t layerCount)5425 void FramebufferDesc::updateLayerCount(uint32_t layerCount)
5426 {
5427 SetBitField(mLayerCount, layerCount);
5428 }
5429
setColorFramebufferFetchMode(bool hasColorFramebufferFetch)5430 void FramebufferDesc::setColorFramebufferFetchMode(bool hasColorFramebufferFetch)
5431 {
5432 SetBitField(mHasColorFramebufferFetch, hasColorFramebufferFetch);
5433 }
5434
updateRenderToTexture(bool isRenderToTexture)5435 void FramebufferDesc::updateRenderToTexture(bool isRenderToTexture)
5436 {
5437 SetBitField(mIsRenderToTexture, isRenderToTexture);
5438 }
5439
destroyCachedObject(Renderer * renderer)5440 void FramebufferDesc::destroyCachedObject(Renderer *renderer)
5441 {
5442 ASSERT(valid());
5443 // Framebuffer cache are implemented in a way that each cache entry tracks GPU progress and we
5444 // always guarantee cache entries are released before calling destroy.
5445 SetBitField(mIsValid, 0);
5446 }
5447
releaseCachedObject(ContextVk * contextVk)5448 void FramebufferDesc::releaseCachedObject(ContextVk *contextVk)
5449 {
5450 ASSERT(valid());
5451 contextVk->getShareGroup()->getFramebufferCache().erase(contextVk, *this);
5452 SetBitField(mIsValid, 0);
5453 }
5454
hasValidCachedObject(ContextVk * contextVk) const5455 bool FramebufferDesc::hasValidCachedObject(ContextVk *contextVk) const
5456 {
5457 ASSERT(valid());
5458 Framebuffer framebuffer;
5459 return contextVk->getShareGroup()->getFramebufferCache().get(contextVk, *this, framebuffer);
5460 }
5461
5462 // YcbcrConversionDesc implementation
YcbcrConversionDesc()5463 YcbcrConversionDesc::YcbcrConversionDesc()
5464 {
5465 reset();
5466 }
5467
5468 YcbcrConversionDesc::~YcbcrConversionDesc() = default;
5469
5470 YcbcrConversionDesc::YcbcrConversionDesc(const YcbcrConversionDesc &other) = default;
5471
5472 YcbcrConversionDesc &YcbcrConversionDesc::operator=(const YcbcrConversionDesc &rhs) = default;
5473
hash() const5474 size_t YcbcrConversionDesc::hash() const
5475 {
5476 return angle::ComputeGenericHash(*this);
5477 }
5478
operator ==(const YcbcrConversionDesc & other) const5479 bool YcbcrConversionDesc::operator==(const YcbcrConversionDesc &other) const
5480 {
5481 return memcmp(this, &other, sizeof(YcbcrConversionDesc)) == 0;
5482 }
5483
reset()5484 void YcbcrConversionDesc::reset()
5485 {
5486 mExternalOrVkFormat = 0;
5487 mIsExternalFormat = 0;
5488 mConversionModel = 0;
5489 mColorRange = 0;
5490 mXChromaOffset = 0;
5491 mYChromaOffset = 0;
5492 mChromaFilter = 0;
5493 mRSwizzle = 0;
5494 mGSwizzle = 0;
5495 mBSwizzle = 0;
5496 mASwizzle = 0;
5497 mLinearFilterSupported = 0;
5498 mPadding = 0;
5499 mReserved = 0;
5500 }
5501
update(Renderer * renderer,uint64_t externalFormat,VkSamplerYcbcrModelConversion conversionModel,VkSamplerYcbcrRange colorRange,VkChromaLocation xChromaOffset,VkChromaLocation yChromaOffset,VkFilter chromaFilter,VkComponentMapping components,angle::FormatID intendedFormatID,YcbcrLinearFilterSupport linearFilterSupported)5502 void YcbcrConversionDesc::update(Renderer *renderer,
5503 uint64_t externalFormat,
5504 VkSamplerYcbcrModelConversion conversionModel,
5505 VkSamplerYcbcrRange colorRange,
5506 VkChromaLocation xChromaOffset,
5507 VkChromaLocation yChromaOffset,
5508 VkFilter chromaFilter,
5509 VkComponentMapping components,
5510 angle::FormatID intendedFormatID,
5511 YcbcrLinearFilterSupport linearFilterSupported)
5512 {
5513 const vk::Format &vkFormat = renderer->getFormat(intendedFormatID);
5514 ASSERT(externalFormat != 0 || vkFormat.getIntendedFormat().isYUV);
5515
5516 SetBitField(mIsExternalFormat, (externalFormat) ? 1 : 0);
5517 SetBitField(mLinearFilterSupported,
5518 linearFilterSupported == YcbcrLinearFilterSupport::Supported);
5519 mExternalOrVkFormat =
5520 (externalFormat) ? externalFormat
5521 : vkFormat.getActualImageVkFormat(renderer, vk::ImageAccess::SampleOnly);
5522
5523 updateChromaFilter(renderer, chromaFilter);
5524
5525 SetBitField(mConversionModel, conversionModel);
5526 SetBitField(mColorRange, colorRange);
5527 SetBitField(mXChromaOffset, xChromaOffset);
5528 SetBitField(mYChromaOffset, yChromaOffset);
5529 SetBitField(mRSwizzle, components.r);
5530 SetBitField(mGSwizzle, components.g);
5531 SetBitField(mBSwizzle, components.b);
5532 SetBitField(mASwizzle, components.a);
5533 }
5534
updateChromaFilter(Renderer * renderer,VkFilter filter)5535 bool YcbcrConversionDesc::updateChromaFilter(Renderer *renderer, VkFilter filter)
5536 {
5537 // The app has requested a specific min/mag filter, reconcile that with the filter
5538 // requested by preferLinearFilterForYUV feature.
5539 //
5540 // preferLinearFilterForYUV enforces linear filter while forceNearestFiltering and
5541 // forceNearestMipFiltering enforces nearest filter, enabling one precludes the other.
5542 ASSERT(!renderer->getFeatures().preferLinearFilterForYUV.enabled ||
5543 (!renderer->getFeatures().forceNearestFiltering.enabled &&
5544 !renderer->getFeatures().forceNearestMipFiltering.enabled));
5545
5546 VkFilter preferredChromaFilter = renderer->getPreferredFilterForYUV(filter);
5547 ASSERT(preferredChromaFilter == VK_FILTER_LINEAR || preferredChromaFilter == VK_FILTER_NEAREST);
5548
5549 if (preferredChromaFilter == VK_FILTER_LINEAR && !mLinearFilterSupported)
5550 {
5551 // Vulkan implementations may not support linear filtering in all cases. If not supported,
5552 // use nearest filtering instead.
5553 preferredChromaFilter = VK_FILTER_NEAREST;
5554 }
5555
5556 if (getChromaFilter() != preferredChromaFilter)
5557 {
5558 SetBitField(mChromaFilter, preferredChromaFilter);
5559 return true;
5560 }
5561 return false;
5562 }
5563
updateConversionModel(VkSamplerYcbcrModelConversion conversionModel)5564 void YcbcrConversionDesc::updateConversionModel(VkSamplerYcbcrModelConversion conversionModel)
5565 {
5566 SetBitField(mConversionModel, conversionModel);
5567 }
5568
init(ErrorContext * context,SamplerYcbcrConversion * conversionOut) const5569 angle::Result YcbcrConversionDesc::init(ErrorContext *context,
5570 SamplerYcbcrConversion *conversionOut) const
5571 {
5572 // Create the VkSamplerYcbcrConversion
5573 VkSamplerYcbcrConversionCreateInfo samplerYcbcrConversionInfo = {};
5574 samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
5575 samplerYcbcrConversionInfo.format =
5576 getExternalFormat() == 0 ? static_cast<VkFormat>(mExternalOrVkFormat) : VK_FORMAT_UNDEFINED;
5577 samplerYcbcrConversionInfo.xChromaOffset = static_cast<VkChromaLocation>(mXChromaOffset);
5578 samplerYcbcrConversionInfo.yChromaOffset = static_cast<VkChromaLocation>(mYChromaOffset);
5579 samplerYcbcrConversionInfo.ycbcrModel =
5580 static_cast<VkSamplerYcbcrModelConversion>(mConversionModel);
5581 samplerYcbcrConversionInfo.ycbcrRange = static_cast<VkSamplerYcbcrRange>(mColorRange);
5582 samplerYcbcrConversionInfo.chromaFilter = static_cast<VkFilter>(mChromaFilter);
5583 samplerYcbcrConversionInfo.components = {
5584 static_cast<VkComponentSwizzle>(mRSwizzle), static_cast<VkComponentSwizzle>(mGSwizzle),
5585 static_cast<VkComponentSwizzle>(mBSwizzle), static_cast<VkComponentSwizzle>(mASwizzle)};
5586
5587 #ifdef VK_USE_PLATFORM_ANDROID_KHR
5588 VkExternalFormatANDROID externalFormat = {};
5589 if (getExternalFormat() != 0)
5590 {
5591 externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
5592 externalFormat.externalFormat = mExternalOrVkFormat;
5593 samplerYcbcrConversionInfo.pNext = &externalFormat;
5594 }
5595 #else
5596 // We do not support external format for any platform other than Android.
5597 ASSERT(mIsExternalFormat == 0);
5598 #endif // VK_USE_PLATFORM_ANDROID_KHR
5599
5600 ANGLE_VK_TRY(context, conversionOut->init(context->getDevice(), samplerYcbcrConversionInfo));
5601 return angle::Result::Continue;
5602 }
5603
5604 // SamplerDesc implementation.
SamplerDesc()5605 SamplerDesc::SamplerDesc()
5606 {
5607 reset();
5608 }
5609
5610 SamplerDesc::~SamplerDesc() = default;
5611
5612 SamplerDesc::SamplerDesc(const SamplerDesc &other) = default;
5613
5614 SamplerDesc &SamplerDesc::operator=(const SamplerDesc &rhs) = default;
5615
SamplerDesc(ErrorContext * context,const gl::SamplerState & samplerState,bool stencilMode,const YcbcrConversionDesc * ycbcrConversionDesc,angle::FormatID intendedFormatID)5616 SamplerDesc::SamplerDesc(ErrorContext *context,
5617 const gl::SamplerState &samplerState,
5618 bool stencilMode,
5619 const YcbcrConversionDesc *ycbcrConversionDesc,
5620 angle::FormatID intendedFormatID)
5621 {
5622 update(context->getRenderer(), samplerState, stencilMode, ycbcrConversionDesc,
5623 intendedFormatID);
5624 }
5625
reset()5626 void SamplerDesc::reset()
5627 {
5628 mMipLodBias = 0.0f;
5629 mMaxAnisotropy = 0.0f;
5630 mMinLod = 0.0f;
5631 mMaxLod = 0.0f;
5632 mYcbcrConversionDesc.reset();
5633 mMagFilter = 0;
5634 mMinFilter = 0;
5635 mMipmapMode = 0;
5636 mAddressModeU = 0;
5637 mAddressModeV = 0;
5638 mAddressModeW = 0;
5639 mCompareEnabled = 0;
5640 mCompareOp = 0;
5641 mPadding = 0;
5642 mBorderColorType = 0;
5643 mBorderColor.red = 0.0f;
5644 mBorderColor.green = 0.0f;
5645 mBorderColor.blue = 0.0f;
5646 mBorderColor.alpha = 0.0f;
5647 mReserved = 0;
5648 }
5649
update(Renderer * renderer,const gl::SamplerState & samplerState,bool stencilMode,const YcbcrConversionDesc * ycbcrConversionDesc,angle::FormatID intendedFormatID)5650 void SamplerDesc::update(Renderer *renderer,
5651 const gl::SamplerState &samplerState,
5652 bool stencilMode,
5653 const YcbcrConversionDesc *ycbcrConversionDesc,
5654 angle::FormatID intendedFormatID)
5655 {
5656 const angle::FeaturesVk &featuresVk = renderer->getFeatures();
5657 mMipLodBias = 0.0f;
5658 if (featuresVk.forceTextureLodOffset1.enabled)
5659 {
5660 mMipLodBias = 1.0f;
5661 }
5662 else if (featuresVk.forceTextureLodOffset2.enabled)
5663 {
5664 mMipLodBias = 2.0f;
5665 }
5666 else if (featuresVk.forceTextureLodOffset3.enabled)
5667 {
5668 mMipLodBias = 3.0f;
5669 }
5670 else if (featuresVk.forceTextureLodOffset4.enabled)
5671 {
5672 mMipLodBias = 4.0f;
5673 }
5674
5675 mMaxAnisotropy = samplerState.getMaxAnisotropy();
5676 mMinLod = samplerState.getMinLod();
5677 mMaxLod = samplerState.getMaxLod();
5678
5679 GLenum minFilter = samplerState.getMinFilter();
5680 GLenum magFilter = samplerState.getMagFilter();
5681 if (ycbcrConversionDesc && ycbcrConversionDesc->valid())
5682 {
5683 // Update the SamplerYcbcrConversionCache key
5684 mYcbcrConversionDesc = *ycbcrConversionDesc;
5685
5686 // Reconcile chroma filter and min/mag filters.
5687 //
5688 // VUID-VkSamplerCreateInfo-minFilter-01645
5689 // If sampler YCBCR conversion is enabled and the potential format features of the
5690 // sampler YCBCR conversion do not support
5691 // VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT,
5692 // minFilter and magFilter must be equal to the sampler YCBCR conversions chromaFilter.
5693 //
5694 // For simplicity assume external formats do not support that feature bit.
5695 ASSERT((mYcbcrConversionDesc.getExternalFormat() != 0) ||
5696 (angle::Format::Get(intendedFormatID).isYUV));
5697 const bool filtersMustMatch =
5698 (mYcbcrConversionDesc.getExternalFormat() != 0) ||
5699 !renderer->hasImageFormatFeatureBits(
5700 intendedFormatID,
5701 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT);
5702 if (filtersMustMatch)
5703 {
5704 GLenum glFilter = (mYcbcrConversionDesc.getChromaFilter() == VK_FILTER_LINEAR)
5705 ? GL_LINEAR
5706 : GL_NEAREST;
5707 minFilter = glFilter;
5708 magFilter = glFilter;
5709 }
5710 }
5711
5712 bool compareEnable = samplerState.getCompareMode() == GL_COMPARE_REF_TO_TEXTURE;
5713 VkCompareOp compareOp = gl_vk::GetCompareOp(samplerState.getCompareFunc());
5714 // When sampling from stencil, deqp tests expect texture compare to have no effect
5715 // dEQP - GLES31.functional.stencil_texturing.misc.compare_mode_effect
5716 // states: NOTE: Texture compare mode has no effect when reading stencil values.
5717 if (stencilMode)
5718 {
5719 compareEnable = VK_FALSE;
5720 compareOp = VK_COMPARE_OP_ALWAYS;
5721 }
5722
5723 if (featuresVk.forceNearestFiltering.enabled)
5724 {
5725 magFilter = gl::ConvertToNearestFilterMode(magFilter);
5726 minFilter = gl::ConvertToNearestFilterMode(minFilter);
5727 }
5728 if (featuresVk.forceNearestMipFiltering.enabled)
5729 {
5730 minFilter = gl::ConvertToNearestMipFilterMode(minFilter);
5731 }
5732
5733 SetBitField(mMagFilter, gl_vk::GetFilter(magFilter));
5734 SetBitField(mMinFilter, gl_vk::GetFilter(minFilter));
5735 SetBitField(mMipmapMode, gl_vk::GetSamplerMipmapMode(samplerState.getMinFilter()));
5736 SetBitField(mAddressModeU, gl_vk::GetSamplerAddressMode(samplerState.getWrapS()));
5737 SetBitField(mAddressModeV, gl_vk::GetSamplerAddressMode(samplerState.getWrapT()));
5738 SetBitField(mAddressModeW, gl_vk::GetSamplerAddressMode(samplerState.getWrapR()));
5739 SetBitField(mCompareEnabled, compareEnable);
5740 SetBitField(mCompareOp, compareOp);
5741
5742 if (!gl::IsMipmapFiltered(minFilter))
5743 {
5744 // Per the Vulkan spec, GL_NEAREST and GL_LINEAR do not map directly to Vulkan, so
5745 // they must be emulated (See "Mapping of OpenGL to Vulkan filter modes")
5746 SetBitField(mMipmapMode, VK_SAMPLER_MIPMAP_MODE_NEAREST);
5747 mMinLod = 0.0f;
5748 mMaxLod = 0.25f;
5749 }
5750
5751 mPadding = 0;
5752
5753 mBorderColorType =
5754 (samplerState.getBorderColor().type == angle::ColorGeneric::Type::Float) ? 0 : 1;
5755
5756 // Adjust border color according to intended format
5757 const vk::Format &vkFormat = renderer->getFormat(intendedFormatID);
5758 gl::ColorGeneric adjustedBorderColor =
5759 AdjustBorderColor(samplerState.getBorderColor(), vkFormat.getIntendedFormat(), stencilMode);
5760 mBorderColor = adjustedBorderColor.colorF;
5761
5762 mReserved = 0;
5763 }
5764
init(ContextVk * contextVk,Sampler * sampler) const5765 angle::Result SamplerDesc::init(ContextVk *contextVk, Sampler *sampler) const
5766 {
5767 const gl::Extensions &extensions = contextVk->getExtensions();
5768
5769 bool anisotropyEnable = extensions.textureFilterAnisotropicEXT && mMaxAnisotropy > 1.0f;
5770
5771 VkSamplerCreateInfo createInfo = {};
5772 createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
5773 createInfo.flags = 0;
5774 createInfo.magFilter = static_cast<VkFilter>(mMagFilter);
5775 createInfo.minFilter = static_cast<VkFilter>(mMinFilter);
5776 createInfo.mipmapMode = static_cast<VkSamplerMipmapMode>(mMipmapMode);
5777 createInfo.addressModeU = static_cast<VkSamplerAddressMode>(mAddressModeU);
5778 createInfo.addressModeV = static_cast<VkSamplerAddressMode>(mAddressModeV);
5779 createInfo.addressModeW = static_cast<VkSamplerAddressMode>(mAddressModeW);
5780 createInfo.mipLodBias = mMipLodBias;
5781 createInfo.anisotropyEnable = anisotropyEnable;
5782 createInfo.maxAnisotropy = mMaxAnisotropy;
5783 createInfo.compareEnable = mCompareEnabled ? VK_TRUE : VK_FALSE;
5784 createInfo.compareOp = static_cast<VkCompareOp>(mCompareOp);
5785 createInfo.minLod = mMinLod;
5786 createInfo.maxLod = mMaxLod;
5787 createInfo.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
5788 createInfo.unnormalizedCoordinates = VK_FALSE;
5789
5790 VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {};
5791 if (mYcbcrConversionDesc.valid())
5792 {
5793 ASSERT((contextVk->getFeatures().supportsYUVSamplerConversion.enabled));
5794 samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
5795 samplerYcbcrConversionInfo.pNext = nullptr;
5796 ANGLE_TRY(contextVk->getRenderer()->getYuvConversionCache().getSamplerYcbcrConversion(
5797 contextVk, mYcbcrConversionDesc, &samplerYcbcrConversionInfo.conversion));
5798 AddToPNextChain(&createInfo, &samplerYcbcrConversionInfo);
5799
5800 // Vulkan spec requires these settings:
5801 createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5802 createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5803 createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5804 createInfo.anisotropyEnable = VK_FALSE;
5805 createInfo.unnormalizedCoordinates = VK_FALSE;
5806 }
5807
5808 VkSamplerCustomBorderColorCreateInfoEXT customBorderColorInfo = {};
5809 if (createInfo.addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
5810 createInfo.addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
5811 createInfo.addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER)
5812 {
5813 ASSERT((contextVk->getFeatures().supportsCustomBorderColor.enabled));
5814 customBorderColorInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT;
5815
5816 customBorderColorInfo.customBorderColor.float32[0] = mBorderColor.red;
5817 customBorderColorInfo.customBorderColor.float32[1] = mBorderColor.green;
5818 customBorderColorInfo.customBorderColor.float32[2] = mBorderColor.blue;
5819 customBorderColorInfo.customBorderColor.float32[3] = mBorderColor.alpha;
5820
5821 if (mBorderColorType == static_cast<uint32_t>(angle::ColorGeneric::Type::Float))
5822 {
5823 createInfo.borderColor = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT;
5824 }
5825 else
5826 {
5827 createInfo.borderColor = VK_BORDER_COLOR_INT_CUSTOM_EXT;
5828 }
5829
5830 vk::AddToPNextChain(&createInfo, &customBorderColorInfo);
5831 }
5832 ANGLE_VK_TRY(contextVk, sampler->init(contextVk->getDevice(), createInfo));
5833
5834 return angle::Result::Continue;
5835 }
5836
hash() const5837 size_t SamplerDesc::hash() const
5838 {
5839 return angle::ComputeGenericHash(*this);
5840 }
5841
operator ==(const SamplerDesc & other) const5842 bool SamplerDesc::operator==(const SamplerDesc &other) const
5843 {
5844 return memcmp(this, &other, sizeof(SamplerDesc)) == 0;
5845 }
5846
SamplerHelper(SamplerHelper && samplerHelper)5847 SamplerHelper::SamplerHelper(SamplerHelper &&samplerHelper)
5848 {
5849 *this = std::move(samplerHelper);
5850 }
5851
operator =(SamplerHelper && rhs)5852 SamplerHelper &SamplerHelper::operator=(SamplerHelper &&rhs)
5853 {
5854 std::swap(mSampler, rhs.mSampler);
5855 std::swap(mSamplerSerial, rhs.mSamplerSerial);
5856 return *this;
5857 }
5858
init(ErrorContext * context,const VkSamplerCreateInfo & createInfo)5859 angle::Result SamplerHelper::init(ErrorContext *context, const VkSamplerCreateInfo &createInfo)
5860 {
5861 mSamplerSerial = context->getRenderer()->getResourceSerialFactory().generateSamplerSerial();
5862 ANGLE_VK_TRY(context, mSampler.init(context->getDevice(), createInfo));
5863 return angle::Result::Continue;
5864 }
init(ContextVk * contextVk,const SamplerDesc & desc)5865 angle::Result SamplerHelper::init(ContextVk *contextVk, const SamplerDesc &desc)
5866 {
5867 mSamplerSerial = contextVk->getRenderer()->getResourceSerialFactory().generateSamplerSerial();
5868 return desc.init(contextVk, &mSampler);
5869 }
5870
5871 // RenderPassHelper implementation.
RenderPassHelper()5872 RenderPassHelper::RenderPassHelper() : mPerfCounters{} {}
5873
5874 RenderPassHelper::~RenderPassHelper() = default;
5875
RenderPassHelper(RenderPassHelper && other)5876 RenderPassHelper::RenderPassHelper(RenderPassHelper &&other)
5877 {
5878 *this = std::move(other);
5879 }
5880
operator =(RenderPassHelper && other)5881 RenderPassHelper &RenderPassHelper::operator=(RenderPassHelper &&other)
5882 {
5883 mRenderPass = std::move(other.mRenderPass);
5884 mPerfCounters = std::move(other.mPerfCounters);
5885 return *this;
5886 }
5887
destroy(VkDevice device)5888 void RenderPassHelper::destroy(VkDevice device)
5889 {
5890 mRenderPass.destroy(device);
5891 }
5892
release(ContextVk * contextVk)5893 void RenderPassHelper::release(ContextVk *contextVk)
5894 {
5895 contextVk->addGarbage(&mRenderPass);
5896 }
5897
getRenderPass() const5898 const RenderPass &RenderPassHelper::getRenderPass() const
5899 {
5900 return mRenderPass;
5901 }
5902
getRenderPass()5903 RenderPass &RenderPassHelper::getRenderPass()
5904 {
5905 return mRenderPass;
5906 }
5907
getPerfCounters() const5908 const RenderPassPerfCounters &RenderPassHelper::getPerfCounters() const
5909 {
5910 return mPerfCounters;
5911 }
5912
getPerfCounters()5913 RenderPassPerfCounters &RenderPassHelper::getPerfCounters()
5914 {
5915 return mPerfCounters;
5916 }
5917
5918 // WriteDescriptorDescs implementation.
updateWriteDesc(uint32_t bindingIndex,VkDescriptorType descriptorType,uint32_t descriptorCount)5919 void WriteDescriptorDescs::updateWriteDesc(uint32_t bindingIndex,
5920 VkDescriptorType descriptorType,
5921 uint32_t descriptorCount)
5922 {
5923 if (hasWriteDescAtIndex(bindingIndex))
5924 {
5925 uint32_t infoIndex = mDescs[bindingIndex].descriptorInfoIndex;
5926 uint32_t oldDescriptorCount = mDescs[bindingIndex].descriptorCount;
5927 if (descriptorCount != oldDescriptorCount)
5928 {
5929 ASSERT(infoIndex + oldDescriptorCount == mCurrentInfoIndex);
5930 ASSERT(descriptorCount > oldDescriptorCount);
5931 uint32_t additionalDescriptors = descriptorCount - oldDescriptorCount;
5932 incrementDescriptorCount(bindingIndex, additionalDescriptors);
5933 mCurrentInfoIndex += additionalDescriptors;
5934 }
5935 }
5936 else
5937 {
5938 WriteDescriptorDesc &writeDesc = mDescs[bindingIndex];
5939 SetBitField(writeDesc.binding, bindingIndex);
5940 SetBitField(writeDesc.descriptorCount, descriptorCount);
5941 SetBitField(writeDesc.descriptorType, descriptorType);
5942 SetBitField(writeDesc.descriptorInfoIndex, mCurrentInfoIndex);
5943 mCurrentInfoIndex += descriptorCount;
5944 ASSERT(writeDesc.descriptorCount > 0);
5945 }
5946 }
5947
updateShaderBuffers(const ShaderInterfaceVariableInfoMap & variableInfoMap,const std::vector<gl::InterfaceBlock> & blocks,VkDescriptorType descriptorType)5948 void WriteDescriptorDescs::updateShaderBuffers(
5949 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5950 const std::vector<gl::InterfaceBlock> &blocks,
5951 VkDescriptorType descriptorType)
5952 {
5953 // Initialize the descriptor writes in a first pass. This ensures we can pack the structures
5954 // corresponding to array elements tightly.
5955 for (uint32_t blockIndex = 0; blockIndex < blocks.size(); ++blockIndex)
5956 {
5957 const gl::InterfaceBlock &block = blocks[blockIndex];
5958
5959 if (block.activeShaders().none())
5960 {
5961 continue;
5962 }
5963
5964 const gl::ShaderType firstShaderType = block.getFirstActiveShaderType();
5965 const ShaderInterfaceVariableInfo &info =
5966 variableInfoMap.getVariableById(firstShaderType, block.getId(firstShaderType));
5967
5968 if (block.pod.isArray && block.pod.arrayElement > 0)
5969 {
5970 incrementDescriptorCount(info.binding, 1);
5971 mCurrentInfoIndex++;
5972 }
5973 else
5974 {
5975 updateWriteDesc(info.binding, descriptorType, 1);
5976 }
5977 }
5978 }
5979
updateAtomicCounters(const ShaderInterfaceVariableInfoMap & variableInfoMap,const std::vector<gl::AtomicCounterBuffer> & atomicCounterBuffers)5980 void WriteDescriptorDescs::updateAtomicCounters(
5981 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5982 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers)
5983 {
5984 if (atomicCounterBuffers.empty())
5985 {
5986 return;
5987 }
5988
5989 static_assert(!IsDynamicDescriptor(kStorageBufferDescriptorType),
5990 "This method needs an update to handle dynamic descriptors");
5991
5992 uint32_t binding = variableInfoMap.getAtomicCounterBufferBinding(
5993 atomicCounterBuffers[0].getFirstActiveShaderType(), 0);
5994
5995 updateWriteDesc(binding, kStorageBufferDescriptorType,
5996 gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS);
5997 }
5998
updateImages(const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap)5999 void WriteDescriptorDescs::updateImages(const gl::ProgramExecutable &executable,
6000 const ShaderInterfaceVariableInfoMap &variableInfoMap)
6001 {
6002 const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings();
6003 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
6004
6005 if (imageBindings.empty())
6006 {
6007 return;
6008 }
6009
6010 for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
6011 {
6012 const gl::ImageBinding &imageBinding = imageBindings[imageIndex];
6013 uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex);
6014 const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
6015
6016 if (imageUniform.activeShaders().none())
6017 {
6018 continue;
6019 }
6020
6021 const gl::ShaderType firstShaderType = imageUniform.getFirstActiveShaderType();
6022 const ShaderInterfaceVariableInfo &info =
6023 variableInfoMap.getVariableById(firstShaderType, imageUniform.getId(firstShaderType));
6024
6025 uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
6026 uint32_t descriptorCount = arraySize * imageUniform.getOuterArraySizeProduct();
6027 VkDescriptorType descriptorType = (imageBinding.textureType == gl::TextureType::Buffer)
6028 ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
6029 : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
6030
6031 updateWriteDesc(info.binding, descriptorType, descriptorCount);
6032 }
6033 }
6034
updateInputAttachments(const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,FramebufferVk * framebufferVk)6035 void WriteDescriptorDescs::updateInputAttachments(
6036 const gl::ProgramExecutable &executable,
6037 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6038 FramebufferVk *framebufferVk)
6039 {
6040 if (framebufferVk->getDepthStencilRenderTarget() != nullptr)
6041 {
6042 if (executable.usesDepthFramebufferFetch())
6043 {
6044 const uint32_t depthBinding =
6045 variableInfoMap
6046 .getVariableById(gl::ShaderType::Fragment,
6047 sh::vk::spirv::kIdDepthInputAttachment)
6048 .binding;
6049 updateWriteDesc(depthBinding, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1);
6050 }
6051
6052 if (executable.usesStencilFramebufferFetch())
6053 {
6054 const uint32_t stencilBinding =
6055 variableInfoMap
6056 .getVariableById(gl::ShaderType::Fragment,
6057 sh::vk::spirv::kIdStencilInputAttachment)
6058 .binding;
6059 updateWriteDesc(stencilBinding, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1);
6060 }
6061 }
6062
6063 if (!executable.usesColorFramebufferFetch())
6064 {
6065 return;
6066 }
6067
6068 const uint32_t firstColorInputAttachment =
6069 static_cast<uint32_t>(executable.getFragmentInoutIndices().first());
6070
6071 const ShaderInterfaceVariableInfo &baseColorInfo = variableInfoMap.getVariableById(
6072 gl::ShaderType::Fragment, sh::vk::spirv::kIdInputAttachment0 + firstColorInputAttachment);
6073
6074 const uint32_t baseColorBinding = baseColorInfo.binding - firstColorInputAttachment;
6075
6076 for (size_t colorIndex : framebufferVk->getState().getColorAttachmentsMask())
6077 {
6078 uint32_t binding = baseColorBinding + static_cast<uint32_t>(colorIndex);
6079 updateWriteDesc(binding, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1);
6080 }
6081 }
6082
updateExecutableActiveTextures(const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ProgramExecutable & executable)6083 void WriteDescriptorDescs::updateExecutableActiveTextures(
6084 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6085 const gl::ProgramExecutable &executable)
6086 {
6087 const std::vector<gl::SamplerBinding> &samplerBindings = executable.getSamplerBindings();
6088 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
6089
6090 for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
6091 {
6092 const gl::SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
6093 uint32_t uniformIndex = executable.getUniformIndexFromSamplerIndex(samplerIndex);
6094 const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
6095
6096 if (samplerUniform.activeShaders().none())
6097 {
6098 continue;
6099 }
6100
6101 const gl::ShaderType firstShaderType = samplerUniform.getFirstActiveShaderType();
6102 const ShaderInterfaceVariableInfo &info =
6103 variableInfoMap.getVariableById(firstShaderType, samplerUniform.getId(firstShaderType));
6104
6105 uint32_t arraySize = static_cast<uint32_t>(samplerBinding.textureUnitsCount);
6106 uint32_t descriptorCount = arraySize * samplerUniform.getOuterArraySizeProduct();
6107 VkDescriptorType descriptorType = (samplerBinding.textureType == gl::TextureType::Buffer)
6108 ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
6109 : VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
6110
6111 updateWriteDesc(info.binding, descriptorType, descriptorCount);
6112 }
6113 }
6114
updateDefaultUniform(gl::ShaderBitSet shaderTypes,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ProgramExecutable & executable)6115 void WriteDescriptorDescs::updateDefaultUniform(
6116 gl::ShaderBitSet shaderTypes,
6117 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6118 const gl::ProgramExecutable &executable)
6119 {
6120 for (const gl::ShaderType shaderType : shaderTypes)
6121 {
6122 uint32_t binding = variableInfoMap.getDefaultUniformBinding(shaderType);
6123 updateWriteDesc(binding, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1);
6124 }
6125 }
6126
updateTransformFeedbackWrite(const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ProgramExecutable & executable)6127 void WriteDescriptorDescs::updateTransformFeedbackWrite(
6128 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6129 const gl::ProgramExecutable &executable)
6130 {
6131 uint32_t xfbBufferCount = static_cast<uint32_t>(executable.getTransformFeedbackBufferCount());
6132 updateWriteDesc(variableInfoMap.getEmulatedXfbBufferBinding(0),
6133 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, xfbBufferCount);
6134 }
6135
updateDynamicDescriptorsCount()6136 void WriteDescriptorDescs::updateDynamicDescriptorsCount()
6137 {
6138 mDynamicDescriptorSetCount = 0;
6139 for (uint32_t index = 0; index < mDescs.size(); ++index)
6140 {
6141 const WriteDescriptorDesc &writeDesc = mDescs[index];
6142 if (IsDynamicDescriptor(static_cast<VkDescriptorType>(writeDesc.descriptorType)))
6143 {
6144 mDynamicDescriptorSetCount += writeDesc.descriptorCount;
6145 }
6146 }
6147 }
6148
operator <<(std::ostream & os,const WriteDescriptorDescs & desc)6149 std::ostream &operator<<(std::ostream &os, const WriteDescriptorDescs &desc)
6150 {
6151 os << " WriteDescriptorDescs[" << desc.size() << "]:";
6152 for (uint32_t index = 0; index < desc.size(); ++index)
6153 {
6154 const WriteDescriptorDesc &writeDesc = desc[index];
6155 os << static_cast<int>(writeDesc.binding) << ": "
6156 << static_cast<int>(writeDesc.descriptorCount) << ": "
6157 << kDescriptorTypeNameMap[writeDesc.descriptorType] << ": "
6158 << writeDesc.descriptorInfoIndex;
6159 }
6160 return os;
6161 }
6162
6163 // DescriptorSetDesc implementation.
updateDescriptorSet(Renderer * renderer,const WriteDescriptorDescs & writeDescriptorDescs,UpdateDescriptorSetsBuilder * updateBuilder,const DescriptorDescHandles * handles,VkDescriptorSet descriptorSet) const6164 void DescriptorSetDesc::updateDescriptorSet(Renderer *renderer,
6165 const WriteDescriptorDescs &writeDescriptorDescs,
6166 UpdateDescriptorSetsBuilder *updateBuilder,
6167 const DescriptorDescHandles *handles,
6168 VkDescriptorSet descriptorSet) const
6169 {
6170 for (uint32_t writeIndex = 0; writeIndex < writeDescriptorDescs.size(); ++writeIndex)
6171 {
6172 const WriteDescriptorDesc &writeDesc = writeDescriptorDescs[writeIndex];
6173
6174 if (writeDesc.descriptorCount == 0)
6175 {
6176 continue;
6177 }
6178
6179 VkWriteDescriptorSet &writeSet = updateBuilder->allocWriteDescriptorSet();
6180
6181 writeSet.descriptorCount = writeDesc.descriptorCount;
6182 writeSet.descriptorType = static_cast<VkDescriptorType>(writeDesc.descriptorType);
6183 writeSet.dstArrayElement = 0;
6184 writeSet.dstBinding = writeIndex;
6185 writeSet.dstSet = descriptorSet;
6186 writeSet.pBufferInfo = nullptr;
6187 writeSet.pImageInfo = nullptr;
6188 writeSet.pNext = nullptr;
6189 writeSet.pTexelBufferView = nullptr;
6190 writeSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
6191
6192 uint32_t infoDescIndex = writeDesc.descriptorInfoIndex;
6193
6194 switch (writeSet.descriptorType)
6195 {
6196 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
6197 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
6198 {
6199 ASSERT(writeDesc.descriptorCount == 1);
6200 VkBufferView &bufferView = updateBuilder->allocBufferView();
6201 bufferView = handles[infoDescIndex].bufferView;
6202 writeSet.pTexelBufferView = &bufferView;
6203 break;
6204 }
6205 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
6206 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
6207 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
6208 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
6209 {
6210 VkDescriptorBufferInfo *writeBuffers =
6211 updateBuilder->allocDescriptorBufferInfos(writeSet.descriptorCount);
6212 for (uint32_t arrayElement = 0; arrayElement < writeSet.descriptorCount;
6213 ++arrayElement)
6214 {
6215 const DescriptorInfoDesc &infoDesc =
6216 mDescriptorInfos[infoDescIndex + arrayElement];
6217 VkDescriptorBufferInfo &bufferInfo = writeBuffers[arrayElement];
6218 bufferInfo.buffer = handles[infoDescIndex + arrayElement].buffer;
6219 bufferInfo.offset = infoDesc.imageViewSerialOrOffset;
6220 bufferInfo.range = infoDesc.imageLayoutOrRange;
6221 }
6222 writeSet.pBufferInfo = writeBuffers;
6223 break;
6224 }
6225 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
6226 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
6227 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
6228 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
6229 {
6230 VkDescriptorImageInfo *writeImages =
6231 updateBuilder->allocDescriptorImageInfos(writeSet.descriptorCount);
6232 for (uint32_t arrayElement = 0; arrayElement < writeSet.descriptorCount;
6233 ++arrayElement)
6234 {
6235 const DescriptorInfoDesc &infoDesc =
6236 mDescriptorInfos[infoDescIndex + arrayElement];
6237 VkDescriptorImageInfo &imageInfo = writeImages[arrayElement];
6238
6239 imageInfo.imageLayout = static_cast<VkImageLayout>(infoDesc.imageLayoutOrRange);
6240 imageInfo.imageView = handles[infoDescIndex + arrayElement].imageView;
6241 imageInfo.sampler = handles[infoDescIndex + arrayElement].sampler;
6242 }
6243 writeSet.pImageInfo = writeImages;
6244 break;
6245 }
6246
6247 default:
6248 UNREACHABLE();
6249 break;
6250 }
6251 }
6252 }
6253
operator <<(std::ostream & os,const DescriptorSetDesc & desc)6254 std::ostream &operator<<(std::ostream &os, const DescriptorSetDesc &desc)
6255 {
6256 os << " desc[" << desc.size() << "]:";
6257 for (uint32_t index = 0; index < desc.size(); ++index)
6258 {
6259 const DescriptorInfoDesc &infoDesc = desc.getInfoDesc(index);
6260 os << "{" << infoDesc.samplerOrBufferSerial << ", " << infoDesc.imageViewSerialOrOffset
6261 << ", " << infoDesc.imageLayoutOrRange << ", " << infoDesc.imageSubresourceRange << "}";
6262 }
6263 return os;
6264 }
6265
6266 // DescriptorSetDescAndPool implementation
destroyCachedObject(Renderer * renderer)6267 void DescriptorSetDescAndPool::destroyCachedObject(Renderer *renderer)
6268 {
6269 ASSERT(valid());
6270 mPool->destroyCachedDescriptorSet(renderer, mDesc);
6271 mPool = nullptr;
6272 }
6273
releaseCachedObject(Renderer * renderer)6274 void DescriptorSetDescAndPool::releaseCachedObject(Renderer *renderer)
6275 {
6276 ASSERT(valid());
6277 mPool->releaseCachedDescriptorSet(renderer, mDesc);
6278 mPool = nullptr;
6279 }
6280
hasValidCachedObject(ContextVk * contextVk) const6281 bool DescriptorSetDescAndPool::hasValidCachedObject(ContextVk *contextVk) const
6282 {
6283 ASSERT(valid());
6284 return mPool->hasCachedDescriptorSet(mDesc);
6285 }
6286
6287 // DescriptorSetDescBuilder implementation.
6288 DescriptorSetDescBuilder::DescriptorSetDescBuilder() = default;
DescriptorSetDescBuilder(size_t descriptorCount)6289 DescriptorSetDescBuilder::DescriptorSetDescBuilder(size_t descriptorCount)
6290 {
6291 resize(descriptorCount);
6292 }
6293
~DescriptorSetDescBuilder()6294 DescriptorSetDescBuilder::~DescriptorSetDescBuilder() {}
6295
DescriptorSetDescBuilder(const DescriptorSetDescBuilder & other)6296 DescriptorSetDescBuilder::DescriptorSetDescBuilder(const DescriptorSetDescBuilder &other)
6297 : mDesc(other.mDesc), mHandles(other.mHandles), mDynamicOffsets(other.mDynamicOffsets)
6298 {}
6299
operator =(const DescriptorSetDescBuilder & other)6300 DescriptorSetDescBuilder &DescriptorSetDescBuilder::operator=(const DescriptorSetDescBuilder &other)
6301 {
6302 mDesc = other.mDesc;
6303 mHandles = other.mHandles;
6304 mDynamicOffsets = other.mDynamicOffsets;
6305 return *this;
6306 }
6307
updateUniformBuffer(uint32_t bindingIndex,const WriteDescriptorDescs & writeDescriptorDescs,const BufferHelper & bufferHelper,VkDeviceSize bufferRange)6308 void DescriptorSetDescBuilder::updateUniformBuffer(uint32_t bindingIndex,
6309 const WriteDescriptorDescs &writeDescriptorDescs,
6310 const BufferHelper &bufferHelper,
6311 VkDeviceSize bufferRange)
6312 {
6313 uint32_t infoIndex = writeDescriptorDescs[bindingIndex].descriptorInfoIndex;
6314 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6315
6316 infoDesc.samplerOrBufferSerial = bufferHelper.getBlockSerial().getValue();
6317 infoDesc.imageViewSerialOrOffset = 0;
6318 SetBitField(infoDesc.imageLayoutOrRange, bufferRange);
6319 infoDesc.imageSubresourceRange = 0;
6320
6321 mHandles[infoIndex].buffer = bufferHelper.getBuffer().getHandle();
6322 }
6323
updateTransformFeedbackBuffer(const Context * context,const ShaderInterfaceVariableInfoMap & variableInfoMap,const WriteDescriptorDescs & writeDescriptorDescs,uint32_t xfbBufferIndex,const BufferHelper & bufferHelper,VkDeviceSize bufferOffset,VkDeviceSize bufferRange)6324 void DescriptorSetDescBuilder::updateTransformFeedbackBuffer(
6325 const Context *context,
6326 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6327 const WriteDescriptorDescs &writeDescriptorDescs,
6328 uint32_t xfbBufferIndex,
6329 const BufferHelper &bufferHelper,
6330 VkDeviceSize bufferOffset,
6331 VkDeviceSize bufferRange)
6332 {
6333 const uint32_t baseBinding = variableInfoMap.getEmulatedXfbBufferBinding(0);
6334
6335 Renderer *renderer = context->getRenderer();
6336 VkDeviceSize offsetAlignment =
6337 renderer->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
6338 // Set the offset as close as possible to the requested offset while remaining aligned.
6339 VkDeviceSize alignedOffset = (bufferOffset / offsetAlignment) * offsetAlignment;
6340 VkDeviceSize adjustedRange = bufferRange + (bufferOffset - alignedOffset);
6341
6342 uint32_t infoIndex = writeDescriptorDescs[baseBinding].descriptorInfoIndex + xfbBufferIndex;
6343 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6344 infoDesc.samplerOrBufferSerial = bufferHelper.getBufferSerial().getValue();
6345 SetBitField(infoDesc.imageViewSerialOrOffset, alignedOffset);
6346 SetBitField(infoDesc.imageLayoutOrRange, adjustedRange);
6347 infoDesc.imageSubresourceRange = 0;
6348
6349 mHandles[infoIndex].buffer = bufferHelper.getBuffer().getHandle();
6350 }
6351
updateUniformsAndXfb(Context * context,const gl::ProgramExecutable & executable,const WriteDescriptorDescs & writeDescriptorDescs,const BufferHelper * currentUniformBuffer,const BufferHelper & emptyBuffer,bool activeUnpaused,TransformFeedbackVk * transformFeedbackVk)6352 void DescriptorSetDescBuilder::updateUniformsAndXfb(
6353 Context *context,
6354 const gl::ProgramExecutable &executable,
6355 const WriteDescriptorDescs &writeDescriptorDescs,
6356 const BufferHelper *currentUniformBuffer,
6357 const BufferHelper &emptyBuffer,
6358 bool activeUnpaused,
6359 TransformFeedbackVk *transformFeedbackVk)
6360 {
6361 const ProgramExecutableVk *executableVk = vk::GetImpl(&executable);
6362 gl::ShaderBitSet linkedStages = executable.getLinkedShaderStages();
6363
6364 const ShaderInterfaceVariableInfoMap &variableInfoMap = executableVk->getVariableInfoMap();
6365
6366 for (const gl::ShaderType shaderType : linkedStages)
6367 {
6368 uint32_t binding = variableInfoMap.getDefaultUniformBinding(shaderType);
6369 VkDeviceSize bufferRange = executableVk->getDefaultUniformAlignedSize(context, shaderType);
6370 if (bufferRange == 0)
6371 {
6372 updateUniformBuffer(binding, writeDescriptorDescs, emptyBuffer, emptyBuffer.getSize());
6373 }
6374 else
6375 {
6376 ASSERT(currentUniformBuffer);
6377 updateUniformBuffer(binding, writeDescriptorDescs, *currentUniformBuffer, bufferRange);
6378 }
6379
6380 if (transformFeedbackVk && shaderType == gl::ShaderType::Vertex &&
6381 context->getFeatures().emulateTransformFeedback.enabled)
6382 {
6383 transformFeedbackVk->updateTransformFeedbackDescriptorDesc(
6384 context, executable, variableInfoMap, writeDescriptorDescs, emptyBuffer,
6385 activeUnpaused, this);
6386 }
6387 }
6388 }
6389
updatePreCacheActiveTextures(Context * context,const gl::ProgramExecutable & executable,const gl::ActiveTextureArray<TextureVk * > & textures,const gl::SamplerBindingVector & samplers)6390 void DescriptorSetDescBuilder::updatePreCacheActiveTextures(
6391 Context *context,
6392 const gl::ProgramExecutable &executable,
6393 const gl::ActiveTextureArray<TextureVk *> &textures,
6394 const gl::SamplerBindingVector &samplers)
6395 {
6396 const std::vector<gl::SamplerBinding> &samplerBindings = executable.getSamplerBindings();
6397 const gl::ActiveTextureMask &activeTextures = executable.getActiveSamplersMask();
6398 const ProgramExecutableVk *executableVk = vk::GetImpl(&executable);
6399
6400 resize(executableVk->getTextureWriteDescriptorDescs().getTotalDescriptorCount());
6401 const WriteDescriptorDescs &writeDescriptorDescs =
6402 executableVk->getTextureWriteDescriptorDescs();
6403
6404 const ShaderInterfaceVariableInfoMap &variableInfoMap = executableVk->getVariableInfoMap();
6405 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
6406
6407 for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
6408 {
6409 const gl::SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
6410 uint16_t arraySize = samplerBinding.textureUnitsCount;
6411 bool isSamplerExternalY2Y = samplerBinding.samplerType == GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT;
6412
6413 uint32_t uniformIndex = executable.getUniformIndexFromSamplerIndex(samplerIndex);
6414 const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
6415
6416 if (samplerUniform.activeShaders().none())
6417 {
6418 continue;
6419 }
6420
6421 const gl::ShaderType firstShaderType = samplerUniform.getFirstActiveShaderType();
6422 const ShaderInterfaceVariableInfo &info =
6423 variableInfoMap.getVariableById(firstShaderType, samplerUniform.getId(firstShaderType));
6424
6425 for (uint16_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
6426 {
6427 GLuint textureUnit = samplerBinding.getTextureUnit(
6428 executable.getSamplerBoundTextureUnits(), arrayElement);
6429 if (!activeTextures.test(textureUnit))
6430 continue;
6431 TextureVk *textureVk = textures[textureUnit];
6432
6433 uint32_t infoIndex = writeDescriptorDescs[info.binding].descriptorInfoIndex +
6434 arrayElement + samplerUniform.getOuterArrayOffset();
6435 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6436
6437 if (textureVk->getState().getType() == gl::TextureType::Buffer)
6438 {
6439 ImageOrBufferViewSubresourceSerial imageViewSerial =
6440 textureVk->getBufferViewSerial();
6441 infoDesc.imageViewSerialOrOffset = imageViewSerial.viewSerial.getValue();
6442 infoDesc.imageLayoutOrRange = 0;
6443 infoDesc.samplerOrBufferSerial = 0;
6444 infoDesc.imageSubresourceRange = 0;
6445 }
6446 else
6447 {
6448 gl::Sampler *sampler = samplers[textureUnit].get();
6449 const SamplerVk *samplerVk = sampler ? vk::GetImpl(sampler) : nullptr;
6450
6451 const SamplerHelper &samplerHelper =
6452 samplerVk ? samplerVk->getSampler()
6453 : textureVk->getSampler(isSamplerExternalY2Y);
6454 const gl::SamplerState &samplerState =
6455 sampler ? sampler->getSamplerState() : textureVk->getState().getSamplerState();
6456
6457 ImageOrBufferViewSubresourceSerial imageViewSerial =
6458 textureVk->getImageViewSubresourceSerial(
6459 samplerState, samplerUniform.isTexelFetchStaticUse());
6460
6461 VkImageLayout imageLayout = textureVk->getImage().getCurrentLayout();
6462 SetBitField(infoDesc.imageLayoutOrRange, imageLayout);
6463 infoDesc.imageViewSerialOrOffset = imageViewSerial.viewSerial.getValue();
6464 infoDesc.samplerOrBufferSerial = samplerHelper.getSamplerSerial().getValue();
6465 memcpy(&infoDesc.imageSubresourceRange, &imageViewSerial.subresource,
6466 sizeof(uint32_t));
6467 }
6468 }
6469 }
6470 }
6471
setEmptyBuffer(uint32_t infoDescIndex,VkDescriptorType descriptorType,const BufferHelper & emptyBuffer)6472 void DescriptorSetDescBuilder::setEmptyBuffer(uint32_t infoDescIndex,
6473 VkDescriptorType descriptorType,
6474 const BufferHelper &emptyBuffer)
6475 {
6476 DescriptorInfoDesc &emptyDesc = mDesc.getInfoDesc(infoDescIndex);
6477 SetBitField(emptyDesc.imageLayoutOrRange, emptyBuffer.getSize());
6478 emptyDesc.imageViewSerialOrOffset = 0;
6479 emptyDesc.samplerOrBufferSerial = emptyBuffer.getBlockSerial().getValue();
6480
6481 mHandles[infoDescIndex].buffer = emptyBuffer.getBuffer().getHandle();
6482
6483 if (IsDynamicDescriptor(descriptorType))
6484 {
6485 mDynamicOffsets[infoDescIndex] = 0;
6486 }
6487 }
6488
6489 template <typename CommandBufferT>
updateOneShaderBuffer(Context * context,CommandBufferT * commandBufferHelper,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::BufferVector & buffers,const gl::InterfaceBlock & block,uint32_t bufferIndex,VkDescriptorType descriptorType,VkDeviceSize maxBoundBufferRange,const BufferHelper & emptyBuffer,const WriteDescriptorDescs & writeDescriptorDescs,const GLbitfield memoryBarrierBits)6490 void DescriptorSetDescBuilder::updateOneShaderBuffer(
6491 Context *context,
6492 CommandBufferT *commandBufferHelper,
6493 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6494 const gl::BufferVector &buffers,
6495 const gl::InterfaceBlock &block,
6496 uint32_t bufferIndex,
6497 VkDescriptorType descriptorType,
6498 VkDeviceSize maxBoundBufferRange,
6499 const BufferHelper &emptyBuffer,
6500 const WriteDescriptorDescs &writeDescriptorDescs,
6501 const GLbitfield memoryBarrierBits)
6502 {
6503 if (block.activeShaders().none())
6504 {
6505 return;
6506 }
6507
6508 const gl::ShaderType firstShaderType = block.getFirstActiveShaderType();
6509 const ShaderInterfaceVariableInfo &info =
6510 variableInfoMap.getVariableById(firstShaderType, block.getId(firstShaderType));
6511
6512 uint32_t binding = info.binding;
6513 uint32_t arrayElement = block.pod.isArray ? block.pod.arrayElement : 0;
6514 uint32_t infoDescIndex = writeDescriptorDescs[binding].descriptorInfoIndex + arrayElement;
6515
6516 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = buffers[bufferIndex];
6517 if (bufferBinding.get() == nullptr)
6518 {
6519 setEmptyBuffer(infoDescIndex, descriptorType, emptyBuffer);
6520 return;
6521 }
6522
6523 // Limit bound buffer size to maximum resource binding size.
6524 GLsizeiptr boundBufferSize = gl::GetBoundBufferAvailableSize(bufferBinding);
6525 VkDeviceSize size = std::min<VkDeviceSize>(boundBufferSize, maxBoundBufferRange);
6526
6527 // Make sure there's no possible under/overflow with binding size.
6528 static_assert(sizeof(VkDeviceSize) >= sizeof(bufferBinding.getSize()),
6529 "VkDeviceSize too small");
6530 ASSERT(bufferBinding.getSize() >= 0);
6531
6532 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
6533 BufferHelper &bufferHelper = bufferVk->getBuffer();
6534
6535 const bool isUniformBuffer = descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
6536 descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
6537 if (isUniformBuffer)
6538 {
6539 commandBufferHelper->bufferRead(context, VK_ACCESS_UNIFORM_READ_BIT, block.activeShaders(),
6540 &bufferHelper);
6541 }
6542 else
6543 {
6544 ASSERT(descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
6545 descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
6546 if (block.pod.isReadOnly)
6547 {
6548 // Avoid unnecessary barriers for readonly SSBOs by making sure the buffers are
6549 // marked read-only. This also helps BufferVk make better decisions during
6550 // buffer data uploads and copies by knowing that the buffers are not actually
6551 // being written to.
6552 commandBufferHelper->bufferRead(context, VK_ACCESS_SHADER_READ_BIT,
6553 block.activeShaders(), &bufferHelper);
6554 }
6555 else if ((bufferHelper.getCurrentWriteAccess() & VK_ACCESS_SHADER_WRITE_BIT) != 0 &&
6556 (memoryBarrierBits & kBufferMemoryBarrierBits) == 0)
6557 {
6558 // Buffer is already in shader write access, and this is not from memoryBarrier call,
6559 // then skip the WAW barrier since GL spec says driver is not required to insert barrier
6560 // here. We still need to maintain object life time tracking here.
6561 // Based on discussion here https://gitlab.khronos.org/opengl/API/-/issues/144, the
6562 // above check of VK_ACCESS_SHADER_WRITE_BIT bit can be removed and instead rely on app
6563 // issue glMemoryBarrier. But almost all usage I am seeing does not issue
6564 // glMemoryBarrier before SSBO write. They only issue glMemoryBarrier after the SSBO
6565 // write. This is to ensure we do not break the existing usage even if we think they are
6566 // out of spec.
6567 commandBufferHelper->retainResourceForWrite(&bufferHelper);
6568 }
6569 else
6570 {
6571 // We set the SHADER_READ_BIT to be conservative.
6572 VkAccessFlags accessFlags = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6573 commandBufferHelper->bufferWrite(context, accessFlags, block.activeShaders(),
6574 &bufferHelper);
6575 }
6576 }
6577
6578 VkDeviceSize offset = bufferBinding.getOffset() + bufferHelper.getOffset();
6579
6580 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoDescIndex);
6581 infoDesc.samplerOrBufferSerial = bufferHelper.getBlockSerial().getValue();
6582 if (IsDynamicDescriptor(descriptorType))
6583 {
6584 SetBitField(mDynamicOffsets[infoDescIndex], offset);
6585 infoDesc.imageViewSerialOrOffset = 0;
6586 }
6587 else
6588 {
6589 SetBitField(infoDesc.imageViewSerialOrOffset, offset);
6590 }
6591 SetBitField(infoDesc.imageLayoutOrRange, size);
6592 infoDesc.imageSubresourceRange = 0;
6593
6594 mHandles[infoDescIndex].buffer = bufferHelper.getBuffer().getHandle();
6595 }
6596
6597 template <typename CommandBufferT>
updateShaderBuffers(Context * context,CommandBufferT * commandBufferHelper,const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::BufferVector & buffers,const std::vector<gl::InterfaceBlock> & blocks,VkDescriptorType descriptorType,VkDeviceSize maxBoundBufferRange,const BufferHelper & emptyBuffer,const WriteDescriptorDescs & writeDescriptorDescs,const GLbitfield memoryBarrierBits)6598 void DescriptorSetDescBuilder::updateShaderBuffers(
6599 Context *context,
6600 CommandBufferT *commandBufferHelper,
6601 const gl::ProgramExecutable &executable,
6602 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6603 const gl::BufferVector &buffers,
6604 const std::vector<gl::InterfaceBlock> &blocks,
6605 VkDescriptorType descriptorType,
6606 VkDeviceSize maxBoundBufferRange,
6607 const BufferHelper &emptyBuffer,
6608 const WriteDescriptorDescs &writeDescriptorDescs,
6609 const GLbitfield memoryBarrierBits)
6610 {
6611 const bool isUniformBuffer = descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
6612 descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
6613
6614 // Now that we have the proper array elements counts, initialize the info structures.
6615 for (uint32_t blockIndex = 0; blockIndex < blocks.size(); ++blockIndex)
6616 {
6617 const GLuint binding = isUniformBuffer
6618 ? executable.getUniformBlockBinding(blockIndex)
6619 : executable.getShaderStorageBlockBinding(blockIndex);
6620 updateOneShaderBuffer(context, commandBufferHelper, variableInfoMap, buffers,
6621 blocks[blockIndex], binding, descriptorType, maxBoundBufferRange,
6622 emptyBuffer, writeDescriptorDescs, memoryBarrierBits);
6623 }
6624 }
6625
6626 template <typename CommandBufferT>
updateAtomicCounters(Context * context,CommandBufferT * commandBufferHelper,const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::BufferVector & buffers,const std::vector<gl::AtomicCounterBuffer> & atomicCounterBuffers,const VkDeviceSize requiredOffsetAlignment,const BufferHelper & emptyBuffer,const WriteDescriptorDescs & writeDescriptorDescs)6627 void DescriptorSetDescBuilder::updateAtomicCounters(
6628 Context *context,
6629 CommandBufferT *commandBufferHelper,
6630 const gl::ProgramExecutable &executable,
6631 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6632 const gl::BufferVector &buffers,
6633 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
6634 const VkDeviceSize requiredOffsetAlignment,
6635 const BufferHelper &emptyBuffer,
6636 const WriteDescriptorDescs &writeDescriptorDescs)
6637 {
6638 ASSERT(!atomicCounterBuffers.empty());
6639 static_assert(!IsDynamicDescriptor(kStorageBufferDescriptorType),
6640 "This method needs an update to handle dynamic descriptors");
6641
6642 if (atomicCounterBuffers.empty())
6643 {
6644 return;
6645 }
6646
6647 uint32_t binding = variableInfoMap.getAtomicCounterBufferBinding(
6648 atomicCounterBuffers[0].getFirstActiveShaderType(), 0);
6649 uint32_t baseInfoIndex = writeDescriptorDescs[binding].descriptorInfoIndex;
6650
6651 // Bind the empty buffer to every array slot that's unused.
6652 for (uint32_t arrayElement = 0;
6653 arrayElement < gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS; ++arrayElement)
6654 {
6655 uint32_t infoIndex = baseInfoIndex + arrayElement;
6656 setEmptyBuffer(infoIndex, kStorageBufferDescriptorType, emptyBuffer);
6657 }
6658
6659 for (uint32_t bufferIndex = 0; bufferIndex < atomicCounterBuffers.size(); ++bufferIndex)
6660 {
6661 const gl::AtomicCounterBuffer &atomicCounterBuffer = atomicCounterBuffers[bufferIndex];
6662 const GLuint arrayElement = executable.getAtomicCounterBufferBinding(bufferIndex);
6663 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = buffers[arrayElement];
6664
6665 uint32_t infoIndex = baseInfoIndex + arrayElement;
6666
6667 if (bufferBinding.get() == nullptr)
6668 {
6669 setEmptyBuffer(infoIndex, kStorageBufferDescriptorType, emptyBuffer);
6670 continue;
6671 }
6672
6673 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
6674 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
6675
6676 VkAccessFlags accessFlags = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6677 commandBufferHelper->bufferWrite(context, accessFlags, atomicCounterBuffer.activeShaders(),
6678 &bufferHelper);
6679
6680 VkDeviceSize offset = bufferBinding.getOffset() + bufferHelper.getOffset();
6681
6682 VkDeviceSize alignedOffset = (offset / requiredOffsetAlignment) * requiredOffsetAlignment;
6683 VkDeviceSize offsetDiff = offset - alignedOffset;
6684
6685 offset = alignedOffset;
6686
6687 VkDeviceSize range = gl::GetBoundBufferAvailableSize(bufferBinding) + offsetDiff;
6688
6689 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6690 SetBitField(infoDesc.imageLayoutOrRange, range);
6691 SetBitField(infoDesc.imageViewSerialOrOffset, offset);
6692 infoDesc.samplerOrBufferSerial = bufferHelper.getBlockSerial().getValue();
6693 infoDesc.imageSubresourceRange = 0;
6694
6695 mHandles[infoIndex].buffer = bufferHelper.getBuffer().getHandle();
6696 }
6697 }
6698
6699 // Explicit instantiation
6700 template void DescriptorSetDescBuilder::updateOneShaderBuffer<vk::RenderPassCommandBufferHelper>(
6701 Context *context,
6702 RenderPassCommandBufferHelper *commandBufferHelper,
6703 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6704 const gl::BufferVector &buffers,
6705 const gl::InterfaceBlock &block,
6706 uint32_t bufferIndex,
6707 VkDescriptorType descriptorType,
6708 VkDeviceSize maxBoundBufferRange,
6709 const BufferHelper &emptyBuffer,
6710 const WriteDescriptorDescs &writeDescriptorDescs,
6711 const GLbitfield memoryBarrierBits);
6712
6713 template void DescriptorSetDescBuilder::updateOneShaderBuffer<OutsideRenderPassCommandBufferHelper>(
6714 Context *context,
6715 OutsideRenderPassCommandBufferHelper *commandBufferHelper,
6716 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6717 const gl::BufferVector &buffers,
6718 const gl::InterfaceBlock &block,
6719 uint32_t bufferIndex,
6720 VkDescriptorType descriptorType,
6721 VkDeviceSize maxBoundBufferRange,
6722 const BufferHelper &emptyBuffer,
6723 const WriteDescriptorDescs &writeDescriptorDescs,
6724 const GLbitfield memoryBarrierBits);
6725
6726 template void DescriptorSetDescBuilder::updateShaderBuffers<OutsideRenderPassCommandBufferHelper>(
6727 Context *context,
6728 OutsideRenderPassCommandBufferHelper *commandBufferHelper,
6729 const gl::ProgramExecutable &executable,
6730 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6731 const gl::BufferVector &buffers,
6732 const std::vector<gl::InterfaceBlock> &blocks,
6733 VkDescriptorType descriptorType,
6734 VkDeviceSize maxBoundBufferRange,
6735 const BufferHelper &emptyBuffer,
6736 const WriteDescriptorDescs &writeDescriptorDescs,
6737 const GLbitfield memoryBarrierBits);
6738
6739 template void DescriptorSetDescBuilder::updateShaderBuffers<RenderPassCommandBufferHelper>(
6740 Context *context,
6741 RenderPassCommandBufferHelper *commandBufferHelper,
6742 const gl::ProgramExecutable &executable,
6743 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6744 const gl::BufferVector &buffers,
6745 const std::vector<gl::InterfaceBlock> &blocks,
6746 VkDescriptorType descriptorType,
6747 VkDeviceSize maxBoundBufferRange,
6748 const BufferHelper &emptyBuffer,
6749 const WriteDescriptorDescs &writeDescriptorDescs,
6750 const GLbitfield memoryBarrierBits);
6751
6752 template void DescriptorSetDescBuilder::updateAtomicCounters<OutsideRenderPassCommandBufferHelper>(
6753 Context *context,
6754 OutsideRenderPassCommandBufferHelper *commandBufferHelper,
6755 const gl::ProgramExecutable &executable,
6756 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6757 const gl::BufferVector &buffers,
6758 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
6759 const VkDeviceSize requiredOffsetAlignment,
6760 const BufferHelper &emptyBuffer,
6761 const WriteDescriptorDescs &writeDescriptorDescs);
6762
6763 template void DescriptorSetDescBuilder::updateAtomicCounters<RenderPassCommandBufferHelper>(
6764 Context *context,
6765 RenderPassCommandBufferHelper *commandBufferHelper,
6766 const gl::ProgramExecutable &executable,
6767 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6768 const gl::BufferVector &buffers,
6769 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
6770 const VkDeviceSize requiredOffsetAlignment,
6771 const BufferHelper &emptyBuffer,
6772 const WriteDescriptorDescs &writeDescriptorDescs);
6773
updateImages(Context * context,const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ActiveTextureArray<TextureVk * > & activeImages,const std::vector<gl::ImageUnit> & imageUnits,const WriteDescriptorDescs & writeDescriptorDescs)6774 angle::Result DescriptorSetDescBuilder::updateImages(
6775 Context *context,
6776 const gl::ProgramExecutable &executable,
6777 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6778 const gl::ActiveTextureArray<TextureVk *> &activeImages,
6779 const std::vector<gl::ImageUnit> &imageUnits,
6780 const WriteDescriptorDescs &writeDescriptorDescs)
6781 {
6782 Renderer *renderer = context->getRenderer();
6783 const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings();
6784 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
6785
6786 if (imageBindings.empty())
6787 {
6788 return angle::Result::Continue;
6789 }
6790
6791 for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
6792 {
6793 const gl::ImageBinding &imageBinding = imageBindings[imageIndex];
6794 uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex);
6795 const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
6796
6797 if (imageUniform.activeShaders().none())
6798 {
6799 continue;
6800 }
6801
6802 const gl::ShaderType firstShaderType = imageUniform.getFirstActiveShaderType();
6803 const ShaderInterfaceVariableInfo &info =
6804 variableInfoMap.getVariableById(firstShaderType, imageUniform.getId(firstShaderType));
6805
6806 uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
6807
6808 // Texture buffers use buffer views, so they are especially handled.
6809 if (imageBinding.textureType == gl::TextureType::Buffer)
6810 {
6811 // Handle format reinterpretation by looking for a view with the format specified in
6812 // the shader (if any, instead of the format specified to glTexBuffer).
6813 const vk::Format *format = nullptr;
6814 if (imageUniform.getImageUnitFormat() != GL_NONE)
6815 {
6816 format = &renderer->getFormat(imageUniform.getImageUnitFormat());
6817 }
6818
6819 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
6820 {
6821 GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
6822 TextureVk *textureVk = activeImages[imageUnit];
6823
6824 uint32_t infoIndex = writeDescriptorDescs[info.binding].descriptorInfoIndex +
6825 arrayElement + imageUniform.getOuterArrayOffset();
6826
6827 const vk::BufferView *view = nullptr;
6828 ANGLE_TRY(textureVk->getBufferView(context, format, nullptr, true, &view));
6829
6830 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6831 infoDesc.imageViewSerialOrOffset =
6832 textureVk->getBufferViewSerial().viewSerial.getValue();
6833 infoDesc.imageLayoutOrRange = 0;
6834 infoDesc.imageSubresourceRange = 0;
6835 infoDesc.samplerOrBufferSerial = 0;
6836
6837 mHandles[infoIndex].bufferView = view->getHandle();
6838 }
6839 }
6840 else
6841 {
6842 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
6843 {
6844 GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
6845 const gl::ImageUnit &binding = imageUnits[imageUnit];
6846 TextureVk *textureVk = activeImages[imageUnit];
6847
6848 vk::ImageHelper *image = &textureVk->getImage();
6849 const vk::ImageView *imageView = nullptr;
6850
6851 vk::ImageOrBufferViewSubresourceSerial serial =
6852 textureVk->getStorageImageViewSerial(binding);
6853
6854 ANGLE_TRY(textureVk->getStorageImageView(context, binding, &imageView));
6855
6856 uint32_t infoIndex = writeDescriptorDescs[info.binding].descriptorInfoIndex +
6857 arrayElement + imageUniform.getOuterArrayOffset();
6858
6859 // Note: binding.access is unused because it is implied by the shader.
6860
6861 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6862 SetBitField(infoDesc.imageLayoutOrRange, image->getCurrentLayout());
6863 memcpy(&infoDesc.imageSubresourceRange, &serial.subresource, sizeof(uint32_t));
6864 infoDesc.imageViewSerialOrOffset = serial.viewSerial.getValue();
6865 infoDesc.samplerOrBufferSerial = 0;
6866
6867 mHandles[infoIndex].imageView = imageView->getHandle();
6868 }
6869 }
6870 }
6871
6872 return angle::Result::Continue;
6873 }
6874
updateInputAttachments(vk::Context * context,const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,FramebufferVk * framebufferVk,const WriteDescriptorDescs & writeDescriptorDescs)6875 angle::Result DescriptorSetDescBuilder::updateInputAttachments(
6876 vk::Context *context,
6877 const gl::ProgramExecutable &executable,
6878 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6879 FramebufferVk *framebufferVk,
6880 const WriteDescriptorDescs &writeDescriptorDescs)
6881 {
6882 // Note: Depth/stencil input attachments are only supported in ANGLE when using
6883 // VK_KHR_dynamic_rendering_local_read, so the layout is chosen to be the one specifically made
6884 // for that extension.
6885 if (executable.usesDepthFramebufferFetch() || executable.usesStencilFramebufferFetch())
6886 {
6887 RenderTargetVk *renderTargetVk = framebufferVk->getDepthStencilRenderTarget();
6888 ASSERT(context->getFeatures().preferDynamicRendering.enabled);
6889
6890 if (renderTargetVk != nullptr)
6891 {
6892 const ImageOrBufferViewSubresourceSerial serial =
6893 renderTargetVk->getDrawSubresourceSerial();
6894 const VkImageAspectFlags aspects =
6895 renderTargetVk->getImageForRenderPass().getAspectFlags();
6896
6897 if (executable.usesDepthFramebufferFetch() &&
6898 (aspects & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
6899 {
6900 const vk::ImageView *imageView = nullptr;
6901 ANGLE_TRY(renderTargetVk->getDepthOrStencilImageView(
6902 context, VK_IMAGE_ASPECT_DEPTH_BIT, &imageView));
6903
6904 const uint32_t depthBinding =
6905 variableInfoMap
6906 .getVariableById(gl::ShaderType::Fragment,
6907 sh::vk::spirv::kIdDepthInputAttachment)
6908 .binding;
6909 updateInputAttachment(context, depthBinding,
6910 VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR, imageView, serial,
6911 writeDescriptorDescs);
6912 }
6913
6914 if (executable.usesStencilFramebufferFetch() &&
6915 (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
6916 {
6917 const vk::ImageView *imageView = nullptr;
6918 ANGLE_TRY(renderTargetVk->getDepthOrStencilImageView(
6919 context, VK_IMAGE_ASPECT_STENCIL_BIT, &imageView));
6920
6921 const uint32_t stencilBinding =
6922 variableInfoMap
6923 .getVariableById(gl::ShaderType::Fragment,
6924 sh::vk::spirv::kIdStencilInputAttachment)
6925 .binding;
6926 updateInputAttachment(context, stencilBinding,
6927 VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR, imageView, serial,
6928 writeDescriptorDescs);
6929 }
6930 }
6931 }
6932
6933 if (!executable.usesColorFramebufferFetch())
6934 {
6935 return angle::Result::Continue;
6936 }
6937
6938 const uint32_t firstColorInputAttachment =
6939 static_cast<uint32_t>(executable.getFragmentInoutIndices().first());
6940
6941 const ShaderInterfaceVariableInfo &baseColorInfo = variableInfoMap.getVariableById(
6942 gl::ShaderType::Fragment, sh::vk::spirv::kIdInputAttachment0 + firstColorInputAttachment);
6943
6944 const uint32_t baseColorBinding = baseColorInfo.binding - firstColorInputAttachment;
6945
6946 for (size_t colorIndex : framebufferVk->getState().getColorAttachmentsMask())
6947 {
6948 uint32_t binding = baseColorBinding + static_cast<uint32_t>(colorIndex);
6949 RenderTargetVk *renderTargetVk = framebufferVk->getColorDrawRenderTarget(colorIndex);
6950
6951 const vk::ImageView *imageView = nullptr;
6952 ANGLE_TRY(renderTargetVk->getImageView(context, &imageView));
6953 const ImageOrBufferViewSubresourceSerial serial =
6954 renderTargetVk->getDrawSubresourceSerial();
6955
6956 // We just need any layout that represents GENERAL for render pass objects. With dynamic
6957 // rendering, there's a specific layout.
6958 updateInputAttachment(context, binding,
6959 context->getFeatures().preferDynamicRendering.enabled
6960 ? VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR
6961 : VK_IMAGE_LAYOUT_GENERAL,
6962 imageView, serial, writeDescriptorDescs);
6963 }
6964
6965 return angle::Result::Continue;
6966 }
6967
updateInputAttachment(Context * context,uint32_t binding,VkImageLayout layout,const vk::ImageView * imageView,ImageOrBufferViewSubresourceSerial serial,const WriteDescriptorDescs & writeDescriptorDescs)6968 void DescriptorSetDescBuilder::updateInputAttachment(
6969 Context *context,
6970 uint32_t binding,
6971 VkImageLayout layout,
6972 const vk::ImageView *imageView,
6973 ImageOrBufferViewSubresourceSerial serial,
6974 const WriteDescriptorDescs &writeDescriptorDescs)
6975 {
6976 uint32_t infoIndex = writeDescriptorDescs[binding].descriptorInfoIndex;
6977
6978 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6979
6980 // The serial is not totally precise.
6981 SetBitField(infoDesc.imageLayoutOrRange, layout);
6982 infoDesc.imageViewSerialOrOffset = serial.viewSerial.getValue();
6983 memcpy(&infoDesc.imageSubresourceRange, &serial.subresource, sizeof(uint32_t));
6984 infoDesc.samplerOrBufferSerial = 0;
6985
6986 mHandles[infoIndex].imageView = imageView->getHandle();
6987 }
6988
updateDescriptorSet(Renderer * renderer,const WriteDescriptorDescs & writeDescriptorDescs,UpdateDescriptorSetsBuilder * updateBuilder,VkDescriptorSet descriptorSet) const6989 void DescriptorSetDescBuilder::updateDescriptorSet(Renderer *renderer,
6990 const WriteDescriptorDescs &writeDescriptorDescs,
6991 UpdateDescriptorSetsBuilder *updateBuilder,
6992 VkDescriptorSet descriptorSet) const
6993 {
6994 mDesc.updateDescriptorSet(renderer, writeDescriptorDescs, updateBuilder, mHandles.data(),
6995 descriptorSet);
6996 }
6997
6998 // SharedCacheKeyManager implementation.
6999 template <class SharedCacheKeyT>
updateEmptySlotBits()7000 size_t SharedCacheKeyManager<SharedCacheKeyT>::updateEmptySlotBits()
7001 {
7002 ASSERT(mSharedCacheKeys.size() == mEmptySlotBits.size() * kSlotBitCount);
7003 size_t emptySlot = kInvalidSlot;
7004 for (size_t slot = 0; slot < mSharedCacheKeys.size(); ++slot)
7005 {
7006 SharedCacheKeyT &sharedCacheKey = mSharedCacheKeys[slot];
7007 if (!sharedCacheKey->valid())
7008 {
7009 mEmptySlotBits[slot / kSlotBitCount].set(slot % kSlotBitCount);
7010 emptySlot = slot;
7011 }
7012 }
7013 return emptySlot;
7014 }
7015
7016 template <class SharedCacheKeyT>
addKeyImpl(const SharedCacheKeyT & key)7017 void SharedCacheKeyManager<SharedCacheKeyT>::addKeyImpl(const SharedCacheKeyT &key)
7018 {
7019 // Search for available slots and use that if any
7020 size_t slot = 0;
7021 for (SlotBitMask &emptyBits : mEmptySlotBits)
7022 {
7023 if (emptyBits.any())
7024 {
7025 slot += emptyBits.first();
7026 SharedCacheKeyT &sharedCacheKey = mSharedCacheKeys[slot];
7027 ASSERT(!sharedCacheKey->valid());
7028 sharedCacheKey = key;
7029 emptyBits.reset(slot % kSlotBitCount);
7030 return;
7031 }
7032 slot += kSlotBitCount;
7033 }
7034
7035 // Some cached entries may have been released. Try to update and use any available slot if any.
7036 slot = updateEmptySlotBits();
7037 if (slot != kInvalidSlot)
7038 {
7039 SharedCacheKeyT &sharedCacheKey = mSharedCacheKeys[slot];
7040 ASSERT(!sharedCacheKey->valid());
7041 sharedCacheKey = key;
7042 SlotBitMask &emptyBits = mEmptySlotBits[slot / kSlotBitCount];
7043 emptyBits.reset(slot % kSlotBitCount);
7044 return;
7045 }
7046
7047 // No slot available, expand mSharedCacheKeys
7048 ASSERT(mSharedCacheKeys.size() == mEmptySlotBits.size() * kSlotBitCount);
7049 if (!mEmptySlotBits.empty())
7050 {
7051 // On first insertion, let std::vector allocate a single entry for minimal memory overhead,
7052 // since this is the most common usage case. If that exceeds, reserve a larger chunk to
7053 // avoid storage reallocation for efficiency (enough storage enough for 512 cache entries).
7054 mEmptySlotBits.reserve(8);
7055 }
7056 mEmptySlotBits.emplace_back(0xFFFFFFFE);
7057 mSharedCacheKeys.emplace_back(key);
7058 while (mSharedCacheKeys.size() < mEmptySlotBits.size() * kSlotBitCount)
7059 {
7060 mSharedCacheKeys.emplace_back();
7061 SharedCacheKeyT &sharedCacheKey = mSharedCacheKeys.back();
7062 // Insert an empty cache key so that sharedCacheKey will not be null.
7063 MakeInvalidCachedObject(&sharedCacheKey);
7064 ASSERT(!sharedCacheKey->valid());
7065 }
7066 }
7067
7068 template <class SharedCacheKeyT>
releaseKeys(ContextVk * contextVk)7069 void SharedCacheKeyManager<SharedCacheKeyT>::releaseKeys(ContextVk *contextVk)
7070 {
7071 ASSERT(mSharedCacheKeys.size() == mEmptySlotBits.size() * kSlotBitCount);
7072 for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
7073 {
7074 if (sharedCacheKey->valid())
7075 {
7076 // Immediate destroy the cached object and the key itself when first releaseRef call is
7077 // made
7078 sharedCacheKey->releaseCachedObject(contextVk);
7079 }
7080 }
7081 mSharedCacheKeys.clear();
7082 mEmptySlotBits.clear();
7083 }
7084
7085 template <class SharedCacheKeyT>
releaseKeys(Renderer * renderer)7086 void SharedCacheKeyManager<SharedCacheKeyT>::releaseKeys(Renderer *renderer)
7087 {
7088 ASSERT(mSharedCacheKeys.size() == mEmptySlotBits.size() * kSlotBitCount);
7089 for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
7090 {
7091 if (sharedCacheKey->valid())
7092 {
7093 // Immediate destroy the cached object and the key itself when first releaseKeys call is
7094 // made
7095 sharedCacheKey->releaseCachedObject(renderer);
7096 }
7097 }
7098 mSharedCacheKeys.clear();
7099 mEmptySlotBits.clear();
7100 }
7101
7102 template <class SharedCacheKeyT>
destroyKeys(Renderer * renderer)7103 void SharedCacheKeyManager<SharedCacheKeyT>::destroyKeys(Renderer *renderer)
7104 {
7105 ASSERT(mSharedCacheKeys.size() == mEmptySlotBits.size() * kSlotBitCount);
7106 for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
7107 {
7108 // destroy the cache key
7109 if (sharedCacheKey->valid())
7110 {
7111 // Immediate destroy the cached object and the key
7112 sharedCacheKey->destroyCachedObject(renderer);
7113 }
7114 }
7115 mSharedCacheKeys.clear();
7116 mEmptySlotBits.clear();
7117 }
7118
7119 template <class SharedCacheKeyT>
clear()7120 void SharedCacheKeyManager<SharedCacheKeyT>::clear()
7121 {
7122 // Caller must have already freed all caches
7123 assertAllEntriesDestroyed();
7124 mSharedCacheKeys.clear();
7125 mEmptySlotBits.clear();
7126 }
7127
7128 template <class SharedCacheKeyT>
containsKeyWithOwnerEqual(const SharedCacheKeyT & key) const7129 bool SharedCacheKeyManager<SharedCacheKeyT>::containsKeyWithOwnerEqual(
7130 const SharedCacheKeyT &key) const
7131 {
7132 for (const SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
7133 {
7134 if (key.owner_equal(sharedCacheKey))
7135 {
7136 return true;
7137 }
7138 }
7139 return false;
7140 }
7141
7142 template <class SharedCacheKeyT>
assertAllEntriesDestroyed() const7143 void SharedCacheKeyManager<SharedCacheKeyT>::assertAllEntriesDestroyed() const
7144 {
7145 // Caller must have already freed all caches
7146 for (const SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
7147 {
7148 ASSERT(!sharedCacheKey->valid());
7149 }
7150 }
7151
7152 template <class SharedCacheKeyT>
allValidEntriesAreCached(ContextVk * contextVk) const7153 bool SharedCacheKeyManager<SharedCacheKeyT>::allValidEntriesAreCached(ContextVk *contextVk) const
7154 {
7155 for (const SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
7156 {
7157 if (sharedCacheKey->valid() && !sharedCacheKey->hasValidCachedObject(contextVk))
7158 {
7159 return false;
7160 }
7161 }
7162 return true;
7163 }
7164
7165 // Explict instantiate for FramebufferCacheManager
7166 template class SharedCacheKeyManager<SharedFramebufferCacheKey>;
7167 template <>
addKey(const SharedFramebufferCacheKey & key)7168 void SharedCacheKeyManager<SharedFramebufferCacheKey>::addKey(const SharedFramebufferCacheKey &key)
7169 {
7170 addKeyImpl(key);
7171 }
7172
7173 // Explict instantiate for DescriptorSetCacheManager
7174 template class SharedCacheKeyManager<SharedDescriptorSetCacheKey>;
7175 template <>
addKey(const SharedDescriptorSetCacheKey & key)7176 void SharedCacheKeyManager<SharedDescriptorSetCacheKey>::addKey(
7177 const SharedDescriptorSetCacheKey &key)
7178 {
7179 // There are cases that same texture or buffer are bound in multiple binding point. When we have
7180 // a cache miss, we end up looping binding point and calling addKey which may end up adding same
7181 // key multiple times. This is a quick way to avoid that.
7182 if (mLastAddedSharedCacheKey.owner_equal(key))
7183 {
7184 return;
7185 }
7186
7187 // In case of the texture or buffer is part of many descriptorSets, lets not track it any more
7188 // to alleviate the overhead associated with this. We will rely on eviction to free the
7189 // descriptorSets when needed.
7190 static constexpr size_t kMaxEmptySlots = 4;
7191 static constexpr size_t kMaxSharedCacheKeyTracked = kSlotBitCount * kMaxEmptySlots;
7192 if (mSharedCacheKeys.size() >= kMaxSharedCacheKeyTracked)
7193 {
7194 return;
7195 }
7196
7197 mLastAddedSharedCacheKey = key;
7198 ASSERT(!containsKeyWithOwnerEqual(key));
7199
7200 addKeyImpl(key);
7201 }
7202
7203 // PipelineCacheAccess implementation.
getLock()7204 std::unique_lock<angle::SimpleMutex> PipelineCacheAccess::getLock()
7205 {
7206 if (mMutex == nullptr)
7207 {
7208 return std::unique_lock<angle::SimpleMutex>();
7209 }
7210
7211 return std::unique_lock<angle::SimpleMutex>(*mMutex);
7212 }
7213
createGraphicsPipeline(vk::ErrorContext * context,const VkGraphicsPipelineCreateInfo & createInfo,vk::Pipeline * pipelineOut)7214 VkResult PipelineCacheAccess::createGraphicsPipeline(vk::ErrorContext *context,
7215 const VkGraphicsPipelineCreateInfo &createInfo,
7216 vk::Pipeline *pipelineOut)
7217 {
7218 std::unique_lock<angle::SimpleMutex> lock = getLock();
7219
7220 return pipelineOut->initGraphics(context->getDevice(), createInfo, *mPipelineCache);
7221 }
7222
createComputePipeline(vk::ErrorContext * context,const VkComputePipelineCreateInfo & createInfo,vk::Pipeline * pipelineOut)7223 VkResult PipelineCacheAccess::createComputePipeline(vk::ErrorContext *context,
7224 const VkComputePipelineCreateInfo &createInfo,
7225 vk::Pipeline *pipelineOut)
7226 {
7227 std::unique_lock<angle::SimpleMutex> lock = getLock();
7228
7229 return pipelineOut->initCompute(context->getDevice(), createInfo, *mPipelineCache);
7230 }
7231
getCacheData(vk::ErrorContext * context,size_t * cacheSize,void * cacheData)7232 VkResult PipelineCacheAccess::getCacheData(vk::ErrorContext *context,
7233 size_t *cacheSize,
7234 void *cacheData)
7235 {
7236 std::unique_lock<angle::SimpleMutex> lock = getLock();
7237 return mPipelineCache->getCacheData(context->getDevice(), cacheSize, cacheData);
7238 }
7239
merge(Renderer * renderer,const vk::PipelineCache & pipelineCache)7240 void PipelineCacheAccess::merge(Renderer *renderer, const vk::PipelineCache &pipelineCache)
7241 {
7242 ASSERT(isThreadSafe());
7243
7244 std::unique_lock<angle::SimpleMutex> lock = getLock();
7245
7246 mPipelineCache->merge(renderer->getDevice(), 1, pipelineCache.ptr());
7247 }
7248 } // namespace vk
7249
7250 // UpdateDescriptorSetsBuilder implementation.
UpdateDescriptorSetsBuilder()7251 UpdateDescriptorSetsBuilder::UpdateDescriptorSetsBuilder()
7252 {
7253 // Reserve reasonable amount of spaces so that for majority of apps we don't need to grow at all
7254 constexpr size_t kDescriptorBufferInfosInitialSize = 16;
7255 constexpr size_t kDescriptorImageInfosInitialSize = 16;
7256 constexpr size_t kDescriptorBufferViewsInitialSize = 1;
7257 constexpr size_t kDescriptorWriteInfosInitialSize =
7258 kDescriptorBufferInfosInitialSize + kDescriptorImageInfosInitialSize;
7259
7260 mDescriptorBufferInfos.init(kDescriptorBufferInfosInitialSize);
7261 mDescriptorImageInfos.init(kDescriptorImageInfosInitialSize);
7262 mBufferViews.init(kDescriptorBufferViewsInitialSize);
7263 mWriteDescriptorSets.init(kDescriptorWriteInfosInitialSize);
7264 }
7265
7266 UpdateDescriptorSetsBuilder::~UpdateDescriptorSetsBuilder() = default;
7267
7268 template <typename T>
allocate(uint32_t count)7269 T *UpdateDescriptorSetsBuilder::DescriptorInfoAllocator<T>::allocate(uint32_t count)
7270 {
7271 size_t oldSize = mCurrentVector->size();
7272 size_t newSize = oldSize + count;
7273 if (newSize <= mCurrentVector->capacity())
7274 {
7275 (*mCurrentVector).resize(newSize);
7276 mTotalSize += count;
7277 return &(*mCurrentVector)[oldSize];
7278 }
7279
7280 ++mCurrentVector;
7281 // clear() always ensures we have a single element left.
7282 ASSERT(mCurrentVector == mDescriptorInfos.end());
7283
7284 // We have reached capacity, grow the storage
7285 mVectorCapacity = std::max(count, mVectorCapacity);
7286 mDescriptorInfos.emplace_back();
7287 mDescriptorInfos.back().reserve(mVectorCapacity);
7288 mCurrentVector = mDescriptorInfos.end() - 1;
7289
7290 mCurrentVector->resize(count);
7291 mTotalSize += count;
7292
7293 return &mCurrentVector->front();
7294 }
7295
updateDescriptorSets(VkDevice device) const7296 uint32_t UpdateDescriptorSetsBuilder::WriteDescriptorSetAllocator::updateDescriptorSets(
7297 VkDevice device) const
7298 {
7299 for (const std::vector<VkWriteDescriptorSet> &vector : mDescriptorInfos)
7300 {
7301 if (!vector.empty())
7302 {
7303 vkUpdateDescriptorSets(device, static_cast<uint32_t>(vector.size()), vector.data(), 0,
7304 nullptr);
7305 }
7306 }
7307 return mTotalSize;
7308 }
7309
flushDescriptorSetUpdates(VkDevice device)7310 uint32_t UpdateDescriptorSetsBuilder::flushDescriptorSetUpdates(VkDevice device)
7311 {
7312 if (mWriteDescriptorSets.empty())
7313 {
7314 ASSERT(mDescriptorBufferInfos.empty());
7315 ASSERT(mDescriptorImageInfos.empty());
7316 return 0;
7317 }
7318
7319 uint32_t totalSize = mWriteDescriptorSets.updateDescriptorSets(device);
7320
7321 mWriteDescriptorSets.clear();
7322 mDescriptorBufferInfos.clear();
7323 mDescriptorImageInfos.clear();
7324 mBufferViews.clear();
7325
7326 return totalSize;
7327 }
7328
7329 // FramebufferCache implementation.
destroy(vk::Renderer * renderer)7330 void FramebufferCache::destroy(vk::Renderer *renderer)
7331 {
7332 renderer->accumulateCacheStats(VulkanCacheType::Framebuffer, mCacheStats);
7333 for (auto &entry : mPayload)
7334 {
7335 vk::FramebufferHelper &tmpFB = entry.second;
7336 tmpFB.destroy(renderer);
7337 }
7338 mPayload.clear();
7339 }
7340
get(ContextVk * contextVk,const vk::FramebufferDesc & desc,vk::Framebuffer & framebuffer)7341 bool FramebufferCache::get(ContextVk *contextVk,
7342 const vk::FramebufferDesc &desc,
7343 vk::Framebuffer &framebuffer)
7344 {
7345 ASSERT(!contextVk->getFeatures().supportsImagelessFramebuffer.enabled);
7346
7347 auto iter = mPayload.find(desc);
7348 if (iter != mPayload.end())
7349 {
7350 framebuffer.setHandle(iter->second.getFramebuffer().getHandle());
7351 mCacheStats.hit();
7352 return true;
7353 }
7354
7355 mCacheStats.miss();
7356 return false;
7357 }
7358
insert(ContextVk * contextVk,const vk::FramebufferDesc & desc,vk::FramebufferHelper && framebufferHelper)7359 void FramebufferCache::insert(ContextVk *contextVk,
7360 const vk::FramebufferDesc &desc,
7361 vk::FramebufferHelper &&framebufferHelper)
7362 {
7363 ASSERT(!contextVk->getFeatures().supportsImagelessFramebuffer.enabled);
7364
7365 mPayload.emplace(desc, std::move(framebufferHelper));
7366 }
7367
erase(ContextVk * contextVk,const vk::FramebufferDesc & desc)7368 void FramebufferCache::erase(ContextVk *contextVk, const vk::FramebufferDesc &desc)
7369 {
7370 ASSERT(!contextVk->getFeatures().supportsImagelessFramebuffer.enabled);
7371
7372 auto iter = mPayload.find(desc);
7373 if (iter != mPayload.end())
7374 {
7375 vk::FramebufferHelper &tmpFB = iter->second;
7376 tmpFB.release(contextVk);
7377 mPayload.erase(desc);
7378 }
7379 }
7380
7381 // RenderPassCache implementation.
7382 RenderPassCache::RenderPassCache() = default;
7383
~RenderPassCache()7384 RenderPassCache::~RenderPassCache()
7385 {
7386 ASSERT(mPayload.empty());
7387 }
7388
destroy(ContextVk * contextVk)7389 void RenderPassCache::destroy(ContextVk *contextVk)
7390 {
7391 vk::Renderer *renderer = contextVk->getRenderer();
7392
7393 renderer->accumulateCacheStats(VulkanCacheType::CompatibleRenderPass,
7394 mCompatibleRenderPassCacheStats);
7395 renderer->accumulateCacheStats(VulkanCacheType::RenderPassWithOps,
7396 mRenderPassWithOpsCacheStats);
7397
7398 VkDevice device = renderer->getDevice();
7399
7400 // Make sure there are no jobs referencing the render pass cache.
7401 contextVk->getShareGroup()->waitForCurrentMonolithicPipelineCreationTask();
7402
7403 for (auto &outerIt : mPayload)
7404 {
7405 for (auto &innerIt : outerIt.second)
7406 {
7407 innerIt.second.destroy(device);
7408 }
7409 }
7410 mPayload.clear();
7411 }
7412
clear(ContextVk * contextVk)7413 void RenderPassCache::clear(ContextVk *contextVk)
7414 {
7415 // Make sure there are no jobs referencing the render pass cache.
7416 contextVk->getShareGroup()->waitForCurrentMonolithicPipelineCreationTask();
7417
7418 for (auto &outerIt : mPayload)
7419 {
7420 for (auto &innerIt : outerIt.second)
7421 {
7422 innerIt.second.release(contextVk);
7423 }
7424 }
7425 mPayload.clear();
7426 }
7427
7428 // static
InitializeOpsForCompatibleRenderPass(const vk::RenderPassDesc & desc,vk::AttachmentOpsArray * opsOut)7429 void RenderPassCache::InitializeOpsForCompatibleRenderPass(const vk::RenderPassDesc &desc,
7430 vk::AttachmentOpsArray *opsOut)
7431 {
7432 // This API is only used by getCompatibleRenderPass() to create a compatible render pass. The
7433 // following does not participate in render pass compatibility, so could take any value:
7434 //
7435 // - Load and store ops
7436 // - Attachment layouts
7437 // - Existance of resolve attachment (if single subpass)
7438 //
7439 // The values chosen here are arbitrary.
7440
7441 vk::PackedAttachmentIndex colorIndexVk(0);
7442 for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
7443 {
7444 if (!desc.isColorAttachmentEnabled(colorIndexGL))
7445 {
7446 continue;
7447 }
7448
7449 const vk::ImageLayout imageLayout = vk::ImageLayout::ColorWrite;
7450 opsOut->initWithLoadStore(colorIndexVk, imageLayout, imageLayout);
7451 ++colorIndexVk;
7452 }
7453
7454 if (desc.hasDepthStencilAttachment())
7455 {
7456 const vk::ImageLayout imageLayout = vk::ImageLayout::DepthWriteStencilWrite;
7457 opsOut->initWithLoadStore(colorIndexVk, imageLayout, imageLayout);
7458 }
7459 }
7460
addCompatibleRenderPass(ContextVk * contextVk,const vk::RenderPassDesc & desc,const vk::RenderPass ** renderPassOut)7461 angle::Result RenderPassCache::addCompatibleRenderPass(ContextVk *contextVk,
7462 const vk::RenderPassDesc &desc,
7463 const vk::RenderPass **renderPassOut)
7464 {
7465 vk::AttachmentOpsArray ops;
7466 InitializeOpsForCompatibleRenderPass(desc, &ops);
7467
7468 return getRenderPassWithOpsImpl(contextVk, desc, ops, false, renderPassOut);
7469 }
7470
getRenderPassWithOps(ContextVk * contextVk,const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & attachmentOps,const vk::RenderPass ** renderPassOut)7471 angle::Result RenderPassCache::getRenderPassWithOps(ContextVk *contextVk,
7472 const vk::RenderPassDesc &desc,
7473 const vk::AttachmentOpsArray &attachmentOps,
7474 const vk::RenderPass **renderPassOut)
7475 {
7476 return getRenderPassWithOpsImpl(contextVk, desc, attachmentOps, true, renderPassOut);
7477 }
7478
getRenderPassWithOpsImpl(ContextVk * contextVk,const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & attachmentOps,bool updatePerfCounters,const vk::RenderPass ** renderPassOut)7479 angle::Result RenderPassCache::getRenderPassWithOpsImpl(ContextVk *contextVk,
7480 const vk::RenderPassDesc &desc,
7481 const vk::AttachmentOpsArray &attachmentOps,
7482 bool updatePerfCounters,
7483 const vk::RenderPass **renderPassOut)
7484 {
7485 ASSERT(!contextVk->getFeatures().preferDynamicRendering.enabled);
7486
7487 auto outerIt = mPayload.find(desc);
7488 if (outerIt != mPayload.end())
7489 {
7490 InnerCache &innerCache = outerIt->second;
7491
7492 auto innerIt = innerCache.find(attachmentOps);
7493 if (innerIt != innerCache.end())
7494 {
7495 // TODO(jmadill): Could possibly use an MRU cache here.
7496 vk::GetRenderPassAndUpdateCounters(contextVk, updatePerfCounters, &innerIt->second,
7497 renderPassOut);
7498 mRenderPassWithOpsCacheStats.hit();
7499 return angle::Result::Continue;
7500 }
7501 }
7502 else
7503 {
7504 auto emplaceResult = mPayload.emplace(desc, InnerCache());
7505 outerIt = emplaceResult.first;
7506 }
7507
7508 mRenderPassWithOpsCacheStats.missAndIncrementSize();
7509 vk::RenderPassHelper newRenderPass;
7510 ANGLE_TRY(MakeRenderPass(contextVk, desc, attachmentOps, &newRenderPass.getRenderPass(),
7511 &newRenderPass.getPerfCounters()));
7512
7513 InnerCache &innerCache = outerIt->second;
7514 auto insertPos = innerCache.emplace(attachmentOps, std::move(newRenderPass));
7515 vk::GetRenderPassAndUpdateCounters(contextVk, updatePerfCounters, &insertPos.first->second,
7516 renderPassOut);
7517
7518 // TODO(jmadill): Trim cache, and pre-populate with the most common RPs on startup.
7519 return angle::Result::Continue;
7520 }
7521
7522 // static
MakeRenderPass(vk::ErrorContext * context,const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & ops,vk::RenderPass * renderPass,vk::RenderPassPerfCounters * renderPassCounters)7523 angle::Result RenderPassCache::MakeRenderPass(vk::ErrorContext *context,
7524 const vk::RenderPassDesc &desc,
7525 const vk::AttachmentOpsArray &ops,
7526 vk::RenderPass *renderPass,
7527 vk::RenderPassPerfCounters *renderPassCounters)
7528 {
7529 ASSERT(!context->getFeatures().preferDynamicRendering.enabled);
7530
7531 vk::Renderer *renderer = context->getRenderer();
7532 constexpr VkAttachmentReference2 kUnusedAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
7533 nullptr, VK_ATTACHMENT_UNUSED,
7534 VK_IMAGE_LAYOUT_UNDEFINED, 0};
7535
7536 ASSERT(!desc.hasDepthStencilFramebufferFetch());
7537 const bool needInputAttachments = desc.hasColorFramebufferFetch();
7538 const bool isRenderToTextureThroughExtension =
7539 desc.isRenderToTexture() &&
7540 renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled;
7541 const bool isRenderToTextureThroughEmulation =
7542 desc.isRenderToTexture() && !isRenderToTextureThroughExtension;
7543
7544 const uint8_t descSamples = desc.samples();
7545 const uint8_t attachmentSamples = isRenderToTextureThroughExtension ? 1 : descSamples;
7546 const uint8_t renderToTextureSamples = isRenderToTextureThroughExtension ? descSamples : 1;
7547
7548 // Unpack the packed and split representation into the format required by Vulkan.
7549 gl::DrawBuffersVector<VkAttachmentReference2> colorAttachmentRefs;
7550 gl::DrawBuffersVector<VkAttachmentReference2> colorResolveAttachmentRefs;
7551 VkAttachmentReference2 depthStencilAttachmentRef = kUnusedAttachment;
7552 VkAttachmentReference2 depthStencilResolveAttachmentRef = kUnusedAttachment;
7553 VkAttachmentReference2 fragmentShadingRateAttachmentRef = kUnusedAttachment;
7554
7555 // The list of attachments includes all non-resolve and resolve attachments.
7556 vk::FramebufferAttachmentArray<VkAttachmentDescription2> attachmentDescs;
7557
7558 // Track invalidated attachments so their resolve attachments can be invalidated as well.
7559 // Resolve attachments can be removed in that case if the render pass has only one subpass
7560 // (which is the case if there are no unresolve attachments).
7561 gl::DrawBufferMask isMSRTTEmulationColorInvalidated;
7562 bool isMSRTTEmulationDepthInvalidated = false;
7563 bool isMSRTTEmulationStencilInvalidated = false;
7564 const bool hasUnresolveAttachments =
7565 desc.getColorUnresolveAttachmentMask().any() || desc.hasDepthStencilUnresolveAttachment();
7566 const bool canRemoveResolveAttachments =
7567 isRenderToTextureThroughEmulation && !hasUnresolveAttachments;
7568
7569 #if defined(ANGLE_PLATFORM_ANDROID)
7570 // if yuv, we're going to chain this on to some VkAttachmentDescription2
7571 VkExternalFormatANDROID externalFormat = {VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID, nullptr,
7572 0};
7573 #endif
7574
7575 gl::DrawBuffersArray<vk::ImageLayout> colorResolveImageLayout = {};
7576
7577 // Pack color attachments
7578 vk::PackedAttachmentIndex attachmentCount(0);
7579 for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
7580 {
7581 // Vulkan says:
7582 //
7583 // > Each element of the pColorAttachments array corresponds to an output location in the
7584 // > shader, i.e. if the shader declares an output variable decorated with a Location value
7585 // > of X, then it uses the attachment provided in pColorAttachments[X].
7586 //
7587 // This means that colorAttachmentRefs is indexed by colorIndexGL. Where the color
7588 // attachment is disabled, a reference with VK_ATTACHMENT_UNUSED is given.
7589
7590 if (!desc.isColorAttachmentEnabled(colorIndexGL))
7591 {
7592 colorAttachmentRefs.push_back(kUnusedAttachment);
7593 continue;
7594 }
7595
7596 angle::FormatID attachmentFormatID = desc[colorIndexGL];
7597 ASSERT(attachmentFormatID != angle::FormatID::NONE);
7598
7599 bool isYUVExternalFormat = vk::IsYUVExternalFormat(attachmentFormatID);
7600
7601 // If nullColorAttachmentWithExternalFormatResolve is VK_TRUE, pack YUV resolve first as if
7602 // it is the color attachment.
7603 if (isYUVExternalFormat && renderer->nullColorAttachmentWithExternalFormatResolve())
7604 {
7605 colorAttachmentRefs.push_back(kUnusedAttachment);
7606 // temporary workaround for ARM driver assertion. Will remove once driver fix lands
7607 colorAttachmentRefs.back().layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
7608 colorAttachmentRefs.back().aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
7609
7610 VkAttachmentReference2 colorRef = {};
7611 colorRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
7612 colorRef.attachment = attachmentCount.get();
7613 colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
7614 colorRef.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
7615
7616 colorResolveAttachmentRefs.push_back(colorRef);
7617 vk::UnpackAttachmentDesc(renderer, &attachmentDescs[attachmentCount.get()],
7618 attachmentFormatID, attachmentSamples, ops[attachmentCount]);
7619
7620 #if defined(ANGLE_PLATFORM_ANDROID)
7621 // For rendering to YUV, chain on the external format info to the resolve
7622 // attachment
7623 const vk::ExternalYuvFormatInfo &externalFormatInfo =
7624 renderer->getExternalFormatTable()->getExternalFormatInfo(attachmentFormatID);
7625 externalFormat.externalFormat = externalFormatInfo.externalFormat;
7626 VkAttachmentDescription2 &attachment = attachmentDescs[attachmentCount.get()];
7627 attachment.pNext = &externalFormat;
7628 ASSERT(attachment.format == VK_FORMAT_UNDEFINED);
7629 #endif
7630 ++attachmentCount;
7631 continue;
7632 }
7633
7634 ASSERT(static_cast<vk::ImageLayout>(ops[attachmentCount].initialLayout) !=
7635 vk::ImageLayout::SharedPresent ||
7636 static_cast<vk::ImageLayout>(ops[attachmentCount].finalLayout) ==
7637 vk::ImageLayout::SharedPresent);
7638
7639 VkAttachmentReference2 colorRef = {};
7640 colorRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
7641 colorRef.attachment = attachmentCount.get();
7642 colorRef.layout = needInputAttachments
7643 ? VK_IMAGE_LAYOUT_GENERAL
7644 : vk::ConvertImageLayoutToVkImageLayout(static_cast<vk::ImageLayout>(
7645 ops[attachmentCount].initialLayout));
7646 colorRef.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
7647 colorAttachmentRefs.push_back(colorRef);
7648
7649 vk::UnpackAttachmentDesc(renderer, &attachmentDescs[attachmentCount.get()],
7650 attachmentFormatID, attachmentSamples, ops[attachmentCount]);
7651 colorResolveImageLayout[colorIndexGL] =
7652 static_cast<vk::ImageLayout>(ops[attachmentCount].finalResolveLayout);
7653
7654 if (isYUVExternalFormat)
7655 {
7656 const vk::ExternalYuvFormatInfo &externalFormatInfo =
7657 renderer->getExternalFormatTable()->getExternalFormatInfo(attachmentFormatID);
7658 attachmentDescs[attachmentCount.get()].format =
7659 externalFormatInfo.colorAttachmentFormat;
7660 }
7661 else
7662 {
7663 attachmentDescs[attachmentCount.get()].format =
7664 vk::GetVkFormatFromFormatID(renderer, attachmentFormatID);
7665 }
7666 ASSERT(attachmentDescs[attachmentCount.get()].format != VK_FORMAT_UNDEFINED);
7667
7668 // When multisampled-render-to-texture is used, invalidating an attachment invalidates both
7669 // the multisampled and the resolve attachments. Otherwise, the resolve attachment is
7670 // independent of the multisampled attachment, and is never invalidated.
7671 // This is also the case for external format resolve
7672 if (isRenderToTextureThroughEmulation)
7673 {
7674 isMSRTTEmulationColorInvalidated.set(colorIndexGL, ops[attachmentCount].isInvalidated);
7675 }
7676
7677 ++attachmentCount;
7678 }
7679
7680 // Pack depth/stencil attachment, if any
7681 if (desc.hasDepthStencilAttachment())
7682 {
7683 uint32_t depthStencilIndexGL = static_cast<uint32_t>(desc.depthStencilAttachmentIndex());
7684
7685 angle::FormatID attachmentFormatID = desc[depthStencilIndexGL];
7686 ASSERT(attachmentFormatID != angle::FormatID::NONE);
7687
7688 depthStencilAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
7689 depthStencilAttachmentRef.attachment = attachmentCount.get();
7690 depthStencilAttachmentRef.layout = ConvertImageLayoutToVkImageLayout(
7691 static_cast<vk::ImageLayout>(ops[attachmentCount].initialLayout));
7692 depthStencilAttachmentRef.aspectMask =
7693 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
7694
7695 vk::UnpackAttachmentDesc(renderer, &attachmentDescs[attachmentCount.get()],
7696 attachmentFormatID, attachmentSamples, ops[attachmentCount]);
7697
7698 if (isRenderToTextureThroughEmulation)
7699 {
7700 isMSRTTEmulationDepthInvalidated = ops[attachmentCount].isInvalidated;
7701 isMSRTTEmulationStencilInvalidated = ops[attachmentCount].isStencilInvalidated;
7702 }
7703
7704 ++attachmentCount;
7705 }
7706
7707 // Pack fragment shading rate attachment, if any
7708 if (desc.hasFragmentShadingAttachment())
7709 {
7710 vk::UnpackFragmentShadingRateAttachmentDesc(&attachmentDescs[attachmentCount.get()]);
7711
7712 fragmentShadingRateAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
7713 fragmentShadingRateAttachmentRef.attachment = attachmentCount.get();
7714 fragmentShadingRateAttachmentRef.layout =
7715 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
7716
7717 ++attachmentCount;
7718 }
7719
7720 // Pack color resolve attachments
7721 uint32_t nonResolveAttachmentCount = attachmentCount.get();
7722 for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
7723 {
7724 if (!desc.hasColorResolveAttachment(colorIndexGL))
7725 {
7726 colorResolveAttachmentRefs.push_back(kUnusedAttachment);
7727 continue;
7728 }
7729
7730 ASSERT(desc.isColorAttachmentEnabled(colorIndexGL));
7731
7732 angle::FormatID attachmentFormatID = desc[colorIndexGL];
7733 bool isYUVExternalFormat = vk::IsYUVExternalFormat(attachmentFormatID);
7734
7735 if (isYUVExternalFormat && renderer->nullColorAttachmentWithExternalFormatResolve())
7736 {
7737 // attachmentCount counts the YUV resolve, so decrease nonResolveAttachmentCount here.
7738 --nonResolveAttachmentCount;
7739 continue;
7740 }
7741
7742 const VkImageLayout finalLayout =
7743 ConvertImageLayoutToVkImageLayout(colorResolveImageLayout[colorIndexGL]);
7744 const VkImageLayout initialLayout = (finalLayout == VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
7745 ? VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
7746 : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
7747
7748 VkAttachmentReference2 colorRef = {};
7749 colorRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
7750 colorRef.attachment = attachmentCount.get();
7751 colorRef.layout = initialLayout;
7752 colorRef.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
7753
7754 // If color attachment is invalidated, try to remove its resolve attachment altogether.
7755 if (canRemoveResolveAttachments && isMSRTTEmulationColorInvalidated.test(colorIndexGL))
7756 {
7757 colorResolveAttachmentRefs.push_back(kUnusedAttachment);
7758 }
7759 else
7760 {
7761 colorResolveAttachmentRefs.push_back(colorRef);
7762 }
7763
7764 const bool isInvalidated = isMSRTTEmulationColorInvalidated.test(colorIndexGL);
7765
7766 vk::UnpackColorResolveAttachmentDesc(
7767 renderer, &attachmentDescs[attachmentCount.get()], attachmentFormatID,
7768 {desc.hasColorUnresolveAttachment(colorIndexGL), isInvalidated, false}, initialLayout,
7769 finalLayout);
7770
7771 #if defined(ANGLE_PLATFORM_ANDROID)
7772 // For rendering to YUV, chain on the external format info to the resolve attachment
7773 if (isYUVExternalFormat)
7774 {
7775 const vk::ExternalYuvFormatInfo &externalFormatInfo =
7776 renderer->getExternalFormatTable()->getExternalFormatInfo(attachmentFormatID);
7777 externalFormat.externalFormat = externalFormatInfo.externalFormat;
7778 VkAttachmentDescription2 &attachment = attachmentDescs[attachmentCount.get()];
7779 attachment.pNext = &externalFormat;
7780 ASSERT(attachment.format == VK_FORMAT_UNDEFINED);
7781 }
7782 #endif
7783
7784 ++attachmentCount;
7785 }
7786
7787 // Pack depth/stencil resolve attachment, if any
7788 if (desc.hasDepthStencilResolveAttachment())
7789 {
7790 ASSERT(desc.hasDepthStencilAttachment());
7791
7792 uint32_t depthStencilIndexGL = static_cast<uint32_t>(desc.depthStencilAttachmentIndex());
7793
7794 angle::FormatID attachmentFormatID = desc[depthStencilIndexGL];
7795 const angle::Format &angleFormat = angle::Format::Get(attachmentFormatID);
7796
7797 bool isDepthUnused = false;
7798 bool isStencilUnused = false;
7799
7800 // Treat missing aspect as invalidated for the purpose of the resolve attachment.
7801 if (angleFormat.depthBits == 0)
7802 {
7803 isMSRTTEmulationDepthInvalidated = true;
7804 }
7805 else if (!desc.hasDepthResolveAttachment())
7806 {
7807 isDepthUnused = true;
7808 }
7809 if (angleFormat.stencilBits == 0)
7810 {
7811 isMSRTTEmulationStencilInvalidated = true;
7812 }
7813 else if (!desc.hasStencilResolveAttachment())
7814 {
7815 isStencilUnused = true;
7816 }
7817
7818 depthStencilResolveAttachmentRef.attachment = attachmentCount.get();
7819 depthStencilResolveAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
7820 depthStencilResolveAttachmentRef.aspectMask = 0;
7821
7822 if (!isMSRTTEmulationDepthInvalidated && !isDepthUnused)
7823 {
7824 depthStencilResolveAttachmentRef.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
7825 }
7826 if (!isMSRTTEmulationStencilInvalidated && !isStencilUnused)
7827 {
7828 depthStencilResolveAttachmentRef.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
7829 }
7830
7831 vk::UnpackDepthStencilResolveAttachmentDesc(
7832 context, &attachmentDescs[attachmentCount.get()], attachmentFormatID,
7833 {desc.hasDepthUnresolveAttachment(), isMSRTTEmulationDepthInvalidated, isDepthUnused},
7834 {desc.hasStencilUnresolveAttachment(), isMSRTTEmulationStencilInvalidated,
7835 isStencilUnused});
7836
7837 ++attachmentCount;
7838 }
7839
7840 vk::SubpassVector<VkSubpassDescription2> subpassDesc;
7841
7842 // If any attachment needs to be unresolved, create an initial subpass for this purpose. Note
7843 // that the following arrays are used in initializing a VkSubpassDescription2 in subpassDesc,
7844 // which is in turn used in VkRenderPassCreateInfo below. That is why they are declared in the
7845 // same scope.
7846 gl::DrawBuffersVector<VkAttachmentReference2> unresolveColorAttachmentRefs;
7847 VkAttachmentReference2 unresolveDepthStencilAttachmentRef = kUnusedAttachment;
7848 vk::FramebufferAttachmentsVector<VkAttachmentReference2> unresolveInputAttachmentRefs;
7849 vk::FramebufferAttachmentsVector<uint32_t> unresolvePreserveAttachmentRefs;
7850 if (hasUnresolveAttachments)
7851 {
7852 subpassDesc.push_back({});
7853 vk::InitializeUnresolveSubpass(
7854 desc, colorAttachmentRefs, colorResolveAttachmentRefs, depthStencilAttachmentRef,
7855 depthStencilResolveAttachmentRef, &unresolveColorAttachmentRefs,
7856 &unresolveDepthStencilAttachmentRef, &unresolveInputAttachmentRefs,
7857 &unresolvePreserveAttachmentRefs, &subpassDesc.back());
7858 }
7859
7860 subpassDesc.push_back({});
7861 VkSubpassDescription2 *applicationSubpass = &subpassDesc.back();
7862
7863 applicationSubpass->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
7864 applicationSubpass->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
7865 applicationSubpass->inputAttachmentCount =
7866 needInputAttachments ? static_cast<uint32_t>(colorAttachmentRefs.size()) : 0;
7867 applicationSubpass->pInputAttachments =
7868 needInputAttachments ? colorAttachmentRefs.data() : nullptr;
7869 applicationSubpass->colorAttachmentCount = static_cast<uint32_t>(colorAttachmentRefs.size());
7870 applicationSubpass->pColorAttachments = colorAttachmentRefs.data();
7871 applicationSubpass->pResolveAttachments = attachmentCount.get() > nonResolveAttachmentCount
7872 ? colorResolveAttachmentRefs.data()
7873 : nullptr;
7874 applicationSubpass->pDepthStencilAttachment =
7875 (depthStencilAttachmentRef.attachment != VK_ATTACHMENT_UNUSED ? &depthStencilAttachmentRef
7876 : nullptr);
7877
7878 // Specify rasterization order for color on the subpass when available and
7879 // there is framebuffer fetch. This is required when the corresponding
7880 // flag is set on the pipeline.
7881 if (renderer->getFeatures().supportsRasterizationOrderAttachmentAccess.enabled &&
7882 desc.hasColorFramebufferFetch())
7883 {
7884 for (VkSubpassDescription2 &subpass : subpassDesc)
7885 {
7886 subpass.flags |=
7887 VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT;
7888 }
7889 }
7890
7891 if (desc.isLegacyDitherEnabled())
7892 {
7893 ASSERT(renderer->getFeatures().supportsLegacyDithering.enabled);
7894 subpassDesc.back().flags |= VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT;
7895 }
7896
7897 // If depth/stencil is to be resolved, add a VkSubpassDescriptionDepthStencilResolve to the
7898 // pNext chain of the subpass description.
7899 VkSubpassDescriptionDepthStencilResolve depthStencilResolve = {};
7900 VkSubpassDescriptionDepthStencilResolve msrtssResolve = {};
7901 VkMultisampledRenderToSingleSampledInfoEXT msrtss = {};
7902 if (desc.hasDepthStencilResolveAttachment())
7903 {
7904 ASSERT(!isRenderToTextureThroughExtension);
7905
7906 uint32_t depthStencilIndexGL = static_cast<uint32_t>(desc.depthStencilAttachmentIndex());
7907 const angle::Format &angleFormat = angle::Format::Get(desc[depthStencilIndexGL]);
7908
7909 depthStencilResolve.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
7910
7911 if (!renderer->getFeatures().supportsDepthStencilIndependentResolveNone.enabled)
7912 {
7913 // Assert that depth/stencil is not separately resolved without this feature
7914 ASSERT(desc.hasDepthResolveAttachment() || angleFormat.depthBits == 0);
7915 ASSERT(desc.hasStencilResolveAttachment() || angleFormat.stencilBits == 0);
7916
7917 depthStencilResolve.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
7918 depthStencilResolve.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
7919 }
7920 else
7921 {
7922 depthStencilResolve.depthResolveMode =
7923 desc.hasDepthResolveAttachment() && !isMSRTTEmulationDepthInvalidated
7924 ? VK_RESOLVE_MODE_SAMPLE_ZERO_BIT
7925 : VK_RESOLVE_MODE_NONE;
7926 depthStencilResolve.stencilResolveMode =
7927 desc.hasStencilResolveAttachment() && !isMSRTTEmulationStencilInvalidated
7928 ? VK_RESOLVE_MODE_SAMPLE_ZERO_BIT
7929 : VK_RESOLVE_MODE_NONE;
7930 }
7931
7932 // If depth/stencil attachment is invalidated or is otherwise not really resolved, don't set
7933 // it as the resolve attachment in the first place.
7934 const bool isResolvingDepth = !isMSRTTEmulationDepthInvalidated &&
7935 angleFormat.depthBits > 0 &&
7936 depthStencilResolve.depthResolveMode != VK_RESOLVE_MODE_NONE;
7937 const bool isResolvingStencil =
7938 !isMSRTTEmulationStencilInvalidated && angleFormat.stencilBits > 0 &&
7939 depthStencilResolve.stencilResolveMode != VK_RESOLVE_MODE_NONE;
7940
7941 if (isResolvingDepth || isResolvingStencil)
7942 {
7943 depthStencilResolve.pDepthStencilResolveAttachment = &depthStencilResolveAttachmentRef;
7944 vk::AddToPNextChain(&subpassDesc.back(), &depthStencilResolve);
7945 }
7946 }
7947 else if (isRenderToTextureThroughExtension)
7948 {
7949 ASSERT(subpassDesc.size() == 1);
7950 vk::InitializeMSRTSS(context, renderToTextureSamples, &subpassDesc.back(), &msrtssResolve,
7951 &msrtss);
7952 }
7953
7954 VkFragmentShadingRateAttachmentInfoKHR fragmentShadingRateAttachmentInfo = {};
7955 if (desc.hasFragmentShadingAttachment())
7956 {
7957 fragmentShadingRateAttachmentInfo.sType =
7958 VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
7959 fragmentShadingRateAttachmentInfo.pFragmentShadingRateAttachment =
7960 &fragmentShadingRateAttachmentRef;
7961 fragmentShadingRateAttachmentInfo.shadingRateAttachmentTexelSize =
7962 renderer->getMaxFragmentShadingRateAttachmentTexelSize();
7963
7964 vk::AddToPNextChain(&subpassDesc.back(), &fragmentShadingRateAttachmentInfo);
7965 }
7966
7967 std::vector<VkSubpassDependency2> subpassDependencies;
7968 if (hasUnresolveAttachments)
7969 {
7970 vk::InitializeUnresolveSubpassDependencies(
7971 subpassDesc, desc.getColorUnresolveAttachmentMask().any(),
7972 desc.hasDepthStencilUnresolveAttachment(), &subpassDependencies);
7973 }
7974
7975 const uint32_t drawSubpassIndex = static_cast<uint32_t>(subpassDesc.size()) - 1;
7976 vk::InitializeDefaultSubpassSelfDependencies(context, desc, drawSubpassIndex,
7977 &subpassDependencies);
7978
7979 VkRenderPassCreateInfo2 createInfo = {};
7980 createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2;
7981 createInfo.attachmentCount = attachmentCount.get();
7982 createInfo.pAttachments = attachmentDescs.data();
7983 createInfo.subpassCount = static_cast<uint32_t>(subpassDesc.size());
7984 createInfo.pSubpasses = subpassDesc.data();
7985
7986 if (!subpassDependencies.empty())
7987 {
7988 createInfo.dependencyCount = static_cast<uint32_t>(subpassDependencies.size());
7989 createInfo.pDependencies = subpassDependencies.data();
7990 }
7991
7992 const uint32_t viewMask = angle::BitMask<uint32_t>(desc.viewCount());
7993 if (desc.viewCount() > 0)
7994 {
7995 vk::SetRenderPassViewMask(context, &viewMask, &createInfo, &subpassDesc);
7996 }
7997
7998 // If VK_KHR_create_renderpass2 is not supported, we must use core Vulkan 1.0. This is
7999 // increasingly uncommon. Note that extensions that require chaining information to subpasses
8000 // are automatically not used when this extension is not available.
8001 if (!renderer->getFeatures().supportsRenderpass2.enabled)
8002 {
8003 ANGLE_TRY(vk::CreateRenderPass1(context, createInfo, desc.viewCount(), renderPass));
8004 }
8005 else
8006 {
8007 ANGLE_VK_TRY(context, renderPass->init2(context->getDevice(), createInfo));
8008 }
8009
8010 if (renderPassCounters != nullptr)
8011 {
8012 // Calculate perf counters associated with this render pass, such as load/store ops,
8013 // unresolve and resolve operations etc. This information is taken out of the render pass
8014 // create info. Depth/stencil resolve attachment uses RenderPass2 structures, so it's
8015 // passed in separately.
8016 vk::UpdateRenderPassPerfCounters(desc, createInfo, depthStencilResolve, renderPassCounters);
8017 }
8018
8019 return angle::Result::Continue;
8020 }
8021
8022 // ComputePipelineCache implementation
destroy(vk::ErrorContext * context)8023 void ComputePipelineCache::destroy(vk::ErrorContext *context)
8024 {
8025 VkDevice device = context->getDevice();
8026
8027 for (auto &item : mPayload)
8028 {
8029 vk::PipelineHelper &pipeline = item.second;
8030 ASSERT(context->getRenderer()->hasResourceUseFinished(pipeline.getResourceUse()));
8031 pipeline.destroy(device);
8032 }
8033
8034 mPayload.clear();
8035 }
8036
release(vk::ErrorContext * context)8037 void ComputePipelineCache::release(vk::ErrorContext *context)
8038 {
8039 for (auto &item : mPayload)
8040 {
8041 vk::PipelineHelper &pipeline = item.second;
8042 pipeline.release(context);
8043 }
8044
8045 mPayload.clear();
8046 }
8047
getOrCreatePipeline(vk::ErrorContext * context,vk::PipelineCacheAccess * pipelineCache,const vk::PipelineLayout & pipelineLayout,rx::vk::ComputePipelineOptions & pipelineOptions,PipelineSource source,vk::PipelineHelper ** pipelineOut,const char * shaderName,VkSpecializationInfo * specializationInfo,const vk::ShaderModuleMap & shaderModuleMap)8048 angle::Result ComputePipelineCache::getOrCreatePipeline(
8049 vk::ErrorContext *context,
8050 vk::PipelineCacheAccess *pipelineCache,
8051 const vk::PipelineLayout &pipelineLayout,
8052 rx::vk::ComputePipelineOptions &pipelineOptions,
8053 PipelineSource source,
8054 vk::PipelineHelper **pipelineOut,
8055 const char *shaderName,
8056 VkSpecializationInfo *specializationInfo,
8057 const vk::ShaderModuleMap &shaderModuleMap)
8058 {
8059 vk::ComputePipelineDesc desc(specializationInfo, pipelineOptions);
8060
8061 auto iter = mPayload.find(desc);
8062 if (iter != mPayload.end())
8063 {
8064 mCacheStats.hit();
8065 *pipelineOut = &iter->second;
8066 return angle::Result::Continue;
8067 }
8068 return createPipeline(context, pipelineCache, pipelineLayout, pipelineOptions, source,
8069 shaderName, *shaderModuleMap[gl::ShaderType::Compute].get(),
8070 specializationInfo, desc, pipelineOut);
8071 }
8072
createPipeline(vk::ErrorContext * context,vk::PipelineCacheAccess * pipelineCache,const vk::PipelineLayout & pipelineLayout,vk::ComputePipelineOptions & pipelineOptions,PipelineSource source,const char * shaderName,const vk::ShaderModule & shaderModule,VkSpecializationInfo * specializationInfo,const vk::ComputePipelineDesc & desc,vk::PipelineHelper ** pipelineOut)8073 angle::Result ComputePipelineCache::createPipeline(vk::ErrorContext *context,
8074 vk::PipelineCacheAccess *pipelineCache,
8075 const vk::PipelineLayout &pipelineLayout,
8076 vk::ComputePipelineOptions &pipelineOptions,
8077 PipelineSource source,
8078 const char *shaderName,
8079 const vk::ShaderModule &shaderModule,
8080 VkSpecializationInfo *specializationInfo,
8081 const vk::ComputePipelineDesc &desc,
8082 vk::PipelineHelper **pipelineOut)
8083 {
8084 VkPipelineShaderStageCreateInfo shaderStage = {};
8085 VkComputePipelineCreateInfo createInfo = {};
8086
8087 shaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
8088 shaderStage.flags = 0;
8089 shaderStage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
8090 shaderStage.module = shaderModule.getHandle();
8091 shaderStage.pName = shaderName ? shaderName : "main";
8092 shaderStage.pSpecializationInfo = specializationInfo;
8093
8094 createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
8095 createInfo.flags = 0;
8096 createInfo.stage = shaderStage;
8097 createInfo.layout = pipelineLayout.getHandle();
8098 createInfo.basePipelineHandle = VK_NULL_HANDLE;
8099 createInfo.basePipelineIndex = 0;
8100
8101 VkPipelineRobustnessCreateInfoEXT robustness = {};
8102 robustness.sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT;
8103
8104 // Enable robustness on the pipeline if needed. Note that the global robustBufferAccess feature
8105 // must be disabled by default.
8106 if (pipelineOptions.robustness != 0)
8107 {
8108 ASSERT(context->getFeatures().supportsPipelineRobustness.enabled);
8109
8110 robustness.storageBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
8111 robustness.uniformBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
8112 robustness.vertexInputs = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT;
8113 robustness.images = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT;
8114
8115 vk::AddToPNextChain(&createInfo, &robustness);
8116 }
8117
8118 // Restrict pipeline to protected or unprotected command buffers if possible.
8119 if (pipelineOptions.protectedAccess != 0)
8120 {
8121 ASSERT(context->getFeatures().supportsPipelineProtectedAccess.enabled);
8122 createInfo.flags |= VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT;
8123 }
8124 else if (context->getFeatures().supportsPipelineProtectedAccess.enabled)
8125 {
8126 createInfo.flags |= VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT;
8127 }
8128
8129 VkPipelineCreationFeedback feedback = {};
8130 VkPipelineCreationFeedback perStageFeedback = {};
8131 VkPipelineCreationFeedbackCreateInfo feedbackInfo = {};
8132 feedbackInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO;
8133 feedbackInfo.pPipelineCreationFeedback = &feedback;
8134 // Note: see comment in GraphicsPipelineDesc::initializePipeline about why per-stage feedback is
8135 // specified even though unused.
8136 feedbackInfo.pipelineStageCreationFeedbackCount = 1;
8137 feedbackInfo.pPipelineStageCreationFeedbacks = &perStageFeedback;
8138
8139 const bool supportsFeedback =
8140 context->getRenderer()->getFeatures().supportsPipelineCreationFeedback.enabled;
8141 if (supportsFeedback)
8142 {
8143 vk::AddToPNextChain(&createInfo, &feedbackInfo);
8144 }
8145
8146 vk::Pipeline pipeline;
8147 ANGLE_VK_TRY(context, pipelineCache->createComputePipeline(context, createInfo, &pipeline));
8148
8149 vk::CacheLookUpFeedback lookUpFeedback = vk::CacheLookUpFeedback::None;
8150
8151 if (supportsFeedback)
8152 {
8153 const bool cacheHit =
8154 (feedback.flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT) !=
8155 0;
8156
8157 lookUpFeedback = cacheHit ? vk::CacheLookUpFeedback::Hit : vk::CacheLookUpFeedback::Miss;
8158 ApplyPipelineCreationFeedback(context, feedback);
8159 }
8160 vk::PipelineHelper computePipeline = vk::PipelineHelper();
8161 computePipeline.setComputePipeline(std::move(pipeline), lookUpFeedback);
8162
8163 mCacheStats.missAndIncrementSize();
8164 mPayload[desc] = std::move(computePipeline);
8165 *pipelineOut = &mPayload[desc];
8166
8167 return angle::Result::Continue;
8168 }
8169
8170 // GraphicsPipelineCache implementation.
8171 template <typename Hash>
destroy(vk::ErrorContext * context)8172 void GraphicsPipelineCache<Hash>::destroy(vk::ErrorContext *context)
8173 {
8174 if (vk::ShouldDumpPipelineCacheGraph(context) && !mPayload.empty())
8175 {
8176 vk::DumpPipelineCacheGraph<Hash>(context, mPayload);
8177 }
8178
8179 accumulateCacheStats(context->getRenderer());
8180
8181 VkDevice device = context->getDevice();
8182
8183 for (auto &item : mPayload)
8184 {
8185 vk::PipelineHelper &pipeline = item.second;
8186 pipeline.destroy(device);
8187 }
8188
8189 mPayload.clear();
8190 }
8191
8192 template <typename Hash>
release(vk::ErrorContext * context)8193 void GraphicsPipelineCache<Hash>::release(vk::ErrorContext *context)
8194 {
8195 if (vk::ShouldDumpPipelineCacheGraph(context) && !mPayload.empty())
8196 {
8197 vk::DumpPipelineCacheGraph<Hash>(context, mPayload);
8198 }
8199
8200 for (auto &item : mPayload)
8201 {
8202 vk::PipelineHelper &pipeline = item.second;
8203 pipeline.release(context);
8204 }
8205
8206 mPayload.clear();
8207 }
8208
8209 template <typename Hash>
createPipeline(vk::ErrorContext * context,vk::PipelineCacheAccess * pipelineCache,const vk::RenderPass & compatibleRenderPass,const vk::PipelineLayout & pipelineLayout,const vk::GraphicsPipelineShadersInfo & shaders,PipelineSource source,const vk::GraphicsPipelineDesc & desc,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)8210 angle::Result GraphicsPipelineCache<Hash>::createPipeline(
8211 vk::ErrorContext *context,
8212 vk::PipelineCacheAccess *pipelineCache,
8213 const vk::RenderPass &compatibleRenderPass,
8214 const vk::PipelineLayout &pipelineLayout,
8215 const vk::GraphicsPipelineShadersInfo &shaders,
8216 PipelineSource source,
8217 const vk::GraphicsPipelineDesc &desc,
8218 const vk::GraphicsPipelineDesc **descPtrOut,
8219 vk::PipelineHelper **pipelineOut)
8220 {
8221 vk::Pipeline newPipeline;
8222 vk::CacheLookUpFeedback feedback = vk::CacheLookUpFeedback::None;
8223
8224 // This "if" is left here for the benefit of VulkanPipelineCachePerfTest.
8225 if (context != nullptr)
8226 {
8227 constexpr vk::GraphicsPipelineSubset kSubset =
8228 GraphicsPipelineCacheTypeHelper<Hash>::kSubset;
8229
8230 ANGLE_VK_TRY(context,
8231 desc.initializePipeline(context, pipelineCache, kSubset, compatibleRenderPass,
8232 pipelineLayout, shaders, &newPipeline, &feedback));
8233 }
8234
8235 if (source == PipelineSource::WarmUp)
8236 {
8237 // Warm up task will pass in the placeholder PipelineHelper created in
8238 // ProgramExecutableVk::getPipelineCacheWarmUpTasks. Update that with the newly created
8239 // pipeline.
8240 **pipelineOut =
8241 vk::PipelineHelper(std::move(newPipeline), vk::CacheLookUpFeedback::WarmUpMiss);
8242 ASSERT(!shaders.usePipelineLibrary());
8243 }
8244 else
8245 {
8246 addToCache(source, desc, std::move(newPipeline), feedback, descPtrOut, pipelineOut);
8247 if (shaders.usePipelineLibrary())
8248 {
8249 (*pipelineOut)->setLinkedLibraryReferences(shaders.pipelineLibrary());
8250 }
8251 }
8252 return angle::Result::Continue;
8253 }
8254
8255 template <typename Hash>
addToCache(PipelineSource source,const vk::GraphicsPipelineDesc & desc,vk::Pipeline && pipeline,vk::CacheLookUpFeedback feedback,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)8256 void GraphicsPipelineCache<Hash>::addToCache(PipelineSource source,
8257 const vk::GraphicsPipelineDesc &desc,
8258 vk::Pipeline &&pipeline,
8259 vk::CacheLookUpFeedback feedback,
8260 const vk::GraphicsPipelineDesc **descPtrOut,
8261 vk::PipelineHelper **pipelineOut)
8262 {
8263 ASSERT(mPayload.find(desc) == mPayload.end());
8264
8265 mCacheStats.missAndIncrementSize();
8266
8267 switch (source)
8268 {
8269 case PipelineSource::WarmUp:
8270 feedback = feedback == vk::CacheLookUpFeedback::Hit
8271 ? vk::CacheLookUpFeedback::WarmUpHit
8272 : vk::CacheLookUpFeedback::WarmUpMiss;
8273 break;
8274 case PipelineSource::DrawLinked:
8275 feedback = feedback == vk::CacheLookUpFeedback::Hit
8276 ? vk::CacheLookUpFeedback::LinkedDrawHit
8277 : vk::CacheLookUpFeedback::LinkedDrawMiss;
8278 break;
8279 case PipelineSource::Utils:
8280 feedback = feedback == vk::CacheLookUpFeedback::Hit
8281 ? vk::CacheLookUpFeedback::UtilsHit
8282 : vk::CacheLookUpFeedback::UtilsMiss;
8283 break;
8284 default:
8285 break;
8286 }
8287
8288 auto insertedItem = mPayload.emplace(std::piecewise_construct, std::forward_as_tuple(desc),
8289 std::forward_as_tuple(std::move(pipeline), feedback));
8290 *descPtrOut = &insertedItem.first->first;
8291 *pipelineOut = &insertedItem.first->second;
8292 }
8293
8294 template <typename Hash>
populate(const vk::GraphicsPipelineDesc & desc,vk::Pipeline && pipeline,vk::PipelineHelper ** pipelineHelperOut)8295 void GraphicsPipelineCache<Hash>::populate(const vk::GraphicsPipelineDesc &desc,
8296 vk::Pipeline &&pipeline,
8297 vk::PipelineHelper **pipelineHelperOut)
8298 {
8299 auto item = mPayload.find(desc);
8300 if (item != mPayload.end())
8301 {
8302 return;
8303 }
8304
8305 // This function is used by -
8306 // 1. WarmUp tasks to insert placeholder pipelines
8307 // 2. VulkanPipelineCachePerfTest
8308 auto insertedItem =
8309 mPayload.emplace(std::piecewise_construct, std::forward_as_tuple(desc),
8310 std::forward_as_tuple(std::move(pipeline), vk::CacheLookUpFeedback::None));
8311
8312 if (pipelineHelperOut)
8313 {
8314 ASSERT(insertedItem.second);
8315 *pipelineHelperOut = &insertedItem.first->second;
8316 }
8317 }
8318
8319 // Instantiate the pipeline cache functions
8320 template void GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>::destroy(
8321 vk::ErrorContext *context);
8322 template void GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>::release(
8323 vk::ErrorContext *context);
8324 template angle::Result GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>::createPipeline(
8325 vk::ErrorContext *context,
8326 vk::PipelineCacheAccess *pipelineCache,
8327 const vk::RenderPass &compatibleRenderPass,
8328 const vk::PipelineLayout &pipelineLayout,
8329 const vk::GraphicsPipelineShadersInfo &shaders,
8330 PipelineSource source,
8331 const vk::GraphicsPipelineDesc &desc,
8332 const vk::GraphicsPipelineDesc **descPtrOut,
8333 vk::PipelineHelper **pipelineOut);
8334 template void GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>::populate(
8335 const vk::GraphicsPipelineDesc &desc,
8336 vk::Pipeline &&pipeline,
8337 vk::PipelineHelper **pipelineHelperOut);
8338
8339 template void GraphicsPipelineCache<GraphicsPipelineDescShadersHash>::destroy(
8340 vk::ErrorContext *context);
8341 template void GraphicsPipelineCache<GraphicsPipelineDescShadersHash>::release(
8342 vk::ErrorContext *context);
8343 template angle::Result GraphicsPipelineCache<GraphicsPipelineDescShadersHash>::createPipeline(
8344 vk::ErrorContext *context,
8345 vk::PipelineCacheAccess *pipelineCache,
8346 const vk::RenderPass &compatibleRenderPass,
8347 const vk::PipelineLayout &pipelineLayout,
8348 const vk::GraphicsPipelineShadersInfo &shaders,
8349 PipelineSource source,
8350 const vk::GraphicsPipelineDesc &desc,
8351 const vk::GraphicsPipelineDesc **descPtrOut,
8352 vk::PipelineHelper **pipelineOut);
8353 template void GraphicsPipelineCache<GraphicsPipelineDescShadersHash>::populate(
8354 const vk::GraphicsPipelineDesc &desc,
8355 vk::Pipeline &&pipeline,
8356 vk::PipelineHelper **pipelineHelperOut);
8357
8358 // DescriptorSetLayoutCache implementation.
8359 DescriptorSetLayoutCache::DescriptorSetLayoutCache() = default;
8360
~DescriptorSetLayoutCache()8361 DescriptorSetLayoutCache::~DescriptorSetLayoutCache()
8362 {
8363 ASSERT(mPayload.empty());
8364 }
8365
destroy(vk::Renderer * renderer)8366 void DescriptorSetLayoutCache::destroy(vk::Renderer *renderer)
8367 {
8368 renderer->accumulateCacheStats(VulkanCacheType::DescriptorSetLayout, mCacheStats);
8369 ASSERT(AllCacheEntriesHaveUniqueReference(mPayload));
8370 mPayload.clear();
8371 }
8372
getDescriptorSetLayout(vk::ErrorContext * context,const vk::DescriptorSetLayoutDesc & desc,vk::DescriptorSetLayoutPtr * descriptorSetLayoutOut)8373 angle::Result DescriptorSetLayoutCache::getDescriptorSetLayout(
8374 vk::ErrorContext *context,
8375 const vk::DescriptorSetLayoutDesc &desc,
8376 vk::DescriptorSetLayoutPtr *descriptorSetLayoutOut)
8377 {
8378 // Note: this function may be called without holding the share group lock.
8379 std::unique_lock<angle::SimpleMutex> lock(mMutex);
8380
8381 auto iter = mPayload.find(desc);
8382 if (iter != mPayload.end())
8383 {
8384 *descriptorSetLayoutOut = iter->second;
8385 mCacheStats.hit();
8386 return angle::Result::Continue;
8387 }
8388
8389 // If DescriptorSetLayoutDesc is empty, reuse placeholder descriptor set layout handle
8390 if (desc.empty())
8391 {
8392 *descriptorSetLayoutOut = context->getRenderer()->getEmptyDescriptorLayout();
8393 return angle::Result::Continue;
8394 }
8395
8396 mCacheStats.missAndIncrementSize();
8397 // We must unpack the descriptor set layout description.
8398 vk::DescriptorSetLayoutBindingVector bindingVector;
8399 desc.unpackBindings(&bindingVector);
8400
8401 VkDescriptorSetLayoutCreateInfo createInfo = {};
8402 createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8403 createInfo.flags = 0;
8404 createInfo.bindingCount = static_cast<uint32_t>(bindingVector.size());
8405 createInfo.pBindings = bindingVector.data();
8406
8407 vk::DescriptorSetLayoutPtr newLayout =
8408 vk::DescriptorSetLayoutPtr::MakeShared(context->getDevice());
8409 ANGLE_VK_TRY(context, newLayout->init(context->getDevice(), createInfo));
8410
8411 *descriptorSetLayoutOut = newLayout;
8412 mPayload.emplace(desc, std::move(newLayout));
8413
8414 return angle::Result::Continue;
8415 }
8416
8417 // PipelineLayoutCache implementation.
8418 PipelineLayoutCache::PipelineLayoutCache() = default;
8419
~PipelineLayoutCache()8420 PipelineLayoutCache::~PipelineLayoutCache()
8421 {
8422 ASSERT(mPayload.empty());
8423 }
8424
destroy(vk::Renderer * renderer)8425 void PipelineLayoutCache::destroy(vk::Renderer *renderer)
8426 {
8427 accumulateCacheStats(renderer);
8428 ASSERT(AllCacheEntriesHaveUniqueReference(mPayload));
8429 mPayload.clear();
8430 }
8431
getPipelineLayout(vk::ErrorContext * context,const vk::PipelineLayoutDesc & desc,const vk::DescriptorSetLayoutPointerArray & descriptorSetLayouts,vk::PipelineLayoutPtr * pipelineLayoutOut)8432 angle::Result PipelineLayoutCache::getPipelineLayout(
8433 vk::ErrorContext *context,
8434 const vk::PipelineLayoutDesc &desc,
8435 const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts,
8436 vk::PipelineLayoutPtr *pipelineLayoutOut)
8437 {
8438 // Note: this function may be called without holding the share group lock.
8439 std::unique_lock<angle::SimpleMutex> lock(mMutex);
8440
8441 auto iter = mPayload.find(desc);
8442 if (iter != mPayload.end())
8443 {
8444 *pipelineLayoutOut = iter->second;
8445 mCacheStats.hit();
8446 return angle::Result::Continue;
8447 }
8448
8449 mCacheStats.missAndIncrementSize();
8450 // Note this does not handle gaps in descriptor set layouts gracefully.
8451 angle::FixedVector<VkDescriptorSetLayout, vk::kMaxDescriptorSetLayouts> setLayoutHandles;
8452 for (const vk::DescriptorSetLayoutPtr &layoutPtr : descriptorSetLayouts)
8453 {
8454 if (layoutPtr)
8455 {
8456 VkDescriptorSetLayout setLayout = layoutPtr->getHandle();
8457 ASSERT(setLayout != VK_NULL_HANDLE);
8458 setLayoutHandles.push_back(setLayout);
8459 }
8460 }
8461
8462 const vk::PackedPushConstantRange &descPushConstantRange = desc.getPushConstantRange();
8463 VkPushConstantRange pushConstantRange;
8464 pushConstantRange.stageFlags = descPushConstantRange.stageMask;
8465 pushConstantRange.offset = descPushConstantRange.offset;
8466 pushConstantRange.size = descPushConstantRange.size;
8467
8468 // No pipeline layout found. We must create a new one.
8469 VkPipelineLayoutCreateInfo createInfo = {};
8470 createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8471 createInfo.flags = 0;
8472 createInfo.setLayoutCount = static_cast<uint32_t>(setLayoutHandles.size());
8473 createInfo.pSetLayouts = setLayoutHandles.data();
8474 if (pushConstantRange.size > 0)
8475 {
8476 createInfo.pushConstantRangeCount = 1;
8477 createInfo.pPushConstantRanges = &pushConstantRange;
8478 }
8479
8480 vk::PipelineLayoutPtr newLayout = vk::PipelineLayoutPtr::MakeShared(context->getDevice());
8481 ANGLE_VK_TRY(context, newLayout->init(context->getDevice(), createInfo));
8482
8483 *pipelineLayoutOut = newLayout;
8484 mPayload.emplace(desc, std::move(newLayout));
8485
8486 return angle::Result::Continue;
8487 }
8488
8489 // YuvConversionCache implementation
8490 SamplerYcbcrConversionCache::SamplerYcbcrConversionCache() = default;
8491
~SamplerYcbcrConversionCache()8492 SamplerYcbcrConversionCache::~SamplerYcbcrConversionCache()
8493 {
8494 ASSERT(mExternalFormatPayload.empty() && mVkFormatPayload.empty());
8495 }
8496
destroy(vk::Renderer * renderer)8497 void SamplerYcbcrConversionCache::destroy(vk::Renderer *renderer)
8498 {
8499 renderer->accumulateCacheStats(VulkanCacheType::SamplerYcbcrConversion, mCacheStats);
8500
8501 VkDevice device = renderer->getDevice();
8502
8503 uint32_t count = static_cast<uint32_t>(mExternalFormatPayload.size());
8504 for (auto &iter : mExternalFormatPayload)
8505 {
8506 vk::SamplerYcbcrConversion &samplerYcbcrConversion = iter.second;
8507 samplerYcbcrConversion.destroy(device);
8508 }
8509 renderer->onDeallocateHandle(vk::HandleType::SamplerYcbcrConversion, count);
8510
8511 count = static_cast<uint32_t>(mExternalFormatPayload.size());
8512 for (auto &iter : mVkFormatPayload)
8513 {
8514 vk::SamplerYcbcrConversion &samplerYcbcrConversion = iter.second;
8515 samplerYcbcrConversion.destroy(device);
8516 }
8517 renderer->onDeallocateHandle(vk::HandleType::SamplerYcbcrConversion, count);
8518
8519 mExternalFormatPayload.clear();
8520 mVkFormatPayload.clear();
8521 }
8522
getSamplerYcbcrConversion(vk::ErrorContext * context,const vk::YcbcrConversionDesc & ycbcrConversionDesc,VkSamplerYcbcrConversion * vkSamplerYcbcrConversionOut)8523 angle::Result SamplerYcbcrConversionCache::getSamplerYcbcrConversion(
8524 vk::ErrorContext *context,
8525 const vk::YcbcrConversionDesc &ycbcrConversionDesc,
8526 VkSamplerYcbcrConversion *vkSamplerYcbcrConversionOut)
8527 {
8528 ASSERT(ycbcrConversionDesc.valid());
8529 ASSERT(vkSamplerYcbcrConversionOut);
8530
8531 SamplerYcbcrConversionMap &payload =
8532 (ycbcrConversionDesc.getExternalFormat() != 0) ? mExternalFormatPayload : mVkFormatPayload;
8533 const auto iter = payload.find(ycbcrConversionDesc);
8534 if (iter != payload.end())
8535 {
8536 vk::SamplerYcbcrConversion &samplerYcbcrConversion = iter->second;
8537 mCacheStats.hit();
8538 *vkSamplerYcbcrConversionOut = samplerYcbcrConversion.getHandle();
8539 return angle::Result::Continue;
8540 }
8541
8542 mCacheStats.missAndIncrementSize();
8543
8544 // Create the VkSamplerYcbcrConversion
8545 vk::SamplerYcbcrConversion wrappedSamplerYcbcrConversion;
8546 ANGLE_TRY(ycbcrConversionDesc.init(context, &wrappedSamplerYcbcrConversion));
8547
8548 auto insertedItem = payload.emplace(
8549 ycbcrConversionDesc, vk::SamplerYcbcrConversion(std::move(wrappedSamplerYcbcrConversion)));
8550 vk::SamplerYcbcrConversion &insertedSamplerYcbcrConversion = insertedItem.first->second;
8551 *vkSamplerYcbcrConversionOut = insertedSamplerYcbcrConversion.getHandle();
8552
8553 context->getRenderer()->onAllocateHandle(vk::HandleType::SamplerYcbcrConversion);
8554
8555 return angle::Result::Continue;
8556 }
8557
8558 // SamplerCache implementation.
8559 SamplerCache::SamplerCache() = default;
8560
~SamplerCache()8561 SamplerCache::~SamplerCache()
8562 {
8563 ASSERT(mPayload.empty());
8564 }
8565
destroy(vk::Renderer * renderer)8566 void SamplerCache::destroy(vk::Renderer *renderer)
8567 {
8568 renderer->accumulateCacheStats(VulkanCacheType::Sampler, mCacheStats);
8569
8570 uint32_t count = static_cast<uint32_t>(mPayload.size());
8571 ASSERT(AllCacheEntriesHaveUniqueReference(mPayload));
8572 mPayload.clear();
8573 renderer->onDeallocateHandle(vk::HandleType::Sampler, count);
8574 }
8575
getSampler(ContextVk * contextVk,const vk::SamplerDesc & desc,vk::SharedSamplerPtr * samplerOut)8576 angle::Result SamplerCache::getSampler(ContextVk *contextVk,
8577 const vk::SamplerDesc &desc,
8578 vk::SharedSamplerPtr *samplerOut)
8579 {
8580 auto iter = mPayload.find(desc);
8581 if (iter != mPayload.end())
8582 {
8583 *samplerOut = iter->second;
8584 mCacheStats.hit();
8585 return angle::Result::Continue;
8586 }
8587
8588 mCacheStats.missAndIncrementSize();
8589 vk::SharedSamplerPtr newSampler = vk::SharedSamplerPtr::MakeShared(contextVk->getDevice());
8590 ANGLE_TRY(newSampler->init(contextVk, desc));
8591
8592 (*samplerOut) = newSampler;
8593 mPayload.emplace(desc, std::move(newSampler));
8594
8595 contextVk->getRenderer()->onAllocateHandle(vk::HandleType::Sampler);
8596
8597 return angle::Result::Continue;
8598 }
8599 } // namespace rx
8600