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.h:
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 #ifndef LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
12 #define LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
13
14 #include "common/Color.h"
15 #include "common/FixedVector.h"
16 #include "common/SimpleMutex.h"
17 #include "common/WorkerThread.h"
18 #include "libANGLE/Uniform.h"
19 #include "libANGLE/renderer/vulkan/ShaderInterfaceVariableInfoMap.h"
20 #include "libANGLE/renderer/vulkan/vk_resource.h"
21 #include "libANGLE/renderer/vulkan/vk_utils.h"
22
23 namespace gl
24 {
25 class ProgramExecutable;
26 } // namespace gl
27
28 namespace rx
29 {
30 class ShaderInterfaceVariableInfoMap;
31 class UpdateDescriptorSetsBuilder;
32
33 // Some descriptor set and pipeline layout constants.
34 //
35 // The set/binding assignment is done as following:
36 //
37 // - Set 0 contains uniform blocks created to encompass default uniforms. 1 binding is used per
38 // pipeline stage. Additionally, transform feedback buffers are bound from binding 2 and up.
39 // For internal shaders, set 0 is used for all the needed resources.
40 // - Set 1 contains all textures (including texture buffers).
41 // - Set 2 contains all other shader resources, such as uniform and storage blocks, atomic counter
42 // buffers, images and image buffers.
43
44 enum class DescriptorSetIndex : uint32_t
45 {
46 Internal = 0, // Internal shaders
47 UniformsAndXfb = Internal, // Uniforms set index
48 Texture = 1, // Textures set index
49 ShaderResource = 2, // Other shader resources set index
50
51 InvalidEnum = 3,
52 EnumCount = InvalidEnum,
53 };
54
55 namespace vk
56 {
57 class BufferHelper;
58 class DynamicDescriptorPool;
59 class SamplerHelper;
60 enum class ImageLayout;
61 class PipelineCacheAccess;
62 class RenderPassCommandBufferHelper;
63
64 using RefCountedDescriptorSetLayout = AtomicRefCounted<DescriptorSetLayout>;
65 using RefCountedPipelineLayout = AtomicRefCounted<PipelineLayout>;
66 using RefCountedSamplerYcbcrConversion = RefCounted<SamplerYcbcrConversion>;
67
68 // Packed Vk resource descriptions.
69 // Most Vk types use many more bits than required to represent the underlying data.
70 // Since ANGLE wants to cache things like RenderPasses and Pipeline State Objects using
71 // hashing (and also needs to check equality) we can optimize these operations by
72 // using fewer bits. Hence the packed types.
73 //
74 // One implementation note: these types could potentially be improved by using even
75 // fewer bits. For example, boolean values could be represented by a single bit instead
76 // of a uint8_t. However at the current time there are concerns about the portability
77 // of bitfield operators, and complexity issues with using bit mask operations. This is
78 // something we will likely want to investigate as the Vulkan implementation progresses.
79 //
80 // Second implementation note: the struct packing is also a bit fragile, and some of the
81 // packing requirements depend on using alignas and field ordering to get the result of
82 // packing nicely into the desired space. This is something we could also potentially fix
83 // with a redesign to use bitfields or bit mask operations.
84
85 // Enable struct padding warnings for the code below since it is used in caches.
86 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
87
88 enum class ResourceAccess
89 {
90 Unused = 0x0,
91 ReadOnly = 0x1,
92 WriteOnly = 0x2,
93 ReadWrite = ReadOnly | WriteOnly,
94 };
95
UpdateAccess(ResourceAccess * oldAccess,ResourceAccess newAccess)96 inline void UpdateAccess(ResourceAccess *oldAccess, ResourceAccess newAccess)
97 {
98 *oldAccess = static_cast<ResourceAccess>(ToUnderlying(newAccess) | ToUnderlying(*oldAccess));
99 }
HasResourceWriteAccess(ResourceAccess access)100 inline bool HasResourceWriteAccess(ResourceAccess access)
101 {
102 return (ToUnderlying(access) & ToUnderlying(ResourceAccess::WriteOnly)) != 0;
103 }
104
105 enum class RenderPassLoadOp
106 {
107 Load = VK_ATTACHMENT_LOAD_OP_LOAD,
108 Clear = VK_ATTACHMENT_LOAD_OP_CLEAR,
109 DontCare = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
110 None,
111 };
112 enum class RenderPassStoreOp
113 {
114 Store = VK_ATTACHMENT_STORE_OP_STORE,
115 DontCare = VK_ATTACHMENT_STORE_OP_DONT_CARE,
116 None,
117 };
118
119 // There can be a maximum of IMPLEMENTATION_MAX_DRAW_BUFFERS color and resolve attachments, plus -
120 // - one depth/stencil attachment
121 // - one depth/stencil resolve attachment
122 // - one fragment shading rate attachment
123 constexpr size_t kMaxFramebufferAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 + 3;
124 template <typename T>
125 using FramebufferAttachmentArray = std::array<T, kMaxFramebufferAttachments>;
126 template <typename T>
127 using FramebufferAttachmentsVector = angle::FixedVector<T, kMaxFramebufferAttachments>;
128 using FramebufferAttachmentMask = angle::BitSet<kMaxFramebufferAttachments>;
129
130 constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
131 template <typename T>
132 using FramebufferNonResolveAttachmentArray = std::array<T, kMaxFramebufferNonResolveAttachments>;
133 using FramebufferNonResolveAttachmentMask = angle::BitSet16<kMaxFramebufferNonResolveAttachments>;
134
135 class alignas(4) RenderPassDesc final
136 {
137 public:
138 RenderPassDesc();
139 ~RenderPassDesc();
140 RenderPassDesc(const RenderPassDesc &other);
141 RenderPassDesc &operator=(const RenderPassDesc &other);
142
143 // Set format for an enabled GL color attachment.
144 void packColorAttachment(size_t colorIndexGL, angle::FormatID formatID);
145 // Mark a GL color attachment index as disabled.
146 void packColorAttachmentGap(size_t colorIndexGL);
147 // The caller must pack the depth/stencil attachment last, which is packed right after the color
148 // attachments (including gaps), i.e. with an index starting from |colorAttachmentRange()|.
149 void packDepthStencilAttachment(angle::FormatID angleFormatID);
150 void updateDepthStencilAccess(ResourceAccess access);
151 // Indicate that a color attachment should have a corresponding resolve attachment.
152 void packColorResolveAttachment(size_t colorIndexGL);
153 // Indicate that a YUV texture is attached to the resolve attachment.
154 void packYUVResolveAttachment(size_t colorIndexGL);
155 // Remove the resolve attachment. Used when optimizing blit through resolve attachment to
156 // temporarily pack a resolve attachment and then remove it.
157 void removeColorResolveAttachment(size_t colorIndexGL);
158 // Indicate that a color attachment should take its data from the resolve attachment initially.
159 void packColorUnresolveAttachment(size_t colorIndexGL);
160 void removeColorUnresolveAttachment(size_t colorIndexGL);
161 // Indicate that a depth/stencil attachment should have a corresponding resolve attachment.
162 void packDepthResolveAttachment();
163 void packStencilResolveAttachment();
164 // Indicate that a depth/stencil attachment should take its data from the resolve attachment
165 // initially.
166 void packDepthUnresolveAttachment();
167 void packStencilUnresolveAttachment();
168 void removeDepthStencilUnresolveAttachment();
169
170 void setWriteControlMode(gl::SrgbWriteControlMode mode);
171
172 size_t hash() const;
173
174 // Color attachments are in [0, colorAttachmentRange()), with possible gaps.
colorAttachmentRange()175 size_t colorAttachmentRange() const { return mColorAttachmentRange; }
depthStencilAttachmentIndex()176 size_t depthStencilAttachmentIndex() const { return colorAttachmentRange(); }
177
178 bool isColorAttachmentEnabled(size_t colorIndexGL) const;
hasYUVResolveAttachment()179 bool hasYUVResolveAttachment() const { return mIsYUVResolve; }
180 bool hasDepthStencilAttachment() const;
getColorResolveAttachmentMask()181 gl::DrawBufferMask getColorResolveAttachmentMask() const { return mColorResolveAttachmentMask; }
hasColorResolveAttachment(size_t colorIndexGL)182 bool hasColorResolveAttachment(size_t colorIndexGL) const
183 {
184 return mColorResolveAttachmentMask.test(colorIndexGL);
185 }
getColorUnresolveAttachmentMask()186 gl::DrawBufferMask getColorUnresolveAttachmentMask() const
187 {
188 return mColorUnresolveAttachmentMask;
189 }
hasColorUnresolveAttachment(size_t colorIndexGL)190 bool hasColorUnresolveAttachment(size_t colorIndexGL) const
191 {
192 return mColorUnresolveAttachmentMask.test(colorIndexGL);
193 }
hasDepthStencilResolveAttachment()194 bool hasDepthStencilResolveAttachment() const { return mResolveDepth || mResolveStencil; }
hasDepthResolveAttachment()195 bool hasDepthResolveAttachment() const { return mResolveDepth; }
hasStencilResolveAttachment()196 bool hasStencilResolveAttachment() const { return mResolveStencil; }
hasDepthStencilUnresolveAttachment()197 bool hasDepthStencilUnresolveAttachment() const { return mUnresolveDepth || mUnresolveStencil; }
hasDepthUnresolveAttachment()198 bool hasDepthUnresolveAttachment() const { return mUnresolveDepth; }
hasStencilUnresolveAttachment()199 bool hasStencilUnresolveAttachment() const { return mUnresolveStencil; }
getSRGBWriteControlMode()200 gl::SrgbWriteControlMode getSRGBWriteControlMode() const
201 {
202 return static_cast<gl::SrgbWriteControlMode>(mSrgbWriteControl);
203 }
204
isLegacyDitherEnabled()205 bool isLegacyDitherEnabled() const { return mLegacyDitherEnabled; }
206
207 void setLegacyDither(bool enabled);
208
209 // Get the number of clearable attachments in the Vulkan render pass, i.e. after removing
210 // disabled color attachments.
211 size_t clearableAttachmentCount() const;
212 // Get the total number of attachments in the Vulkan render pass, i.e. after removing disabled
213 // color attachments.
214 size_t attachmentCount() const;
215
setSamples(GLint samples)216 void setSamples(GLint samples) { mSamples = static_cast<uint8_t>(samples); }
samples()217 uint8_t samples() const { return mSamples; }
218
setViewCount(GLsizei viewCount)219 void setViewCount(GLsizei viewCount) { mViewCount = static_cast<uint8_t>(viewCount); }
viewCount()220 uint8_t viewCount() const { return mViewCount; }
221
setFramebufferFetchMode(bool hasFramebufferFetch)222 void setFramebufferFetchMode(bool hasFramebufferFetch)
223 {
224 mHasFramebufferFetch = hasFramebufferFetch;
225 }
hasFramebufferFetch()226 bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
227
updateRenderToTexture(bool isRenderToTexture)228 void updateRenderToTexture(bool isRenderToTexture) { mIsRenderToTexture = isRenderToTexture; }
isRenderToTexture()229 bool isRenderToTexture() const { return mIsRenderToTexture; }
230
setFragmentShadingAttachment(bool value)231 void setFragmentShadingAttachment(bool value) { mHasFragmentShadingAttachment = value; }
hasFragmentShadingAttachment()232 bool hasFragmentShadingAttachment() const { return mHasFragmentShadingAttachment; }
233
234 angle::FormatID operator[](size_t index) const
235 {
236 ASSERT(index < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1);
237 return static_cast<angle::FormatID>(mAttachmentFormats[index]);
238 }
239
240 private:
241 uint8_t mSamples;
242 uint8_t mColorAttachmentRange;
243
244 // Multiview
245 uint8_t mViewCount;
246
247 // sRGB
248 uint8_t mSrgbWriteControl : 1;
249
250 // Framebuffer fetch
251 uint8_t mHasFramebufferFetch : 1;
252
253 // Depth/stencil resolve
254 uint8_t mResolveDepth : 1;
255 uint8_t mResolveStencil : 1;
256
257 // Multisampled render to texture
258 uint8_t mIsRenderToTexture : 1;
259 uint8_t mUnresolveDepth : 1;
260 uint8_t mUnresolveStencil : 1;
261
262 // Dithering state when using VK_EXT_legacy_dithering
263 uint8_t mLegacyDitherEnabled : 1;
264
265 // external_format_resolve
266 uint8_t mIsYUVResolve : 1;
267
268 // Foveated rendering
269 uint8_t mHasFragmentShadingAttachment : 1;
270
271 // Available space for expansion.
272 uint8_t mPadding2 : 6;
273
274 // Whether each color attachment has a corresponding resolve attachment. Color resolve
275 // attachments can be used to optimize resolve through glBlitFramebuffer() as well as support
276 // GL_EXT_multisampled_render_to_texture and GL_EXT_multisampled_render_to_texture2.
277 gl::DrawBufferMask mColorResolveAttachmentMask;
278
279 // Whether each color attachment with a corresponding resolve attachment should be initialized
280 // with said resolve attachment in an initial subpass. This is an optimization to avoid
281 // loadOp=LOAD on the implicit multisampled image used with multisampled-render-to-texture
282 // render targets. This operation is referred to as "unresolve".
283 //
284 // Unused when VK_EXT_multisampled_render_to_single_sampled is available.
285 gl::DrawBufferMask mColorUnresolveAttachmentMask;
286
287 // Color attachment formats are stored with their GL attachment indices. The depth/stencil
288 // attachment formats follow the last enabled color attachment. When creating a render pass,
289 // the disabled attachments are removed and the resulting attachments are packed.
290 //
291 // The attachment indices provided as input to various functions in this file are thus GL
292 // attachment indices. These indices are marked as such, e.g. colorIndexGL. The render pass
293 // (and corresponding framebuffer object) lists the packed attachments, with the corresponding
294 // indices marked with Vk, e.g. colorIndexVk. The subpass attachment references create the
295 // link between the two index spaces. The subpass declares attachment references with GL
296 // indices (which corresponds to the location decoration of shader outputs). The attachment
297 // references then contain the Vulkan indices or VK_ATTACHMENT_UNUSED.
298 //
299 // For example, if GL uses color attachments 0 and 3, then there are two render pass
300 // attachments (indexed 0 and 1) and 4 subpass attachments:
301 //
302 // - Subpass attachment 0 -> Renderpass attachment 0
303 // - Subpass attachment 1 -> VK_ATTACHMENT_UNUSED
304 // - Subpass attachment 2 -> VK_ATTACHMENT_UNUSED
305 // - Subpass attachment 3 -> Renderpass attachment 1
306 //
307 // The resolve attachments are packed after the non-resolve attachments. They use the same
308 // formats, so they are not specified in this array.
309 FramebufferNonResolveAttachmentArray<uint8_t> mAttachmentFormats;
310 };
311
312 bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
313
314 constexpr size_t kRenderPassDescSize = sizeof(RenderPassDesc);
315 static_assert(kRenderPassDescSize == 16, "Size check failed");
316
317 enum class GraphicsPipelineSubset
318 {
319 Complete, // Including all subsets
320 VertexInput,
321 Shaders,
322 FragmentOutput,
323 };
324
325 enum class CacheLookUpFeedback
326 {
327 None,
328 Hit,
329 Miss,
330 LinkedDrawHit,
331 LinkedDrawMiss,
332 WarmUpHit,
333 WarmUpMiss,
334 UtilsHit,
335 UtilsMiss,
336 };
337
338 struct PackedAttachmentOpsDesc final
339 {
340 // RenderPassLoadOp is in range [0, 3], and RenderPassStoreOp is in range [0, 2].
341 uint16_t loadOp : 2;
342 uint16_t storeOp : 2;
343 uint16_t stencilLoadOp : 2;
344 uint16_t stencilStoreOp : 2;
345 // If a corresponding resolve attachment exists, storeOp may already be DONT_CARE, and it's
346 // unclear whether the attachment was invalidated or not. This information is passed along here
347 // so that the resolve attachment's storeOp can be set to DONT_CARE if the attachment is
348 // invalidated, and if possible removed from the list of resolve attachments altogether. Note
349 // that the latter may not be possible if the render pass has multiple subpasses due to Vulkan
350 // render pass compatibility rules.
351 uint16_t isInvalidated : 1;
352 uint16_t isStencilInvalidated : 1;
353 uint16_t padding1 : 6;
354
355 // Layouts take values from ImageLayout, so they are small. Layouts that are possible here are
356 // placed at the beginning of that enum.
357 uint16_t initialLayout : 5;
358 uint16_t finalLayout : 5;
359 uint16_t padding2 : 6;
360 };
361
362 static_assert(sizeof(PackedAttachmentOpsDesc) == 4, "Size check failed");
363
364 class PackedAttachmentIndex;
365
366 class AttachmentOpsArray final
367 {
368 public:
369 AttachmentOpsArray();
370 ~AttachmentOpsArray();
371 AttachmentOpsArray(const AttachmentOpsArray &other);
372 AttachmentOpsArray &operator=(const AttachmentOpsArray &other);
373
374 const PackedAttachmentOpsDesc &operator[](PackedAttachmentIndex index) const;
375 PackedAttachmentOpsDesc &operator[](PackedAttachmentIndex index);
376
377 // Initialize an attachment op with all load and store operations.
378 void initWithLoadStore(PackedAttachmentIndex index,
379 ImageLayout initialLayout,
380 ImageLayout finalLayout);
381
382 void setLayouts(PackedAttachmentIndex index,
383 ImageLayout initialLayout,
384 ImageLayout finalLayout);
385 void setOps(PackedAttachmentIndex index, RenderPassLoadOp loadOp, RenderPassStoreOp storeOp);
386 void setStencilOps(PackedAttachmentIndex index,
387 RenderPassLoadOp loadOp,
388 RenderPassStoreOp storeOp);
389
390 void setClearOp(PackedAttachmentIndex index);
391 void setClearStencilOp(PackedAttachmentIndex index);
392
393 size_t hash() const;
394
395 private:
396 gl::AttachmentArray<PackedAttachmentOpsDesc> mOps;
397 };
398
399 bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs);
400
401 static_assert(sizeof(AttachmentOpsArray) == 40, "Size check failed");
402
403 struct PackedAttribDesc final
404 {
405 uint8_t format;
406 uint8_t divisor;
407
408 // Desktop drivers support
409 uint16_t offset : kAttributeOffsetMaxBits;
410
411 uint16_t compressed : 1;
412 };
413
414 constexpr size_t kPackedAttribDescSize = sizeof(PackedAttribDesc);
415 static_assert(kPackedAttribDescSize == 4, "Size mismatch");
416
417 struct PackedVertexInputAttributes final
418 {
419 PackedAttribDesc attribs[gl::MAX_VERTEX_ATTRIBS];
420
421 // Component type of the corresponding input in the program. Used to adjust the format if
422 // necessary. Takes values from gl::ComponentType.
423 uint32_t shaderAttribComponentType;
424
425 // Although technically stride can be any value in ES 2.0, in practice supporting stride
426 // greater than MAX_USHORT should not be that helpful. Note that stride limits are
427 // introduced in ES 3.1.
428 // Dynamic in VK_EXT_extended_dynamic_state
429 uint16_t strides[gl::MAX_VERTEX_ATTRIBS];
430 };
431
432 constexpr size_t kPackedVertexInputAttributesSize = sizeof(PackedVertexInputAttributes);
433 static_assert(kPackedVertexInputAttributesSize == 100, "Size mismatch");
434
435 struct PackedInputAssemblyState final
436 {
437 struct
438 {
439 uint32_t topology : 4;
440
441 // Dynamic in VK_EXT_extended_dynamic_state2
442 uint32_t primitiveRestartEnable : 1; // ds2
443
444 // Whether dynamic state for vertex stride from VK_EXT_extended_dynamic_state can be used
445 // for. Used by GraphicsPipelineDesc::hash() to exclude |vertexStrides| from the hash
446 uint32_t useVertexInputBindingStrideDynamicState : 1;
447
448 // Whether dynamic state for vertex input state from VK_EXT_vertex_input_dynamic_state can
449 // be used by GraphicsPipelineDesc::hash() to exclude |PackedVertexInputAttributes| from the
450 // hash
451 uint32_t useVertexInputDynamicState : 1;
452
453 // Whether the pipeline is robust (vertex input copy)
454 uint32_t isRobustContext : 1;
455 // Whether the pipeline needs access to protected content (vertex input copy)
456 uint32_t isProtectedContext : 1;
457
458 // Which attributes are actually active in the program and should affect the pipeline.
459 uint32_t programActiveAttributeLocations : gl::MAX_VERTEX_ATTRIBS;
460
461 uint32_t padding : 23 - gl::MAX_VERTEX_ATTRIBS;
462 } bits;
463 };
464
465 constexpr size_t kPackedInputAssemblyStateSize = sizeof(PackedInputAssemblyState);
466 static_assert(kPackedInputAssemblyStateSize == 4, "Size mismatch");
467
468 struct PackedStencilOpState final
469 {
470 uint8_t fail : 4;
471 uint8_t pass : 4;
472 uint8_t depthFail : 4;
473 uint8_t compare : 4;
474 };
475
476 constexpr size_t kPackedStencilOpSize = sizeof(PackedStencilOpState);
477 static_assert(kPackedStencilOpSize == 2, "Size check failed");
478
479 struct PackedPreRasterizationAndFragmentStates final
480 {
481 struct
482 {
483 // Affecting VkPipelineViewportStateCreateInfo
484 uint32_t viewportNegativeOneToOne : 1;
485
486 // Affecting VkPipelineRasterizationStateCreateInfo
487 uint32_t depthClampEnable : 1;
488 uint32_t polygonMode : 2;
489 // Dynamic in VK_EXT_extended_dynamic_state
490 uint32_t cullMode : 4;
491 uint32_t frontFace : 4;
492 // Dynamic in VK_EXT_extended_dynamic_state2
493 uint32_t rasterizerDiscardEnable : 1;
494 uint32_t depthBiasEnable : 1;
495
496 // Affecting VkPipelineTessellationStateCreateInfo
497 uint32_t patchVertices : 6;
498
499 // Affecting VkPipelineDepthStencilStateCreateInfo
500 uint32_t depthBoundsTest : 1;
501 // Dynamic in VK_EXT_extended_dynamic_state
502 uint32_t depthTest : 1;
503 uint32_t depthWrite : 1;
504 uint32_t stencilTest : 1;
505 uint32_t nonZeroStencilWriteMaskWorkaround : 1;
506 // Dynamic in VK_EXT_extended_dynamic_state2
507 uint32_t depthCompareOp : 4;
508
509 // Affecting specialization constants
510 uint32_t surfaceRotation : 1;
511
512 // Whether the pipeline is robust (shader stages copy)
513 uint32_t isRobustContext : 1;
514 // Whether the pipeline needs access to protected content (shader stages copy)
515 uint32_t isProtectedContext : 1;
516 } bits;
517
518 // Affecting specialization constants
519 static_assert(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS <= 8,
520 "2 bits per draw buffer is needed for dither emulation");
521 uint16_t emulatedDitherControl;
522 uint16_t padding;
523
524 // Affecting VkPipelineDepthStencilStateCreateInfo
525 // Dynamic in VK_EXT_extended_dynamic_state
526 PackedStencilOpState front;
527 PackedStencilOpState back;
528 };
529
530 constexpr size_t kPackedPreRasterizationAndFragmentStatesSize =
531 sizeof(PackedPreRasterizationAndFragmentStates);
532 static_assert(kPackedPreRasterizationAndFragmentStatesSize == 12, "Size check failed");
533
534 struct PackedMultisampleAndSubpassState final
535 {
536 struct
537 {
538 // Affecting VkPipelineMultisampleStateCreateInfo
539 // Note: Only up to 16xMSAA is supported in the Vulkan backend.
540 uint16_t sampleMask;
541 // Stored as minus one so sample count 16 can fit in 4 bits.
542 uint16_t rasterizationSamplesMinusOne : 4;
543 uint16_t sampleShadingEnable : 1;
544 uint16_t alphaToCoverageEnable : 1;
545 uint16_t alphaToOneEnable : 1;
546 // The subpass index affects both the shader stages and the fragment output similarly to
547 // multisampled state, so they are grouped together.
548 // Note: Currently only 2 subpasses possible.
549 uint16_t subpass : 1;
550 // 8-bit normalized instead of float to align the struct.
551 uint16_t minSampleShading : 8;
552 } bits;
553 };
554
555 constexpr size_t kPackedMultisampleAndSubpassStateSize = sizeof(PackedMultisampleAndSubpassState);
556 static_assert(kPackedMultisampleAndSubpassStateSize == 4, "Size check failed");
557
558 struct PackedColorBlendAttachmentState final
559 {
560 uint16_t srcColorBlendFactor : 5;
561 uint16_t dstColorBlendFactor : 5;
562 uint16_t colorBlendOp : 6;
563 uint16_t srcAlphaBlendFactor : 5;
564 uint16_t dstAlphaBlendFactor : 5;
565 uint16_t alphaBlendOp : 6;
566 };
567
568 constexpr size_t kPackedColorBlendAttachmentStateSize = sizeof(PackedColorBlendAttachmentState);
569 static_assert(kPackedColorBlendAttachmentStateSize == 4, "Size check failed");
570
571 struct PackedColorBlendState final
572 {
573 uint8_t colorWriteMaskBits[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS / 2];
574 PackedColorBlendAttachmentState attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS];
575 };
576
577 constexpr size_t kPackedColorBlendStateSize = sizeof(PackedColorBlendState);
578 static_assert(kPackedColorBlendStateSize == 36, "Size check failed");
579
580 struct PackedBlendMaskAndLogicOpState final
581 {
582 struct
583 {
584 uint32_t blendEnableMask : 8;
585 uint32_t logicOpEnable : 1;
586 // Dynamic in VK_EXT_extended_dynamic_state2
587 uint32_t logicOp : 4;
588
589 // Whether the pipeline needs access to protected content (fragment output copy)
590 uint32_t isProtectedContext : 1;
591
592 // Output that is present in the framebuffer but is never written to in the shader. Used by
593 // GL_ANGLE_robust_fragment_shader_output which defines the behavior in this case (which is
594 // to mask these outputs)
595 uint32_t missingOutputsMask : gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
596
597 uint32_t padding : 18 - gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
598 } bits;
599 };
600
601 constexpr size_t kPackedBlendMaskAndLogicOpStateSize = sizeof(PackedBlendMaskAndLogicOpState);
602 static_assert(kPackedBlendMaskAndLogicOpStateSize == 4, "Size check failed");
603
604 // The vertex input subset of the pipeline.
605 struct PipelineVertexInputState final
606 {
607 PackedInputAssemblyState inputAssembly;
608 PackedVertexInputAttributes vertex;
609 };
610
611 // The pre-rasterization and fragment shader subsets of the pipeline. This is excluding
612 // multisampled and render pass states which are shared with fragment output.
613 struct PipelineShadersState final
614 {
615 PackedPreRasterizationAndFragmentStates shaders;
616 };
617
618 // Multisampled and render pass states.
619 struct PipelineSharedNonVertexInputState final
620 {
621 PackedMultisampleAndSubpassState multisample;
622 RenderPassDesc renderPass;
623 };
624
625 // The fragment output subset of the pipeline. This is excluding multisampled and render pass
626 // states which are shared with the shader subsets.
627 struct PipelineFragmentOutputState final
628 {
629 PackedColorBlendState blend;
630 PackedBlendMaskAndLogicOpState blendMaskAndLogic;
631 };
632
633 constexpr size_t kGraphicsPipelineVertexInputStateSize =
634 kPackedVertexInputAttributesSize + kPackedInputAssemblyStateSize;
635 constexpr size_t kGraphicsPipelineShadersStateSize = kPackedPreRasterizationAndFragmentStatesSize;
636 constexpr size_t kGraphicsPipelineSharedNonVertexInputStateSize =
637 kPackedMultisampleAndSubpassStateSize + kRenderPassDescSize;
638 constexpr size_t kGraphicsPipelineFragmentOutputStateSize =
639 kPackedColorBlendStateSize + kPackedBlendMaskAndLogicOpStateSize;
640
641 constexpr size_t kGraphicsPipelineDescSumOfSizes =
642 kGraphicsPipelineVertexInputStateSize + kGraphicsPipelineShadersStateSize +
643 kGraphicsPipelineSharedNonVertexInputStateSize + kGraphicsPipelineFragmentOutputStateSize;
644
645 // Number of dirty bits in the dirty bit set.
646 constexpr size_t kGraphicsPipelineDirtyBitBytes = 4;
647 constexpr static size_t kNumGraphicsPipelineDirtyBits =
648 kGraphicsPipelineDescSumOfSizes / kGraphicsPipelineDirtyBitBytes;
649 static_assert(kNumGraphicsPipelineDirtyBits <= 64, "Too many pipeline dirty bits");
650
651 // Set of dirty bits. Each bit represents kGraphicsPipelineDirtyBitBytes in the desc.
652 using GraphicsPipelineTransitionBits = angle::BitSet<kNumGraphicsPipelineDirtyBits>;
653
654 GraphicsPipelineTransitionBits GetGraphicsPipelineTransitionBitsMask(GraphicsPipelineSubset subset);
655
656 // Disable padding warnings for a few helper structs that aggregate Vulkan state objects. These are
657 // not used as hash keys, they just simplify passing them around to functions.
658 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
659
660 struct GraphicsPipelineVertexInputVulkanStructs
661 {
662 VkPipelineVertexInputStateCreateInfo vertexInputState = {};
663 VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {};
664 VkPipelineVertexInputDivisorStateCreateInfoEXT divisorState = {};
665
666 // Support storage
667 gl::AttribArray<VkVertexInputBindingDescription> bindingDescs;
668 gl::AttribArray<VkVertexInputAttributeDescription> attributeDescs;
669 gl::AttribArray<VkVertexInputBindingDivisorDescriptionEXT> divisorDesc;
670 };
671
672 struct GraphicsPipelineShadersVulkanStructs
673 {
674 VkPipelineViewportStateCreateInfo viewportState = {};
675 VkPipelineRasterizationStateCreateInfo rasterState = {};
676 VkPipelineDepthStencilStateCreateInfo depthStencilState = {};
677 VkPipelineTessellationStateCreateInfo tessellationState = {};
678 VkPipelineTessellationDomainOriginStateCreateInfo domainOriginState = {};
679 VkPipelineViewportDepthClipControlCreateInfoEXT depthClipControl = {};
680 VkPipelineRasterizationLineStateCreateInfoEXT rasterLineState = {};
681 VkPipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexState = {};
682 VkPipelineRasterizationStateStreamCreateInfoEXT rasterStreamState = {};
683 VkSpecializationInfo specializationInfo = {};
684
685 // Support storage
686 angle::FixedVector<VkPipelineShaderStageCreateInfo, 5> shaderStages;
687 SpecializationConstantMap<VkSpecializationMapEntry> specializationEntries;
688 };
689
690 struct GraphicsPipelineSharedNonVertexInputVulkanStructs
691 {
692 VkPipelineMultisampleStateCreateInfo multisampleState = {};
693
694 // Support storage
695 uint32_t sampleMask;
696 };
697
698 struct GraphicsPipelineFragmentOutputVulkanStructs
699 {
700 VkPipelineColorBlendStateCreateInfo blendState = {};
701
702 // Support storage
703 gl::DrawBuffersArray<VkPipelineColorBlendAttachmentState> blendAttachmentState;
704 };
705
706 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
707
708 using GraphicsPipelineDynamicStateList = angle::FixedVector<VkDynamicState, 23>;
709
710 enum class PipelineRobustness
711 {
712 NonRobust,
713 Robust,
714 };
715
716 enum class PipelineProtectedAccess
717 {
718 Unprotected,
719 Protected,
720 };
721
722 // State changes are applied through the update methods. Each update method can also have a
723 // sibling method that applies the update without marking a state transition. The non-transition
724 // update methods are used for internal shader pipelines. Not every non-transition update method
725 // is implemented yet as not every state is used in internal shaders.
726 class GraphicsPipelineDesc final
727 {
728 public:
729 // Use aligned allocation and free so we can use the alignas keyword.
730 void *operator new(std::size_t size);
731 void operator delete(void *ptr);
732
733 GraphicsPipelineDesc();
734 ~GraphicsPipelineDesc();
735 GraphicsPipelineDesc(const GraphicsPipelineDesc &other);
736 GraphicsPipelineDesc &operator=(const GraphicsPipelineDesc &other);
737
738 size_t hash(GraphicsPipelineSubset subset) const;
739 bool keyEqual(const GraphicsPipelineDesc &other, GraphicsPipelineSubset subset) const;
740
741 void initDefaults(const Context *context,
742 GraphicsPipelineSubset subset,
743 PipelineRobustness contextRobustness,
744 PipelineProtectedAccess contextProtectedAccess);
745
746 // For custom comparisons.
747 template <typename T>
getPtr()748 const T *getPtr() const
749 {
750 return reinterpret_cast<const T *>(this);
751 }
752
753 VkResult initializePipeline(Context *context,
754 PipelineCacheAccess *pipelineCache,
755 GraphicsPipelineSubset subset,
756 const RenderPass &compatibleRenderPass,
757 const PipelineLayout &pipelineLayout,
758 const ShaderModuleMap &shaders,
759 const SpecializationConstants &specConsts,
760 Pipeline *pipelineOut,
761 CacheLookUpFeedback *feedbackOut) const;
762
763 // Vertex input state. For ES 3.1 this should be separated into binding and attribute.
764 void updateVertexInput(ContextVk *contextVk,
765 GraphicsPipelineTransitionBits *transition,
766 uint32_t attribIndex,
767 GLuint stride,
768 GLuint divisor,
769 angle::FormatID format,
770 bool compressed,
771 GLuint relativeOffset);
772 void setVertexShaderComponentTypes(gl::AttributesMask activeAttribLocations,
773 gl::ComponentTypeMask componentTypeMask);
774 void updateVertexShaderComponentTypes(GraphicsPipelineTransitionBits *transition,
775 gl::AttributesMask activeAttribLocations,
776 gl::ComponentTypeMask componentTypeMask);
777
778 // Input assembly info
779 void setTopology(gl::PrimitiveMode drawMode);
780 void updateTopology(GraphicsPipelineTransitionBits *transition, gl::PrimitiveMode drawMode);
781 void updatePrimitiveRestartEnabled(GraphicsPipelineTransitionBits *transition,
782 bool primitiveRestartEnabled);
783
784 // Viewport states
785 void updateDepthClipControl(GraphicsPipelineTransitionBits *transition, bool negativeOneToOne);
786
787 // Raster states
788 void updatePolygonMode(GraphicsPipelineTransitionBits *transition, gl::PolygonMode polygonMode);
789 void updateCullMode(GraphicsPipelineTransitionBits *transition,
790 const gl::RasterizerState &rasterState);
791 void updateFrontFace(GraphicsPipelineTransitionBits *transition,
792 const gl::RasterizerState &rasterState,
793 bool invertFrontFace);
794 void updateRasterizerDiscardEnabled(GraphicsPipelineTransitionBits *transition,
795 bool rasterizerDiscardEnabled);
796
797 // Multisample states
798 uint32_t getRasterizationSamples() const;
799 void setRasterizationSamples(uint32_t rasterizationSamples);
800 void updateRasterizationSamples(GraphicsPipelineTransitionBits *transition,
801 uint32_t rasterizationSamples);
802 void updateAlphaToCoverageEnable(GraphicsPipelineTransitionBits *transition, bool enable);
803 void updateAlphaToOneEnable(GraphicsPipelineTransitionBits *transition, bool enable);
804 void updateSampleMask(GraphicsPipelineTransitionBits *transition,
805 uint32_t maskNumber,
806 uint32_t mask);
807
808 void updateSampleShading(GraphicsPipelineTransitionBits *transition, bool enable, float value);
809
810 // RenderPass description.
getRenderPassDesc()811 const RenderPassDesc &getRenderPassDesc() const { return mSharedNonVertexInput.renderPass; }
812
813 void setRenderPassDesc(const RenderPassDesc &renderPassDesc);
814 void updateRenderPassDesc(GraphicsPipelineTransitionBits *transition,
815 const RenderPassDesc &renderPassDesc);
816 void setRenderPassSampleCount(GLint samples);
817 void setRenderPassFramebufferFetchMode(bool hasFramebufferFetch);
getRenderPassFramebufferFetchMode()818 bool getRenderPassFramebufferFetchMode() const
819 {
820 return mSharedNonVertexInput.renderPass.hasFramebufferFetch();
821 }
822
823 void setRenderPassFoveation(bool isFoveated);
getRenderPassFoveation()824 bool getRenderPassFoveation() const
825 {
826 return mSharedNonVertexInput.renderPass.hasFragmentShadingAttachment();
827 }
828
829 void setRenderPassColorAttachmentFormat(size_t colorIndexGL, angle::FormatID formatID);
830
831 // Blend states
832 void setSingleBlend(uint32_t colorIndexGL,
833 bool enabled,
834 VkBlendOp op,
835 VkBlendFactor srcFactor,
836 VkBlendFactor dstFactor);
837 void updateBlendEnabled(GraphicsPipelineTransitionBits *transition,
838 gl::DrawBufferMask blendEnabledMask);
839 void updateBlendFuncs(GraphicsPipelineTransitionBits *transition,
840 const gl::BlendStateExt &blendStateExt,
841 gl::DrawBufferMask attachmentMask);
842 void updateBlendEquations(GraphicsPipelineTransitionBits *transition,
843 const gl::BlendStateExt &blendStateExt,
844 gl::DrawBufferMask attachmentMask);
845 void resetBlendFuncsAndEquations(GraphicsPipelineTransitionBits *transition,
846 const gl::BlendStateExt &blendStateExt,
847 gl::DrawBufferMask previousAttachmentsMask,
848 gl::DrawBufferMask newAttachmentsMask);
849 void setColorWriteMasks(gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
850 const gl::DrawBufferMask &alphaMask,
851 const gl::DrawBufferMask &enabledDrawBuffers);
852 void setSingleColorWriteMask(uint32_t colorIndexGL, VkColorComponentFlags colorComponentFlags);
853 void updateColorWriteMasks(GraphicsPipelineTransitionBits *transition,
854 gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
855 const gl::DrawBufferMask &alphaMask,
856 const gl::DrawBufferMask &enabledDrawBuffers);
857 void updateMissingOutputsMask(GraphicsPipelineTransitionBits *transition,
858 gl::DrawBufferMask missingOutputsMask);
859
860 // Logic op
861 void updateLogicOpEnabled(GraphicsPipelineTransitionBits *transition, bool enable);
862 void updateLogicOp(GraphicsPipelineTransitionBits *transition, VkLogicOp logicOp);
863
864 // Depth/stencil states.
865 void setDepthTestEnabled(bool enabled);
866 void setDepthWriteEnabled(bool enabled);
867 void setDepthFunc(VkCompareOp op);
868 void setDepthClampEnabled(bool enabled);
869 void setStencilTestEnabled(bool enabled);
870 void setStencilFrontFuncs(VkCompareOp compareOp);
871 void setStencilBackFuncs(VkCompareOp compareOp);
872 void setStencilFrontOps(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp);
873 void setStencilBackOps(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp);
874 void setStencilFrontWriteMask(uint8_t mask);
875 void setStencilBackWriteMask(uint8_t mask);
876 void updateDepthTestEnabled(GraphicsPipelineTransitionBits *transition,
877 const gl::DepthStencilState &depthStencilState,
878 const gl::Framebuffer *drawFramebuffer);
879 void updateDepthFunc(GraphicsPipelineTransitionBits *transition,
880 const gl::DepthStencilState &depthStencilState);
881 void updateDepthClampEnabled(GraphicsPipelineTransitionBits *transition, bool enabled);
882 void updateDepthWriteEnabled(GraphicsPipelineTransitionBits *transition,
883 const gl::DepthStencilState &depthStencilState,
884 const gl::Framebuffer *drawFramebuffer);
885 void updateStencilTestEnabled(GraphicsPipelineTransitionBits *transition,
886 const gl::DepthStencilState &depthStencilState,
887 const gl::Framebuffer *drawFramebuffer);
888 void updateStencilFrontFuncs(GraphicsPipelineTransitionBits *transition,
889 const gl::DepthStencilState &depthStencilState);
890 void updateStencilBackFuncs(GraphicsPipelineTransitionBits *transition,
891 const gl::DepthStencilState &depthStencilState);
892 void updateStencilFrontOps(GraphicsPipelineTransitionBits *transition,
893 const gl::DepthStencilState &depthStencilState);
894 void updateStencilBackOps(GraphicsPipelineTransitionBits *transition,
895 const gl::DepthStencilState &depthStencilState);
896
897 // Depth offset.
898 void updatePolygonOffsetEnabled(GraphicsPipelineTransitionBits *transition, bool enabled);
899
900 // Tessellation
901 void updatePatchVertices(GraphicsPipelineTransitionBits *transition, GLuint value);
902
903 // Subpass
904 void resetSubpass(GraphicsPipelineTransitionBits *transition);
905 void nextSubpass(GraphicsPipelineTransitionBits *transition);
906 void setSubpass(uint32_t subpass);
907 uint32_t getSubpass() const;
908
909 void updateSurfaceRotation(GraphicsPipelineTransitionBits *transition,
910 bool isRotatedAspectRatio);
getSurfaceRotation()911 bool getSurfaceRotation() const { return mShaders.shaders.bits.surfaceRotation; }
912
913 void updateEmulatedDitherControl(GraphicsPipelineTransitionBits *transition, uint16_t value);
getEmulatedDitherControl()914 uint32_t getEmulatedDitherControl() const { return mShaders.shaders.emulatedDitherControl; }
915
isLegacyDitherEnabled()916 bool isLegacyDitherEnabled() const
917 {
918 return mSharedNonVertexInput.renderPass.isLegacyDitherEnabled();
919 }
920
921 void updateNonZeroStencilWriteMaskWorkaround(GraphicsPipelineTransitionBits *transition,
922 bool enabled);
923
setSupportsDynamicStateForTest(bool supports)924 void setSupportsDynamicStateForTest(bool supports)
925 {
926 mVertexInput.inputAssembly.bits.useVertexInputBindingStrideDynamicState = supports;
927 mShaders.shaders.bits.nonZeroStencilWriteMaskWorkaround = false;
928 }
929
930 static VkFormat getPipelineVertexInputStateFormat(Context *context,
931 angle::FormatID formatID,
932 bool compressed,
933 const gl::ComponentType programAttribType,
934 uint32_t attribIndex);
935
936 // Helpers to dump the state
getVertexInputStateForLog()937 const PipelineVertexInputState &getVertexInputStateForLog() const { return mVertexInput; }
getShadersStateForLog()938 const PipelineShadersState &getShadersStateForLog() const { return mShaders; }
getSharedNonVertexInputStateForLog()939 const PipelineSharedNonVertexInputState &getSharedNonVertexInputStateForLog() const
940 {
941 return mSharedNonVertexInput;
942 }
getFragmentOutputStateForLog()943 const PipelineFragmentOutputState &getFragmentOutputStateForLog() const
944 {
945 return mFragmentOutput;
946 }
947
948 private:
949 void updateSubpass(GraphicsPipelineTransitionBits *transition, uint32_t subpass);
950
951 const void *getPipelineSubsetMemory(GraphicsPipelineSubset subset, size_t *sizeOut) const;
952
953 void initializePipelineVertexInputState(
954 Context *context,
955 GraphicsPipelineVertexInputVulkanStructs *stateOut,
956 GraphicsPipelineDynamicStateList *dynamicStateListOut) const;
957
958 void initializePipelineShadersState(
959 Context *context,
960 const ShaderModuleMap &shaders,
961 const SpecializationConstants &specConsts,
962 GraphicsPipelineShadersVulkanStructs *stateOut,
963 GraphicsPipelineDynamicStateList *dynamicStateListOut) const;
964
965 void initializePipelineSharedNonVertexInputState(
966 Context *context,
967 GraphicsPipelineSharedNonVertexInputVulkanStructs *stateOut,
968 GraphicsPipelineDynamicStateList *dynamicStateListOut) const;
969
970 void initializePipelineFragmentOutputState(
971 Context *context,
972 GraphicsPipelineFragmentOutputVulkanStructs *stateOut,
973 GraphicsPipelineDynamicStateList *dynamicStateListOut) const;
974
975 PipelineShadersState mShaders;
976 PipelineSharedNonVertexInputState mSharedNonVertexInput;
977 PipelineFragmentOutputState mFragmentOutput;
978 PipelineVertexInputState mVertexInput;
979 };
980
981 // Verify the packed pipeline description has no gaps in the packing.
982 // This is not guaranteed by the spec, but is validated by a compile-time check.
983 // No gaps or padding at the end ensures that hashing and memcmp checks will not run
984 // into uninitialized memory regions.
985 constexpr size_t kGraphicsPipelineDescSize = sizeof(GraphicsPipelineDesc);
986 static_assert(kGraphicsPipelineDescSize == kGraphicsPipelineDescSumOfSizes, "Size mismatch");
987
988 // Values are based on data recorded here -> https://anglebug.com/8677#c4
989 constexpr size_t kDefaultDescriptorSetLayoutBindingsCount = 8;
990 constexpr size_t kDefaultImmutableSamplerBindingsCount = 1;
991 using DescriptorSetLayoutBindingVector =
992 angle::FastVector<VkDescriptorSetLayoutBinding, kDefaultDescriptorSetLayoutBindingsCount>;
993
994 // A packed description of a descriptor set layout. Use similarly to RenderPassDesc and
995 // GraphicsPipelineDesc. Currently we only need to differentiate layouts based on sampler and ubo
996 // usage. In the future we could generalize this.
997 class DescriptorSetLayoutDesc final
998 {
999 public:
1000 DescriptorSetLayoutDesc();
1001 ~DescriptorSetLayoutDesc();
1002 DescriptorSetLayoutDesc(const DescriptorSetLayoutDesc &other);
1003 DescriptorSetLayoutDesc &operator=(const DescriptorSetLayoutDesc &other);
1004
1005 size_t hash() const;
1006 bool operator==(const DescriptorSetLayoutDesc &other) const;
1007
1008 void update(uint32_t bindingIndex,
1009 VkDescriptorType descriptorType,
1010 uint32_t count,
1011 VkShaderStageFlags stages,
1012 const Sampler *immutableSampler);
1013
1014 void unpackBindings(DescriptorSetLayoutBindingVector *bindings) const;
1015
empty()1016 bool empty() const { return mDescriptorSetLayoutBindings.empty(); }
1017
1018 private:
1019 // There is a small risk of an issue if the sampler cache is evicted but not the descriptor
1020 // cache we would have an invalid handle here. Thus propose follow-up work:
1021 // TODO: https://issuetracker.google.com/issues/159156775: Have immutable sampler use serial
1022 union PackedDescriptorSetBinding
1023 {
1024 struct
1025 {
1026 uint8_t type; // Stores a packed VkDescriptorType descriptorType.
1027 uint8_t stages; // Stores a packed VkShaderStageFlags.
1028 uint16_t count; // Stores a packed uint32_t descriptorCount
1029 uint16_t bindingIndex; // Stores the binding index
1030 uint16_t hasImmutableSampler; // Whether this binding has an immutable sampler
1031 };
1032 uint64_t value;
1033
1034 bool operator==(const PackedDescriptorSetBinding &other) const
1035 {
1036 return value == other.value;
1037 }
1038 };
1039
1040 // 1x 64bit
1041 static_assert(sizeof(PackedDescriptorSetBinding) == 8, "Unexpected size");
1042
1043 angle::FastVector<PackedDescriptorSetBinding, kDefaultDescriptorSetLayoutBindingsCount>
1044 mDescriptorSetLayoutBindings;
1045 angle::FastVector<VkSampler, kDefaultImmutableSamplerBindingsCount> mImmutableSamplers;
1046 };
1047
1048 // The following are for caching descriptor set layouts. Limited to max three descriptor set
1049 // layouts. This can be extended in the future.
1050 constexpr size_t kMaxDescriptorSetLayouts = ToUnderlying(DescriptorSetIndex::EnumCount);
1051
1052 union PackedPushConstantRange
1053 {
1054 struct
1055 {
1056 uint8_t offset;
1057 uint8_t size;
1058 uint16_t stageMask;
1059 };
1060 uint32_t value;
1061
1062 bool operator==(const PackedPushConstantRange &other) const { return value == other.value; }
1063 };
1064
1065 static_assert(sizeof(PackedPushConstantRange) == sizeof(uint32_t), "Unexpected Size");
1066
1067 template <typename T>
1068 using DescriptorSetArray = angle::PackedEnumMap<DescriptorSetIndex, T>;
1069 using DescriptorSetLayoutPointerArray =
1070 DescriptorSetArray<AtomicBindingPointer<DescriptorSetLayout>>;
1071
1072 class PipelineLayoutDesc final
1073 {
1074 public:
1075 PipelineLayoutDesc();
1076 ~PipelineLayoutDesc();
1077 PipelineLayoutDesc(const PipelineLayoutDesc &other);
1078 PipelineLayoutDesc &operator=(const PipelineLayoutDesc &rhs);
1079
1080 size_t hash() const;
1081 bool operator==(const PipelineLayoutDesc &other) const;
1082
1083 void updateDescriptorSetLayout(DescriptorSetIndex setIndex,
1084 const DescriptorSetLayoutDesc &desc);
1085 void updatePushConstantRange(VkShaderStageFlags stageMask, uint32_t offset, uint32_t size);
1086
getPushConstantRange()1087 const PackedPushConstantRange &getPushConstantRange() const { return mPushConstantRange; }
1088
1089 private:
1090 DescriptorSetArray<DescriptorSetLayoutDesc> mDescriptorSetLayouts;
1091 PackedPushConstantRange mPushConstantRange;
1092 ANGLE_MAYBE_UNUSED_PRIVATE_FIELD uint32_t mPadding;
1093
1094 // Verify the arrays are properly packed.
1095 static_assert(sizeof(decltype(mDescriptorSetLayouts)) ==
1096 (sizeof(DescriptorSetLayoutDesc) * kMaxDescriptorSetLayouts),
1097 "Unexpected size");
1098 };
1099
1100 // Verify the structure is properly packed.
1101 static_assert(sizeof(PipelineLayoutDesc) == sizeof(DescriptorSetArray<DescriptorSetLayoutDesc>) +
1102 sizeof(PackedPushConstantRange) + sizeof(uint32_t),
1103 "Unexpected Size");
1104
1105 enum class YcbcrLinearFilterSupport
1106 {
1107 Unsupported,
1108 Supported,
1109 };
1110
1111 class YcbcrConversionDesc final
1112 {
1113 public:
1114 YcbcrConversionDesc();
1115 ~YcbcrConversionDesc();
1116 YcbcrConversionDesc(const YcbcrConversionDesc &other);
1117 YcbcrConversionDesc &operator=(const YcbcrConversionDesc &other);
1118
1119 size_t hash() const;
1120 bool operator==(const YcbcrConversionDesc &other) const;
1121
valid()1122 bool valid() const { return mExternalOrVkFormat != 0; }
1123 void reset();
1124 void update(Renderer *renderer,
1125 uint64_t externalFormat,
1126 VkSamplerYcbcrModelConversion conversionModel,
1127 VkSamplerYcbcrRange colorRange,
1128 VkChromaLocation xChromaOffset,
1129 VkChromaLocation yChromaOffset,
1130 VkFilter chromaFilter,
1131 VkComponentMapping components,
1132 angle::FormatID intendedFormatID,
1133 YcbcrLinearFilterSupport linearFilterSupported);
getChromaFilter()1134 VkFilter getChromaFilter() const { return static_cast<VkFilter>(mChromaFilter); }
1135 bool updateChromaFilter(Renderer *renderer, VkFilter filter);
1136 void updateConversionModel(VkSamplerYcbcrModelConversion conversionModel);
getExternalFormat()1137 uint64_t getExternalFormat() const { return mIsExternalFormat ? mExternalOrVkFormat : 0; }
1138
1139 angle::Result init(Context *context, SamplerYcbcrConversion *conversionOut) const;
1140
1141 private:
1142 // If the sampler needs to convert the image content (e.g. from YUV to RGB) then
1143 // mExternalOrVkFormat will be non-zero. The value is either the external format
1144 // as returned by vkGetAndroidHardwareBufferPropertiesANDROID or a YUV VkFormat.
1145 // For VkSamplerYcbcrConversion, mExternalOrVkFormat along with mIsExternalFormat,
1146 // mConversionModel and mColorRange works as a Serial() used elsewhere in ANGLE.
1147 uint64_t mExternalOrVkFormat;
1148 // 1 bit to identify if external format is used
1149 uint32_t mIsExternalFormat : 1;
1150 // 3 bits to identify conversion model
1151 uint32_t mConversionModel : 3;
1152 // 1 bit to identify color component range
1153 uint32_t mColorRange : 1;
1154 // 1 bit to identify x chroma location
1155 uint32_t mXChromaOffset : 1;
1156 // 1 bit to identify y chroma location
1157 uint32_t mYChromaOffset : 1;
1158 // 1 bit to identify chroma filtering
1159 uint32_t mChromaFilter : 1;
1160 // 3 bit to identify R component swizzle
1161 uint32_t mRSwizzle : 3;
1162 // 3 bit to identify G component swizzle
1163 uint32_t mGSwizzle : 3;
1164 // 3 bit to identify B component swizzle
1165 uint32_t mBSwizzle : 3;
1166 // 3 bit to identify A component swizzle
1167 uint32_t mASwizzle : 3;
1168 // 1 bit for whether linear filtering is supported (independent of whether currently enabled)
1169 uint32_t mLinearFilterSupported : 1;
1170 uint32_t mPadding : 11;
1171 uint32_t mReserved;
1172 };
1173
1174 static_assert(sizeof(YcbcrConversionDesc) == 16, "Unexpected YcbcrConversionDesc size");
1175
1176 // Packed sampler description for the sampler cache.
1177 class SamplerDesc final
1178 {
1179 public:
1180 SamplerDesc();
1181 SamplerDesc(ContextVk *contextVk,
1182 const gl::SamplerState &samplerState,
1183 bool stencilMode,
1184 const YcbcrConversionDesc *ycbcrConversionDesc,
1185 angle::FormatID intendedFormatID);
1186 ~SamplerDesc();
1187
1188 SamplerDesc(const SamplerDesc &other);
1189 SamplerDesc &operator=(const SamplerDesc &rhs);
1190
1191 void update(ContextVk *contextVk,
1192 const gl::SamplerState &samplerState,
1193 bool stencilMode,
1194 const YcbcrConversionDesc *ycbcrConversionDesc,
1195 angle::FormatID intendedFormatID);
1196 void reset();
1197 angle::Result init(ContextVk *contextVk, Sampler *sampler) const;
1198
1199 size_t hash() const;
1200 bool operator==(const SamplerDesc &other) const;
1201
1202 private:
1203 // 32*4 bits for floating point data.
1204 // Note: anisotropy enabled is implicitly determined by maxAnisotropy and caps.
1205 float mMipLodBias;
1206 float mMaxAnisotropy;
1207 float mMinLod;
1208 float mMaxLod;
1209
1210 // 16*8 bits to uniquely identify a YCbCr conversion sampler.
1211 YcbcrConversionDesc mYcbcrConversionDesc;
1212
1213 // 16 bits for modes + states.
1214 // 1 bit per filter (only 2 possible values in GL: linear/nearest)
1215 uint16_t mMagFilter : 1;
1216 uint16_t mMinFilter : 1;
1217 uint16_t mMipmapMode : 1;
1218
1219 // 3 bits per address mode (5 possible values)
1220 uint16_t mAddressModeU : 3;
1221 uint16_t mAddressModeV : 3;
1222 uint16_t mAddressModeW : 3;
1223
1224 // 1 bit for compare enabled (2 possible values)
1225 uint16_t mCompareEnabled : 1;
1226
1227 // 3 bits for compare op. (8 possible values)
1228 uint16_t mCompareOp : 3;
1229
1230 // Values from angle::ColorGeneric::Type. Float is 0 and others are 1.
1231 uint16_t mBorderColorType : 1;
1232
1233 uint16_t mPadding : 15;
1234
1235 // 16*8 bits for BorderColor
1236 angle::ColorF mBorderColor;
1237
1238 // 32 bits reserved for future use.
1239 uint32_t mReserved;
1240 };
1241
1242 static_assert(sizeof(SamplerDesc) == 56, "Unexpected SamplerDesc size");
1243
1244 // Disable warnings about struct padding.
1245 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
1246
1247 class PipelineHelper;
1248
1249 struct GraphicsPipelineTransition
1250 {
1251 GraphicsPipelineTransition();
1252 GraphicsPipelineTransition(const GraphicsPipelineTransition &other);
1253 GraphicsPipelineTransition(GraphicsPipelineTransitionBits bits,
1254 const GraphicsPipelineDesc *desc,
1255 PipelineHelper *pipeline);
1256
1257 GraphicsPipelineTransitionBits bits;
1258 const GraphicsPipelineDesc *desc;
1259 PipelineHelper *target;
1260 };
1261
1262 ANGLE_INLINE GraphicsPipelineTransition::GraphicsPipelineTransition() = default;
1263
1264 ANGLE_INLINE GraphicsPipelineTransition::GraphicsPipelineTransition(
1265 const GraphicsPipelineTransition &other) = default;
1266
GraphicsPipelineTransition(GraphicsPipelineTransitionBits bits,const GraphicsPipelineDesc * desc,PipelineHelper * pipeline)1267 ANGLE_INLINE GraphicsPipelineTransition::GraphicsPipelineTransition(
1268 GraphicsPipelineTransitionBits bits,
1269 const GraphicsPipelineDesc *desc,
1270 PipelineHelper *pipeline)
1271 : bits(bits), desc(desc), target(pipeline)
1272 {}
1273
GraphicsPipelineTransitionMatch(GraphicsPipelineTransitionBits bitsA,GraphicsPipelineTransitionBits bitsB,const GraphicsPipelineDesc & descA,const GraphicsPipelineDesc & descB)1274 ANGLE_INLINE bool GraphicsPipelineTransitionMatch(GraphicsPipelineTransitionBits bitsA,
1275 GraphicsPipelineTransitionBits bitsB,
1276 const GraphicsPipelineDesc &descA,
1277 const GraphicsPipelineDesc &descB)
1278 {
1279 if (bitsA != bitsB)
1280 return false;
1281
1282 // We currently mask over 4 bytes of the pipeline description with each dirty bit.
1283 // We could consider using 8 bytes and a mask of 32 bits. This would make some parts
1284 // of the code faster. The for loop below would scan over twice as many bits per iteration.
1285 // But there may be more collisions between the same dirty bit masks leading to different
1286 // transitions. Thus there may be additional cost when applications use many transitions.
1287 // We should revisit this in the future and investigate using different bit widths.
1288 static_assert(sizeof(uint32_t) == kGraphicsPipelineDirtyBitBytes, "Size mismatch");
1289
1290 const uint32_t *rawPtrA = descA.getPtr<uint32_t>();
1291 const uint32_t *rawPtrB = descB.getPtr<uint32_t>();
1292
1293 for (size_t dirtyBit : bitsA)
1294 {
1295 if (rawPtrA[dirtyBit] != rawPtrB[dirtyBit])
1296 return false;
1297 }
1298
1299 return true;
1300 }
1301
1302 // A class that encapsulates the vk::PipelineCache and associated mutex. The mutex may be nullptr
1303 // if synchronization is not necessary.
1304 class PipelineCacheAccess
1305 {
1306 public:
1307 PipelineCacheAccess() = default;
1308 ~PipelineCacheAccess() = default;
1309
init(const vk::PipelineCache * pipelineCache,angle::SimpleMutex * mutex)1310 void init(const vk::PipelineCache *pipelineCache, angle::SimpleMutex *mutex)
1311 {
1312 mPipelineCache = pipelineCache;
1313 mMutex = mutex;
1314 }
1315
1316 VkResult createGraphicsPipeline(vk::Context *context,
1317 const VkGraphicsPipelineCreateInfo &createInfo,
1318 vk::Pipeline *pipelineOut);
1319 VkResult createComputePipeline(vk::Context *context,
1320 const VkComputePipelineCreateInfo &createInfo,
1321 vk::Pipeline *pipelineOut);
1322
1323 void merge(Renderer *renderer, const vk::PipelineCache &pipelineCache);
1324
isThreadSafe()1325 bool isThreadSafe() const { return mMutex != nullptr; }
1326
1327 private:
1328 std::unique_lock<angle::SimpleMutex> getLock();
1329
1330 const vk::PipelineCache *mPipelineCache = nullptr;
1331 angle::SimpleMutex *mMutex;
1332 };
1333
1334 // Monolithic pipeline creation tasks are created as soon as a pipeline is created out of libraries.
1335 // However, they are not immediately posted to the worker queue to allow pacing. One each use of a
1336 // pipeline, an attempt is made to post the task.
1337 class CreateMonolithicPipelineTask : public Context, public angle::Closure
1338 {
1339 public:
1340 CreateMonolithicPipelineTask(Renderer *renderer,
1341 const PipelineCacheAccess &pipelineCache,
1342 const PipelineLayout &pipelineLayout,
1343 const ShaderModuleMap &shaders,
1344 const SpecializationConstants &specConsts,
1345 const GraphicsPipelineDesc &desc);
1346
1347 // The compatible render pass is set only when the task is ready to run. This is because the
1348 // render pass cache may have been cleared since the task was created (e.g. to accomodate
1349 // framebuffer fetch). Such render pass cache clears ensure there are no active tasks, so it's
1350 // safe to hold on to this pointer for the brief period between task post and completion.
getRenderPassDesc()1351 const RenderPassDesc &getRenderPassDesc() const { return mDesc.getRenderPassDesc(); }
1352 void setCompatibleRenderPass(const RenderPass *compatibleRenderPass);
1353
1354 void operator()() override;
1355
getResult()1356 VkResult getResult() const { return mResult; }
getPipeline()1357 Pipeline &getPipeline() { return mPipeline; }
getFeedback()1358 CacheLookUpFeedback getFeedback() const { return mFeedback; }
1359
1360 void handleError(VkResult result,
1361 const char *file,
1362 const char *function,
1363 unsigned int line) override;
1364
1365 private:
1366 // Input to pipeline creation
1367 PipelineCacheAccess mPipelineCache;
1368 const RenderPass *mCompatibleRenderPass;
1369 const PipelineLayout &mPipelineLayout;
1370 const ShaderModuleMap &mShaders;
1371 SpecializationConstants mSpecConsts;
1372 GraphicsPipelineDesc mDesc;
1373
1374 // Results
1375 VkResult mResult;
1376 Pipeline mPipeline;
1377 CacheLookUpFeedback mFeedback;
1378 };
1379
1380 class WaitableMonolithicPipelineCreationTask
1381 {
1382 public:
1383 ~WaitableMonolithicPipelineCreationTask();
1384
setTask(std::shared_ptr<CreateMonolithicPipelineTask> && task)1385 void setTask(std::shared_ptr<CreateMonolithicPipelineTask> &&task) { mTask = std::move(task); }
setRenderPass(const RenderPass * compatibleRenderPass)1386 void setRenderPass(const RenderPass *compatibleRenderPass)
1387 {
1388 mTask->setCompatibleRenderPass(compatibleRenderPass);
1389 }
onSchedule(const std::shared_ptr<angle::WaitableEvent> & waitableEvent)1390 void onSchedule(const std::shared_ptr<angle::WaitableEvent> &waitableEvent)
1391 {
1392 mWaitableEvent = waitableEvent;
1393 }
reset()1394 void reset()
1395 {
1396 mWaitableEvent.reset();
1397 mTask.reset();
1398 }
1399
isValid()1400 bool isValid() const { return mTask.get() != nullptr; }
isPosted()1401 bool isPosted() const { return mWaitableEvent.get() != nullptr; }
isReady()1402 bool isReady() { return mWaitableEvent->isReady(); }
wait()1403 void wait() { return mWaitableEvent->wait(); }
1404
getTask()1405 std::shared_ptr<CreateMonolithicPipelineTask> getTask() const { return mTask; }
1406
1407 private:
1408 std::shared_ptr<angle::WaitableEvent> mWaitableEvent;
1409 std::shared_ptr<CreateMonolithicPipelineTask> mTask;
1410 };
1411
1412 class PipelineHelper final : public Resource
1413 {
1414 public:
1415 PipelineHelper();
1416 ~PipelineHelper() override;
1417 inline explicit PipelineHelper(Pipeline &&pipeline, CacheLookUpFeedback feedback);
1418 PipelineHelper &operator=(PipelineHelper &&other);
1419
1420 void destroy(VkDevice device);
1421 void release(Context *context);
1422
valid()1423 bool valid() const { return mPipeline.valid(); }
getPipeline()1424 const Pipeline &getPipeline() const { return mPipeline; }
1425
1426 // Get the pipeline. If there is a monolithic pipeline creation task pending, scheduling it is
1427 // attempted. If that task is done, the pipeline is replaced with the results and the old
1428 // pipeline released.
1429 angle::Result getPreferredPipeline(ContextVk *contextVk, const Pipeline **pipelineOut);
1430
findTransition(GraphicsPipelineTransitionBits bits,const GraphicsPipelineDesc & desc,PipelineHelper ** pipelineOut)1431 ANGLE_INLINE bool findTransition(GraphicsPipelineTransitionBits bits,
1432 const GraphicsPipelineDesc &desc,
1433 PipelineHelper **pipelineOut) const
1434 {
1435 // Search could be improved using sorting or hashing.
1436 for (const GraphicsPipelineTransition &transition : mTransitions)
1437 {
1438 if (GraphicsPipelineTransitionMatch(transition.bits, bits, *transition.desc, desc))
1439 {
1440 *pipelineOut = transition.target;
1441 return true;
1442 }
1443 }
1444
1445 return false;
1446 }
1447
1448 void addTransition(GraphicsPipelineTransitionBits bits,
1449 const GraphicsPipelineDesc *desc,
1450 PipelineHelper *pipeline);
1451
getTransitions()1452 const std::vector<GraphicsPipelineTransition> getTransitions() const { return mTransitions; }
1453
setComputePipeline(Pipeline && pipeline,CacheLookUpFeedback feedback)1454 void setComputePipeline(Pipeline &&pipeline, CacheLookUpFeedback feedback)
1455 {
1456 ASSERT(!mPipeline.valid());
1457 mPipeline = std::move(pipeline);
1458
1459 ASSERT(mCacheLookUpFeedback == CacheLookUpFeedback::None);
1460 mCacheLookUpFeedback = feedback;
1461 }
getCacheLookUpFeedback()1462 CacheLookUpFeedback getCacheLookUpFeedback() const { return mCacheLookUpFeedback; }
1463
1464 void setLinkedLibraryReferences(vk::PipelineHelper *shadersPipeline);
1465
1466 void retainInRenderPass(RenderPassCommandBufferHelper *renderPassCommands);
1467
setMonolithicPipelineCreationTask(std::shared_ptr<CreateMonolithicPipelineTask> && task)1468 void setMonolithicPipelineCreationTask(std::shared_ptr<CreateMonolithicPipelineTask> &&task)
1469 {
1470 mMonolithicPipelineCreationTask.setTask(std::move(task));
1471 }
1472
1473 private:
1474 void reset();
1475
1476 std::vector<GraphicsPipelineTransition> mTransitions;
1477 Pipeline mPipeline;
1478 CacheLookUpFeedback mCacheLookUpFeedback = CacheLookUpFeedback::None;
1479 CacheLookUpFeedback mMonolithicCacheLookUpFeedback = CacheLookUpFeedback::None;
1480
1481 // The list of pipeline helpers that were referenced when creating a linked pipeline. These
1482 // pipelines must be kept alive, so their serial is updated at the same time as this object.
1483 // Not necessary for vertex input and fragment output as they stay alive until context's
1484 // destruction.
1485 PipelineHelper *mLinkedShaders = nullptr;
1486
1487 // If pipeline libraries are used and monolithic pipelines are created in parallel, this is the
1488 // temporary library created (previously in |mPipeline|) that is now replaced by the monolithic
1489 // one. It is not immediately garbage collected when replaced, because there is currently a bug
1490 // with that. http://anglebug.com/7862
1491 Pipeline mLinkedPipelineToRelease;
1492
1493 // An async task to create a monolithic pipeline. Only used if the pipeline was originally
1494 // created as a linked library. The |getPipeline()| call will attempt to schedule this task
1495 // through the share group, which manages and paces these tasks. Once the task results are
1496 // ready, |mPipeline| is released and replaced by the result of this task.
1497 WaitableMonolithicPipelineCreationTask mMonolithicPipelineCreationTask;
1498 };
1499
1500 class FramebufferHelper : public Resource
1501 {
1502 public:
1503 FramebufferHelper();
1504 ~FramebufferHelper() override;
1505
1506 FramebufferHelper(FramebufferHelper &&other);
1507 FramebufferHelper &operator=(FramebufferHelper &&other);
1508
1509 angle::Result init(Context *context, const VkFramebufferCreateInfo &createInfo);
1510 void destroy(Renderer *renderer);
1511 void release(ContextVk *contextVk);
1512
valid()1513 bool valid() { return mFramebuffer.valid(); }
1514
getFramebuffer()1515 const Framebuffer &getFramebuffer() const
1516 {
1517 ASSERT(mFramebuffer.valid());
1518 return mFramebuffer;
1519 }
1520
getFramebuffer()1521 Framebuffer &getFramebuffer()
1522 {
1523 ASSERT(mFramebuffer.valid());
1524 return mFramebuffer;
1525 }
1526
1527 private:
1528 // Vulkan object.
1529 Framebuffer mFramebuffer;
1530 };
1531
PipelineHelper(Pipeline && pipeline,CacheLookUpFeedback feedback)1532 ANGLE_INLINE PipelineHelper::PipelineHelper(Pipeline &&pipeline, CacheLookUpFeedback feedback)
1533 : mPipeline(std::move(pipeline)), mCacheLookUpFeedback(feedback)
1534 {}
1535
1536 ANGLE_INLINE PipelineHelper &PipelineHelper::operator=(PipelineHelper &&other)
1537 {
1538 ASSERT(!mPipeline.valid());
1539
1540 std::swap(mPipeline, other.mPipeline);
1541 mCacheLookUpFeedback = other.mCacheLookUpFeedback;
1542
1543 return *this;
1544 }
1545
1546 struct ImageSubresourceRange
1547 {
1548 // GL max is 1000 (fits in 10 bits).
1549 uint32_t level : 10;
1550 // Max 31 levels (2 ** 5 - 1). Can store levelCount-1 if we need to save another bit.
1551 uint32_t levelCount : 5;
1552 // Implementation max is 2048 (11 bits).
1553 uint32_t layer : 12;
1554 // One of vk::LayerMode values. If 0, it means all layers. Otherwise it's the count of layers
1555 // which is usually 1, except for multiview in which case it can be up to
1556 // gl::IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS.
1557 uint32_t layerMode : 3;
1558 // Values from vk::SrgbDecodeMode. Unused with draw views.
1559 uint32_t srgbDecodeMode : 1;
1560 // For read views: Values from gl::SrgbOverride, either Default or SRGB.
1561 // For draw views: Values from gl::SrgbWriteControlMode.
1562 uint32_t srgbMode : 1;
1563
1564 static_assert(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS < (1 << 5),
1565 "Not enough bits for level count");
1566 static_assert(gl::IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS <= (1 << 12),
1567 "Not enough bits for layer index");
1568 static_assert(gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS <= (1 << 3),
1569 "Not enough bits for layer count");
1570 };
1571
1572 static_assert(sizeof(ImageSubresourceRange) == sizeof(uint32_t), "Size mismatch");
1573
1574 inline bool operator==(const ImageSubresourceRange &a, const ImageSubresourceRange &b)
1575 {
1576 return a.level == b.level && a.levelCount == b.levelCount && a.layer == b.layer &&
1577 a.layerMode == b.layerMode && a.srgbDecodeMode == b.srgbDecodeMode &&
1578 a.srgbMode == b.srgbMode;
1579 }
1580
1581 constexpr ImageSubresourceRange kInvalidImageSubresourceRange = {0, 0, 0, 0, 0, 0};
1582
1583 struct ImageOrBufferViewSubresourceSerial
1584 {
1585 ImageOrBufferViewSerial viewSerial;
1586 ImageSubresourceRange subresource;
1587 };
1588
1589 inline bool operator==(const ImageOrBufferViewSubresourceSerial &a,
1590 const ImageOrBufferViewSubresourceSerial &b)
1591 {
1592 return a.viewSerial == b.viewSerial && a.subresource == b.subresource;
1593 }
1594
1595 constexpr ImageOrBufferViewSubresourceSerial kInvalidImageOrBufferViewSubresourceSerial = {
1596 kInvalidImageOrBufferViewSerial, kInvalidImageSubresourceRange};
1597
1598 // Always starts with array element zero, with descriptorCount descriptors.
1599 struct WriteDescriptorDesc
1600 {
1601 uint8_t binding; // Redundant: determined by the containing WriteDesc array.
1602 uint8_t descriptorCount; // Number of array elements in this descriptor write.
1603 uint8_t descriptorType; // Packed VkDescriptorType.
1604 uint8_t descriptorInfoIndex; // Base index into an array of DescriptorInfoDescs.
1605 };
1606
1607 static_assert(sizeof(WriteDescriptorDesc) == 4, "Size mismatch");
1608
1609 struct DescriptorInfoDesc
1610 {
1611 uint32_t samplerOrBufferSerial;
1612 uint32_t imageViewSerialOrOffset;
1613 uint32_t imageLayoutOrRange; // Packed VkImageLayout
1614 uint32_t imageSubresourceRange;
1615 };
1616
1617 static_assert(sizeof(DescriptorInfoDesc) == 16, "Size mismatch");
1618
1619 // Generic description of a descriptor set. Used as a key when indexing descriptor set caches. The
1620 // key storage is an angle:FixedVector. Beyond a certain fixed size we'll end up using heap memory
1621 // to store keys. Currently we specialize the structure for three use cases: uniforms, textures,
1622 // and other shader resources. Because of the way the specialization works we can't currently cache
1623 // programs that use some types of resources.
1624 static constexpr size_t kFastDescriptorSetDescLimit = 8;
1625
1626 struct DescriptorDescHandles
1627 {
1628 VkBuffer buffer;
1629 VkSampler sampler;
1630 VkImageView imageView;
1631 VkBufferView bufferView;
1632 };
1633
1634 class WriteDescriptorDescs
1635 {
1636 public:
reset()1637 void reset()
1638 {
1639 mDescs.clear();
1640 mDynamicDescriptorSetCount = 0;
1641 mCurrentInfoIndex = 0;
1642 }
1643
1644 void updateShaderBuffers(const ShaderInterfaceVariableInfoMap &variableInfoMap,
1645 const std::vector<gl::InterfaceBlock> &blocks,
1646 VkDescriptorType descriptorType);
1647
1648 void updateAtomicCounters(const ShaderInterfaceVariableInfoMap &variableInfoMap,
1649 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers);
1650
1651 void updateImages(const gl::ProgramExecutable &executable,
1652 const ShaderInterfaceVariableInfoMap &variableInfoMap);
1653
1654 void updateInputAttachments(const gl::ProgramExecutable &executable,
1655 const ShaderInterfaceVariableInfoMap &variableInfoMap,
1656 FramebufferVk *framebufferVk);
1657
1658 void updateExecutableActiveTextures(const ShaderInterfaceVariableInfoMap &variableInfoMap,
1659 const gl::ProgramExecutable &executable);
1660
1661 void updateDefaultUniform(gl::ShaderBitSet shaderTypes,
1662 const ShaderInterfaceVariableInfoMap &variableInfoMap,
1663 const gl::ProgramExecutable &executable);
1664
1665 void updateTransformFeedbackWrite(const ShaderInterfaceVariableInfoMap &variableInfoMap,
1666 const gl::ProgramExecutable &executable);
1667
1668 void updateDynamicDescriptorsCount();
1669
size()1670 size_t size() const { return mDescs.size(); }
empty()1671 bool empty() const { return mDescs.size() == 0; }
1672
1673 const WriteDescriptorDesc &operator[](uint32_t bindingIndex) const
1674 {
1675 return mDescs[bindingIndex];
1676 }
1677
getTotalDescriptorCount()1678 size_t getTotalDescriptorCount() const { return mCurrentInfoIndex; }
getDynamicDescriptorSetCount()1679 size_t getDynamicDescriptorSetCount() const { return mDynamicDescriptorSetCount; }
1680
1681 void streamOut(std::ostream &os) const;
1682
1683 private:
hasWriteDescAtIndex(uint32_t bindingIndex)1684 bool hasWriteDescAtIndex(uint32_t bindingIndex) const
1685 {
1686 return bindingIndex < mDescs.size() && mDescs[bindingIndex].descriptorCount > 0;
1687 }
1688
incrementDescriptorCount(uint32_t bindingIndex,uint32_t count)1689 void incrementDescriptorCount(uint32_t bindingIndex, uint32_t count)
1690 {
1691 // Validate we have no subsequent writes.
1692 ASSERT(hasWriteDescAtIndex(bindingIndex));
1693 mDescs[bindingIndex].descriptorCount += count;
1694 }
1695
1696 void updateWriteDesc(uint32_t bindingIndex,
1697 VkDescriptorType descriptorType,
1698 uint32_t descriptorCount);
1699
1700 // After a preliminary minimum size, use heap memory.
1701 angle::FastMap<WriteDescriptorDesc, kFastDescriptorSetDescLimit> mDescs;
1702 size_t mDynamicDescriptorSetCount = 0;
1703 uint32_t mCurrentInfoIndex = 0;
1704 };
1705
1706 class DescriptorSetDesc
1707 {
1708 public:
1709 DescriptorSetDesc() = default;
1710 ~DescriptorSetDesc() = default;
1711
DescriptorSetDesc(const DescriptorSetDesc & other)1712 DescriptorSetDesc(const DescriptorSetDesc &other) : mDescriptorInfos(other.mDescriptorInfos) {}
1713
1714 DescriptorSetDesc &operator=(const DescriptorSetDesc &other)
1715 {
1716 mDescriptorInfos = other.mDescriptorInfos;
1717 return *this;
1718 }
1719
1720 size_t hash() const;
1721
resize(size_t count)1722 void resize(size_t count) { mDescriptorInfos.resize(count); }
1723
getKeySizeBytes()1724 size_t getKeySizeBytes() const { return mDescriptorInfos.size() * sizeof(DescriptorInfoDesc); }
1725
1726 bool operator==(const DescriptorSetDesc &other) const
1727 {
1728 return mDescriptorInfos.size() == other.mDescriptorInfos.size() &&
1729 memcmp(mDescriptorInfos.data(), other.mDescriptorInfos.data(),
1730 mDescriptorInfos.size() * sizeof(DescriptorInfoDesc)) == 0;
1731 }
1732
getInfoDesc(uint32_t infoDescIndex)1733 DescriptorInfoDesc &getInfoDesc(uint32_t infoDescIndex)
1734 {
1735 return mDescriptorInfos[infoDescIndex];
1736 }
1737
1738 void updateDescriptorSet(Renderer *renderer,
1739 const WriteDescriptorDescs &writeDescriptorDescs,
1740 UpdateDescriptorSetsBuilder *updateBuilder,
1741 const DescriptorDescHandles *handles,
1742 VkDescriptorSet descriptorSet) const;
1743
1744 void streamOut(std::ostream &os) const;
1745
1746 private:
1747 // After a preliminary minimum size, use heap memory.
1748 angle::FastVector<DescriptorInfoDesc, kFastDescriptorSetDescLimit> mDescriptorInfos;
1749 };
1750
1751 class DescriptorPoolHelper;
1752 using RefCountedDescriptorPoolHelper = RefCounted<DescriptorPoolHelper>;
1753
1754 // SharedDescriptorSetCacheKey.
1755 // Because DescriptorSet must associate with a pool, we need to define a structure that wraps both.
1756 struct DescriptorSetDescAndPool
1757 {
1758 DescriptorSetDesc mDesc;
1759 DynamicDescriptorPool *mPool;
1760 };
1761 using DescriptorSetAndPoolPointer = std::unique_ptr<DescriptorSetDescAndPool>;
1762 using SharedDescriptorSetCacheKey = std::shared_ptr<DescriptorSetAndPoolPointer>;
1763 ANGLE_INLINE const SharedDescriptorSetCacheKey
CreateSharedDescriptorSetCacheKey(const DescriptorSetDesc & desc,DynamicDescriptorPool * pool)1764 CreateSharedDescriptorSetCacheKey(const DescriptorSetDesc &desc, DynamicDescriptorPool *pool)
1765 {
1766 DescriptorSetAndPoolPointer DescriptorAndPoolPointer =
1767 std::make_unique<DescriptorSetDescAndPool>(DescriptorSetDescAndPool{desc, pool});
1768 return std::make_shared<DescriptorSetAndPoolPointer>(std::move(DescriptorAndPoolPointer));
1769 }
1770
1771 constexpr VkDescriptorType kStorageBufferDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1772
1773 // Manages a descriptor set desc with a few helper routines and also stores object handles.
1774 class DescriptorSetDescBuilder final
1775 {
1776 public:
1777 DescriptorSetDescBuilder();
1778 DescriptorSetDescBuilder(size_t descriptorCount);
1779 ~DescriptorSetDescBuilder();
1780
1781 DescriptorSetDescBuilder(const DescriptorSetDescBuilder &other);
1782 DescriptorSetDescBuilder &operator=(const DescriptorSetDescBuilder &other);
1783
getDesc()1784 const DescriptorSetDesc &getDesc() const { return mDesc; }
1785
resize(size_t descriptorCount)1786 void resize(size_t descriptorCount)
1787 {
1788 mDesc.resize(descriptorCount);
1789 mHandles.resize(descriptorCount);
1790 mDynamicOffsets.resize(descriptorCount);
1791 }
1792
1793 // Specific helpers for uniforms/xfb descriptors.
1794 void updateUniformBuffer(uint32_t shaderIndex,
1795 const WriteDescriptorDescs &writeDescriptorDescs,
1796 const BufferHelper &bufferHelper,
1797 VkDeviceSize bufferRange);
1798
1799 void updateTransformFeedbackBuffer(const Context *context,
1800 const ShaderInterfaceVariableInfoMap &variableInfoMap,
1801 const WriteDescriptorDescs &writeDescriptorDescs,
1802 uint32_t xfbBufferIndex,
1803 const BufferHelper &bufferHelper,
1804 VkDeviceSize bufferOffset,
1805 VkDeviceSize bufferRange);
1806
1807 void updateUniformsAndXfb(Context *context,
1808 const gl::ProgramExecutable &executable,
1809 const WriteDescriptorDescs &writeDescriptorDescs,
1810 const BufferHelper *currentUniformBuffer,
1811 const BufferHelper &emptyBuffer,
1812 bool activeUnpaused,
1813 TransformFeedbackVk *transformFeedbackVk);
1814
1815 // Specific helpers for shader resource descriptors.
1816 template <typename CommandBufferT>
1817 void updateOneShaderBuffer(ContextVk *contextVk,
1818 CommandBufferT *commandBufferHelper,
1819 const ShaderInterfaceVariableInfoMap &variableInfoMap,
1820 const gl::BufferVector &buffers,
1821 const gl::InterfaceBlock &block,
1822 uint32_t bufferIndex,
1823 VkDescriptorType descriptorType,
1824 VkDeviceSize maxBoundBufferRange,
1825 const BufferHelper &emptyBuffer,
1826 const WriteDescriptorDescs &writeDescriptorDescs);
1827 template <typename CommandBufferT>
1828 void updateShaderBuffers(ContextVk *contextVk,
1829 CommandBufferT *commandBufferHelper,
1830 const gl::ProgramExecutable &executable,
1831 const ShaderInterfaceVariableInfoMap &variableInfoMap,
1832 const gl::BufferVector &buffers,
1833 const std::vector<gl::InterfaceBlock> &blocks,
1834 VkDescriptorType descriptorType,
1835 VkDeviceSize maxBoundBufferRange,
1836 const BufferHelper &emptyBuffer,
1837 const WriteDescriptorDescs &writeDescriptorDescs);
1838 template <typename CommandBufferT>
1839 void updateAtomicCounters(ContextVk *contextVk,
1840 CommandBufferT *commandBufferHelper,
1841 const gl::ProgramExecutable &executable,
1842 const ShaderInterfaceVariableInfoMap &variableInfoMap,
1843 const gl::BufferVector &buffers,
1844 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
1845 const VkDeviceSize requiredOffsetAlignment,
1846 const BufferHelper &emptyBuffer,
1847 const WriteDescriptorDescs &writeDescriptorDescs);
1848 angle::Result updateImages(Context *context,
1849 const gl::ProgramExecutable &executable,
1850 const ShaderInterfaceVariableInfoMap &variableInfoMap,
1851 const gl::ActiveTextureArray<TextureVk *> &activeImages,
1852 const std::vector<gl::ImageUnit> &imageUnits,
1853 const WriteDescriptorDescs &writeDescriptorDescs);
1854 angle::Result updateInputAttachments(vk::Context *context,
1855 const gl::ProgramExecutable &executable,
1856 const ShaderInterfaceVariableInfoMap &variableInfoMap,
1857 FramebufferVk *framebufferVk,
1858 const WriteDescriptorDescs &writeDescriptorDescs);
1859
1860 // Specific helpers for image descriptors.
1861 void updatePreCacheActiveTextures(const gl::ActiveTextureMask &activeTextures,
1862 const gl::ActiveTextureArray<TextureVk *> &textures,
1863 const gl::SamplerBindingVector &samplers);
1864
1865 angle::Result updateFullActiveTextures(Context *context,
1866 const ShaderInterfaceVariableInfoMap &variableInfoMap,
1867 const WriteDescriptorDescs &writeDescriptorDescs,
1868 const gl::ProgramExecutable &executable,
1869 const gl::ActiveTextureArray<TextureVk *> &textures,
1870 const gl::SamplerBindingVector &samplers,
1871 bool emulateSeamfulCubeMapSampling,
1872 PipelineType pipelineType,
1873 const SharedDescriptorSetCacheKey &sharedCacheKey);
1874
1875 void updateDescriptorSet(Renderer *renderer,
1876 const WriteDescriptorDescs &writeDescriptorDescs,
1877 UpdateDescriptorSetsBuilder *updateBuilder,
1878 VkDescriptorSet descriptorSet) const;
1879
getDynamicOffsets()1880 const uint32_t *getDynamicOffsets() const { return mDynamicOffsets.data(); }
getDynamicOffsetsSize()1881 size_t getDynamicOffsetsSize() const { return mDynamicOffsets.size(); }
1882
1883 private:
1884 void setEmptyBuffer(uint32_t infoDescIndex,
1885 VkDescriptorType descriptorType,
1886 const BufferHelper &emptyBuffer);
1887
1888 DescriptorSetDesc mDesc;
1889 angle::FastVector<DescriptorDescHandles, kFastDescriptorSetDescLimit> mHandles;
1890 angle::FastVector<uint32_t, kFastDescriptorSetDescLimit> mDynamicOffsets;
1891 };
1892
1893 // Specialized update for textures.
1894 void UpdatePreCacheActiveTextures(const gl::ProgramExecutable &executable,
1895 const std::vector<gl::SamplerBinding> &samplerBindings,
1896 const gl::ActiveTextureMask &activeTextures,
1897 const gl::ActiveTextureArray<TextureVk *> &textures,
1898 const gl::SamplerBindingVector &samplers,
1899 DescriptorSetDesc *desc);
1900
1901 // In the FramebufferDesc object:
1902 // - Depth/stencil serial is at index 0
1903 // - Color serials are at indices [1, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]
1904 // - Depth/stencil resolve attachment is at index gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+1
1905 // - Resolve attachments are at indices [gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+2,
1906 // gl::IMPLEMENTATION_MAX_DRAW_BUFFERS*2+1]
1907 // Fragment shading rate attachment serial is at index
1908 // (gl::IMPLEMENTATION_MAX_DRAW_BUFFERS*2+1)+1
1909 constexpr size_t kFramebufferDescDepthStencilIndex = 0;
1910 constexpr size_t kFramebufferDescColorIndexOffset = kFramebufferDescDepthStencilIndex + 1;
1911 constexpr size_t kFramebufferDescDepthStencilResolveIndexOffset =
1912 kFramebufferDescColorIndexOffset + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
1913 constexpr size_t kFramebufferDescColorResolveIndexOffset =
1914 kFramebufferDescDepthStencilResolveIndexOffset + 1;
1915 constexpr size_t kFramebufferDescFragmentShadingRateAttachmentIndexOffset =
1916 kFramebufferDescColorResolveIndexOffset + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
1917
1918 // Enable struct padding warnings for the code below since it is used in caches.
1919 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
1920
1921 class FramebufferDesc
1922 {
1923 public:
1924 FramebufferDesc();
1925 ~FramebufferDesc();
1926
1927 FramebufferDesc(const FramebufferDesc &other);
1928 FramebufferDesc &operator=(const FramebufferDesc &other);
1929
1930 void updateColor(uint32_t index, ImageOrBufferViewSubresourceSerial serial);
1931 void updateColorResolve(uint32_t index, ImageOrBufferViewSubresourceSerial serial);
1932 void updateUnresolveMask(FramebufferNonResolveAttachmentMask unresolveMask);
1933 void updateDepthStencil(ImageOrBufferViewSubresourceSerial serial);
1934 void updateDepthStencilResolve(ImageOrBufferViewSubresourceSerial serial);
setWriteControlMode(gl::SrgbWriteControlMode mode)1935 ANGLE_INLINE void setWriteControlMode(gl::SrgbWriteControlMode mode)
1936 {
1937 mSrgbWriteControlMode = static_cast<uint16_t>(mode);
1938 }
updateIsMultiview(bool isMultiview)1939 void updateIsMultiview(bool isMultiview) { mIsMultiview = isMultiview; }
1940 size_t hash() const;
1941
1942 bool operator==(const FramebufferDesc &other) const;
1943
1944 uint32_t attachmentCount() const;
1945
getColorImageViewSerial(uint32_t index)1946 ImageOrBufferViewSubresourceSerial getColorImageViewSerial(uint32_t index)
1947 {
1948 ASSERT(kFramebufferDescColorIndexOffset + index < mSerials.size());
1949 return mSerials[kFramebufferDescColorIndexOffset + index];
1950 }
1951
1952 FramebufferNonResolveAttachmentMask getUnresolveAttachmentMask() const;
getWriteControlMode()1953 ANGLE_INLINE gl::SrgbWriteControlMode getWriteControlMode() const
1954 {
1955 return (mSrgbWriteControlMode == 1) ? gl::SrgbWriteControlMode::Linear
1956 : gl::SrgbWriteControlMode::Default;
1957 }
1958
1959 void updateLayerCount(uint32_t layerCount);
getLayerCount()1960 uint32_t getLayerCount() const { return mLayerCount; }
1961 void setFramebufferFetchMode(bool hasFramebufferFetch);
hasFramebufferFetch()1962 bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
1963
isMultiview()1964 bool isMultiview() const { return mIsMultiview; }
1965
1966 void updateRenderToTexture(bool isRenderToTexture);
1967
1968 void updateFragmentShadingRate(ImageOrBufferViewSubresourceSerial serial);
1969 bool hasFragmentShadingRateAttachment() const;
1970
1971 private:
1972 void reset();
1973 void update(uint32_t index, ImageOrBufferViewSubresourceSerial serial);
1974
1975 // Note: this is an exclusive index. If there is one index it will be "1".
1976 // Maximum value is 18
1977 uint16_t mMaxIndex : 5;
1978 uint16_t mHasFramebufferFetch : 1;
1979 static_assert(gl::IMPLEMENTATION_MAX_FRAMEBUFFER_LAYERS < (1 << 9) - 1,
1980 "Not enough bits for mLayerCount");
1981
1982 uint16_t mLayerCount : 9;
1983
1984 uint16_t mSrgbWriteControlMode : 1;
1985
1986 // If the render pass contains an initial subpass to unresolve a number of attachments, the
1987 // subpass description is derived from the following mask, specifying which attachments need
1988 // to be unresolved. Includes both color and depth/stencil attachments.
1989 uint16_t mUnresolveAttachmentMask : kMaxFramebufferNonResolveAttachments;
1990
1991 // Whether this is a multisampled-render-to-single-sampled framebuffer. Only used when using
1992 // VK_EXT_multisampled_render_to_single_sampled. Only one bit is used and the rest is padding.
1993 uint16_t mIsRenderToTexture : 15 - kMaxFramebufferNonResolveAttachments;
1994
1995 uint16_t mIsMultiview : 1;
1996
1997 FramebufferAttachmentArray<ImageOrBufferViewSubresourceSerial> mSerials;
1998 };
1999
2000 constexpr size_t kFramebufferDescSize = sizeof(FramebufferDesc);
2001 static_assert(kFramebufferDescSize == 156, "Size check failed");
2002
2003 // Disable warnings about struct padding.
2004 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
2005
2006 // SharedFramebufferCacheKey
2007 using FramebufferDescPointer = std::unique_ptr<FramebufferDesc>;
2008 using SharedFramebufferCacheKey = std::shared_ptr<FramebufferDescPointer>;
2009 ANGLE_INLINE const SharedFramebufferCacheKey
CreateSharedFramebufferCacheKey(const FramebufferDesc & desc)2010 CreateSharedFramebufferCacheKey(const FramebufferDesc &desc)
2011 {
2012 FramebufferDescPointer framebufferDescPointer = std::make_unique<FramebufferDesc>(desc);
2013 return std::make_shared<FramebufferDescPointer>(std::move(framebufferDescPointer));
2014 }
2015
2016 // The SamplerHelper allows a Sampler to be coupled with a serial.
2017 // Must be included before we declare SamplerCache.
2018 class SamplerHelper final : angle::NonCopyable
2019 {
2020 public:
2021 SamplerHelper(ContextVk *contextVk);
2022 ~SamplerHelper();
2023
2024 explicit SamplerHelper(SamplerHelper &&samplerHelper);
2025 SamplerHelper &operator=(SamplerHelper &&rhs);
2026
valid()2027 bool valid() const { return mSampler.valid(); }
get()2028 const Sampler &get() const { return mSampler; }
get()2029 Sampler &get() { return mSampler; }
getSamplerSerial()2030 SamplerSerial getSamplerSerial() const { return mSamplerSerial; }
2031
2032 private:
2033 Sampler mSampler;
2034 SamplerSerial mSamplerSerial;
2035 };
2036
2037 using RefCountedSampler = RefCounted<SamplerHelper>;
2038 using SamplerBinding = BindingPointer<SamplerHelper>;
2039
2040 class RenderPassHelper final : angle::NonCopyable
2041 {
2042 public:
2043 RenderPassHelper();
2044 ~RenderPassHelper();
2045
2046 RenderPassHelper(RenderPassHelper &&other);
2047 RenderPassHelper &operator=(RenderPassHelper &&other);
2048
2049 void destroy(VkDevice device);
2050 void release(ContextVk *contextVk);
2051
2052 const RenderPass &getRenderPass() const;
2053 RenderPass &getRenderPass();
2054
2055 const RenderPassPerfCounters &getPerfCounters() const;
2056 RenderPassPerfCounters &getPerfCounters();
2057
2058 private:
2059 RenderPass mRenderPass;
2060 RenderPassPerfCounters mPerfCounters;
2061 };
2062
2063 // Helper class manages the lifetime of various cache objects so that the cache entry can be
2064 // destroyed when one of the components becomes invalid.
2065 template <class SharedCacheKeyT>
2066 class SharedCacheKeyManager
2067 {
2068 public:
2069 SharedCacheKeyManager() = default;
~SharedCacheKeyManager()2070 ~SharedCacheKeyManager() { ASSERT(empty()); }
2071 // Store the pointer to the cache key and retains it
2072 void addKey(const SharedCacheKeyT &key);
2073 // Iterate over the descriptor array and release the descriptor and cache.
2074 void releaseKeys(ContextVk *contextVk);
2075 void releaseKeys(Renderer *renderer);
2076 // Iterate over the descriptor array and destroy the descriptor and cache.
2077 void destroyKeys(Renderer *renderer);
2078 void clear();
2079
2080 // The following APIs are expected to be used for assertion only
2081 bool containsKey(const SharedCacheKeyT &key) const;
empty()2082 bool empty() const { return mSharedCacheKeys.empty(); }
2083 void assertAllEntriesDestroyed();
2084
2085 private:
2086 // Tracks an array of cache keys with refcounting. Note this owns one refcount of
2087 // SharedCacheKeyT object.
2088 std::vector<SharedCacheKeyT> mSharedCacheKeys;
2089 };
2090
2091 using FramebufferCacheManager = SharedCacheKeyManager<SharedFramebufferCacheKey>;
2092 using DescriptorSetCacheManager = SharedCacheKeyManager<SharedDescriptorSetCacheKey>;
2093 } // namespace vk
2094 } // namespace rx
2095
2096 // Introduce std::hash for the above classes.
2097 namespace std
2098 {
2099 template <>
2100 struct hash<rx::vk::RenderPassDesc>
2101 {
2102 size_t operator()(const rx::vk::RenderPassDesc &key) const { return key.hash(); }
2103 };
2104
2105 template <>
2106 struct hash<rx::vk::AttachmentOpsArray>
2107 {
2108 size_t operator()(const rx::vk::AttachmentOpsArray &key) const { return key.hash(); }
2109 };
2110
2111 template <>
2112 struct hash<rx::vk::DescriptorSetLayoutDesc>
2113 {
2114 size_t operator()(const rx::vk::DescriptorSetLayoutDesc &key) const { return key.hash(); }
2115 };
2116
2117 template <>
2118 struct hash<rx::vk::PipelineLayoutDesc>
2119 {
2120 size_t operator()(const rx::vk::PipelineLayoutDesc &key) const { return key.hash(); }
2121 };
2122
2123 template <>
2124 struct hash<rx::vk::ImageSubresourceRange>
2125 {
2126 size_t operator()(const rx::vk::ImageSubresourceRange &key) const
2127 {
2128 return *reinterpret_cast<const uint32_t *>(&key);
2129 }
2130 };
2131
2132 template <>
2133 struct hash<rx::vk::DescriptorSetDesc>
2134 {
2135 size_t operator()(const rx::vk::DescriptorSetDesc &key) const { return key.hash(); }
2136 };
2137
2138 template <>
2139 struct hash<rx::vk::FramebufferDesc>
2140 {
2141 size_t operator()(const rx::vk::FramebufferDesc &key) const { return key.hash(); }
2142 };
2143
2144 template <>
2145 struct hash<rx::vk::YcbcrConversionDesc>
2146 {
2147 size_t operator()(const rx::vk::YcbcrConversionDesc &key) const { return key.hash(); }
2148 };
2149
2150 template <>
2151 struct hash<rx::vk::SamplerDesc>
2152 {
2153 size_t operator()(const rx::vk::SamplerDesc &key) const { return key.hash(); }
2154 };
2155
2156 // See Resource Serial types defined in vk_utils.h.
2157 #define ANGLE_HASH_VK_SERIAL(Type) \
2158 template <> \
2159 struct hash<rx::vk::Type##Serial> \
2160 { \
2161 size_t operator()(const rx::vk::Type##Serial &key) const \
2162 { \
2163 return key.getValue(); \
2164 } \
2165 };
2166
2167 ANGLE_VK_SERIAL_OP(ANGLE_HASH_VK_SERIAL)
2168
2169 } // namespace std
2170
2171 namespace rx
2172 {
2173 // Cache types for various Vulkan objects
2174 enum class VulkanCacheType
2175 {
2176 CompatibleRenderPass,
2177 RenderPassWithOps,
2178 GraphicsPipeline,
2179 PipelineLayout,
2180 Sampler,
2181 SamplerYcbcrConversion,
2182 DescriptorSetLayout,
2183 DriverUniformsDescriptors,
2184 TextureDescriptors,
2185 UniformsAndXfbDescriptors,
2186 ShaderResourcesDescriptors,
2187 Framebuffer,
2188 DescriptorMetaCache,
2189 EnumCount
2190 };
2191
2192 // Base class for all caches. Provides cache hit and miss counters.
2193 class CacheStats final : angle::NonCopyable
2194 {
2195 public:
2196 CacheStats() { reset(); }
2197 ~CacheStats() {}
2198
2199 CacheStats(const CacheStats &rhs)
2200 : mHitCount(rhs.mHitCount), mMissCount(rhs.mMissCount), mSize(rhs.mSize)
2201 {}
2202
2203 CacheStats &operator=(const CacheStats &rhs)
2204 {
2205 mHitCount = rhs.mHitCount;
2206 mMissCount = rhs.mMissCount;
2207 mSize = rhs.mSize;
2208 return *this;
2209 }
2210
2211 ANGLE_INLINE void hit() { mHitCount++; }
2212 ANGLE_INLINE void miss() { mMissCount++; }
2213 ANGLE_INLINE void incrementSize() { mSize++; }
2214 ANGLE_INLINE void decrementSize() { mSize--; }
2215 ANGLE_INLINE void missAndIncrementSize()
2216 {
2217 mMissCount++;
2218 mSize++;
2219 }
2220 ANGLE_INLINE void accumulate(const CacheStats &stats)
2221 {
2222 mHitCount += stats.mHitCount;
2223 mMissCount += stats.mMissCount;
2224 mSize += stats.mSize;
2225 }
2226
2227 uint32_t getHitCount() const { return mHitCount; }
2228 uint32_t getMissCount() const { return mMissCount; }
2229
2230 ANGLE_INLINE double getHitRatio() const
2231 {
2232 if (mHitCount + mMissCount == 0)
2233 {
2234 return 0;
2235 }
2236 else
2237 {
2238 return static_cast<double>(mHitCount) / (mHitCount + mMissCount);
2239 }
2240 }
2241
2242 ANGLE_INLINE uint32_t getSize() const { return mSize; }
2243 ANGLE_INLINE void setSize(uint32_t size) { mSize = size; }
2244
2245 void reset()
2246 {
2247 mHitCount = 0;
2248 mMissCount = 0;
2249 mSize = 0;
2250 }
2251
2252 void resetHitAndMissCount()
2253 {
2254 mHitCount = 0;
2255 mMissCount = 0;
2256 }
2257
2258 void accumulateCacheStats(VulkanCacheType cacheType, const CacheStats &cacheStats)
2259 {
2260 mHitCount += cacheStats.getHitCount();
2261 mMissCount += cacheStats.getMissCount();
2262 }
2263
2264 private:
2265 uint32_t mHitCount;
2266 uint32_t mMissCount;
2267 uint32_t mSize;
2268 };
2269
2270 template <VulkanCacheType CacheType>
2271 class HasCacheStats : angle::NonCopyable
2272 {
2273 public:
2274 template <typename Accumulator>
2275 void accumulateCacheStats(Accumulator *accum)
2276 {
2277 accum->accumulateCacheStats(CacheType, mCacheStats);
2278 mCacheStats.reset();
2279 }
2280
2281 void getCacheStats(CacheStats *accum) const { accum->accumulate(mCacheStats); }
2282
2283 protected:
2284 HasCacheStats() = default;
2285 virtual ~HasCacheStats() = default;
2286
2287 CacheStats mCacheStats;
2288 };
2289
2290 using VulkanCacheStats = angle::PackedEnumMap<VulkanCacheType, CacheStats>;
2291
2292 // FramebufferVk Cache
2293 class FramebufferCache final : angle::NonCopyable
2294 {
2295 public:
2296 FramebufferCache() = default;
2297 ~FramebufferCache() { ASSERT(mPayload.empty()); }
2298
2299 void destroy(vk::Renderer *renderer);
2300
2301 bool get(ContextVk *contextVk, const vk::FramebufferDesc &desc, vk::Framebuffer &framebuffer);
2302 void insert(ContextVk *contextVk,
2303 const vk::FramebufferDesc &desc,
2304 vk::FramebufferHelper &&framebufferHelper);
2305 void erase(ContextVk *contextVk, const vk::FramebufferDesc &desc);
2306
2307 size_t getSize() const { return mPayload.size(); }
2308 bool empty() const { return mPayload.empty(); }
2309
2310 private:
2311 angle::HashMap<vk::FramebufferDesc, vk::FramebufferHelper> mPayload;
2312 CacheStats mCacheStats;
2313 };
2314
2315 // TODO(jmadill): Add cache trimming/eviction.
2316 class RenderPassCache final : angle::NonCopyable
2317 {
2318 public:
2319 RenderPassCache();
2320 ~RenderPassCache();
2321
2322 void destroy(ContextVk *contextVk);
2323 void clear(ContextVk *contextVk);
2324
2325 ANGLE_INLINE angle::Result getCompatibleRenderPass(ContextVk *contextVk,
2326 const vk::RenderPassDesc &desc,
2327 const vk::RenderPass **renderPassOut)
2328 {
2329 auto outerIt = mPayload.find(desc);
2330 if (outerIt != mPayload.end())
2331 {
2332 InnerCache &innerCache = outerIt->second;
2333 ASSERT(!innerCache.empty());
2334
2335 // Find the first element and return it.
2336 *renderPassOut = &innerCache.begin()->second.getRenderPass();
2337 mCompatibleRenderPassCacheStats.hit();
2338 return angle::Result::Continue;
2339 }
2340
2341 mCompatibleRenderPassCacheStats.missAndIncrementSize();
2342 return addCompatibleRenderPass(contextVk, desc, renderPassOut);
2343 }
2344
2345 angle::Result getRenderPassWithOps(ContextVk *contextVk,
2346 const vk::RenderPassDesc &desc,
2347 const vk::AttachmentOpsArray &attachmentOps,
2348 const vk::RenderPass **renderPassOut);
2349
2350 static void InitializeOpsForCompatibleRenderPass(const vk::RenderPassDesc &desc,
2351 vk::AttachmentOpsArray *opsOut);
2352 static angle::Result MakeRenderPass(vk::Context *context,
2353 const vk::RenderPassDesc &desc,
2354 const vk::AttachmentOpsArray &ops,
2355 vk::RenderPass *renderPass,
2356 vk::RenderPassPerfCounters *renderPassCounters);
2357
2358 private:
2359 angle::Result getRenderPassWithOpsImpl(ContextVk *contextVk,
2360 const vk::RenderPassDesc &desc,
2361 const vk::AttachmentOpsArray &attachmentOps,
2362 bool updatePerfCounters,
2363 const vk::RenderPass **renderPassOut);
2364
2365 angle::Result addCompatibleRenderPass(ContextVk *contextVk,
2366 const vk::RenderPassDesc &desc,
2367 const vk::RenderPass **renderPassOut);
2368
2369 // Use a two-layer caching scheme. The top level matches the "compatible" RenderPass elements.
2370 // The second layer caches the attachment load/store ops and initial/final layout.
2371 // Switch to `std::unordered_map` to retain pointer stability.
2372 using InnerCache = std::unordered_map<vk::AttachmentOpsArray, vk::RenderPassHelper>;
2373 using OuterCache = std::unordered_map<vk::RenderPassDesc, InnerCache>;
2374
2375 OuterCache mPayload;
2376 CacheStats mCompatibleRenderPassCacheStats;
2377 CacheStats mRenderPassWithOpsCacheStats;
2378 };
2379
2380 enum class PipelineSource
2381 {
2382 // Pipeline created when warming up the program's pipeline cache
2383 WarmUp,
2384 // Monolithic pipeline created at draw time
2385 Draw,
2386 // Pipeline created at draw time by linking partial pipeline libraries
2387 DrawLinked,
2388 // Pipeline created for UtilsVk
2389 Utils,
2390 };
2391
2392 struct GraphicsPipelineDescCompleteHash
2393 {
2394 size_t operator()(const rx::vk::GraphicsPipelineDesc &key) const
2395 {
2396 return key.hash(vk::GraphicsPipelineSubset::Complete);
2397 }
2398 };
2399 struct GraphicsPipelineDescVertexInputHash
2400 {
2401 size_t operator()(const rx::vk::GraphicsPipelineDesc &key) const
2402 {
2403 return key.hash(vk::GraphicsPipelineSubset::VertexInput);
2404 }
2405 };
2406 struct GraphicsPipelineDescShadersHash
2407 {
2408 size_t operator()(const rx::vk::GraphicsPipelineDesc &key) const
2409 {
2410 return key.hash(vk::GraphicsPipelineSubset::Shaders);
2411 }
2412 };
2413 struct GraphicsPipelineDescFragmentOutputHash
2414 {
2415 size_t operator()(const rx::vk::GraphicsPipelineDesc &key) const
2416 {
2417 return key.hash(vk::GraphicsPipelineSubset::FragmentOutput);
2418 }
2419 };
2420
2421 struct GraphicsPipelineDescCompleteKeyEqual
2422 {
2423 size_t operator()(const rx::vk::GraphicsPipelineDesc &first,
2424 const rx::vk::GraphicsPipelineDesc &second) const
2425 {
2426 return first.keyEqual(second, vk::GraphicsPipelineSubset::Complete);
2427 }
2428 };
2429 struct GraphicsPipelineDescVertexInputKeyEqual
2430 {
2431 size_t operator()(const rx::vk::GraphicsPipelineDesc &first,
2432 const rx::vk::GraphicsPipelineDesc &second) const
2433 {
2434 return first.keyEqual(second, vk::GraphicsPipelineSubset::VertexInput);
2435 }
2436 };
2437 struct GraphicsPipelineDescShadersKeyEqual
2438 {
2439 size_t operator()(const rx::vk::GraphicsPipelineDesc &first,
2440 const rx::vk::GraphicsPipelineDesc &second) const
2441 {
2442 return first.keyEqual(second, vk::GraphicsPipelineSubset::Shaders);
2443 }
2444 };
2445 struct GraphicsPipelineDescFragmentOutputKeyEqual
2446 {
2447 size_t operator()(const rx::vk::GraphicsPipelineDesc &first,
2448 const rx::vk::GraphicsPipelineDesc &second) const
2449 {
2450 return first.keyEqual(second, vk::GraphicsPipelineSubset::FragmentOutput);
2451 }
2452 };
2453
2454 // Derive the KeyEqual and GraphicsPipelineSubset enum from the Hash struct
2455 template <typename Hash>
2456 struct GraphicsPipelineCacheTypeHelper
2457 {
2458 using KeyEqual = GraphicsPipelineDescCompleteKeyEqual;
2459 static constexpr vk::GraphicsPipelineSubset kSubset = vk::GraphicsPipelineSubset::Complete;
2460 };
2461
2462 template <>
2463 struct GraphicsPipelineCacheTypeHelper<GraphicsPipelineDescVertexInputHash>
2464 {
2465 using KeyEqual = GraphicsPipelineDescVertexInputKeyEqual;
2466 static constexpr vk::GraphicsPipelineSubset kSubset = vk::GraphicsPipelineSubset::VertexInput;
2467 };
2468 template <>
2469 struct GraphicsPipelineCacheTypeHelper<GraphicsPipelineDescShadersHash>
2470 {
2471 using KeyEqual = GraphicsPipelineDescShadersKeyEqual;
2472 static constexpr vk::GraphicsPipelineSubset kSubset = vk::GraphicsPipelineSubset::Shaders;
2473 };
2474 template <>
2475 struct GraphicsPipelineCacheTypeHelper<GraphicsPipelineDescFragmentOutputHash>
2476 {
2477 using KeyEqual = GraphicsPipelineDescFragmentOutputKeyEqual;
2478 static constexpr vk::GraphicsPipelineSubset kSubset =
2479 vk::GraphicsPipelineSubset::FragmentOutput;
2480 };
2481
2482 // TODO(jmadill): Add cache trimming/eviction.
2483 template <typename Hash>
2484 class GraphicsPipelineCache final : public HasCacheStats<VulkanCacheType::GraphicsPipeline>
2485 {
2486 public:
2487 GraphicsPipelineCache() = default;
2488 ~GraphicsPipelineCache() override { ASSERT(mPayload.empty()); }
2489
2490 void destroy(vk::Context *context);
2491 void release(vk::Context *context);
2492
2493 void populate(const vk::GraphicsPipelineDesc &desc,
2494 vk::Pipeline &&pipeline,
2495 vk::PipelineHelper **pipelineHelperOut);
2496
2497 // Get a pipeline from the cache, if it exists
2498 ANGLE_INLINE bool getPipeline(const vk::GraphicsPipelineDesc &desc,
2499 const vk::GraphicsPipelineDesc **descPtrOut,
2500 vk::PipelineHelper **pipelineOut)
2501 {
2502 auto item = mPayload.find(desc);
2503 if (item == mPayload.end())
2504 {
2505 return false;
2506 }
2507
2508 *descPtrOut = &item->first;
2509 *pipelineOut = &item->second;
2510
2511 mCacheStats.hit();
2512
2513 return true;
2514 }
2515
2516 angle::Result createPipeline(vk::Context *context,
2517 vk::PipelineCacheAccess *pipelineCache,
2518 const vk::RenderPass &compatibleRenderPass,
2519 const vk::PipelineLayout &pipelineLayout,
2520 const vk::ShaderModuleMap &shaders,
2521 const vk::SpecializationConstants &specConsts,
2522 PipelineSource source,
2523 const vk::GraphicsPipelineDesc &desc,
2524 const vk::GraphicsPipelineDesc **descPtrOut,
2525 vk::PipelineHelper **pipelineOut);
2526
2527 angle::Result linkLibraries(vk::Context *context,
2528 vk::PipelineCacheAccess *pipelineCache,
2529 const vk::GraphicsPipelineDesc &desc,
2530 const vk::PipelineLayout &pipelineLayout,
2531 vk::PipelineHelper *vertexInputPipeline,
2532 vk::PipelineHelper *shadersPipeline,
2533 vk::PipelineHelper *fragmentOutputPipeline,
2534 const vk::GraphicsPipelineDesc **descPtrOut,
2535 vk::PipelineHelper **pipelineOut);
2536
2537 // Helper for VulkanPipelineCachePerf that resets the object without destroying any object.
2538 void reset() { mPayload.clear(); }
2539
2540 private:
2541 void addToCache(PipelineSource source,
2542 const vk::GraphicsPipelineDesc &desc,
2543 vk::Pipeline &&pipeline,
2544 vk::CacheLookUpFeedback feedback,
2545 const vk::GraphicsPipelineDesc **descPtrOut,
2546 vk::PipelineHelper **pipelineOut);
2547
2548 using KeyEqual = typename GraphicsPipelineCacheTypeHelper<Hash>::KeyEqual;
2549 std::unordered_map<vk::GraphicsPipelineDesc, vk::PipelineHelper, Hash, KeyEqual> mPayload;
2550 };
2551
2552 using CompleteGraphicsPipelineCache = GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>;
2553 using VertexInputGraphicsPipelineCache = GraphicsPipelineCache<GraphicsPipelineDescVertexInputHash>;
2554 using ShadersGraphicsPipelineCache = GraphicsPipelineCache<GraphicsPipelineDescShadersHash>;
2555 using FragmentOutputGraphicsPipelineCache =
2556 GraphicsPipelineCache<GraphicsPipelineDescFragmentOutputHash>;
2557
2558 class DescriptorSetLayoutCache final : angle::NonCopyable
2559 {
2560 public:
2561 DescriptorSetLayoutCache();
2562 ~DescriptorSetLayoutCache();
2563
2564 void destroy(vk::Renderer *renderer);
2565
2566 angle::Result getDescriptorSetLayout(
2567 vk::Context *context,
2568 const vk::DescriptorSetLayoutDesc &desc,
2569 vk::AtomicBindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut);
2570
2571 // Helpers for white box tests
2572 size_t getCacheHitCount() const { return mCacheStats.getHitCount(); }
2573 size_t getCacheMissCount() const { return mCacheStats.getMissCount(); }
2574
2575 private:
2576 mutable angle::SimpleMutex mMutex;
2577 std::unordered_map<vk::DescriptorSetLayoutDesc, vk::RefCountedDescriptorSetLayout> mPayload;
2578 CacheStats mCacheStats;
2579 };
2580
2581 class PipelineLayoutCache final : public HasCacheStats<VulkanCacheType::PipelineLayout>
2582 {
2583 public:
2584 PipelineLayoutCache();
2585 ~PipelineLayoutCache() override;
2586
2587 void destroy(vk::Renderer *renderer);
2588
2589 angle::Result getPipelineLayout(
2590 vk::Context *context,
2591 const vk::PipelineLayoutDesc &desc,
2592 const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts,
2593 vk::AtomicBindingPointer<vk::PipelineLayout> *pipelineLayoutOut);
2594
2595 private:
2596 mutable angle::SimpleMutex mMutex;
2597 std::unordered_map<vk::PipelineLayoutDesc, vk::RefCountedPipelineLayout> mPayload;
2598 };
2599
2600 class SamplerCache final : public HasCacheStats<VulkanCacheType::Sampler>
2601 {
2602 public:
2603 SamplerCache();
2604 ~SamplerCache() override;
2605
2606 void destroy(vk::Renderer *renderer);
2607
2608 angle::Result getSampler(ContextVk *contextVk,
2609 const vk::SamplerDesc &desc,
2610 vk::SamplerBinding *samplerOut);
2611
2612 private:
2613 std::unordered_map<vk::SamplerDesc, vk::RefCountedSampler> mPayload;
2614 };
2615
2616 // YuvConversion Cache
2617 class SamplerYcbcrConversionCache final
2618 : public HasCacheStats<VulkanCacheType::SamplerYcbcrConversion>
2619 {
2620 public:
2621 SamplerYcbcrConversionCache();
2622 ~SamplerYcbcrConversionCache() override;
2623
2624 void destroy(vk::Renderer *renderer);
2625
2626 angle::Result getSamplerYcbcrConversion(vk::Context *context,
2627 const vk::YcbcrConversionDesc &ycbcrConversionDesc,
2628 VkSamplerYcbcrConversion *vkSamplerYcbcrConversionOut);
2629
2630 private:
2631 using SamplerYcbcrConversionMap =
2632 std::unordered_map<vk::YcbcrConversionDesc, vk::SamplerYcbcrConversion>;
2633 SamplerYcbcrConversionMap mExternalFormatPayload;
2634 SamplerYcbcrConversionMap mVkFormatPayload;
2635 };
2636
2637 // Descriptor Set Cache
2638 class DescriptorSetCache final : angle::NonCopyable
2639 {
2640 public:
2641 DescriptorSetCache() = default;
2642 ~DescriptorSetCache() { ASSERT(mPayload.empty()); }
2643
2644 DescriptorSetCache(DescriptorSetCache &&other) : DescriptorSetCache()
2645 {
2646 *this = std::move(other);
2647 }
2648
2649 DescriptorSetCache &operator=(DescriptorSetCache &&other)
2650 {
2651 std::swap(mPayload, other.mPayload);
2652 return *this;
2653 }
2654
2655 void resetCache() { mPayload.clear(); }
2656
2657 ANGLE_INLINE bool getDescriptorSet(const vk::DescriptorSetDesc &desc,
2658 VkDescriptorSet *descriptorSetOut,
2659 vk::RefCountedDescriptorPoolHelper **poolOut)
2660 {
2661 auto iter = mPayload.find(desc);
2662 if (iter != mPayload.end())
2663 {
2664 *descriptorSetOut = iter->second->getDescriptorSet();
2665 *poolOut = iter->second->getPool();
2666 return true;
2667 }
2668 return false;
2669 }
2670
2671 ANGLE_INLINE void insertDescriptorSet(const vk::DescriptorSetDesc &desc,
2672 VkDescriptorSet descriptorSet,
2673 vk::RefCountedDescriptorPoolHelper *pool)
2674 {
2675 mPayload.emplace(desc, std::make_unique<dsCacheEntry>(descriptorSet, pool));
2676 }
2677
2678 ANGLE_INLINE void eraseDescriptorSet(const vk::DescriptorSetDesc &desc)
2679 {
2680 mPayload.erase(desc);
2681 }
2682
2683 ANGLE_INLINE size_t getTotalCacheSize() const { return mPayload.size(); }
2684
2685 size_t getTotalCacheKeySizeBytes() const
2686 {
2687 size_t totalSize = 0;
2688 for (const auto &iter : mPayload)
2689 {
2690 const vk::DescriptorSetDesc &desc = iter.first;
2691 totalSize += desc.getKeySizeBytes();
2692 }
2693 return totalSize;
2694 }
2695
2696 bool empty() const { return mPayload.empty(); }
2697
2698 private:
2699 class dsCacheEntry
2700 {
2701 public:
2702 dsCacheEntry(VkDescriptorSet descriptorSet, vk::RefCountedDescriptorPoolHelper *pool)
2703 : mDescriptorSet(descriptorSet), mPool(pool)
2704 {}
2705 VkDescriptorSet getDescriptorSet() const { return mDescriptorSet; }
2706 vk::RefCountedDescriptorPoolHelper *getPool() const { return mPool; }
2707
2708 private:
2709 VkDescriptorSet mDescriptorSet;
2710 // Weak pointer to the pool this descriptorSet allocated from. The RefCount is tracking if
2711 // this pool is bound as the current pool in any ProgramExecutableVk or not, so we should
2712 // not add refcount from the cache.
2713 vk::RefCountedDescriptorPoolHelper *mPool;
2714 };
2715 angle::HashMap<vk::DescriptorSetDesc, std::unique_ptr<dsCacheEntry>> mPayload;
2716 };
2717
2718 // There is 1 default uniform binding used per stage.
2719 constexpr uint32_t kReservedPerStageDefaultUniformBindingCount = 1;
2720
2721 class UpdateDescriptorSetsBuilder final : angle::NonCopyable
2722 {
2723 public:
2724 UpdateDescriptorSetsBuilder();
2725 ~UpdateDescriptorSetsBuilder();
2726
2727 VkDescriptorBufferInfo *allocDescriptorBufferInfos(size_t count);
2728 VkDescriptorImageInfo *allocDescriptorImageInfos(size_t count);
2729 VkWriteDescriptorSet *allocWriteDescriptorSets(size_t count);
2730 VkBufferView *allocBufferViews(size_t count);
2731
2732 VkDescriptorBufferInfo &allocDescriptorBufferInfo() { return *allocDescriptorBufferInfos(1); }
2733 VkDescriptorImageInfo &allocDescriptorImageInfo() { return *allocDescriptorImageInfos(1); }
2734 VkWriteDescriptorSet &allocWriteDescriptorSet() { return *allocWriteDescriptorSets(1); }
2735 VkBufferView &allocBufferView() { return *allocBufferViews(1); }
2736
2737 // Returns the number of written descriptor sets.
2738 uint32_t flushDescriptorSetUpdates(VkDevice device);
2739
2740 private:
2741 template <typename T, const T *VkWriteDescriptorSet::*pInfo>
2742 T *allocDescriptorInfos(std::vector<T> *descriptorVector, size_t count);
2743 template <typename T, const T *VkWriteDescriptorSet::*pInfo>
2744 void growDescriptorCapacity(std::vector<T> *descriptorVector, size_t newSize);
2745
2746 std::vector<VkDescriptorBufferInfo> mDescriptorBufferInfos;
2747 std::vector<VkDescriptorImageInfo> mDescriptorImageInfos;
2748 std::vector<VkWriteDescriptorSet> mWriteDescriptorSets;
2749 std::vector<VkBufferView> mBufferViews;
2750 };
2751
2752 } // namespace rx
2753
2754 #endif // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
2755