• 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 "libANGLE/renderer/vulkan/ResourceVk.h"
17 #include "libANGLE/renderer/vulkan/vk_utils.h"
18 
19 namespace rx
20 {
21 
22 // Some descriptor set and pipeline layout constants.
23 //
24 // The set/binding assignment is done as following:
25 //
26 // - Set 0 contains the ANGLE driver uniforms at binding 0.  Note that driver uniforms are updated
27 //   only under rare circumstances, such as viewport or depth range change.  However, there is only
28 //   one binding in this set.  This set is placed before Set 1 containing transform feedback
29 //   buffers, so that switching between xfb and non-xfb programs doesn't require rebinding this set.
30 //   Otherwise, as the layout of Set 1 changes (due to addition and removal of xfb buffers), and all
31 //   subsequent sets need to be rebound (due to Vulkan pipeline layout validation rules), we would
32 //   have needed to invalidateGraphicsDriverUniforms().
33 // - Set 1 contains uniform blocks created to encompass default uniforms.  1 binding is used per
34 //   pipeline stage.  Additionally, transform feedback buffers are bound from binding 2 and up.
35 // - Set 2 contains all textures (including texture buffers).
36 // - Set 3 contains all other shader resources, such as uniform and storage blocks, atomic counter
37 //   buffers, images and image buffers.
38 
39 enum class DescriptorSetIndex : uint32_t
40 {
41     Internal,        // ANGLE driver uniforms or internal shaders
42     UniformsAndXfb,  // Uniforms set index
43     Texture,         // Textures set index
44     ShaderResource,  // Other shader resources set index
45 
46     InvalidEnum,
47     EnumCount = InvalidEnum,
48 };
49 
50 namespace vk
51 {
52 class DynamicDescriptorPool;
53 class ImageHelper;
54 enum class ImageLayout;
55 
56 using RefCountedDescriptorSetLayout    = RefCounted<DescriptorSetLayout>;
57 using RefCountedPipelineLayout         = RefCounted<PipelineLayout>;
58 using RefCountedSamplerYcbcrConversion = RefCounted<SamplerYcbcrConversion>;
59 
60 // Helper macro that casts to a bitfield type then verifies no bits were dropped.
61 #define SetBitField(lhs, rhs)                                                         \
62     do                                                                                \
63     {                                                                                 \
64         auto ANGLE_LOCAL_VAR = rhs;                                                   \
65         lhs = static_cast<typename std::decay<decltype(lhs)>::type>(ANGLE_LOCAL_VAR); \
66         ASSERT(static_cast<decltype(ANGLE_LOCAL_VAR)>(lhs) == ANGLE_LOCAL_VAR);       \
67     } while (0)
68 
69 // Packed Vk resource descriptions.
70 // Most Vk types use many more bits than required to represent the underlying data.
71 // Since ANGLE wants to cache things like RenderPasses and Pipeline State Objects using
72 // hashing (and also needs to check equality) we can optimize these operations by
73 // using fewer bits. Hence the packed types.
74 //
75 // One implementation note: these types could potentially be improved by using even
76 // fewer bits. For example, boolean values could be represented by a single bit instead
77 // of a uint8_t. However at the current time there are concerns about the portability
78 // of bitfield operators, and complexity issues with using bit mask operations. This is
79 // something we will likely want to investigate as the Vulkan implementation progresses.
80 //
81 // Second implementation note: the struct packing is also a bit fragile, and some of the
82 // packing requirements depend on using alignas and field ordering to get the result of
83 // packing nicely into the desired space. This is something we could also potentially fix
84 // with a redesign to use bitfields or bit mask operations.
85 
86 // Enable struct padding warnings for the code below since it is used in caches.
87 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
88 
89 enum ResourceAccess
90 {
91     Unused,
92     ReadOnly,
93     Write,
94 };
95 
UpdateAccess(ResourceAccess * oldAccess,ResourceAccess newAccess)96 inline void UpdateAccess(ResourceAccess *oldAccess, ResourceAccess newAccess)
97 {
98     if (newAccess > *oldAccess)
99     {
100         *oldAccess = newAccess;
101     }
102 }
103 
104 enum class RenderPassLoadOp
105 {
106     Load     = VK_ATTACHMENT_LOAD_OP_LOAD,
107     Clear    = VK_ATTACHMENT_LOAD_OP_CLEAR,
108     DontCare = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
109     None,
110 };
111 enum class RenderPassStoreOp
112 {
113     Store    = VK_ATTACHMENT_STORE_OP_STORE,
114     DontCare = VK_ATTACHMENT_STORE_OP_DONT_CARE,
115     None,
116 };
117 
118 // There can be a maximum of IMPLEMENTATION_MAX_DRAW_BUFFERS color and resolve attachments, plus one
119 // depth/stencil attachment and one depth/stencil resolve attachment.
120 constexpr size_t kMaxFramebufferAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 + 2;
121 template <typename T>
122 using FramebufferAttachmentArray = std::array<T, kMaxFramebufferAttachments>;
123 template <typename T>
124 using FramebufferAttachmentsVector = angle::FixedVector<T, kMaxFramebufferAttachments>;
125 using FramebufferAttachmentMask    = angle::BitSet<kMaxFramebufferAttachments>;
126 
127 constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
128 template <typename T>
129 using FramebufferNonResolveAttachmentArray = std::array<T, kMaxFramebufferNonResolveAttachments>;
130 using FramebufferNonResolveAttachmentMask  = angle::BitSet16<kMaxFramebufferNonResolveAttachments>;
131 
132 class alignas(4) RenderPassDesc final
133 {
134   public:
135     RenderPassDesc();
136     ~RenderPassDesc();
137     RenderPassDesc(const RenderPassDesc &other);
138     RenderPassDesc &operator=(const RenderPassDesc &other);
139 
140     // Set format for an enabled GL color attachment.
141     void packColorAttachment(size_t colorIndexGL, angle::FormatID formatID);
142     // Mark a GL color attachment index as disabled.
143     void packColorAttachmentGap(size_t colorIndexGL);
144     // The caller must pack the depth/stencil attachment last, which is packed right after the color
145     // attachments (including gaps), i.e. with an index starting from |colorAttachmentRange()|.
146     void packDepthStencilAttachment(angle::FormatID angleFormatID);
147     void updateDepthStencilAccess(ResourceAccess access);
148     // Indicate that a color attachment should have a corresponding resolve attachment.
149     void packColorResolveAttachment(size_t colorIndexGL);
150     // Remove the resolve attachment.  Used when optimizing blit through resolve attachment to
151     // temporarily pack a resolve attachment and then remove it.
152     void removeColorResolveAttachment(size_t colorIndexGL);
153     // Indicate that a color attachment should take its data from the resolve attachment initially.
154     void packColorUnresolveAttachment(size_t colorIndexGL);
155     void removeColorUnresolveAttachment(size_t colorIndexGL);
156     // Indicate that a depth/stencil attachment should have a corresponding resolve attachment.
157     void packDepthStencilResolveAttachment();
158     // Indicate that a depth/stencil attachment should take its data from the resolve attachment
159     // initially.
160     void packDepthStencilUnresolveAttachment(bool unresolveDepth, bool unresolveStencil);
161     void removeDepthStencilUnresolveAttachment();
162 
163     void setWriteControlMode(gl::SrgbWriteControlMode mode);
164 
165     size_t hash() const;
166 
167     // Color attachments are in [0, colorAttachmentRange()), with possible gaps.
colorAttachmentRange()168     size_t colorAttachmentRange() const { return mColorAttachmentRange; }
depthStencilAttachmentIndex()169     size_t depthStencilAttachmentIndex() const { return colorAttachmentRange(); }
170 
171     bool isColorAttachmentEnabled(size_t colorIndexGL) const;
172     bool hasDepthStencilAttachment() const;
hasColorResolveAttachment(size_t colorIndexGL)173     bool hasColorResolveAttachment(size_t colorIndexGL) const
174     {
175         return mColorResolveAttachmentMask.test(colorIndexGL);
176     }
getColorUnresolveAttachmentMask()177     gl::DrawBufferMask getColorUnresolveAttachmentMask() const
178     {
179         return mColorUnresolveAttachmentMask;
180     }
hasColorUnresolveAttachment(size_t colorIndexGL)181     bool hasColorUnresolveAttachment(size_t colorIndexGL) const
182     {
183         return mColorUnresolveAttachmentMask.test(colorIndexGL);
184     }
hasDepthStencilResolveAttachment()185     bool hasDepthStencilResolveAttachment() const { return mResolveDepthStencil; }
hasDepthStencilUnresolveAttachment()186     bool hasDepthStencilUnresolveAttachment() const { return mUnresolveDepth || mUnresolveStencil; }
hasDepthUnresolveAttachment()187     bool hasDepthUnresolveAttachment() const { return mUnresolveDepth; }
hasStencilUnresolveAttachment()188     bool hasStencilUnresolveAttachment() const { return mUnresolveStencil; }
getSRGBWriteControlMode()189     gl::SrgbWriteControlMode getSRGBWriteControlMode() const
190     {
191         return static_cast<gl::SrgbWriteControlMode>(mSrgbWriteControl);
192     }
193 
194     // Get the number of attachments in the Vulkan render pass, i.e. after removing disabled
195     // color attachments.
196     size_t attachmentCount() const;
197 
setSamples(GLint samples)198     void setSamples(GLint samples) { mSamples = static_cast<uint8_t>(samples); }
samples()199     uint8_t samples() const { return mSamples; }
200 
setViewCount(GLsizei viewCount)201     void setViewCount(GLsizei viewCount) { mViewCount = static_cast<uint8_t>(viewCount); }
viewCount()202     uint8_t viewCount() const { return mViewCount; }
203 
setFramebufferFetchMode(bool hasFramebufferFetch)204     void setFramebufferFetchMode(bool hasFramebufferFetch)
205     {
206         mHasFramebufferFetch = hasFramebufferFetch;
207     }
getFramebufferFetchMode()208     bool getFramebufferFetchMode() const { return mHasFramebufferFetch; }
209 
updateRenderToTexture(bool isRenderToTexture)210     void updateRenderToTexture(bool isRenderToTexture) { mIsRenderToTexture = isRenderToTexture; }
isRenderToTexture()211     bool isRenderToTexture() const { return mIsRenderToTexture; }
212 
213     angle::FormatID operator[](size_t index) const
214     {
215         ASSERT(index < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1);
216         return static_cast<angle::FormatID>(mAttachmentFormats[index]);
217     }
218 
219   private:
220     uint8_t mSamples;
221     uint8_t mColorAttachmentRange;
222 
223     // Multivew
224     uint8_t mViewCount;
225 
226     // sRGB
227     uint8_t mSrgbWriteControl : 1;
228 
229     // Framebuffer fetch
230     uint8_t mHasFramebufferFetch : 1;
231 
232     // Multisampled render to texture
233     uint8_t mIsRenderToTexture : 1;
234     uint8_t mResolveDepthStencil : 1;
235     uint8_t mUnresolveDepth : 1;
236     uint8_t mUnresolveStencil : 1;
237 
238     // Available space for expansion.
239     uint8_t mPadding1 : 2;
240     uint8_t mPadding2;
241 
242     // Whether each color attachment has a corresponding resolve attachment.  Color resolve
243     // attachments can be used to optimize resolve through glBlitFramebuffer() as well as support
244     // GL_EXT_multisampled_render_to_texture and GL_EXT_multisampled_render_to_texture2.
245     gl::DrawBufferMask mColorResolveAttachmentMask;
246 
247     // Whether each color attachment with a corresponding resolve attachment should be initialized
248     // with said resolve attachment in an initial subpass.  This is an optimization to avoid
249     // loadOp=LOAD on the implicit multisampled image used with multisampled-render-to-texture
250     // render targets.  This operation is referred to as "unresolve".
251     //
252     // Unused when VK_EXT_multisampled_render_to_single_sampled is available.
253     gl::DrawBufferMask mColorUnresolveAttachmentMask;
254 
255     // Color attachment formats are stored with their GL attachment indices.  The depth/stencil
256     // attachment formats follow the last enabled color attachment.  When creating a render pass,
257     // the disabled attachments are removed and the resulting attachments are packed.
258     //
259     // The attachment indices provided as input to various functions in this file are thus GL
260     // attachment indices.  These indices are marked as such, e.g. colorIndexGL.  The render pass
261     // (and corresponding framebuffer object) lists the packed attachments, with the corresponding
262     // indices marked with Vk, e.g. colorIndexVk.  The subpass attachment references create the
263     // link between the two index spaces.  The subpass declares attachment references with GL
264     // indices (which corresponds to the location decoration of shader outputs).  The attachment
265     // references then contain the Vulkan indices or VK_ATTACHMENT_UNUSED.
266     //
267     // For example, if GL uses color attachments 0 and 3, then there are two render pass
268     // attachments (indexed 0 and 1) and 4 subpass attachments:
269     //
270     //  - Subpass attachment 0 -> Renderpass attachment 0
271     //  - Subpass attachment 1 -> VK_ATTACHMENT_UNUSED
272     //  - Subpass attachment 2 -> VK_ATTACHMENT_UNUSED
273     //  - Subpass attachment 3 -> Renderpass attachment 1
274     //
275     // The resolve attachments are packed after the non-resolve attachments.  They use the same
276     // formats, so they are not specified in this array.
277     FramebufferNonResolveAttachmentArray<uint8_t> mAttachmentFormats;
278 };
279 
280 bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
281 
282 constexpr size_t kRenderPassDescSize = sizeof(RenderPassDesc);
283 static_assert(kRenderPassDescSize == 16, "Size check failed");
284 
285 struct PackedAttachmentOpsDesc final
286 {
287     // RenderPassLoadOp is in range [0, 3], and RenderPassStoreOp is in range [0, 2].
288     uint16_t loadOp : 2;
289     uint16_t storeOp : 2;
290     uint16_t stencilLoadOp : 2;
291     uint16_t stencilStoreOp : 2;
292     // If a corresponding resolve attachment exists, storeOp may already be DONT_CARE, and it's
293     // unclear whether the attachment was invalidated or not.  This information is passed along here
294     // so that the resolve attachment's storeOp can be set to DONT_CARE if the attachment is
295     // invalidated, and if possible removed from the list of resolve attachments altogether.  Note
296     // that the latter may not be possible if the render pass has multiple subpasses due to Vulkan
297     // render pass compatibility rules.
298     uint16_t isInvalidated : 1;
299     uint16_t isStencilInvalidated : 1;
300     uint16_t padding1 : 6;
301 
302     // 4-bits to force pad the structure to exactly 2 bytes.  Note that we currently don't support
303     // any of the extension layouts, whose values start at 1'000'000'000.
304     uint16_t initialLayout : 4;
305     uint16_t finalLayout : 4;
306     uint16_t padding2 : 8;
307 };
308 
309 static_assert(sizeof(PackedAttachmentOpsDesc) == 4, "Size check failed");
310 
311 class PackedAttachmentIndex;
312 
313 class AttachmentOpsArray final
314 {
315   public:
316     AttachmentOpsArray();
317     ~AttachmentOpsArray();
318     AttachmentOpsArray(const AttachmentOpsArray &other);
319     AttachmentOpsArray &operator=(const AttachmentOpsArray &other);
320 
321     const PackedAttachmentOpsDesc &operator[](PackedAttachmentIndex index) const;
322     PackedAttachmentOpsDesc &operator[](PackedAttachmentIndex index);
323 
324     // Initialize an attachment op with all load and store operations.
325     void initWithLoadStore(PackedAttachmentIndex index,
326                            ImageLayout initialLayout,
327                            ImageLayout finalLayout);
328 
329     void setLayouts(PackedAttachmentIndex index,
330                     ImageLayout initialLayout,
331                     ImageLayout finalLayout);
332     void setOps(PackedAttachmentIndex index, RenderPassLoadOp loadOp, RenderPassStoreOp storeOp);
333     void setStencilOps(PackedAttachmentIndex index,
334                        RenderPassLoadOp loadOp,
335                        RenderPassStoreOp storeOp);
336 
337     void setClearOp(PackedAttachmentIndex index);
338     void setClearStencilOp(PackedAttachmentIndex index);
339 
340     size_t hash() const;
341 
342   private:
343     gl::AttachmentArray<PackedAttachmentOpsDesc> mOps;
344 };
345 
346 bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs);
347 
348 static_assert(sizeof(AttachmentOpsArray) == 40, "Size check failed");
349 
350 struct PackedAttribDesc final
351 {
352     uint8_t format;
353     uint8_t divisor;
354 
355     // Desktop drivers support
356     uint16_t offset : kAttributeOffsetMaxBits;
357 
358     uint16_t compressed : 1;
359 
360     // Although technically stride can be any value in ES 2.0, in practice supporting stride
361     // greater than MAX_USHORT should not be that helpful. Note that stride limits are
362     // introduced in ES 3.1.
363     uint16_t stride;
364 };
365 
366 constexpr size_t kPackedAttribDescSize = sizeof(PackedAttribDesc);
367 static_assert(kPackedAttribDescSize == 6, "Size mismatch");
368 
369 struct VertexInputAttributes final
370 {
371     PackedAttribDesc attribs[gl::MAX_VERTEX_ATTRIBS];
372 };
373 
374 constexpr size_t kVertexInputAttributesSize = sizeof(VertexInputAttributes);
375 static_assert(kVertexInputAttributesSize == 96, "Size mismatch");
376 
377 struct RasterizationStateBits final
378 {
379     // Note: Currently only 2 subpasses possible, so there are 5 bits in subpass that can be
380     // repurposed.
381     uint32_t subpass : 6;
382     uint32_t depthClampEnable : 1;
383     uint32_t rasterizationDiscardEnable : 1;
384     uint32_t polygonMode : 4;
385     uint32_t cullMode : 4;
386     uint32_t frontFace : 4;
387     uint32_t depthBiasEnable : 1;
388     uint32_t sampleShadingEnable : 1;
389     uint32_t alphaToCoverageEnable : 1;
390     uint32_t alphaToOneEnable : 1;
391     uint32_t rasterizationSamples : 8;
392 };
393 
394 constexpr size_t kRasterizationStateBitsSize = sizeof(RasterizationStateBits);
395 static_assert(kRasterizationStateBitsSize == 4, "Size check failed");
396 
397 struct PackedRasterizationAndMultisampleStateInfo final
398 {
399     RasterizationStateBits bits;
400     // Padded to ensure there's no gaps in this structure or those that use it.
401     float minSampleShading;
402     uint32_t sampleMask[gl::MAX_SAMPLE_MASK_WORDS];
403     // Note: depth bias clamp is only exposed in a 3.1 extension, but left here for completeness.
404     float depthBiasClamp;
405     float depthBiasConstantFactor;
406     float depthBiasSlopeFactor;
407     float lineWidth;
408 };
409 
410 constexpr size_t kPackedRasterizationAndMultisampleStateSize =
411     sizeof(PackedRasterizationAndMultisampleStateInfo);
412 static_assert(kPackedRasterizationAndMultisampleStateSize == 32, "Size check failed");
413 
414 struct StencilOps final
415 {
416     uint8_t fail : 4;
417     uint8_t pass : 4;
418     uint8_t depthFail : 4;
419     uint8_t compare : 4;
420 };
421 
422 constexpr size_t kStencilOpsSize = sizeof(StencilOps);
423 static_assert(kStencilOpsSize == 2, "Size check failed");
424 
425 struct PackedStencilOpState final
426 {
427     StencilOps ops;
428     uint8_t compareMask;
429     uint8_t writeMask;
430 };
431 
432 constexpr size_t kPackedStencilOpSize = sizeof(PackedStencilOpState);
433 static_assert(kPackedStencilOpSize == 4, "Size check failed");
434 
435 struct DepthStencilEnableFlags final
436 {
437     uint8_t depthTest : 2;  // these only need one bit each. the extra is used as padding.
438     uint8_t depthWrite : 2;
439     uint8_t depthBoundsTest : 2;
440     uint8_t stencilTest : 2;
441 };
442 
443 constexpr size_t kDepthStencilEnableFlagsSize = sizeof(DepthStencilEnableFlags);
444 static_assert(kDepthStencilEnableFlagsSize == 1, "Size check failed");
445 
446 // We are borrowing three bits here for surface rotation, even though it has nothing to do with
447 // depth stencil.
448 struct DepthCompareOpAndSurfaceRotation final
449 {
450     uint8_t depthCompareOp : 4;
451     uint8_t surfaceRotation : 3;
452     uint8_t padding : 1;
453 };
454 constexpr size_t kDepthCompareOpAndSurfaceRotationSize = sizeof(DepthCompareOpAndSurfaceRotation);
455 static_assert(kDepthCompareOpAndSurfaceRotationSize == 1, "Size check failed");
456 
457 struct PackedDepthStencilStateInfo final
458 {
459     DepthStencilEnableFlags enable;
460     uint8_t frontStencilReference;
461     uint8_t backStencilReference;
462     DepthCompareOpAndSurfaceRotation depthCompareOpAndSurfaceRotation;
463 
464     float minDepthBounds;
465     float maxDepthBounds;
466     PackedStencilOpState front;
467     PackedStencilOpState back;
468 };
469 
470 constexpr size_t kPackedDepthStencilStateSize = sizeof(PackedDepthStencilStateInfo);
471 static_assert(kPackedDepthStencilStateSize == 20, "Size check failed");
472 static_assert(static_cast<int>(SurfaceRotation::EnumCount) <= 8, "Size check failed");
473 
474 struct LogicOpState final
475 {
476     uint8_t opEnable : 1;
477     uint8_t op : 7;
478 };
479 
480 constexpr size_t kLogicOpStateSize = sizeof(LogicOpState);
481 static_assert(kLogicOpStateSize == 1, "Size check failed");
482 
483 struct PackedColorBlendAttachmentState final
484 {
485     uint16_t srcColorBlendFactor : 5;
486     uint16_t dstColorBlendFactor : 5;
487     uint16_t colorBlendOp : 6;
488     uint16_t srcAlphaBlendFactor : 5;
489     uint16_t dstAlphaBlendFactor : 5;
490     uint16_t alphaBlendOp : 6;
491 };
492 
493 constexpr size_t kPackedColorBlendAttachmentStateSize = sizeof(PackedColorBlendAttachmentState);
494 static_assert(kPackedColorBlendAttachmentStateSize == 4, "Size check failed");
495 
496 struct PrimitiveState final
497 {
498     uint16_t topology : 9;
499     uint16_t patchVertices : 6;
500     uint16_t restartEnable : 1;
501 };
502 
503 constexpr size_t kPrimitiveStateSize = sizeof(PrimitiveState);
504 static_assert(kPrimitiveStateSize == 2, "Size check failed");
505 
506 struct PackedInputAssemblyAndColorBlendStateInfo final
507 {
508     uint8_t colorWriteMaskBits[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS / 2];
509     PackedColorBlendAttachmentState attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS];
510     float blendConstants[4];
511     LogicOpState logic;
512     uint8_t blendEnableMask;
513     PrimitiveState primitive;
514 };
515 
516 struct PackedExtent final
517 {
518     uint16_t width;
519     uint16_t height;
520 };
521 
522 constexpr size_t kPackedInputAssemblyAndColorBlendStateSize =
523     sizeof(PackedInputAssemblyAndColorBlendStateInfo);
524 static_assert(kPackedInputAssemblyAndColorBlendStateSize == 56, "Size check failed");
525 
526 constexpr size_t kGraphicsPipelineDescSumOfSizes =
527     kVertexInputAttributesSize + kRenderPassDescSize + kPackedRasterizationAndMultisampleStateSize +
528     kPackedDepthStencilStateSize + kPackedInputAssemblyAndColorBlendStateSize +
529     sizeof(PackedExtent);
530 
531 // Number of dirty bits in the dirty bit set.
532 constexpr size_t kGraphicsPipelineDirtyBitBytes = 4;
533 constexpr static size_t kNumGraphicsPipelineDirtyBits =
534     kGraphicsPipelineDescSumOfSizes / kGraphicsPipelineDirtyBitBytes;
535 static_assert(kNumGraphicsPipelineDirtyBits <= 64, "Too many pipeline dirty bits");
536 
537 // Set of dirty bits. Each bit represents kGraphicsPipelineDirtyBitBytes in the desc.
538 using GraphicsPipelineTransitionBits = angle::BitSet<kNumGraphicsPipelineDirtyBits>;
539 
540 // State changes are applied through the update methods. Each update method can also have a
541 // sibling method that applies the update without marking a state transition. The non-transition
542 // update methods are used for internal shader pipelines. Not every non-transition update method
543 // is implemented yet as not every state is used in internal shaders.
544 class GraphicsPipelineDesc final
545 {
546   public:
547     // Use aligned allocation and free so we can use the alignas keyword.
548     void *operator new(std::size_t size);
549     void operator delete(void *ptr);
550 
551     GraphicsPipelineDesc();
552     ~GraphicsPipelineDesc();
553     GraphicsPipelineDesc(const GraphicsPipelineDesc &other);
554     GraphicsPipelineDesc &operator=(const GraphicsPipelineDesc &other);
555 
556     size_t hash() const;
557     bool operator==(const GraphicsPipelineDesc &other) const;
558 
559     void initDefaults(const ContextVk *contextVk);
560 
561     // For custom comparisons.
562     template <typename T>
getPtr()563     const T *getPtr() const
564     {
565         return reinterpret_cast<const T *>(this);
566     }
567 
568     angle::Result initializePipeline(ContextVk *contextVk,
569                                      const PipelineCache &pipelineCacheVk,
570                                      const RenderPass &compatibleRenderPass,
571                                      const PipelineLayout &pipelineLayout,
572                                      const gl::AttributesMask &activeAttribLocationsMask,
573                                      const gl::ComponentTypeMask &programAttribsTypeMask,
574                                      const gl::DrawBufferMask &missingOutputsMask,
575                                      const ShaderAndSerialMap &shaders,
576                                      const SpecializationConstants &specConsts,
577                                      Pipeline *pipelineOut) const;
578 
579     // Vertex input state. For ES 3.1 this should be separated into binding and attribute.
580     void updateVertexInput(GraphicsPipelineTransitionBits *transition,
581                            uint32_t attribIndex,
582                            GLuint stride,
583                            GLuint divisor,
584                            angle::FormatID format,
585                            bool compressed,
586                            GLuint relativeOffset);
587 
588     // Input assembly info
589     void updateTopology(GraphicsPipelineTransitionBits *transition, gl::PrimitiveMode drawMode);
590     void updatePrimitiveRestartEnabled(GraphicsPipelineTransitionBits *transition,
591                                        bool primitiveRestartEnabled);
592 
593     // Raster states
594     void setCullMode(VkCullModeFlagBits cullMode);
595     void updateCullMode(GraphicsPipelineTransitionBits *transition,
596                         const gl::RasterizerState &rasterState);
597     void updateFrontFace(GraphicsPipelineTransitionBits *transition,
598                          const gl::RasterizerState &rasterState,
599                          bool invertFrontFace);
600     void updateLineWidth(GraphicsPipelineTransitionBits *transition, float lineWidth);
601     void updateRasterizerDiscardEnabled(GraphicsPipelineTransitionBits *transition,
602                                         bool rasterizerDiscardEnabled);
603 
604     // Multisample states
605     uint32_t getRasterizationSamples() const;
606     void setRasterizationSamples(uint32_t rasterizationSamples);
607     void updateRasterizationSamples(GraphicsPipelineTransitionBits *transition,
608                                     uint32_t rasterizationSamples);
609     void updateAlphaToCoverageEnable(GraphicsPipelineTransitionBits *transition, bool enable);
610     void updateAlphaToOneEnable(GraphicsPipelineTransitionBits *transition, bool enable);
611     void updateSampleMask(GraphicsPipelineTransitionBits *transition,
612                           uint32_t maskNumber,
613                           uint32_t mask);
614 
615     void updateSampleShading(GraphicsPipelineTransitionBits *transition, bool enable, float value);
616 
617     // RenderPass description.
getRenderPassDesc()618     const RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; }
619 
620     void setRenderPassDesc(const RenderPassDesc &renderPassDesc);
621     void updateRenderPassDesc(GraphicsPipelineTransitionBits *transition,
622                               const RenderPassDesc &renderPassDesc);
623 
624     // Blend states
625     void updateBlendEnabled(GraphicsPipelineTransitionBits *transition,
626                             gl::DrawBufferMask blendEnabledMask);
627     void updateBlendColor(GraphicsPipelineTransitionBits *transition, const gl::ColorF &color);
628     void updateBlendFuncs(GraphicsPipelineTransitionBits *transition,
629                           const gl::BlendStateExt &blendStateExt,
630                           gl::DrawBufferMask attachmentMask);
631     void updateBlendEquations(GraphicsPipelineTransitionBits *transition,
632                               const gl::BlendStateExt &blendStateExt,
633                               gl::DrawBufferMask attachmentMask);
634     void resetBlendFuncsAndEquations(GraphicsPipelineTransitionBits *transition,
635                                      gl::DrawBufferMask previousAttachmentsMask,
636                                      gl::DrawBufferMask newAttachmentsMask);
637     void setColorWriteMasks(gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
638                             const gl::DrawBufferMask &alphaMask,
639                             const gl::DrawBufferMask &enabledDrawBuffers);
640     void setSingleColorWriteMask(uint32_t colorIndexGL, VkColorComponentFlags colorComponentFlags);
641     void updateColorWriteMasks(GraphicsPipelineTransitionBits *transition,
642                                gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
643                                const gl::DrawBufferMask &alphaMask,
644                                const gl::DrawBufferMask &enabledDrawBuffers);
645 
646     // Depth/stencil states.
647     void setDepthTestEnabled(bool enabled);
648     void setDepthWriteEnabled(bool enabled);
649     void setDepthFunc(VkCompareOp op);
650     void setDepthClampEnabled(bool enabled);
651     void setStencilTestEnabled(bool enabled);
652     void setStencilFrontFuncs(uint8_t reference, VkCompareOp compareOp, uint8_t compareMask);
653     void setStencilBackFuncs(uint8_t reference, VkCompareOp compareOp, uint8_t compareMask);
654     void setStencilFrontOps(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp);
655     void setStencilBackOps(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp);
656     void setStencilFrontWriteMask(uint8_t mask);
657     void setStencilBackWriteMask(uint8_t mask);
658     void updateDepthTestEnabled(GraphicsPipelineTransitionBits *transition,
659                                 const gl::DepthStencilState &depthStencilState,
660                                 const gl::Framebuffer *drawFramebuffer);
661     void updateDepthFunc(GraphicsPipelineTransitionBits *transition,
662                          const gl::DepthStencilState &depthStencilState);
663     void updateDepthWriteEnabled(GraphicsPipelineTransitionBits *transition,
664                                  const gl::DepthStencilState &depthStencilState,
665                                  const gl::Framebuffer *drawFramebuffer);
666     void updateStencilTestEnabled(GraphicsPipelineTransitionBits *transition,
667                                   const gl::DepthStencilState &depthStencilState,
668                                   const gl::Framebuffer *drawFramebuffer);
669     void updateStencilFrontFuncs(GraphicsPipelineTransitionBits *transition,
670                                  GLint ref,
671                                  const gl::DepthStencilState &depthStencilState);
672     void updateStencilBackFuncs(GraphicsPipelineTransitionBits *transition,
673                                 GLint ref,
674                                 const gl::DepthStencilState &depthStencilState);
675     void updateStencilFrontOps(GraphicsPipelineTransitionBits *transition,
676                                const gl::DepthStencilState &depthStencilState);
677     void updateStencilBackOps(GraphicsPipelineTransitionBits *transition,
678                               const gl::DepthStencilState &depthStencilState);
679     void updateStencilFrontWriteMask(GraphicsPipelineTransitionBits *transition,
680                                      const gl::DepthStencilState &depthStencilState,
681                                      const gl::Framebuffer *drawFramebuffer);
682     void updateStencilBackWriteMask(GraphicsPipelineTransitionBits *transition,
683                                     const gl::DepthStencilState &depthStencilState,
684                                     const gl::Framebuffer *drawFramebuffer);
685 
686     // Depth offset.
687     void updatePolygonOffsetFillEnabled(GraphicsPipelineTransitionBits *transition, bool enabled);
688     void updatePolygonOffset(GraphicsPipelineTransitionBits *transition,
689                              const gl::RasterizerState &rasterState);
690 
691     // Tessellation
692     void updatePatchVertices(GraphicsPipelineTransitionBits *transition, GLuint value);
693 
694     // Subpass
695     void resetSubpass(GraphicsPipelineTransitionBits *transition);
696     void nextSubpass(GraphicsPipelineTransitionBits *transition);
697     void setSubpass(uint32_t subpass);
698     uint32_t getSubpass() const;
699 
700     void updateSurfaceRotation(GraphicsPipelineTransitionBits *transition,
701                                const SurfaceRotation surfaceRotation);
getSurfaceRotation()702     SurfaceRotation getSurfaceRotation() const
703     {
704         return static_cast<SurfaceRotation>(
705             mDepthStencilStateInfo.depthCompareOpAndSurfaceRotation.surfaceRotation);
706     }
707 
708     void updateDrawableSize(GraphicsPipelineTransitionBits *transition,
709                             uint32_t width,
710                             uint32_t height);
getDrawableSize()711     const PackedExtent &getDrawableSize() const { return mDrawableSize; }
712 
713   private:
714     void updateSubpass(GraphicsPipelineTransitionBits *transition, uint32_t subpass);
715 
716     VertexInputAttributes mVertexInputAttribs;
717     RenderPassDesc mRenderPassDesc;
718     PackedRasterizationAndMultisampleStateInfo mRasterizationAndMultisampleStateInfo;
719     PackedDepthStencilStateInfo mDepthStencilStateInfo;
720     PackedInputAssemblyAndColorBlendStateInfo mInputAssemblyAndColorBlendStateInfo;
721     PackedExtent mDrawableSize;
722 };
723 
724 // Verify the packed pipeline description has no gaps in the packing.
725 // This is not guaranteed by the spec, but is validated by a compile-time check.
726 // No gaps or padding at the end ensures that hashing and memcmp checks will not run
727 // into uninitialized memory regions.
728 constexpr size_t kGraphicsPipelineDescSize = sizeof(GraphicsPipelineDesc);
729 static_assert(kGraphicsPipelineDescSize == kGraphicsPipelineDescSumOfSizes, "Size mismatch");
730 
731 constexpr uint32_t kMaxDescriptorSetLayoutBindings =
732     std::max(gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
733              gl::IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS);
734 
735 using DescriptorSetLayoutBindingVector =
736     angle::FixedVector<VkDescriptorSetLayoutBinding, kMaxDescriptorSetLayoutBindings>;
737 
738 // A packed description of a descriptor set layout. Use similarly to RenderPassDesc and
739 // GraphicsPipelineDesc. Currently we only need to differentiate layouts based on sampler and ubo
740 // usage. In the future we could generalize this.
741 class DescriptorSetLayoutDesc final
742 {
743   public:
744     DescriptorSetLayoutDesc();
745     ~DescriptorSetLayoutDesc();
746     DescriptorSetLayoutDesc(const DescriptorSetLayoutDesc &other);
747     DescriptorSetLayoutDesc &operator=(const DescriptorSetLayoutDesc &other);
748 
749     size_t hash() const;
750     bool operator==(const DescriptorSetLayoutDesc &other) const;
751 
752     void update(uint32_t bindingIndex,
753                 VkDescriptorType type,
754                 uint32_t count,
755                 VkShaderStageFlags stages,
756                 const Sampler *immutableSampler);
757 
758     void unpackBindings(DescriptorSetLayoutBindingVector *bindings,
759                         std::vector<VkSampler> *immutableSamplers) const;
760 
761   private:
762     // There is a small risk of an issue if the sampler cache is evicted but not the descriptor
763     // cache we would have an invalid handle here. Thus propose follow-up work:
764     // TODO: https://issuetracker.google.com/issues/159156775: Have immutable sampler use serial
765     struct PackedDescriptorSetBinding
766     {
767         uint8_t type;    // Stores a packed VkDescriptorType descriptorType.
768         uint8_t stages;  // Stores a packed VkShaderStageFlags.
769         uint16_t count;  // Stores a packed uint32_t descriptorCount.
770         uint32_t pad;
771         VkSampler immutableSampler;
772     };
773 
774     // 4x 32bit
775     static_assert(sizeof(PackedDescriptorSetBinding) == 16, "Unexpected size");
776 
777     // This is a compact representation of a descriptor set layout.
778     std::array<PackedDescriptorSetBinding, kMaxDescriptorSetLayoutBindings>
779         mPackedDescriptorSetLayout;
780 };
781 
782 // The following are for caching descriptor set layouts. Limited to max four descriptor set layouts.
783 // This can be extended in the future.
784 constexpr size_t kMaxDescriptorSetLayouts = 4;
785 
786 struct PackedPushConstantRange
787 {
788     uint32_t offset;
789     uint32_t size;
790 };
791 
792 template <typename T>
793 using DescriptorSetArray              = angle::PackedEnumMap<DescriptorSetIndex, T>;
794 using DescriptorSetLayoutPointerArray = DescriptorSetArray<BindingPointer<DescriptorSetLayout>>;
795 template <typename T>
796 using PushConstantRangeArray = gl::ShaderMap<T>;
797 
798 class PipelineLayoutDesc final
799 {
800   public:
801     PipelineLayoutDesc();
802     ~PipelineLayoutDesc();
803     PipelineLayoutDesc(const PipelineLayoutDesc &other);
804     PipelineLayoutDesc &operator=(const PipelineLayoutDesc &rhs);
805 
806     size_t hash() const;
807     bool operator==(const PipelineLayoutDesc &other) const;
808 
809     void updateDescriptorSetLayout(DescriptorSetIndex setIndex,
810                                    const DescriptorSetLayoutDesc &desc);
811     void updatePushConstantRange(gl::ShaderType shaderType, uint32_t offset, uint32_t size);
812 
813     const PushConstantRangeArray<PackedPushConstantRange> &getPushConstantRanges() const;
814 
815   private:
816     DescriptorSetArray<DescriptorSetLayoutDesc> mDescriptorSetLayouts;
817     PushConstantRangeArray<PackedPushConstantRange> mPushConstantRanges;
818 
819     // Verify the arrays are properly packed.
820     static_assert(sizeof(decltype(mDescriptorSetLayouts)) ==
821                       (sizeof(DescriptorSetLayoutDesc) * kMaxDescriptorSetLayouts),
822                   "Unexpected size");
823     static_assert(sizeof(decltype(mPushConstantRanges)) ==
824                       (sizeof(PackedPushConstantRange) * angle::EnumSize<gl::ShaderType>()),
825                   "Unexpected size");
826 };
827 
828 // Verify the structure is properly packed.
829 static_assert(sizeof(PipelineLayoutDesc) == (sizeof(DescriptorSetArray<DescriptorSetLayoutDesc>) +
830                                              sizeof(gl::ShaderMap<PackedPushConstantRange>)),
831               "Unexpected Size");
832 
833 struct YcbcrConversionDesc final
834 {
835     YcbcrConversionDesc();
836     ~YcbcrConversionDesc();
837     YcbcrConversionDesc(const YcbcrConversionDesc &other);
838     YcbcrConversionDesc &operator=(const YcbcrConversionDesc &other);
839 
840     size_t hash() const;
841     bool operator==(const YcbcrConversionDesc &other) const;
842 
validfinal843     bool valid() const { return mExternalOrVkFormat != 0; }
844     void reset();
845     void update(RendererVk *rendererVk,
846                 uint64_t externalFormat,
847                 VkSamplerYcbcrModelConversion conversionModel,
848                 VkSamplerYcbcrRange colorRange,
849                 VkChromaLocation xChromaOffset,
850                 VkChromaLocation yChromaOffset,
851                 VkFilter chromaFilter,
852                 angle::FormatID intendedFormatID);
853 
854     // If the sampler needs to convert the image content (e.g. from YUV to RGB) then
855     // mExternalOrVkFormat will be non-zero. The value is either the external format
856     // as returned by vkGetAndroidHardwareBufferPropertiesANDROID or a YUV VkFormat.
857     // For VkSamplerYcbcrConversion, mExternalOrVkFormat along with mIsExternalFormat,
858     // mConversionModel and mColorRange works as a Serial() used elsewhere in ANGLE.
859     uint64_t mExternalOrVkFormat;
860     // 1 bit to identify if external format is used
861     uint16_t mIsExternalFormat : 1;
862     // 3 bits to identify conversion model
863     uint16_t mConversionModel : 3;
864     // 1 bit to identify color component range
865     uint16_t mColorRange : 1;
866     // 1 bit to identify x chroma location
867     uint16_t mXChromaOffset : 1;
868     // 1 bit to identify y chroma location
869     uint16_t mYChromaOffset : 1;
870     // 1 bit to identify chroma filtering
871     uint16_t mChromaFilter : 1;
872     uint16_t mPadding : 8;
873     uint16_t mReserved0;
874     uint32_t mReserved1;
875 };
876 
877 static_assert(sizeof(YcbcrConversionDesc) == 16, "Unexpected YcbcrConversionDesc size");
878 
879 // Packed sampler description for the sampler cache.
880 class SamplerDesc final
881 {
882   public:
883     SamplerDesc();
884     SamplerDesc(ContextVk *contextVk,
885                 const gl::SamplerState &samplerState,
886                 bool stencilMode,
887                 const YcbcrConversionDesc *ycbcrConversionDesc,
888                 angle::FormatID intendedFormatID);
889     ~SamplerDesc();
890 
891     SamplerDesc(const SamplerDesc &other);
892     SamplerDesc &operator=(const SamplerDesc &rhs);
893 
894     void update(ContextVk *contextVk,
895                 const gl::SamplerState &samplerState,
896                 bool stencilMode,
897                 const YcbcrConversionDesc *ycbcrConversionDesc,
898                 angle::FormatID intendedFormatID);
899     void reset();
900     angle::Result init(ContextVk *contextVk, Sampler *sampler) const;
901 
902     size_t hash() const;
903     bool operator==(const SamplerDesc &other) const;
904 
905   private:
906     // 32*4 bits for floating point data.
907     // Note: anisotropy enabled is implicitly determined by maxAnisotropy and caps.
908     float mMipLodBias;
909     float mMaxAnisotropy;
910     float mMinLod;
911     float mMaxLod;
912 
913     // 16*8 bits to uniquely identify a YCbCr conversion sampler.
914     YcbcrConversionDesc mYcbcrConversionDesc;
915 
916     // 16 bits for modes + states.
917     // 1 bit per filter (only 2 possible values in GL: linear/nearest)
918     uint16_t mMagFilter : 1;
919     uint16_t mMinFilter : 1;
920     uint16_t mMipmapMode : 1;
921 
922     // 3 bits per address mode (5 possible values)
923     uint16_t mAddressModeU : 3;
924     uint16_t mAddressModeV : 3;
925     uint16_t mAddressModeW : 3;
926 
927     // 1 bit for compare enabled (2 possible values)
928     uint16_t mCompareEnabled : 1;
929 
930     // 3 bits for compare op. (8 possible values)
931     uint16_t mCompareOp : 3;
932 
933     // Values from angle::ColorGeneric::Type. Float is 0 and others are 1.
934     uint16_t mBorderColorType : 1;
935 
936     uint16_t mPadding : 15;
937 
938     // 16*8 bits for BorderColor
939     angle::ColorF mBorderColor;
940 
941     // 32 bits reserved for future use.
942     uint32_t mReserved;
943 };
944 
945 static_assert(sizeof(SamplerDesc) == 56, "Unexpected SamplerDesc size");
946 
947 // Disable warnings about struct padding.
948 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
949 
950 class PipelineHelper;
951 
952 struct GraphicsPipelineTransition
953 {
954     GraphicsPipelineTransition();
955     GraphicsPipelineTransition(const GraphicsPipelineTransition &other);
956     GraphicsPipelineTransition(GraphicsPipelineTransitionBits bits,
957                                const GraphicsPipelineDesc *desc,
958                                PipelineHelper *pipeline);
959 
960     GraphicsPipelineTransitionBits bits;
961     const GraphicsPipelineDesc *desc;
962     PipelineHelper *target;
963 };
964 
965 ANGLE_INLINE GraphicsPipelineTransition::GraphicsPipelineTransition() = default;
966 
967 ANGLE_INLINE GraphicsPipelineTransition::GraphicsPipelineTransition(
968     const GraphicsPipelineTransition &other) = default;
969 
GraphicsPipelineTransition(GraphicsPipelineTransitionBits bits,const GraphicsPipelineDesc * desc,PipelineHelper * pipeline)970 ANGLE_INLINE GraphicsPipelineTransition::GraphicsPipelineTransition(
971     GraphicsPipelineTransitionBits bits,
972     const GraphicsPipelineDesc *desc,
973     PipelineHelper *pipeline)
974     : bits(bits), desc(desc), target(pipeline)
975 {}
976 
GraphicsPipelineTransitionMatch(GraphicsPipelineTransitionBits bitsA,GraphicsPipelineTransitionBits bitsB,const GraphicsPipelineDesc & descA,const GraphicsPipelineDesc & descB)977 ANGLE_INLINE bool GraphicsPipelineTransitionMatch(GraphicsPipelineTransitionBits bitsA,
978                                                   GraphicsPipelineTransitionBits bitsB,
979                                                   const GraphicsPipelineDesc &descA,
980                                                   const GraphicsPipelineDesc &descB)
981 {
982     if (bitsA != bitsB)
983         return false;
984 
985     // We currently mask over 4 bytes of the pipeline description with each dirty bit.
986     // We could consider using 8 bytes and a mask of 32 bits. This would make some parts
987     // of the code faster. The for loop below would scan over twice as many bits per iteration.
988     // But there may be more collisions between the same dirty bit masks leading to different
989     // transitions. Thus there may be additional cost when applications use many transitions.
990     // We should revisit this in the future and investigate using different bit widths.
991     static_assert(sizeof(uint32_t) == kGraphicsPipelineDirtyBitBytes, "Size mismatch");
992 
993     const uint32_t *rawPtrA = descA.getPtr<uint32_t>();
994     const uint32_t *rawPtrB = descB.getPtr<uint32_t>();
995 
996     for (size_t dirtyBit : bitsA)
997     {
998         if (rawPtrA[dirtyBit] != rawPtrB[dirtyBit])
999             return false;
1000     }
1001 
1002     return true;
1003 }
1004 
1005 class PipelineHelper final : public Resource
1006 {
1007   public:
1008     PipelineHelper();
1009     ~PipelineHelper() override;
1010     inline explicit PipelineHelper(Pipeline &&pipeline);
1011 
1012     void destroy(VkDevice device);
1013 
valid()1014     bool valid() const { return mPipeline.valid(); }
getPipeline()1015     Pipeline &getPipeline() { return mPipeline; }
1016 
findTransition(GraphicsPipelineTransitionBits bits,const GraphicsPipelineDesc & desc,PipelineHelper ** pipelineOut)1017     ANGLE_INLINE bool findTransition(GraphicsPipelineTransitionBits bits,
1018                                      const GraphicsPipelineDesc &desc,
1019                                      PipelineHelper **pipelineOut) const
1020     {
1021         // Search could be improved using sorting or hashing.
1022         for (const GraphicsPipelineTransition &transition : mTransitions)
1023         {
1024             if (GraphicsPipelineTransitionMatch(transition.bits, bits, *transition.desc, desc))
1025             {
1026                 *pipelineOut = transition.target;
1027                 return true;
1028             }
1029         }
1030 
1031         return false;
1032     }
1033 
1034     void addTransition(GraphicsPipelineTransitionBits bits,
1035                        const GraphicsPipelineDesc *desc,
1036                        PipelineHelper *pipeline);
1037 
1038   private:
1039     std::vector<GraphicsPipelineTransition> mTransitions;
1040     Pipeline mPipeline;
1041 };
1042 
PipelineHelper(Pipeline && pipeline)1043 ANGLE_INLINE PipelineHelper::PipelineHelper(Pipeline &&pipeline) : mPipeline(std::move(pipeline)) {}
1044 
1045 struct ImageSubresourceRange
1046 {
1047     // GL max is 1000 (fits in 10 bits).
1048     uint32_t level : 10;
1049     // Max 31 levels (2 ** 5 - 1). Can store levelCount-1 if we need to save another bit.
1050     uint32_t levelCount : 5;
1051     // Implementation max is 2048 (11 bits).
1052     uint32_t layer : 12;
1053     // One of vk::LayerMode values.  If 0, it means all layers.  Otherwise it's the count of layers
1054     // which is usually 1, except for multiview in which case it can be up to
1055     // gl::IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS.
1056     uint32_t layerMode : 3;
1057     // Values from vk::SrgbDecodeMode.  Unused with draw views.
1058     uint32_t srgbDecodeMode : 1;
1059     // For read views: Values from gl::SrgbOverride, either Default or SRGB.
1060     // For draw views: Values from gl::SrgbWriteControlMode.
1061     uint32_t srgbMode : 1;
1062 
1063     static_assert(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS < (1 << 5),
1064                   "Not enough bits for level count");
1065     static_assert(gl::IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS <= (1 << 12),
1066                   "Not enough bits for layer index");
1067     static_assert(gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS <= (1 << 3),
1068                   "Not enough bits for layer count");
1069 };
1070 
1071 static_assert(sizeof(ImageSubresourceRange) == sizeof(uint32_t), "Size mismatch");
1072 
1073 inline bool operator==(const ImageSubresourceRange &a, const ImageSubresourceRange &b)
1074 {
1075     return a.level == b.level && a.levelCount == b.levelCount && a.layer == b.layer &&
1076            a.layerMode == b.layerMode && a.srgbDecodeMode == b.srgbDecodeMode &&
1077            a.srgbMode == b.srgbMode;
1078 }
1079 
1080 constexpr ImageSubresourceRange kInvalidImageSubresourceRange = {0, 0, 0, 0, 0, 0};
1081 
1082 struct ImageOrBufferViewSubresourceSerial
1083 {
1084     ImageOrBufferViewSerial viewSerial;
1085     ImageSubresourceRange subresource;
1086 };
1087 
1088 static_assert(sizeof(ImageOrBufferViewSubresourceSerial) == sizeof(uint64_t), "Size mismatch");
1089 
1090 constexpr ImageOrBufferViewSubresourceSerial kInvalidImageOrBufferViewSubresourceSerial = {
1091     kInvalidImageOrBufferViewSerial, kInvalidImageSubresourceRange};
1092 
1093 class TextureDescriptorDesc
1094 {
1095   public:
1096     TextureDescriptorDesc();
1097     ~TextureDescriptorDesc();
1098 
1099     TextureDescriptorDesc(const TextureDescriptorDesc &other);
1100     TextureDescriptorDesc &operator=(const TextureDescriptorDesc &other);
1101 
1102     void update(size_t index,
1103                 ImageOrBufferViewSubresourceSerial viewSerial,
1104                 SamplerSerial samplerSerial);
1105     size_t hash() const;
1106     void reset();
1107 
1108     bool operator==(const TextureDescriptorDesc &other) const;
1109 
1110     // Note: this is an exclusive index. If there is one index it will return "1".
getMaxIndex()1111     uint32_t getMaxIndex() const { return mMaxIndex; }
1112 
1113   private:
1114     uint32_t mMaxIndex;
1115 
1116     ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
1117     struct TexUnitSerials
1118     {
1119         ImageOrBufferViewSubresourceSerial view;
1120         SamplerSerial sampler;
1121     };
1122     gl::ActiveTextureArray<TexUnitSerials> mSerials;
1123     ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
1124 };
1125 
1126 class UniformsAndXfbDescriptorDesc
1127 {
1128   public:
1129     UniformsAndXfbDescriptorDesc();
1130     ~UniformsAndXfbDescriptorDesc();
1131 
1132     UniformsAndXfbDescriptorDesc(const UniformsAndXfbDescriptorDesc &other);
1133     UniformsAndXfbDescriptorDesc &operator=(const UniformsAndXfbDescriptorDesc &other);
1134 
getDefaultUniformBufferSerial()1135     BufferSerial getDefaultUniformBufferSerial() const
1136     {
1137         return mBufferSerials[kDefaultUniformBufferIndex];
1138     }
updateDefaultUniformBuffer(BufferSerial bufferSerial)1139     void updateDefaultUniformBuffer(BufferSerial bufferSerial)
1140     {
1141         mBufferSerials[kDefaultUniformBufferIndex] = bufferSerial;
1142         mBufferCount = std::max(mBufferCount, static_cast<uint32_t>(1));
1143     }
updateTransformFeedbackBuffer(size_t xfbIndex,BufferSerial bufferSerial,VkDeviceSize bufferOffset)1144     void updateTransformFeedbackBuffer(size_t xfbIndex,
1145                                        BufferSerial bufferSerial,
1146                                        VkDeviceSize bufferOffset)
1147     {
1148         uint32_t bufferIndex        = static_cast<uint32_t>(xfbIndex) + 1;
1149         mBufferSerials[bufferIndex] = bufferSerial;
1150 
1151         ASSERT(static_cast<uint64_t>(bufferOffset) <=
1152                static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()));
1153         mXfbBufferOffsets[xfbIndex] = static_cast<uint32_t>(bufferOffset);
1154 
1155         mBufferCount = std::max(mBufferCount, (bufferIndex + 1));
1156     }
1157     size_t hash() const;
1158     void reset();
1159 
1160     bool operator==(const UniformsAndXfbDescriptorDesc &other) const;
1161 
1162   private:
1163     uint32_t mBufferCount;
1164     // The array index 0 is used for default uniform buffer
1165     static constexpr size_t kDefaultUniformBufferIndex = 0;
1166     static constexpr size_t kDefaultUniformBufferCount = 1;
1167     static constexpr size_t kMaxBufferCount =
1168         kDefaultUniformBufferCount + gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
1169     std::array<BufferSerial, kMaxBufferCount> mBufferSerials;
1170     std::array<uint32_t, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS> mXfbBufferOffsets;
1171 };
1172 
1173 class ShaderBuffersDescriptorDesc
1174 {
1175   public:
1176     ShaderBuffersDescriptorDesc();
1177     ~ShaderBuffersDescriptorDesc();
1178 
1179     ShaderBuffersDescriptorDesc(const ShaderBuffersDescriptorDesc &other);
1180     ShaderBuffersDescriptorDesc &operator=(const ShaderBuffersDescriptorDesc &other);
1181 
1182     size_t hash() const;
1183     void reset();
1184 
1185     bool operator==(const ShaderBuffersDescriptorDesc &other) const;
1186 
appendBufferSerial(BufferSerial bufferSerial)1187     ANGLE_INLINE void appendBufferSerial(BufferSerial bufferSerial)
1188     {
1189         mPayload.push_back(bufferSerial.getValue());
1190     }
append32BitValue(uint32_t value)1191     ANGLE_INLINE void append32BitValue(uint32_t value) { mPayload.push_back(value); }
1192 
1193   private:
1194     // After a preliminary minimum size, use heap memory.
1195     static constexpr size_t kFastBufferWordLimit = 32;
1196     angle::FastVector<uint32_t, kFastBufferWordLimit> mPayload;
1197 };
1198 
1199 // In the FramebufferDesc object:
1200 //  - Depth/stencil serial is at index 0
1201 //  - Color serials are at indices [1, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]
1202 //  - Depth/stencil resolve attachment is at index gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+1
1203 //  - Resolve attachments are at indices [gl::IMPLEMENTATION_MAX_DRAW_BUFFERS+2,
1204 //                                        gl::IMPLEMENTATION_MAX_DRAW_BUFFERS*2+1]
1205 constexpr size_t kFramebufferDescDepthStencilIndex = 0;
1206 constexpr size_t kFramebufferDescColorIndexOffset  = kFramebufferDescDepthStencilIndex + 1;
1207 constexpr size_t kFramebufferDescDepthStencilResolveIndexOffset =
1208     kFramebufferDescColorIndexOffset + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
1209 constexpr size_t kFramebufferDescColorResolveIndexOffset =
1210     kFramebufferDescDepthStencilResolveIndexOffset + 1;
1211 
1212 // Enable struct padding warnings for the code below since it is used in caches.
1213 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
1214 
1215 class FramebufferDesc
1216 {
1217   public:
1218     FramebufferDesc();
1219     ~FramebufferDesc();
1220 
1221     FramebufferDesc(const FramebufferDesc &other);
1222     FramebufferDesc &operator=(const FramebufferDesc &other);
1223 
1224     void updateColor(uint32_t index, ImageOrBufferViewSubresourceSerial serial);
1225     void updateColorResolve(uint32_t index, ImageOrBufferViewSubresourceSerial serial);
1226     void updateUnresolveMask(FramebufferNonResolveAttachmentMask unresolveMask);
1227     void updateDepthStencil(ImageOrBufferViewSubresourceSerial serial);
1228     void updateDepthStencilResolve(ImageOrBufferViewSubresourceSerial serial);
setWriteControlMode(gl::SrgbWriteControlMode mode)1229     ANGLE_INLINE void setWriteControlMode(gl::SrgbWriteControlMode mode)
1230     {
1231         mSrgbWriteControlMode = static_cast<uint16_t>(mode);
1232     }
updateIsMultiview(bool isMultiview)1233     void updateIsMultiview(bool isMultiview) { mIsMultiview = isMultiview; }
1234     size_t hash() const;
1235 
1236     bool operator==(const FramebufferDesc &other) const;
1237 
1238     uint32_t attachmentCount() const;
1239 
getColorImageViewSerial(uint32_t index)1240     ImageOrBufferViewSubresourceSerial getColorImageViewSerial(uint32_t index)
1241     {
1242         ASSERT(kFramebufferDescColorIndexOffset + index < mSerials.size());
1243         return mSerials[kFramebufferDescColorIndexOffset + index];
1244     }
1245 
1246     FramebufferNonResolveAttachmentMask getUnresolveAttachmentMask() const;
getWriteControlMode()1247     ANGLE_INLINE gl::SrgbWriteControlMode getWriteControlMode() const
1248     {
1249         return (mSrgbWriteControlMode == 1) ? gl::SrgbWriteControlMode::Linear
1250                                             : gl::SrgbWriteControlMode::Default;
1251     }
1252 
1253     void updateLayerCount(uint32_t layerCount);
getLayerCount()1254     uint32_t getLayerCount() const { return mLayerCount; }
1255     void updateFramebufferFetchMode(bool hasFramebufferFetch);
1256 
isMultiview()1257     bool isMultiview() const { return mIsMultiview; }
1258 
1259     void updateRenderToTexture(bool isRenderToTexture);
1260 
1261   private:
1262     void reset();
1263     void update(uint32_t index, ImageOrBufferViewSubresourceSerial serial);
1264 
1265     // Note: this is an exclusive index. If there is one index it will be "1".
1266     // Maximum value is 18
1267     uint16_t mMaxIndex : 5;
1268     uint16_t mHasFramebufferFetch : 1;
1269     static_assert(gl::IMPLEMENTATION_MAX_FRAMEBUFFER_LAYERS < (1 << 9) - 1,
1270                   "Not enough bits for mLayerCount");
1271 
1272     uint16_t mLayerCount : 9;
1273 
1274     uint16_t mSrgbWriteControlMode : 1;
1275 
1276     // If the render pass contains an initial subpass to unresolve a number of attachments, the
1277     // subpass description is derived from the following mask, specifying which attachments need
1278     // to be unresolved.  Includes both color and depth/stencil attachments.
1279     uint16_t mUnresolveAttachmentMask : kMaxFramebufferNonResolveAttachments;
1280 
1281     // Whether this is a multisampled-render-to-single-sampled framebuffer.  Only used when using
1282     // VK_EXT_multisampled_render_to_single_sampled.  Only one bit is used and the rest is padding.
1283     uint16_t mIsRenderToTexture : 15 - kMaxFramebufferNonResolveAttachments;
1284 
1285     uint16_t mIsMultiview : 1;
1286 
1287     FramebufferAttachmentArray<ImageOrBufferViewSubresourceSerial> mSerials;
1288 };
1289 
1290 constexpr size_t kFramebufferDescSize = sizeof(FramebufferDesc);
1291 static_assert(kFramebufferDescSize == 148, "Size check failed");
1292 
1293 // Disable warnings about struct padding.
1294 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
1295 
1296 // The SamplerHelper allows a Sampler to be coupled with a serial.
1297 // Must be included before we declare SamplerCache.
1298 class SamplerHelper final : angle::NonCopyable
1299 {
1300   public:
1301     SamplerHelper(ContextVk *contextVk);
1302     ~SamplerHelper();
1303 
1304     explicit SamplerHelper(SamplerHelper &&samplerHelper);
1305     SamplerHelper &operator=(SamplerHelper &&rhs);
1306 
valid()1307     bool valid() const { return mSampler.valid(); }
get()1308     const Sampler &get() const { return mSampler; }
get()1309     Sampler &get() { return mSampler; }
getSamplerSerial()1310     SamplerSerial getSamplerSerial() const { return mSamplerSerial; }
1311 
1312   private:
1313     Sampler mSampler;
1314     SamplerSerial mSamplerSerial;
1315 };
1316 
1317 using RefCountedSampler = RefCounted<SamplerHelper>;
1318 using SamplerBinding    = BindingPointer<SamplerHelper>;
1319 
1320 class RenderPassHelper final : angle::NonCopyable
1321 {
1322   public:
1323     RenderPassHelper();
1324     ~RenderPassHelper();
1325 
1326     RenderPassHelper(RenderPassHelper &&other);
1327     RenderPassHelper &operator=(RenderPassHelper &&other);
1328 
1329     void destroy(VkDevice device);
1330 
1331     const RenderPass &getRenderPass() const;
1332     RenderPass &getRenderPass();
1333 
1334     const RenderPassPerfCounters &getPerfCounters() const;
1335     RenderPassPerfCounters &getPerfCounters();
1336 
1337   private:
1338     RenderPass mRenderPass;
1339     RenderPassPerfCounters mPerfCounters;
1340 };
1341 }  // namespace vk
1342 }  // namespace rx
1343 
1344 // Introduce std::hash for the above classes.
1345 namespace std
1346 {
1347 template <>
1348 struct hash<rx::vk::RenderPassDesc>
1349 {
1350     size_t operator()(const rx::vk::RenderPassDesc &key) const { return key.hash(); }
1351 };
1352 
1353 template <>
1354 struct hash<rx::vk::AttachmentOpsArray>
1355 {
1356     size_t operator()(const rx::vk::AttachmentOpsArray &key) const { return key.hash(); }
1357 };
1358 
1359 template <>
1360 struct hash<rx::vk::GraphicsPipelineDesc>
1361 {
1362     size_t operator()(const rx::vk::GraphicsPipelineDesc &key) const { return key.hash(); }
1363 };
1364 
1365 template <>
1366 struct hash<rx::vk::DescriptorSetLayoutDesc>
1367 {
1368     size_t operator()(const rx::vk::DescriptorSetLayoutDesc &key) const { return key.hash(); }
1369 };
1370 
1371 template <>
1372 struct hash<rx::vk::PipelineLayoutDesc>
1373 {
1374     size_t operator()(const rx::vk::PipelineLayoutDesc &key) const { return key.hash(); }
1375 };
1376 
1377 template <>
1378 struct hash<rx::vk::ImageSubresourceRange>
1379 {
1380     size_t operator()(const rx::vk::ImageSubresourceRange &key) const
1381     {
1382         return *reinterpret_cast<const uint32_t *>(&key);
1383     }
1384 };
1385 
1386 template <>
1387 struct hash<rx::vk::TextureDescriptorDesc>
1388 {
1389     size_t operator()(const rx::vk::TextureDescriptorDesc &key) const { return key.hash(); }
1390 };
1391 
1392 template <>
1393 struct hash<rx::vk::UniformsAndXfbDescriptorDesc>
1394 {
1395     size_t operator()(const rx::vk::UniformsAndXfbDescriptorDesc &key) const { return key.hash(); }
1396 };
1397 
1398 template <>
1399 struct hash<rx::vk::ShaderBuffersDescriptorDesc>
1400 {
1401     size_t operator()(const rx::vk::ShaderBuffersDescriptorDesc &key) const { return key.hash(); }
1402 };
1403 
1404 template <>
1405 struct hash<rx::vk::FramebufferDesc>
1406 {
1407     size_t operator()(const rx::vk::FramebufferDesc &key) const { return key.hash(); }
1408 };
1409 
1410 template <>
1411 struct hash<rx::vk::YcbcrConversionDesc>
1412 {
1413     size_t operator()(const rx::vk::YcbcrConversionDesc &key) const { return key.hash(); }
1414 };
1415 
1416 template <>
1417 struct hash<rx::vk::SamplerDesc>
1418 {
1419     size_t operator()(const rx::vk::SamplerDesc &key) const { return key.hash(); }
1420 };
1421 
1422 // See Resource Serial types defined in vk_utils.h.
1423 #define ANGLE_HASH_VK_SERIAL(Type)                                                          \
1424     template <>                                                                             \
1425     struct hash<rx::vk::Type##Serial>                                                       \
1426     {                                                                                       \
1427         size_t operator()(const rx::vk::Type##Serial &key) const { return key.getValue(); } \
1428     };
1429 
1430 ANGLE_VK_SERIAL_OP(ANGLE_HASH_VK_SERIAL)
1431 
1432 }  // namespace std
1433 
1434 namespace rx
1435 {
1436 // Cache types for various Vulkan objects
1437 enum class VulkanCacheType
1438 {
1439     CompatibleRenderPass,
1440     RenderPassWithOps,
1441     GraphicsPipeline,
1442     PipelineLayout,
1443     Sampler,
1444     SamplerYcbcrConversion,
1445     DescriptorSetLayout,
1446     DriverUniformsDescriptors,
1447     TextureDescriptors,
1448     UniformsAndXfbDescriptors,
1449     ShaderBuffersDescriptors,
1450     Framebuffer,
1451     EnumCount
1452 };
1453 
1454 // Base class for all caches. Provides cache hit and miss counters.
1455 class CacheStats final : angle::NonCopyable
1456 {
1457   public:
1458     CacheStats() { reset(); }
1459     ~CacheStats() {}
1460 
1461     ANGLE_INLINE void hit() { mHitCount++; }
1462     ANGLE_INLINE void miss() { mMissCount++; }
1463     ANGLE_INLINE void accumulate(const CacheStats &stats)
1464     {
1465         mHitCount += stats.mHitCount;
1466         mMissCount += stats.mMissCount;
1467     }
1468 
1469     uint64_t getHitCount() const { return mHitCount; }
1470     uint64_t getMissCount() const { return mMissCount; }
1471 
1472     ANGLE_INLINE double getHitRatio() const
1473     {
1474         if (mHitCount + mMissCount == 0)
1475         {
1476             return 0;
1477         }
1478         else
1479         {
1480             return static_cast<double>(mHitCount) / (mHitCount + mMissCount);
1481         }
1482     }
1483 
1484     void reset()
1485     {
1486         mHitCount  = 0;
1487         mMissCount = 0;
1488     }
1489 
1490   private:
1491     uint64_t mHitCount;
1492     uint64_t mMissCount;
1493 };
1494 
1495 template <VulkanCacheType CacheType>
1496 class HasCacheStats : angle::NonCopyable
1497 {
1498   public:
1499     template <typename Accumulator>
1500     void accumulateCacheStats(Accumulator *accum)
1501     {
1502         accum->accumulateCacheStats(CacheType, mCacheStats);
1503         mCacheStats.reset();
1504     }
1505 
1506   protected:
1507     HasCacheStats()          = default;
1508     virtual ~HasCacheStats() = default;
1509 
1510     CacheStats mCacheStats;
1511 };
1512 
1513 // TODO(jmadill): Add cache trimming/eviction.
1514 class RenderPassCache final : angle::NonCopyable
1515 {
1516   public:
1517     RenderPassCache();
1518     ~RenderPassCache();
1519 
1520     void destroy(RendererVk *rendererVk);
1521 
1522     ANGLE_INLINE angle::Result getCompatibleRenderPass(ContextVk *contextVk,
1523                                                        const vk::RenderPassDesc &desc,
1524                                                        vk::RenderPass **renderPassOut)
1525     {
1526         auto outerIt = mPayload.find(desc);
1527         if (outerIt != mPayload.end())
1528         {
1529             InnerCache &innerCache = outerIt->second;
1530             ASSERT(!innerCache.empty());
1531 
1532             // Find the first element and return it.
1533             *renderPassOut = &innerCache.begin()->second.getRenderPass();
1534             mCompatibleRenderPassCacheStats.hit();
1535             return angle::Result::Continue;
1536         }
1537 
1538         mCompatibleRenderPassCacheStats.miss();
1539         return addRenderPass(contextVk, desc, renderPassOut);
1540     }
1541 
1542     angle::Result getRenderPassWithOps(ContextVk *contextVk,
1543                                        const vk::RenderPassDesc &desc,
1544                                        const vk::AttachmentOpsArray &attachmentOps,
1545                                        vk::RenderPass **renderPassOut);
1546 
1547   private:
1548     angle::Result getRenderPassWithOpsImpl(ContextVk *contextVk,
1549                                            const vk::RenderPassDesc &desc,
1550                                            const vk::AttachmentOpsArray &attachmentOps,
1551                                            bool updatePerfCounters,
1552                                            vk::RenderPass **renderPassOut);
1553 
1554     angle::Result addRenderPass(ContextVk *contextVk,
1555                                 const vk::RenderPassDesc &desc,
1556                                 vk::RenderPass **renderPassOut);
1557 
1558     // Use a two-layer caching scheme. The top level matches the "compatible" RenderPass elements.
1559     // The second layer caches the attachment load/store ops and initial/final layout.
1560     // Switch to `std::unordered_map` to retain pointer stability.
1561     using InnerCache = std::unordered_map<vk::AttachmentOpsArray, vk::RenderPassHelper>;
1562     using OuterCache = std::unordered_map<vk::RenderPassDesc, InnerCache>;
1563 
1564     OuterCache mPayload;
1565     CacheStats mCompatibleRenderPassCacheStats;
1566     CacheStats mRenderPassWithOpsCacheStats;
1567 };
1568 
1569 // TODO(jmadill): Add cache trimming/eviction.
1570 class GraphicsPipelineCache final : public HasCacheStats<VulkanCacheType::GraphicsPipeline>
1571 {
1572   public:
1573     GraphicsPipelineCache();
1574     ~GraphicsPipelineCache() override;
1575 
1576     void destroy(RendererVk *rendererVk);
1577     void release(ContextVk *context);
1578 
1579     void populate(const vk::GraphicsPipelineDesc &desc, vk::Pipeline &&pipeline);
1580 
1581     ANGLE_INLINE angle::Result getPipeline(ContextVk *contextVk,
1582                                            const vk::PipelineCache &pipelineCacheVk,
1583                                            const vk::RenderPass &compatibleRenderPass,
1584                                            const vk::PipelineLayout &pipelineLayout,
1585                                            const gl::AttributesMask &activeAttribLocationsMask,
1586                                            const gl::ComponentTypeMask &programAttribsTypeMask,
1587                                            const gl::DrawBufferMask &missingOutputsMask,
1588                                            const vk::ShaderAndSerialMap &shaders,
1589                                            const vk::SpecializationConstants &specConsts,
1590                                            const vk::GraphicsPipelineDesc &desc,
1591                                            const vk::GraphicsPipelineDesc **descPtrOut,
1592                                            vk::PipelineHelper **pipelineOut)
1593     {
1594         auto item = mPayload.find(desc);
1595         if (item != mPayload.end())
1596         {
1597             *descPtrOut  = &item->first;
1598             *pipelineOut = &item->second;
1599             mCacheStats.hit();
1600             return angle::Result::Continue;
1601         }
1602 
1603         mCacheStats.miss();
1604         return insertPipeline(contextVk, pipelineCacheVk, compatibleRenderPass, pipelineLayout,
1605                               activeAttribLocationsMask, programAttribsTypeMask, missingOutputsMask,
1606                               shaders, specConsts, desc, descPtrOut, pipelineOut);
1607     }
1608 
1609   private:
1610     angle::Result insertPipeline(ContextVk *contextVk,
1611                                  const vk::PipelineCache &pipelineCacheVk,
1612                                  const vk::RenderPass &compatibleRenderPass,
1613                                  const vk::PipelineLayout &pipelineLayout,
1614                                  const gl::AttributesMask &activeAttribLocationsMask,
1615                                  const gl::ComponentTypeMask &programAttribsTypeMask,
1616                                  const gl::DrawBufferMask &missingOutputsMask,
1617                                  const vk::ShaderAndSerialMap &shaders,
1618                                  const vk::SpecializationConstants &specConsts,
1619                                  const vk::GraphicsPipelineDesc &desc,
1620                                  const vk::GraphicsPipelineDesc **descPtrOut,
1621                                  vk::PipelineHelper **pipelineOut);
1622 
1623     std::unordered_map<vk::GraphicsPipelineDesc, vk::PipelineHelper> mPayload;
1624 };
1625 
1626 class DescriptorSetLayoutCache final : angle::NonCopyable
1627 {
1628   public:
1629     DescriptorSetLayoutCache();
1630     ~DescriptorSetLayoutCache();
1631 
1632     void destroy(RendererVk *rendererVk);
1633 
1634     angle::Result getDescriptorSetLayout(
1635         vk::Context *context,
1636         const vk::DescriptorSetLayoutDesc &desc,
1637         vk::BindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut);
1638 
1639   private:
1640     std::unordered_map<vk::DescriptorSetLayoutDesc, vk::RefCountedDescriptorSetLayout> mPayload;
1641     CacheStats mCacheStats;
1642 };
1643 
1644 class PipelineLayoutCache final : public HasCacheStats<VulkanCacheType::PipelineLayout>
1645 {
1646   public:
1647     PipelineLayoutCache();
1648     ~PipelineLayoutCache() override;
1649 
1650     void destroy(RendererVk *rendererVk);
1651 
1652     angle::Result getPipelineLayout(vk::Context *context,
1653                                     const vk::PipelineLayoutDesc &desc,
1654                                     const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts,
1655                                     vk::BindingPointer<vk::PipelineLayout> *pipelineLayoutOut);
1656 
1657   private:
1658     std::unordered_map<vk::PipelineLayoutDesc, vk::RefCountedPipelineLayout> mPayload;
1659 };
1660 
1661 class SamplerCache final : public HasCacheStats<VulkanCacheType::Sampler>
1662 {
1663   public:
1664     SamplerCache();
1665     ~SamplerCache() override;
1666 
1667     void destroy(RendererVk *rendererVk);
1668 
1669     angle::Result getSampler(ContextVk *contextVk,
1670                              const vk::SamplerDesc &desc,
1671                              vk::SamplerBinding *samplerOut);
1672 
1673   private:
1674     std::unordered_map<vk::SamplerDesc, vk::RefCountedSampler> mPayload;
1675 };
1676 
1677 // YuvConversion Cache
1678 class SamplerYcbcrConversionCache final
1679     : public HasCacheStats<VulkanCacheType::SamplerYcbcrConversion>
1680 {
1681   public:
1682     SamplerYcbcrConversionCache();
1683     ~SamplerYcbcrConversionCache() override;
1684 
1685     void destroy(RendererVk *rendererVk);
1686 
1687     angle::Result getYuvConversion(
1688         vk::Context *context,
1689         const vk::YcbcrConversionDesc &ycbcrConversionDesc,
1690         const VkSamplerYcbcrConversionCreateInfo &yuvConversionCreateInfo,
1691         vk::BindingPointer<vk::SamplerYcbcrConversion> *yuvConversionOut);
1692     VkSamplerYcbcrConversion getSamplerYcbcrConversion(
1693         const vk::YcbcrConversionDesc &ycbcrConversionDesc) const;
1694 
1695   private:
1696     using SamplerYcbcrConversionMap =
1697         std::unordered_map<vk::YcbcrConversionDesc, vk::RefCountedSamplerYcbcrConversion>;
1698     SamplerYcbcrConversionMap mExternalFormatPayload;
1699     SamplerYcbcrConversionMap mVkFormatPayload;
1700 };
1701 
1702 // DescriptorSet Cache
1703 class DriverUniformsDescriptorSetCache final
1704     : public HasCacheStats<VulkanCacheType::DriverUniformsDescriptors>
1705 {
1706   public:
1707     DriverUniformsDescriptorSetCache() = default;
1708     ~DriverUniformsDescriptorSetCache() override { ASSERT(mPayload.empty()); }
1709 
1710     void destroy(RendererVk *rendererVk);
1711 
1712     ANGLE_INLINE bool get(uint32_t serial, VkDescriptorSet *descriptorSet)
1713     {
1714         if (mPayload.get(serial, descriptorSet))
1715         {
1716             mCacheStats.hit();
1717             return true;
1718         }
1719         mCacheStats.miss();
1720         return false;
1721     }
1722 
1723     ANGLE_INLINE void insert(uint32_t serial, VkDescriptorSet descriptorSet)
1724     {
1725         mPayload.insert(serial, descriptorSet);
1726     }
1727 
1728     ANGLE_INLINE void clear() { mPayload.clear(); }
1729 
1730   private:
1731     angle::FastIntegerMap<VkDescriptorSet> mPayload;
1732 };
1733 
1734 // Templated Descriptors Cache
1735 template <typename Key, VulkanCacheType CacheType>
1736 class DescriptorSetCache final : public HasCacheStats<CacheType>
1737 {
1738   public:
1739     DescriptorSetCache() = default;
1740     ~DescriptorSetCache() override { ASSERT(mPayload.empty()); }
1741 
1742     void destroy(RendererVk *rendererVk);
1743 
1744     ANGLE_INLINE bool get(const Key &desc, VkDescriptorSet *descriptorSet)
1745     {
1746         auto iter = mPayload.find(desc);
1747         if (iter != mPayload.end())
1748         {
1749             *descriptorSet = iter->second;
1750             this->mCacheStats.hit();
1751             return true;
1752         }
1753         this->mCacheStats.miss();
1754         return false;
1755     }
1756 
1757     ANGLE_INLINE void insert(const Key &desc, VkDescriptorSet descriptorSet)
1758     {
1759         mPayload.emplace(desc, descriptorSet);
1760     }
1761 
1762   private:
1763     angle::HashMap<Key, VkDescriptorSet> mPayload;
1764 };
1765 
1766 // Only 1 driver uniform binding is used.
1767 constexpr uint32_t kReservedDriverUniformBindingCount = 1;
1768 // There is 1 default uniform binding used per stage.  Currently, a maxium of three stages are
1769 // supported.
1770 constexpr uint32_t kReservedPerStageDefaultUniformBindingCount = 1;
1771 constexpr uint32_t kReservedDefaultUniformBindingCount         = 3;
1772 }  // namespace rx
1773 
1774 #endif  // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
1775