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