• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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