mirrored from https://chromium.googlesource.com/angle/angle
-
Notifications
You must be signed in to change notification settings - Fork 614
/
vk_cache_utils.h
2842 lines (2371 loc) · 111 KB
/
vk_cache_utils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// vk_cache_utils.h:
// Contains the classes for the Pipeline State Object cache as well as the RenderPass cache.
// Also contains the structures for the packed descriptions for the RenderPass and Pipeline.
//
#ifndef LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
#define LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
#include "common/Color.h"
#include "common/FixedVector.h"
#include "common/SimpleMutex.h"
#include "common/WorkerThread.h"
#include "libANGLE/Uniform.h"
#include "libANGLE/renderer/vulkan/ShaderInterfaceVariableInfoMap.h"
#include "libANGLE/renderer/vulkan/vk_resource.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace gl
{
class ProgramExecutable;
} // namespace gl
namespace rx
{
class ShaderInterfaceVariableInfoMap;
class UpdateDescriptorSetsBuilder;
// Some descriptor set and pipeline layout constants.
//
// The set/binding assignment is done as following:
//
// - Set 0 contains uniform blocks created to encompass default uniforms. 1 binding is used per
// pipeline stage. Additionally, transform feedback buffers are bound from binding 2 and up.
// For internal shaders, set 0 is used for all the needed resources.
// - Set 1 contains all textures (including texture buffers).
// - Set 2 contains all other shader resources, such as uniform and storage blocks, atomic counter
// buffers, images and image buffers.
// - Set 3 reserved for OpenCL
enum class DescriptorSetIndex : uint32_t
{
Internal = 0, // Internal shaders
UniformsAndXfb = Internal, // Uniforms set index
Texture = 1, // Textures set index
ShaderResource = 2, // Other shader resources set index
// CL specific naming for set indices
LiteralSampler = 0,
KernelArguments = 1,
ModuleConstants = 2,
Printf = 3,
InvalidEnum = 4,
EnumCount = InvalidEnum,
};
namespace vk
{
class BufferHelper;
class DynamicDescriptorPool;
class SamplerHelper;
enum class ImageLayout;
class PipelineCacheAccess;
class RenderPassCommandBufferHelper;
class PackedClearValuesArray;
class AttachmentOpsArray;
using RefCountedDescriptorSetLayout = AtomicRefCounted<DescriptorSetLayout>;
using RefCountedPipelineLayout = AtomicRefCounted<PipelineLayout>;
using RefCountedSamplerYcbcrConversion = RefCounted<SamplerYcbcrConversion>;
// Packed Vk resource descriptions.
// Most Vk types use many more bits than required to represent the underlying data.
// Since ANGLE wants to cache things like RenderPasses and Pipeline State Objects using
// hashing (and also needs to check equality) we can optimize these operations by
// using fewer bits. Hence the packed types.
//
// One implementation note: these types could potentially be improved by using even
// fewer bits. For example, boolean values could be represented by a single bit instead
// of a uint8_t. However at the current time there are concerns about the portability
// of bitfield operators, and complexity issues with using bit mask operations. This is
// something we will likely want to investigate as the Vulkan implementation progresses.
//
// Second implementation note: the struct packing is also a bit fragile, and some of the
// packing requirements depend on using alignas and field ordering to get the result of
// packing nicely into the desired space. This is something we could also potentially fix
// with a redesign to use bitfields or bit mask operations.
// Enable struct padding warnings for the code below since it is used in caches.
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
enum class ResourceAccess
{
Unused = 0x0,
ReadOnly = 0x1,
WriteOnly = 0x2,
ReadWrite = ReadOnly | WriteOnly,
};
inline void UpdateAccess(ResourceAccess *oldAccess, ResourceAccess newAccess)
{
*oldAccess = static_cast<ResourceAccess>(ToUnderlying(newAccess) | ToUnderlying(*oldAccess));
}
inline bool HasResourceWriteAccess(ResourceAccess access)
{
return (ToUnderlying(access) & ToUnderlying(ResourceAccess::WriteOnly)) != 0;
}
enum class RenderPassLoadOp
{
Load = VK_ATTACHMENT_LOAD_OP_LOAD,
Clear = VK_ATTACHMENT_LOAD_OP_CLEAR,
DontCare = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
None,
};
enum class RenderPassStoreOp
{
Store = VK_ATTACHMENT_STORE_OP_STORE,
DontCare = VK_ATTACHMENT_STORE_OP_DONT_CARE,
None,
};
enum class FramebufferFetchMode
{
None,
Color,
DepthStencil,
ColorAndDepthStencil,
};
FramebufferFetchMode GetProgramFramebufferFetchMode(const gl::ProgramExecutable *executable);
ANGLE_INLINE bool FramebufferFetchModeHasColor(FramebufferFetchMode framebufferFetchMode)
{
static_assert(ToUnderlying(FramebufferFetchMode::Color) == 0x1);
static_assert(ToUnderlying(FramebufferFetchMode::ColorAndDepthStencil) == 0x3);
return (ToUnderlying(framebufferFetchMode) & 0x1) != 0;
}
ANGLE_INLINE bool FramebufferFetchModeHasDepthStencil(FramebufferFetchMode framebufferFetchMode)
{
static_assert(ToUnderlying(FramebufferFetchMode::DepthStencil) == 0x2);
static_assert(ToUnderlying(FramebufferFetchMode::ColorAndDepthStencil) == 0x3);
return (ToUnderlying(framebufferFetchMode) & 0x2) != 0;
}
ANGLE_INLINE FramebufferFetchMode FramebufferFetchModeMerge(FramebufferFetchMode mode1,
FramebufferFetchMode mode2)
{
constexpr uint32_t kNone = ToUnderlying(FramebufferFetchMode::None);
constexpr uint32_t kColor = ToUnderlying(FramebufferFetchMode::Color);
constexpr uint32_t kDepthStencil = ToUnderlying(FramebufferFetchMode::DepthStencil);
constexpr uint32_t kColorAndDepthStencil =
ToUnderlying(FramebufferFetchMode::ColorAndDepthStencil);
static_assert(kNone == 0);
static_assert((kColor & kColorAndDepthStencil) == kColor);
static_assert((kDepthStencil & kColorAndDepthStencil) == kDepthStencil);
static_assert((kColor | kDepthStencil) == kColorAndDepthStencil);
return static_cast<FramebufferFetchMode>(ToUnderlying(mode1) | ToUnderlying(mode2));
}
// There can be a maximum of IMPLEMENTATION_MAX_DRAW_BUFFERS color and resolve attachments, plus -
// - one depth/stencil attachment
// - one depth/stencil resolve attachment
// - one fragment shading rate attachment
constexpr size_t kMaxFramebufferAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 + 3;
template <typename T>
using FramebufferAttachmentArray = std::array<T, kMaxFramebufferAttachments>;
template <typename T>
using FramebufferAttachmentsVector = angle::FixedVector<T, kMaxFramebufferAttachments>;
using FramebufferAttachmentMask = angle::BitSet<kMaxFramebufferAttachments>;
constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
template <typename T>
using FramebufferNonResolveAttachmentArray = std::array<T, kMaxFramebufferNonResolveAttachments>;
using FramebufferNonResolveAttachmentMask = angle::BitSet16<kMaxFramebufferNonResolveAttachments>;
class PackedAttachmentIndex;
class alignas(4) RenderPassDesc final
{
public:
RenderPassDesc();
~RenderPassDesc();
RenderPassDesc(const RenderPassDesc &other);
RenderPassDesc &operator=(const RenderPassDesc &other);
// Set format for an enabled GL color attachment.
void packColorAttachment(size_t colorIndexGL, angle::FormatID formatID);
// Mark a GL color attachment index as disabled.
void packColorAttachmentGap(size_t colorIndexGL);
// The caller must pack the depth/stencil attachment last, which is packed right after the color
// attachments (including gaps), i.e. with an index starting from |colorAttachmentRange()|.
void packDepthStencilAttachment(angle::FormatID angleFormatID);
void updateDepthStencilAccess(ResourceAccess access);
// Indicate that a color attachment should have a corresponding resolve attachment.
void packColorResolveAttachment(size_t colorIndexGL);
// Indicate that a YUV texture is attached to the resolve attachment.
void packYUVResolveAttachment(size_t colorIndexGL);
// Remove the resolve attachment. Used when optimizing blit through resolve attachment to
// temporarily pack a resolve attachment and then remove it.
void removeColorResolveAttachment(size_t colorIndexGL);
// Indicate that a color attachment should take its data from the resolve attachment initially.
void packColorUnresolveAttachment(size_t colorIndexGL);
void removeColorUnresolveAttachment(size_t colorIndexGL);
// Indicate that a depth/stencil attachment should have a corresponding resolve attachment.
void packDepthResolveAttachment();
void packStencilResolveAttachment();
// Indicate that a depth/stencil attachment should take its data from the resolve attachment
// initially.
void packDepthUnresolveAttachment();
void packStencilUnresolveAttachment();
void removeDepthStencilUnresolveAttachment();
PackedAttachmentIndex getPackedColorAttachmentIndex(size_t colorIndexGL);
void setWriteControlMode(gl::SrgbWriteControlMode mode);
size_t hash() const;
// Color attachments are in [0, colorAttachmentRange()), with possible gaps.
size_t colorAttachmentRange() const { return mColorAttachmentRange; }
size_t depthStencilAttachmentIndex() const { return colorAttachmentRange(); }
bool isColorAttachmentEnabled(size_t colorIndexGL) const;
bool hasYUVResolveAttachment() const { return mIsYUVResolve; }
bool hasDepthStencilAttachment() const;
gl::DrawBufferMask getColorResolveAttachmentMask() const { return mColorResolveAttachmentMask; }
bool hasColorResolveAttachment(size_t colorIndexGL) const
{
return mColorResolveAttachmentMask.test(colorIndexGL);
}
gl::DrawBufferMask getColorUnresolveAttachmentMask() const
{
return mColorUnresolveAttachmentMask;
}
bool hasColorUnresolveAttachment(size_t colorIndexGL) const
{
return mColorUnresolveAttachmentMask.test(colorIndexGL);
}
bool hasDepthStencilResolveAttachment() const { return mResolveDepth || mResolveStencil; }
bool hasDepthResolveAttachment() const { return mResolveDepth; }
bool hasStencilResolveAttachment() const { return mResolveStencil; }
bool hasDepthStencilUnresolveAttachment() const { return mUnresolveDepth || mUnresolveStencil; }
bool hasDepthUnresolveAttachment() const { return mUnresolveDepth; }
bool hasStencilUnresolveAttachment() const { return mUnresolveStencil; }
gl::SrgbWriteControlMode getSRGBWriteControlMode() const
{
return static_cast<gl::SrgbWriteControlMode>(mSrgbWriteControl);
}
bool isLegacyDitherEnabled() const { return mLegacyDitherEnabled; }
void setLegacyDither(bool enabled);
// Get the number of clearable attachments in the Vulkan render pass, i.e. after removing
// disabled color attachments.
size_t clearableAttachmentCount() const;
// Get the total number of attachments in the Vulkan render pass, i.e. after removing disabled
// color attachments.
size_t attachmentCount() const;
void setSamples(GLint samples) { mSamples = static_cast<uint8_t>(samples); }
uint8_t samples() const { return mSamples; }
void setViewCount(GLsizei viewCount) { mViewCount = static_cast<uint8_t>(viewCount); }
uint8_t viewCount() const { return mViewCount; }
void setFramebufferFetchMode(FramebufferFetchMode framebufferFetchMode)
{
SetBitField(mFramebufferFetchMode, framebufferFetchMode);
}
FramebufferFetchMode framebufferFetchMode() const
{
return static_cast<FramebufferFetchMode>(mFramebufferFetchMode);
}
bool hasColorFramebufferFetch() const
{
return FramebufferFetchModeHasColor(framebufferFetchMode());
}
bool hasDepthStencilFramebufferFetch() const
{
return FramebufferFetchModeHasDepthStencil(framebufferFetchMode());
}
void updateRenderToTexture(bool isRenderToTexture) { mIsRenderToTexture = isRenderToTexture; }
bool isRenderToTexture() const { return mIsRenderToTexture; }
void setFragmentShadingAttachment(bool value) { mHasFragmentShadingAttachment = value; }
bool hasFragmentShadingAttachment() const { return mHasFragmentShadingAttachment; }
angle::FormatID operator[](size_t index) const
{
ASSERT(index < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1);
return static_cast<angle::FormatID>(mAttachmentFormats[index]);
}
// Start a render pass with a render pass object.
void beginRenderPass(Context *context,
PrimaryCommandBuffer *primary,
const RenderPass &renderPass,
VkFramebuffer framebuffer,
const gl::Rectangle &renderArea,
VkSubpassContents subpassContents,
PackedClearValuesArray &clearValues,
const VkRenderPassAttachmentBeginInfo *attachmentBeginInfo) const;
// Start a render pass with dynamic rendering.
void beginRendering(Context *context,
PrimaryCommandBuffer *primary,
const gl::Rectangle &renderArea,
VkSubpassContents subpassContents,
const FramebufferAttachmentsVector<VkImageView> &attachmentViews,
const AttachmentOpsArray &ops,
PackedClearValuesArray &clearValues,
uint32_t layerCount) const;
void populateRenderingInheritanceInfo(
Renderer *renderer,
VkCommandBufferInheritanceRenderingInfo *infoOut,
gl::DrawBuffersArray<VkFormat> *colorFormatStorageOut) const;
// Calculate perf counters for a dynamic rendering render pass instance. For render pass
// objects, the perf counters are updated when creating the render pass, where access to
// ContextVk is available.
void updatePerfCounters(Context *context,
const FramebufferAttachmentsVector<VkImageView> &attachmentViews,
const AttachmentOpsArray &ops,
angle::VulkanPerfCounters *countersOut);
private:
uint8_t mSamples;
uint8_t mColorAttachmentRange;
// Multiview
uint8_t mViewCount;
// sRGB
uint8_t mSrgbWriteControl : 1;
// Framebuffer fetch, one of FramebufferFetchMode values
uint8_t mFramebufferFetchMode : 2;
// Depth/stencil resolve
uint8_t mResolveDepth : 1;
uint8_t mResolveStencil : 1;
// Multisampled render to texture
uint8_t mIsRenderToTexture : 1;
uint8_t mUnresolveDepth : 1;
uint8_t mUnresolveStencil : 1;
// Dithering state when using VK_EXT_legacy_dithering
uint8_t mLegacyDitherEnabled : 1;
// external_format_resolve
uint8_t mIsYUVResolve : 1;
// Foveated rendering
uint8_t mHasFragmentShadingAttachment : 1;
// Available space for expansion.
uint8_t mPadding2 : 5;
// Whether each color attachment has a corresponding resolve attachment. Color resolve
// attachments can be used to optimize resolve through glBlitFramebuffer() as well as support
// GL_EXT_multisampled_render_to_texture and GL_EXT_multisampled_render_to_texture2.
gl::DrawBufferMask mColorResolveAttachmentMask;
// Whether each color attachment with a corresponding resolve attachment should be initialized
// with said resolve attachment in an initial subpass. This is an optimization to avoid
// loadOp=LOAD on the implicit multisampled image used with multisampled-render-to-texture
// render targets. This operation is referred to as "unresolve".
//
// Unused when VK_EXT_multisampled_render_to_single_sampled is available.
gl::DrawBufferMask mColorUnresolveAttachmentMask;
// Color attachment formats are stored with their GL attachment indices. The depth/stencil
// attachment formats follow the last enabled color attachment. When creating a render pass,
// the disabled attachments are removed and the resulting attachments are packed.
//
// The attachment indices provided as input to various functions in this file are thus GL
// attachment indices. These indices are marked as such, e.g. colorIndexGL. The render pass
// (and corresponding framebuffer object) lists the packed attachments, with the corresponding
// indices marked with Vk, e.g. colorIndexVk. The subpass attachment references create the
// link between the two index spaces. The subpass declares attachment references with GL
// indices (which corresponds to the location decoration of shader outputs). The attachment
// references then contain the Vulkan indices or VK_ATTACHMENT_UNUSED.
//
// For example, if GL uses color attachments 0 and 3, then there are two render pass
// attachments (indexed 0 and 1) and 4 subpass attachments:
//
// - Subpass attachment 0 -> Renderpass attachment 0
// - Subpass attachment 1 -> VK_ATTACHMENT_UNUSED
// - Subpass attachment 2 -> VK_ATTACHMENT_UNUSED
// - Subpass attachment 3 -> Renderpass attachment 1
//
// The resolve attachments are packed after the non-resolve attachments. They use the same
// formats, so they are not specified in this array.
FramebufferNonResolveAttachmentArray<uint8_t> mAttachmentFormats;
};
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
constexpr size_t kRenderPassDescSize = sizeof(RenderPassDesc);
static_assert(kRenderPassDescSize == 16, "Size check failed");
enum class GraphicsPipelineSubset
{
Complete, // Including all subsets
VertexInput,
Shaders,
FragmentOutput,
};
enum class CacheLookUpFeedback
{
None,
Hit,
Miss,
LinkedDrawHit,
LinkedDrawMiss,
WarmUpHit,
WarmUpMiss,
UtilsHit,
UtilsMiss,
};
struct PackedAttachmentOpsDesc final
{
// RenderPassLoadOp is in range [0, 3], and RenderPassStoreOp is in range [0, 2].
uint16_t loadOp : 2;
uint16_t storeOp : 2;
uint16_t stencilLoadOp : 2;
uint16_t stencilStoreOp : 2;
// If a corresponding resolve attachment exists, storeOp may already be DONT_CARE, and it's
// unclear whether the attachment was invalidated or not. This information is passed along here
// so that the resolve attachment's storeOp can be set to DONT_CARE if the attachment is
// invalidated, and if possible removed from the list of resolve attachments altogether. Note
// that the latter may not be possible if the render pass has multiple subpasses due to Vulkan
// render pass compatibility rules (not an issue with dynamic rendering).
uint16_t isInvalidated : 1;
uint16_t isStencilInvalidated : 1;
uint16_t padding1 : 6;
// Layouts take values from ImageLayout, so they are small. Layouts that are possible here are
// placed at the beginning of that enum.
uint16_t initialLayout : 5;
uint16_t finalLayout : 5;
uint16_t finalResolveLayout : 5;
uint16_t padding2 : 1;
};
static_assert(sizeof(PackedAttachmentOpsDesc) == 4, "Size check failed");
class AttachmentOpsArray final
{
public:
AttachmentOpsArray();
~AttachmentOpsArray();
AttachmentOpsArray(const AttachmentOpsArray &other);
AttachmentOpsArray &operator=(const AttachmentOpsArray &other);
const PackedAttachmentOpsDesc &operator[](PackedAttachmentIndex index) const;
PackedAttachmentOpsDesc &operator[](PackedAttachmentIndex index);
// Initialize an attachment op with all load and store operations.
void initWithLoadStore(PackedAttachmentIndex index,
ImageLayout initialLayout,
ImageLayout finalLayout);
void setLayouts(PackedAttachmentIndex index,
ImageLayout initialLayout,
ImageLayout finalLayout);
void setOps(PackedAttachmentIndex index, RenderPassLoadOp loadOp, RenderPassStoreOp storeOp);
void setStencilOps(PackedAttachmentIndex index,
RenderPassLoadOp loadOp,
RenderPassStoreOp storeOp);
void setClearOp(PackedAttachmentIndex index);
void setClearStencilOp(PackedAttachmentIndex index);
size_t hash() const;
private:
gl::AttachmentArray<PackedAttachmentOpsDesc> mOps;
};
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs);
static_assert(sizeof(AttachmentOpsArray) == 40, "Size check failed");
struct PackedAttribDesc final
{
uint8_t format;
uint8_t divisor;
uint16_t offset : kAttributeOffsetMaxBits;
uint16_t compressed : 1;
};
constexpr size_t kPackedAttribDescSize = sizeof(PackedAttribDesc);
static_assert(kPackedAttribDescSize == 4, "Size mismatch");
struct PackedVertexInputAttributes final
{
PackedAttribDesc attribs[gl::MAX_VERTEX_ATTRIBS];
// Component type of the corresponding input in the program. Used to adjust the format if
// necessary. Takes values from gl::ComponentType.
uint32_t shaderAttribComponentType;
// Although technically stride can be any value in ES 2.0, in practice supporting stride
// greater than MAX_USHORT should not be that helpful. Note that stride limits are
// introduced in ES 3.1.
// Dynamic in VK_EXT_extended_dynamic_state
uint16_t strides[gl::MAX_VERTEX_ATTRIBS];
};
constexpr size_t kPackedVertexInputAttributesSize = sizeof(PackedVertexInputAttributes);
static_assert(kPackedVertexInputAttributesSize == 100, "Size mismatch");
struct PackedInputAssemblyState final
{
struct
{
uint32_t topology : 4;
// Dynamic in VK_EXT_extended_dynamic_state2
uint32_t primitiveRestartEnable : 1; // ds2
// Whether dynamic state for vertex stride from VK_EXT_extended_dynamic_state can be used
// for. Used by GraphicsPipelineDesc::hash() to exclude |vertexStrides| from the hash
uint32_t useVertexInputBindingStrideDynamicState : 1;
// Whether dynamic state for vertex input state from VK_EXT_vertex_input_dynamic_state can
// be used by GraphicsPipelineDesc::hash() to exclude |PackedVertexInputAttributes| from the
// hash
uint32_t useVertexInputDynamicState : 1;
// Whether the pipeline is robust (vertex input copy)
uint32_t isRobustContext : 1;
// Whether the pipeline needs access to protected content (vertex input copy)
uint32_t isProtectedContext : 1;
// Which attributes are actually active in the program and should affect the pipeline.
uint32_t programActiveAttributeLocations : gl::MAX_VERTEX_ATTRIBS;
uint32_t padding : 23 - gl::MAX_VERTEX_ATTRIBS;
} bits;
};
constexpr size_t kPackedInputAssemblyStateSize = sizeof(PackedInputAssemblyState);
static_assert(kPackedInputAssemblyStateSize == 4, "Size mismatch");
struct PackedStencilOpState final
{
uint8_t fail : 4;
uint8_t pass : 4;
uint8_t depthFail : 4;
uint8_t compare : 4;
};
constexpr size_t kPackedStencilOpSize = sizeof(PackedStencilOpState);
static_assert(kPackedStencilOpSize == 2, "Size check failed");
struct PackedPreRasterizationAndFragmentStates final
{
struct
{
// Affecting VkPipelineViewportStateCreateInfo
uint32_t viewportNegativeOneToOne : 1;
// Affecting VkPipelineRasterizationStateCreateInfo
uint32_t depthClampEnable : 1;
uint32_t polygonMode : 2;
// Dynamic in VK_EXT_extended_dynamic_state
uint32_t cullMode : 4;
uint32_t frontFace : 4;
// Dynamic in VK_EXT_extended_dynamic_state2
uint32_t rasterizerDiscardEnable : 1;
uint32_t depthBiasEnable : 1;
// Affecting VkPipelineTessellationStateCreateInfo
uint32_t patchVertices : 6;
// Affecting VkPipelineDepthStencilStateCreateInfo
uint32_t depthBoundsTest : 1;
// Dynamic in VK_EXT_extended_dynamic_state
uint32_t depthTest : 1;
uint32_t depthWrite : 1;
uint32_t stencilTest : 1;
uint32_t nonZeroStencilWriteMaskWorkaround : 1;
// Dynamic in VK_EXT_extended_dynamic_state2
uint32_t depthCompareOp : 4;
// Affecting specialization constants
uint32_t surfaceRotation : 1;
// Whether the pipeline is robust (shader stages copy)
uint32_t isRobustContext : 1;
// Whether the pipeline needs access to protected content (shader stages copy)
uint32_t isProtectedContext : 1;
} bits;
// Affecting specialization constants
static_assert(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS <= 8,
"2 bits per draw buffer is needed for dither emulation");
uint16_t emulatedDitherControl;
uint16_t padding;
// Affecting VkPipelineDepthStencilStateCreateInfo
// Dynamic in VK_EXT_extended_dynamic_state
PackedStencilOpState front;
PackedStencilOpState back;
};
constexpr size_t kPackedPreRasterizationAndFragmentStatesSize =
sizeof(PackedPreRasterizationAndFragmentStates);
static_assert(kPackedPreRasterizationAndFragmentStatesSize == 12, "Size check failed");
struct PackedMultisampleAndSubpassState final
{
struct
{
// Affecting VkPipelineMultisampleStateCreateInfo
// Note: Only up to 16xMSAA is supported in the Vulkan backend.
uint16_t sampleMask;
// Stored as minus one so sample count 16 can fit in 4 bits.
uint16_t rasterizationSamplesMinusOne : 4;
uint16_t sampleShadingEnable : 1;
uint16_t alphaToCoverageEnable : 1;
uint16_t alphaToOneEnable : 1;
// The subpass index affects both the shader stages and the fragment output similarly to
// multisampled state, so they are grouped together.
// Note: Currently only 2 subpasses possible.
uint16_t subpass : 1;
// 8-bit normalized instead of float to align the struct.
uint16_t minSampleShading : 8;
} bits;
};
constexpr size_t kPackedMultisampleAndSubpassStateSize = sizeof(PackedMultisampleAndSubpassState);
static_assert(kPackedMultisampleAndSubpassStateSize == 4, "Size check failed");
struct PackedColorBlendAttachmentState final
{
uint16_t srcColorBlendFactor : 5;
uint16_t dstColorBlendFactor : 5;
uint16_t colorBlendOp : 6;
uint16_t srcAlphaBlendFactor : 5;
uint16_t dstAlphaBlendFactor : 5;
uint16_t alphaBlendOp : 6;
};
constexpr size_t kPackedColorBlendAttachmentStateSize = sizeof(PackedColorBlendAttachmentState);
static_assert(kPackedColorBlendAttachmentStateSize == 4, "Size check failed");
struct PackedColorBlendState final
{
uint8_t colorWriteMaskBits[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS / 2];
PackedColorBlendAttachmentState attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS];
};
constexpr size_t kPackedColorBlendStateSize = sizeof(PackedColorBlendState);
static_assert(kPackedColorBlendStateSize == 36, "Size check failed");
struct PackedBlendMaskAndLogicOpState final
{
struct
{
uint32_t blendEnableMask : 8;
uint32_t logicOpEnable : 1;
// Dynamic in VK_EXT_extended_dynamic_state2
uint32_t logicOp : 4;
// Whether the pipeline needs access to protected content (fragment output copy)
uint32_t isProtectedContext : 1;
// Output that is present in the framebuffer but is never written to in the shader. Used by
// GL_ANGLE_robust_fragment_shader_output which defines the behavior in this case (which is
// to mask these outputs)
uint32_t missingOutputsMask : gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
uint32_t padding : 18 - gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
} bits;
};
constexpr size_t kPackedBlendMaskAndLogicOpStateSize = sizeof(PackedBlendMaskAndLogicOpState);
static_assert(kPackedBlendMaskAndLogicOpStateSize == 4, "Size check failed");
// The vertex input subset of the pipeline.
struct PipelineVertexInputState final
{
PackedInputAssemblyState inputAssembly;
PackedVertexInputAttributes vertex;
};
// The pre-rasterization and fragment shader subsets of the pipeline. This is excluding
// multisampled and render pass states which are shared with fragment output.
struct PipelineShadersState final
{
PackedPreRasterizationAndFragmentStates shaders;
};
// Multisampled and render pass states.
struct PipelineSharedNonVertexInputState final
{
PackedMultisampleAndSubpassState multisample;
RenderPassDesc renderPass;
};
// The fragment output subset of the pipeline. This is excluding multisampled and render pass
// states which are shared with the shader subsets.
struct PipelineFragmentOutputState final
{
PackedColorBlendState blend;
PackedBlendMaskAndLogicOpState blendMaskAndLogic;
};
constexpr size_t kGraphicsPipelineVertexInputStateSize =
kPackedVertexInputAttributesSize + kPackedInputAssemblyStateSize;
constexpr size_t kGraphicsPipelineShadersStateSize = kPackedPreRasterizationAndFragmentStatesSize;
constexpr size_t kGraphicsPipelineSharedNonVertexInputStateSize =
kPackedMultisampleAndSubpassStateSize + kRenderPassDescSize;
constexpr size_t kGraphicsPipelineFragmentOutputStateSize =
kPackedColorBlendStateSize + kPackedBlendMaskAndLogicOpStateSize;
constexpr size_t kGraphicsPipelineDescSumOfSizes =
kGraphicsPipelineVertexInputStateSize + kGraphicsPipelineShadersStateSize +
kGraphicsPipelineSharedNonVertexInputStateSize + kGraphicsPipelineFragmentOutputStateSize;
// Number of dirty bits in the dirty bit set.
constexpr size_t kGraphicsPipelineDirtyBitBytes = 4;
constexpr static size_t kNumGraphicsPipelineDirtyBits =
kGraphicsPipelineDescSumOfSizes / kGraphicsPipelineDirtyBitBytes;
static_assert(kNumGraphicsPipelineDirtyBits <= 64, "Too many pipeline dirty bits");
// Set of dirty bits. Each bit represents kGraphicsPipelineDirtyBitBytes in the desc.
using GraphicsPipelineTransitionBits = angle::BitSet<kNumGraphicsPipelineDirtyBits>;
GraphicsPipelineTransitionBits GetGraphicsPipelineTransitionBitsMask(GraphicsPipelineSubset subset);
// Disable padding warnings for a few helper structs that aggregate Vulkan state objects. These are
// not used as hash keys, they just simplify passing them around to functions.
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
struct GraphicsPipelineVertexInputVulkanStructs
{
VkPipelineVertexInputStateCreateInfo vertexInputState = {};
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {};
VkPipelineVertexInputDivisorStateCreateInfoEXT divisorState = {};
// Support storage
gl::AttribArray<VkVertexInputBindingDescription> bindingDescs;
gl::AttribArray<VkVertexInputAttributeDescription> attributeDescs;
gl::AttribArray<VkVertexInputBindingDivisorDescriptionEXT> divisorDesc;
};
struct GraphicsPipelineShadersVulkanStructs
{
VkPipelineViewportStateCreateInfo viewportState = {};
VkPipelineRasterizationStateCreateInfo rasterState = {};
VkPipelineDepthStencilStateCreateInfo depthStencilState = {};
VkPipelineTessellationStateCreateInfo tessellationState = {};
VkPipelineTessellationDomainOriginStateCreateInfo domainOriginState = {};
VkPipelineViewportDepthClipControlCreateInfoEXT depthClipControl = {};
VkPipelineRasterizationLineStateCreateInfoEXT rasterLineState = {};
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexState = {};
VkPipelineRasterizationStateStreamCreateInfoEXT rasterStreamState = {};
VkSpecializationInfo specializationInfo = {};
// Support storage
angle::FixedVector<VkPipelineShaderStageCreateInfo, 5> shaderStages;
SpecializationConstantMap<VkSpecializationMapEntry> specializationEntries;
};
struct GraphicsPipelineSharedNonVertexInputVulkanStructs
{
VkPipelineMultisampleStateCreateInfo multisampleState = {};
// Support storage
uint32_t sampleMask;
};
struct GraphicsPipelineFragmentOutputVulkanStructs
{
VkPipelineColorBlendStateCreateInfo blendState = {};
// Support storage
gl::DrawBuffersArray<VkPipelineColorBlendAttachmentState> blendAttachmentState;
};
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
using GraphicsPipelineDynamicStateList = angle::FixedVector<VkDynamicState, 23>;
enum class PipelineRobustness
{
NonRobust,
Robust,
};
enum class PipelineProtectedAccess
{
Unprotected,
Protected,
};
// State changes are applied through the update methods. Each update method can also have a
// sibling method that applies the update without marking a state transition. The non-transition
// update methods are used for internal shader pipelines. Not every non-transition update method
// is implemented yet as not every state is used in internal shaders.
class GraphicsPipelineDesc final
{
public:
// Use aligned allocation and free so we can use the alignas keyword.
void *operator new(std::size_t size);
void operator delete(void *ptr);
GraphicsPipelineDesc();
~GraphicsPipelineDesc();
GraphicsPipelineDesc(const GraphicsPipelineDesc &other);
GraphicsPipelineDesc &operator=(const GraphicsPipelineDesc &other);
size_t hash(GraphicsPipelineSubset subset) const;
bool keyEqual(const GraphicsPipelineDesc &other, GraphicsPipelineSubset subset) const;
void initDefaults(const Context *context,
GraphicsPipelineSubset subset,
PipelineRobustness contextRobustness,
PipelineProtectedAccess contextProtectedAccess);
// For custom comparisons.
template <typename T>
const T *getPtr() const
{
return reinterpret_cast<const T *>(this);
}
VkResult initializePipeline(Context *context,
PipelineCacheAccess *pipelineCache,
GraphicsPipelineSubset subset,
const RenderPass &compatibleRenderPass,
const PipelineLayout &pipelineLayout,
const ShaderModuleMap &shaders,
const SpecializationConstants &specConsts,
Pipeline *pipelineOut,
CacheLookUpFeedback *feedbackOut) const;
// Vertex input state. For ES 3.1 this should be separated into binding and attribute.
void updateVertexInput(ContextVk *contextVk,
GraphicsPipelineTransitionBits *transition,
uint32_t attribIndex,
GLuint stride,
GLuint divisor,
angle::FormatID format,
bool compressed,
GLuint relativeOffset);
void setVertexShaderComponentTypes(gl::AttributesMask activeAttribLocations,
gl::ComponentTypeMask componentTypeMask);
void updateVertexShaderComponentTypes(GraphicsPipelineTransitionBits *transition,
gl::AttributesMask activeAttribLocations,
gl::ComponentTypeMask componentTypeMask);
// Input assembly info
void setTopology(gl::PrimitiveMode drawMode);
void updateTopology(GraphicsPipelineTransitionBits *transition, gl::PrimitiveMode drawMode);
void updatePrimitiveRestartEnabled(GraphicsPipelineTransitionBits *transition,
bool primitiveRestartEnabled);
// Viewport states
void updateDepthClipControl(GraphicsPipelineTransitionBits *transition, bool negativeOneToOne);
// Raster states
void updatePolygonMode(GraphicsPipelineTransitionBits *transition, gl::PolygonMode polygonMode);
void updateCullMode(GraphicsPipelineTransitionBits *transition,
const gl::RasterizerState &rasterState);
void updateFrontFace(GraphicsPipelineTransitionBits *transition,
const gl::RasterizerState &rasterState,
bool invertFrontFace);
void updateRasterizerDiscardEnabled(GraphicsPipelineTransitionBits *transition,
bool rasterizerDiscardEnabled);
// Multisample states
uint32_t getRasterizationSamples() const;
void setRasterizationSamples(uint32_t rasterizationSamples);
void updateRasterizationSamples(GraphicsPipelineTransitionBits *transition,
uint32_t rasterizationSamples);
void updateAlphaToCoverageEnable(GraphicsPipelineTransitionBits *transition, bool enable);
void updateAlphaToOneEnable(GraphicsPipelineTransitionBits *transition, bool enable);
void updateSampleMask(GraphicsPipelineTransitionBits *transition,
uint32_t maskNumber,
uint32_t mask);
void updateSampleShading(GraphicsPipelineTransitionBits *transition, bool enable, float value);
// RenderPass description.
const RenderPassDesc &getRenderPassDesc() const { return mSharedNonVertexInput.renderPass; }
void setRenderPassDesc(const RenderPassDesc &renderPassDesc);
void updateRenderPassDesc(GraphicsPipelineTransitionBits *transition,
const angle::FeaturesVk &features,
const RenderPassDesc &renderPassDesc,
FramebufferFetchMode framebufferFetchMode);
void setRenderPassSampleCount(GLint samples);
void setRenderPassFramebufferFetchMode(FramebufferFetchMode framebufferFetchMode);
bool getRenderPassColorFramebufferFetchMode() const
{
return mSharedNonVertexInput.renderPass.hasColorFramebufferFetch();
}
bool getRenderPassDepthStencilFramebufferFetchMode() const
{
return mSharedNonVertexInput.renderPass.hasDepthStencilFramebufferFetch();
}
void setRenderPassFoveation(bool isFoveated);
bool getRenderPassFoveation() const
{
return mSharedNonVertexInput.renderPass.hasFragmentShadingAttachment();
}
void setRenderPassColorAttachmentFormat(size_t colorIndexGL, angle::FormatID formatID);
// Blend states
void setSingleBlend(uint32_t colorIndexGL,
bool enabled,
VkBlendOp op,
VkBlendFactor srcFactor,
VkBlendFactor dstFactor);
void updateBlendEnabled(GraphicsPipelineTransitionBits *transition,
gl::DrawBufferMask blendEnabledMask);
void updateBlendFuncs(GraphicsPipelineTransitionBits *transition,
const gl::BlendStateExt &blendStateExt,
gl::DrawBufferMask attachmentMask);
void updateBlendEquations(GraphicsPipelineTransitionBits *transition,
const gl::BlendStateExt &blendStateExt,
gl::DrawBufferMask attachmentMask);
void resetBlendFuncsAndEquations(GraphicsPipelineTransitionBits *transition,
const gl::BlendStateExt &blendStateExt,
gl::DrawBufferMask previousAttachmentsMask,
gl::DrawBufferMask newAttachmentsMask);
void setColorWriteMasks(gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
const gl::DrawBufferMask &alphaMask,
const gl::DrawBufferMask &enabledDrawBuffers);
void setSingleColorWriteMask(uint32_t colorIndexGL, VkColorComponentFlags colorComponentFlags);
void updateColorWriteMasks(GraphicsPipelineTransitionBits *transition,
gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
const gl::DrawBufferMask &alphaMask,
const gl::DrawBufferMask &enabledDrawBuffers);
void updateMissingOutputsMask(GraphicsPipelineTransitionBits *transition,
gl::DrawBufferMask missingOutputsMask);
// Logic op
void updateLogicOpEnabled(GraphicsPipelineTransitionBits *transition, bool enable);
void updateLogicOp(GraphicsPipelineTransitionBits *transition, VkLogicOp logicOp);
// Depth/stencil states.
void setDepthTestEnabled(bool enabled);
void setDepthWriteEnabled(bool enabled);
void setDepthFunc(VkCompareOp op);
void setDepthClampEnabled(bool enabled);
void setStencilTestEnabled(bool enabled);
void setStencilFrontFuncs(VkCompareOp compareOp);
void setStencilBackFuncs(VkCompareOp compareOp);
void setStencilFrontOps(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp);
void setStencilBackOps(VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp);
void setStencilFrontWriteMask(uint8_t mask);
void setStencilBackWriteMask(uint8_t mask);
void updateDepthTestEnabled(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState,
const gl::Framebuffer *drawFramebuffer);
void updateDepthFunc(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState);
void updateDepthClampEnabled(GraphicsPipelineTransitionBits *transition, bool enabled);
void updateDepthWriteEnabled(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState,
const gl::Framebuffer *drawFramebuffer);
void updateStencilTestEnabled(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState,
const gl::Framebuffer *drawFramebuffer);
void updateStencilFrontFuncs(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState);
void updateStencilBackFuncs(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState);
void updateStencilFrontOps(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState);
void updateStencilBackOps(GraphicsPipelineTransitionBits *transition,
const gl::DepthStencilState &depthStencilState);
// Depth offset.
void updatePolygonOffsetEnabled(GraphicsPipelineTransitionBits *transition, bool enabled);
// Tessellation
void updatePatchVertices(GraphicsPipelineTransitionBits *transition, GLuint value);
// Subpass
void resetSubpass(GraphicsPipelineTransitionBits *transition);
void nextSubpass(GraphicsPipelineTransitionBits *transition);