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