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.cpp:
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 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
12
13 #include "common/aligned_memory.h"
14 #include "common/system_utils.h"
15 #include "common/vulkan/vk_google_filtering_precision.h"
16 #include "libANGLE/BlobCache.h"
17 #include "libANGLE/VertexAttribute.h"
18 #include "libANGLE/renderer/vulkan/DisplayVk.h"
19 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
20 #include "libANGLE/renderer/vulkan/ProgramVk.h"
21 #include "libANGLE/renderer/vulkan/RendererVk.h"
22 #include "libANGLE/renderer/vulkan/TextureVk.h"
23 #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
24 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
25 #include "libANGLE/renderer/vulkan/vk_helpers.h"
26
27 #include <type_traits>
28
29 namespace rx
30 {
31 constexpr bool kDumpPipelineCacheGraph = false;
32
33 namespace vk
34 {
35
36 namespace
37 {
38 static_assert(static_cast<uint32_t>(RenderPassLoadOp::Load) == VK_ATTACHMENT_LOAD_OP_LOAD,
39 "ConvertRenderPassLoadOpToVkLoadOp must be updated");
40 static_assert(static_cast<uint32_t>(RenderPassLoadOp::Clear) == VK_ATTACHMENT_LOAD_OP_CLEAR,
41 "ConvertRenderPassLoadOpToVkLoadOp must be updated");
42 static_assert(static_cast<uint32_t>(RenderPassLoadOp::DontCare) == VK_ATTACHMENT_LOAD_OP_DONT_CARE,
43 "ConvertRenderPassLoadOpToVkLoadOp must be updated");
44 static_assert(static_cast<uint32_t>(RenderPassLoadOp::None) == 3,
45 "ConvertRenderPassLoadOpToVkLoadOp must be updated");
46
47 static_assert(static_cast<uint32_t>(RenderPassStoreOp::Store) == VK_ATTACHMENT_STORE_OP_STORE,
48 "ConvertRenderPassStoreOpToVkStoreOp must be updated");
49 static_assert(static_cast<uint32_t>(RenderPassStoreOp::DontCare) ==
50 VK_ATTACHMENT_STORE_OP_DONT_CARE,
51 "ConvertRenderPassStoreOpToVkStoreOp must be updated");
52 static_assert(static_cast<uint32_t>(RenderPassStoreOp::None) == 2,
53 "ConvertRenderPassStoreOpToVkStoreOp must be updated");
54
55 constexpr uint16_t kMinSampleShadingScale = angle::BitMask<uint16_t>(8);
56
ConvertRenderPassLoadOpToVkLoadOp(RenderPassLoadOp loadOp)57 VkAttachmentLoadOp ConvertRenderPassLoadOpToVkLoadOp(RenderPassLoadOp loadOp)
58 {
59 return loadOp == RenderPassLoadOp::None ? VK_ATTACHMENT_LOAD_OP_NONE_EXT
60 : static_cast<VkAttachmentLoadOp>(loadOp);
61 }
ConvertRenderPassStoreOpToVkStoreOp(RenderPassStoreOp storeOp)62 VkAttachmentStoreOp ConvertRenderPassStoreOpToVkStoreOp(RenderPassStoreOp storeOp)
63 {
64 return storeOp == RenderPassStoreOp::None ? VK_ATTACHMENT_STORE_OP_NONE_EXT
65 : static_cast<VkAttachmentStoreOp>(storeOp);
66 }
67
TransitionBits(size_t size)68 constexpr size_t TransitionBits(size_t size)
69 {
70 return size / kGraphicsPipelineDirtyBitBytes;
71 }
72
73 constexpr size_t kPipelineShadersDescOffset = 0;
74 constexpr size_t kPipelineShadersDescSize =
75 kGraphicsPipelineShadersStateSize + kGraphicsPipelineSharedNonVertexInputStateSize;
76
77 constexpr size_t kPipelineFragmentOutputDescOffset = kGraphicsPipelineShadersStateSize;
78 constexpr size_t kPipelineFragmentOutputDescSize =
79 kGraphicsPipelineSharedNonVertexInputStateSize + kGraphicsPipelineFragmentOutputStateSize;
80
81 constexpr size_t kPipelineVertexInputDescOffset =
82 kGraphicsPipelineShadersStateSize + kPipelineFragmentOutputDescSize;
83 constexpr size_t kPipelineVertexInputDescSize = kGraphicsPipelineVertexInputStateSize;
84
85 static_assert(kPipelineShadersDescOffset % kGraphicsPipelineDirtyBitBytes == 0);
86 static_assert(kPipelineShadersDescSize % kGraphicsPipelineDirtyBitBytes == 0);
87
88 static_assert(kPipelineFragmentOutputDescOffset % kGraphicsPipelineDirtyBitBytes == 0);
89 static_assert(kPipelineFragmentOutputDescSize % kGraphicsPipelineDirtyBitBytes == 0);
90
91 static_assert(kPipelineVertexInputDescOffset % kGraphicsPipelineDirtyBitBytes == 0);
92 static_assert(kPipelineVertexInputDescSize % kGraphicsPipelineDirtyBitBytes == 0);
93
94 constexpr GraphicsPipelineTransitionBits kPipelineShadersTransitionBitsMask =
95 GraphicsPipelineTransitionBits::Mask(TransitionBits(kPipelineShadersDescSize) +
96 TransitionBits(kPipelineShadersDescOffset)) &
97 ~GraphicsPipelineTransitionBits::Mask(TransitionBits(kPipelineShadersDescOffset));
98
99 constexpr GraphicsPipelineTransitionBits kPipelineFragmentOutputTransitionBitsMask =
100 GraphicsPipelineTransitionBits::Mask(TransitionBits(kPipelineFragmentOutputDescSize) +
101 TransitionBits(kPipelineFragmentOutputDescOffset)) &
102 ~GraphicsPipelineTransitionBits::Mask(TransitionBits(kPipelineFragmentOutputDescOffset));
103
104 constexpr GraphicsPipelineTransitionBits kPipelineVertexInputTransitionBitsMask =
105 GraphicsPipelineTransitionBits::Mask(TransitionBits(kPipelineVertexInputDescSize) +
106 TransitionBits(kPipelineVertexInputDescOffset)) &
107 ~GraphicsPipelineTransitionBits::Mask(TransitionBits(kPipelineVertexInputDescOffset));
108
GraphicsPipelineHasVertexInput(GraphicsPipelineSubset subset)109 bool GraphicsPipelineHasVertexInput(GraphicsPipelineSubset subset)
110 {
111 return subset == GraphicsPipelineSubset::Complete ||
112 subset == GraphicsPipelineSubset::VertexInput;
113 }
114
GraphicsPipelineHasShaders(GraphicsPipelineSubset subset)115 bool GraphicsPipelineHasShaders(GraphicsPipelineSubset subset)
116 {
117 return subset == GraphicsPipelineSubset::Complete || subset == GraphicsPipelineSubset::Shaders;
118 }
119
GraphicsPipelineHasShadersOrFragmentOutput(GraphicsPipelineSubset subset)120 bool GraphicsPipelineHasShadersOrFragmentOutput(GraphicsPipelineSubset subset)
121 {
122 return subset != GraphicsPipelineSubset::VertexInput;
123 }
124
GraphicsPipelineHasFragmentOutput(GraphicsPipelineSubset subset)125 bool GraphicsPipelineHasFragmentOutput(GraphicsPipelineSubset subset)
126 {
127 return subset == GraphicsPipelineSubset::Complete ||
128 subset == GraphicsPipelineSubset::FragmentOutput;
129 }
130
PackGLBlendOp(GLenum blendOp)131 uint8_t PackGLBlendOp(GLenum blendOp)
132 {
133 switch (blendOp)
134 {
135 case GL_FUNC_ADD:
136 return static_cast<uint8_t>(VK_BLEND_OP_ADD);
137 case GL_FUNC_SUBTRACT:
138 return static_cast<uint8_t>(VK_BLEND_OP_SUBTRACT);
139 case GL_FUNC_REVERSE_SUBTRACT:
140 return static_cast<uint8_t>(VK_BLEND_OP_REVERSE_SUBTRACT);
141 case GL_MIN:
142 return static_cast<uint8_t>(VK_BLEND_OP_MIN);
143 case GL_MAX:
144 return static_cast<uint8_t>(VK_BLEND_OP_MAX);
145 case GL_MULTIPLY_KHR:
146 return static_cast<uint8_t>(VK_BLEND_OP_MULTIPLY_EXT - VK_BLEND_OP_ZERO_EXT);
147 case GL_SCREEN_KHR:
148 return static_cast<uint8_t>(VK_BLEND_OP_SCREEN_EXT - VK_BLEND_OP_ZERO_EXT);
149 case GL_OVERLAY_KHR:
150 return static_cast<uint8_t>(VK_BLEND_OP_OVERLAY_EXT - VK_BLEND_OP_ZERO_EXT);
151 case GL_DARKEN_KHR:
152 return static_cast<uint8_t>(VK_BLEND_OP_DARKEN_EXT - VK_BLEND_OP_ZERO_EXT);
153 case GL_LIGHTEN_KHR:
154 return static_cast<uint8_t>(VK_BLEND_OP_LIGHTEN_EXT - VK_BLEND_OP_ZERO_EXT);
155 case GL_COLORDODGE_KHR:
156 return static_cast<uint8_t>(VK_BLEND_OP_COLORDODGE_EXT - VK_BLEND_OP_ZERO_EXT);
157 case GL_COLORBURN_KHR:
158 return static_cast<uint8_t>(VK_BLEND_OP_COLORBURN_EXT - VK_BLEND_OP_ZERO_EXT);
159 case GL_HARDLIGHT_KHR:
160 return static_cast<uint8_t>(VK_BLEND_OP_HARDLIGHT_EXT - VK_BLEND_OP_ZERO_EXT);
161 case GL_SOFTLIGHT_KHR:
162 return static_cast<uint8_t>(VK_BLEND_OP_SOFTLIGHT_EXT - VK_BLEND_OP_ZERO_EXT);
163 case GL_DIFFERENCE_KHR:
164 return static_cast<uint8_t>(VK_BLEND_OP_DIFFERENCE_EXT - VK_BLEND_OP_ZERO_EXT);
165 case GL_EXCLUSION_KHR:
166 return static_cast<uint8_t>(VK_BLEND_OP_EXCLUSION_EXT - VK_BLEND_OP_ZERO_EXT);
167 case GL_HSL_HUE_KHR:
168 return static_cast<uint8_t>(VK_BLEND_OP_HSL_HUE_EXT - VK_BLEND_OP_ZERO_EXT);
169 case GL_HSL_SATURATION_KHR:
170 return static_cast<uint8_t>(VK_BLEND_OP_HSL_SATURATION_EXT - VK_BLEND_OP_ZERO_EXT);
171 case GL_HSL_COLOR_KHR:
172 return static_cast<uint8_t>(VK_BLEND_OP_HSL_COLOR_EXT - VK_BLEND_OP_ZERO_EXT);
173 case GL_HSL_LUMINOSITY_KHR:
174 return static_cast<uint8_t>(VK_BLEND_OP_HSL_LUMINOSITY_EXT - VK_BLEND_OP_ZERO_EXT);
175 default:
176 UNREACHABLE();
177 return 0;
178 }
179 }
180
UnpackBlendOp(uint8_t packedBlendOp)181 VkBlendOp UnpackBlendOp(uint8_t packedBlendOp)
182 {
183 if (packedBlendOp <= VK_BLEND_OP_MAX)
184 {
185 return static_cast<VkBlendOp>(packedBlendOp);
186 }
187 return static_cast<VkBlendOp>(packedBlendOp + VK_BLEND_OP_ZERO_EXT);
188 }
189
PackGLBlendFactor(GLenum blendFactor)190 uint8_t PackGLBlendFactor(GLenum blendFactor)
191 {
192 switch (blendFactor)
193 {
194 case GL_ZERO:
195 return static_cast<uint8_t>(VK_BLEND_FACTOR_ZERO);
196 case GL_ONE:
197 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
198 case GL_SRC_COLOR:
199 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC_COLOR);
200 case GL_DST_COLOR:
201 return static_cast<uint8_t>(VK_BLEND_FACTOR_DST_COLOR);
202 case GL_ONE_MINUS_SRC_COLOR:
203 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR);
204 case GL_SRC_ALPHA:
205 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC_ALPHA);
206 case GL_ONE_MINUS_SRC_ALPHA:
207 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
208 case GL_DST_ALPHA:
209 return static_cast<uint8_t>(VK_BLEND_FACTOR_DST_ALPHA);
210 case GL_ONE_MINUS_DST_ALPHA:
211 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA);
212 case GL_ONE_MINUS_DST_COLOR:
213 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR);
214 case GL_SRC_ALPHA_SATURATE:
215 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC_ALPHA_SATURATE);
216 case GL_CONSTANT_COLOR:
217 return static_cast<uint8_t>(VK_BLEND_FACTOR_CONSTANT_COLOR);
218 case GL_CONSTANT_ALPHA:
219 return static_cast<uint8_t>(VK_BLEND_FACTOR_CONSTANT_ALPHA);
220 case GL_ONE_MINUS_CONSTANT_COLOR:
221 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR);
222 case GL_ONE_MINUS_CONSTANT_ALPHA:
223 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA);
224 case GL_SRC1_COLOR_EXT:
225 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC1_COLOR);
226 case GL_SRC1_ALPHA_EXT:
227 return static_cast<uint8_t>(VK_BLEND_FACTOR_SRC1_ALPHA);
228 case GL_ONE_MINUS_SRC1_COLOR_EXT:
229 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR);
230 case GL_ONE_MINUS_SRC1_ALPHA_EXT:
231 return static_cast<uint8_t>(VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA);
232 default:
233 UNREACHABLE();
234 return 0;
235 }
236 }
237
UnpackAttachmentDesc(Context * context,VkAttachmentDescription2 * desc,angle::FormatID formatID,uint8_t samples,const PackedAttachmentOpsDesc & ops)238 void UnpackAttachmentDesc(Context *context,
239 VkAttachmentDescription2 *desc,
240 angle::FormatID formatID,
241 uint8_t samples,
242 const PackedAttachmentOpsDesc &ops)
243 {
244 *desc = {};
245 desc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
246 desc->format = GetVkFormatFromFormatID(formatID);
247 desc->samples = gl_vk::GetSamples(samples, context->getFeatures().limitSampleCountTo2.enabled);
248 desc->loadOp = ConvertRenderPassLoadOpToVkLoadOp(static_cast<RenderPassLoadOp>(ops.loadOp));
249 desc->storeOp =
250 ConvertRenderPassStoreOpToVkStoreOp(static_cast<RenderPassStoreOp>(ops.storeOp));
251 desc->stencilLoadOp =
252 ConvertRenderPassLoadOpToVkLoadOp(static_cast<RenderPassLoadOp>(ops.stencilLoadOp));
253 desc->stencilStoreOp =
254 ConvertRenderPassStoreOpToVkStoreOp(static_cast<RenderPassStoreOp>(ops.stencilStoreOp));
255 desc->initialLayout =
256 ConvertImageLayoutToVkImageLayout(context, static_cast<ImageLayout>(ops.initialLayout));
257 desc->finalLayout =
258 ConvertImageLayoutToVkImageLayout(context, static_cast<ImageLayout>(ops.finalLayout));
259 }
260
UnpackColorResolveAttachmentDesc(VkAttachmentDescription2 * desc,angle::FormatID formatID,bool usedAsInputAttachment,bool isInvalidated)261 void UnpackColorResolveAttachmentDesc(VkAttachmentDescription2 *desc,
262 angle::FormatID formatID,
263 bool usedAsInputAttachment,
264 bool isInvalidated)
265 {
266 *desc = {};
267 desc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
268 desc->format = GetVkFormatFromFormatID(formatID);
269
270 // This function is for color resolve attachments.
271 const angle::Format &angleFormat = angle::Format::Get(formatID);
272 ASSERT(angleFormat.depthBits == 0 && angleFormat.stencilBits == 0);
273
274 // Resolve attachments always have a sample count of 1.
275 //
276 // If the corresponding color attachment needs to take its initial value from the resolve
277 // attachment (i.e. needs to be unresolved), loadOp needs to be set to LOAD, otherwise it should
278 // be DONT_CARE as it gets overwritten during resolve.
279 //
280 // storeOp should be STORE. If the attachment is invalidated, it is set to DONT_CARE.
281 desc->samples = VK_SAMPLE_COUNT_1_BIT;
282 desc->loadOp =
283 usedAsInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
284 desc->storeOp = isInvalidated ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
285 desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
286 desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
287 desc->initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
288 desc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
289 }
290
UnpackDepthStencilResolveAttachmentDesc(VkAttachmentDescription2 * desc,angle::FormatID formatID,bool usedAsDepthInputAttachment,bool usedAsStencilInputAttachment,bool isDepthInvalidated,bool isStencilInvalidated)291 void UnpackDepthStencilResolveAttachmentDesc(VkAttachmentDescription2 *desc,
292 angle::FormatID formatID,
293 bool usedAsDepthInputAttachment,
294 bool usedAsStencilInputAttachment,
295 bool isDepthInvalidated,
296 bool isStencilInvalidated)
297 {
298 // There cannot be simultaneous usages of the depth/stencil resolve image, as depth/stencil
299 // resolve currently only comes from depth/stencil renderbuffers.
300 *desc = {};
301 desc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
302 desc->format = GetVkFormatFromFormatID(formatID);
303
304 // This function is for depth/stencil resolve attachment.
305 const angle::Format &angleFormat = angle::Format::Get(formatID);
306 ASSERT(angleFormat.depthBits != 0 || angleFormat.stencilBits != 0);
307
308 // Missing aspects are folded in is*Invalidated parameters, so no need to double check.
309 ASSERT(angleFormat.depthBits > 0 || isDepthInvalidated);
310 ASSERT(angleFormat.stencilBits > 0 || isStencilInvalidated);
311
312 // Similarly to color resolve attachments, sample count is 1, loadOp is LOAD or DONT_CARE based
313 // on whether unresolve is required, and storeOp is STORE or DONT_CARE based on whether the
314 // attachment is invalidated or the aspect exists.
315 desc->samples = VK_SAMPLE_COUNT_1_BIT;
316 desc->loadOp =
317 usedAsDepthInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
318 desc->storeOp =
319 isDepthInvalidated ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
320 desc->stencilLoadOp =
321 usedAsStencilInputAttachment ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
322 desc->stencilStoreOp =
323 isStencilInvalidated ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
324 desc->initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
325 desc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
326 }
327
UnpackStencilState(const PackedStencilOpState & packedState,VkStencilOpState * stateOut,bool writeMaskWorkaround)328 void UnpackStencilState(const PackedStencilOpState &packedState,
329 VkStencilOpState *stateOut,
330 bool writeMaskWorkaround)
331 {
332 // Any non-zero value works for the purposes of the useNonZeroStencilWriteMaskStaticState driver
333 // bug workaround.
334 constexpr uint32_t kNonZeroWriteMaskForWorkaround = 1;
335
336 stateOut->failOp = static_cast<VkStencilOp>(packedState.fail);
337 stateOut->passOp = static_cast<VkStencilOp>(packedState.pass);
338 stateOut->depthFailOp = static_cast<VkStencilOp>(packedState.depthFail);
339 stateOut->compareOp = static_cast<VkCompareOp>(packedState.compare);
340 stateOut->compareMask = 0;
341 stateOut->writeMask = writeMaskWorkaround ? kNonZeroWriteMaskForWorkaround : 0;
342 stateOut->reference = 0;
343 }
344
UnpackBlendAttachmentState(const PackedColorBlendAttachmentState & packedState,VkPipelineColorBlendAttachmentState * stateOut)345 void UnpackBlendAttachmentState(const PackedColorBlendAttachmentState &packedState,
346 VkPipelineColorBlendAttachmentState *stateOut)
347 {
348 stateOut->srcColorBlendFactor = static_cast<VkBlendFactor>(packedState.srcColorBlendFactor);
349 stateOut->dstColorBlendFactor = static_cast<VkBlendFactor>(packedState.dstColorBlendFactor);
350 stateOut->colorBlendOp = UnpackBlendOp(packedState.colorBlendOp);
351 stateOut->srcAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.srcAlphaBlendFactor);
352 stateOut->dstAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.dstAlphaBlendFactor);
353 stateOut->alphaBlendOp = UnpackBlendOp(packedState.alphaBlendOp);
354 }
355
SetPipelineShaderStageInfo(const VkStructureType type,const VkShaderStageFlagBits stage,const VkShaderModule module,const VkSpecializationInfo & specializationInfo,VkPipelineShaderStageCreateInfo * shaderStage)356 void SetPipelineShaderStageInfo(const VkStructureType type,
357 const VkShaderStageFlagBits stage,
358 const VkShaderModule module,
359 const VkSpecializationInfo &specializationInfo,
360 VkPipelineShaderStageCreateInfo *shaderStage)
361 {
362 shaderStage->sType = type;
363 shaderStage->flags = 0;
364 shaderStage->stage = stage;
365 shaderStage->module = module;
366 shaderStage->pName = "main";
367 shaderStage->pSpecializationInfo = &specializationInfo;
368 }
369
370 // Defines a subpass that uses the resolve attachments as input attachments to initialize color and
371 // depth/stencil attachments that need to be "unresolved" at the start of the render pass. The
372 // subpass will only contain the attachments that need to be unresolved to simplify the shader that
373 // performs the operations.
InitializeUnresolveSubpass(const RenderPassDesc & desc,const gl::DrawBuffersVector<VkAttachmentReference2> & drawSubpassColorAttachmentRefs,const gl::DrawBuffersVector<VkAttachmentReference2> & drawSubpassResolveAttachmentRefs,const VkAttachmentReference2 & depthStencilAttachmentRef,const VkAttachmentReference2 & depthStencilResolveAttachmentRef,gl::DrawBuffersVector<VkAttachmentReference2> * unresolveColorAttachmentRefs,VkAttachmentReference2 * unresolveDepthStencilAttachmentRef,FramebufferAttachmentsVector<VkAttachmentReference2> * unresolveInputAttachmentRefs,FramebufferAttachmentsVector<uint32_t> * unresolvePreserveAttachmentRefs,VkSubpassDescription2 * subpassDesc)374 void InitializeUnresolveSubpass(
375 const RenderPassDesc &desc,
376 const gl::DrawBuffersVector<VkAttachmentReference2> &drawSubpassColorAttachmentRefs,
377 const gl::DrawBuffersVector<VkAttachmentReference2> &drawSubpassResolveAttachmentRefs,
378 const VkAttachmentReference2 &depthStencilAttachmentRef,
379 const VkAttachmentReference2 &depthStencilResolveAttachmentRef,
380 gl::DrawBuffersVector<VkAttachmentReference2> *unresolveColorAttachmentRefs,
381 VkAttachmentReference2 *unresolveDepthStencilAttachmentRef,
382 FramebufferAttachmentsVector<VkAttachmentReference2> *unresolveInputAttachmentRefs,
383 FramebufferAttachmentsVector<uint32_t> *unresolvePreserveAttachmentRefs,
384 VkSubpassDescription2 *subpassDesc)
385 {
386 // Assume the GL Framebuffer has the following attachments enabled:
387 //
388 // GL Color 0
389 // GL Color 3
390 // GL Color 4
391 // GL Color 6
392 // GL Color 7
393 // GL Depth/Stencil
394 //
395 // Additionally, assume Color 0, 4 and 6 are multisampled-render-to-texture (or for any other
396 // reason) have corresponding resolve attachments. Furthermore, say Color 4 and 6 require an
397 // initial unresolve operation.
398 //
399 // In the above example, the render pass is created with the following attachments:
400 //
401 // RP Attachment[0] <- corresponding to GL Color 0
402 // RP Attachment[1] <- corresponding to GL Color 3
403 // RP Attachment[2] <- corresponding to GL Color 4
404 // RP Attachment[3] <- corresponding to GL Color 6
405 // RP Attachment[4] <- corresponding to GL Color 7
406 // RP Attachment[5] <- corresponding to GL Depth/Stencil
407 // RP Attachment[6] <- corresponding to resolve attachment of GL Color 0
408 // RP Attachment[7] <- corresponding to resolve attachment of GL Color 4
409 // RP Attachment[8] <- corresponding to resolve attachment of GL Color 6
410 //
411 // If the depth/stencil attachment is to be resolved, the following attachment would also be
412 // present:
413 //
414 // RP Attachment[9] <- corresponding to resolve attachment of GL Depth/Stencil
415 //
416 // The subpass that takes the application draw calls has the following attachments, creating the
417 // mapping from the Vulkan attachment indices (i.e. RP attachment indices) to GL indices as
418 // indicated by the GL shaders:
419 //
420 // Subpass[1] Color[0] -> RP Attachment[0]
421 // Subpass[1] Color[1] -> VK_ATTACHMENT_UNUSED
422 // Subpass[1] Color[2] -> VK_ATTACHMENT_UNUSED
423 // Subpass[1] Color[3] -> RP Attachment[1]
424 // Subpass[1] Color[4] -> RP Attachment[2]
425 // Subpass[1] Color[5] -> VK_ATTACHMENT_UNUSED
426 // Subpass[1] Color[6] -> RP Attachment[3]
427 // Subpass[1] Color[7] -> RP Attachment[4]
428 // Subpass[1] Depth/Stencil -> RP Attachment[5]
429 // Subpass[1] Resolve[0] -> RP Attachment[6]
430 // Subpass[1] Resolve[1] -> VK_ATTACHMENT_UNUSED
431 // Subpass[1] Resolve[2] -> VK_ATTACHMENT_UNUSED
432 // Subpass[1] Resolve[3] -> VK_ATTACHMENT_UNUSED
433 // Subpass[1] Resolve[4] -> RP Attachment[7]
434 // Subpass[1] Resolve[5] -> VK_ATTACHMENT_UNUSED
435 // Subpass[1] Resolve[6] -> RP Attachment[8]
436 // Subpass[1] Resolve[7] -> VK_ATTACHMENT_UNUSED
437 //
438 // With depth/stencil resolve attachment:
439 //
440 // Subpass[1] Depth/Stencil Resolve -> RP Attachment[9]
441 //
442 // The initial subpass that's created here is (remember that in the above example Color 4 and 6
443 // need to be unresolved):
444 //
445 // Subpass[0] Input[0] -> RP Attachment[7] = Subpass[1] Resolve[4]
446 // Subpass[0] Input[1] -> RP Attachment[8] = Subpass[1] Resolve[6]
447 // Subpass[0] Color[0] -> RP Attachment[2] = Subpass[1] Color[4]
448 // Subpass[0] Color[1] -> RP Attachment[3] = Subpass[1] Color[6]
449 //
450 // The trick here therefore is to use the color attachment refs already created for the
451 // application draw subpass indexed with colorIndexGL.
452 //
453 // If depth/stencil needs to be unresolved (note that as input attachment, it's inserted before
454 // the color attachments. See UtilsVk::unresolve()):
455 //
456 // Subpass[0] Input[0] -> RP Attachment[9] = Subpass[1] Depth/Stencil Resolve
457 // Subpass[0] Depth/Stencil -> RP Attachment[5] = Subpass[1] Depth/Stencil
458 //
459 // As an additional note, the attachments that are not used in the unresolve subpass must be
460 // preserved. That is color attachments and the depth/stencil attachment if any. Resolve
461 // attachments are rewritten by the next subpass, so they don't need to be preserved. Note that
462 // there's no need to preserve attachments whose loadOp is DONT_CARE. For simplicity, we
463 // preserve those as well. The driver would ideally avoid preserving attachments with
464 // loadOp=DONT_CARE.
465 //
466 // With the above example:
467 //
468 // Subpass[0] Preserve[0] -> RP Attachment[0] = Subpass[1] Color[0]
469 // Subpass[0] Preserve[1] -> RP Attachment[1] = Subpass[1] Color[3]
470 // Subpass[0] Preserve[2] -> RP Attachment[4] = Subpass[1] Color[7]
471 //
472 // If depth/stencil is not unresolved:
473 //
474 // Subpass[0] Preserve[3] -> RP Attachment[5] = Subpass[1] Depth/Stencil
475 //
476 // Again, the color attachment refs already created for the application draw subpass can be used
477 // indexed with colorIndexGL.
478 if (desc.hasDepthStencilUnresolveAttachment())
479 {
480 ASSERT(desc.hasDepthStencilAttachment());
481 ASSERT(desc.hasDepthStencilResolveAttachment());
482
483 *unresolveDepthStencilAttachmentRef = depthStencilAttachmentRef;
484
485 VkAttachmentReference2 unresolveDepthStencilInputAttachmentRef = {};
486 unresolveDepthStencilInputAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
487 unresolveDepthStencilInputAttachmentRef.attachment =
488 depthStencilResolveAttachmentRef.attachment;
489 unresolveDepthStencilInputAttachmentRef.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
490
491 unresolveDepthStencilInputAttachmentRef.aspectMask = 0;
492 if (desc.hasDepthUnresolveAttachment())
493 {
494 unresolveDepthStencilInputAttachmentRef.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
495 }
496 if (desc.hasStencilUnresolveAttachment())
497 {
498 unresolveDepthStencilInputAttachmentRef.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
499 }
500
501 unresolveInputAttachmentRefs->push_back(unresolveDepthStencilInputAttachmentRef);
502 }
503 else if (desc.hasDepthStencilAttachment())
504 {
505 // Preserve the depth/stencil attachment if not unresolved. Again, there's no need to
506 // preserve this attachment if loadOp=DONT_CARE, but we do for simplicity.
507 unresolvePreserveAttachmentRefs->push_back(depthStencilAttachmentRef.attachment);
508 }
509
510 for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
511 {
512 if (!desc.hasColorUnresolveAttachment(colorIndexGL))
513 {
514 if (desc.isColorAttachmentEnabled(colorIndexGL))
515 {
516 unresolvePreserveAttachmentRefs->push_back(
517 drawSubpassColorAttachmentRefs[colorIndexGL].attachment);
518 }
519 continue;
520 }
521 ASSERT(desc.isColorAttachmentEnabled(colorIndexGL));
522 ASSERT(desc.hasColorResolveAttachment(colorIndexGL));
523 ASSERT(drawSubpassColorAttachmentRefs[colorIndexGL].attachment != VK_ATTACHMENT_UNUSED);
524 ASSERT(drawSubpassResolveAttachmentRefs[colorIndexGL].attachment != VK_ATTACHMENT_UNUSED);
525
526 unresolveColorAttachmentRefs->push_back(drawSubpassColorAttachmentRefs[colorIndexGL]);
527 unresolveInputAttachmentRefs->push_back(drawSubpassResolveAttachmentRefs[colorIndexGL]);
528
529 // Note the input attachment layout should be shader read-only. The subpass dependency
530 // will take care of transitioning the layout of the resolve attachment to color attachment
531 // automatically.
532 unresolveInputAttachmentRefs->back().layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
533 }
534
535 ASSERT(!unresolveColorAttachmentRefs->empty() ||
536 unresolveDepthStencilAttachmentRef->attachment != VK_ATTACHMENT_UNUSED);
537 ASSERT(unresolveColorAttachmentRefs->size() +
538 (desc.hasDepthStencilUnresolveAttachment() ? 1 : 0) ==
539 unresolveInputAttachmentRefs->size());
540
541 subpassDesc->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
542 subpassDesc->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
543 subpassDesc->inputAttachmentCount = static_cast<uint32_t>(unresolveInputAttachmentRefs->size());
544 subpassDesc->pInputAttachments = unresolveInputAttachmentRefs->data();
545 subpassDesc->colorAttachmentCount = static_cast<uint32_t>(unresolveColorAttachmentRefs->size());
546 subpassDesc->pColorAttachments = unresolveColorAttachmentRefs->data();
547 subpassDesc->pDepthStencilAttachment = unresolveDepthStencilAttachmentRef;
548 subpassDesc->preserveAttachmentCount =
549 static_cast<uint32_t>(unresolvePreserveAttachmentRefs->size());
550 subpassDesc->pPreserveAttachments = unresolvePreserveAttachmentRefs->data();
551 }
552
553 // There is normally one subpass, and occasionally another for the unresolve operation.
554 constexpr size_t kSubpassFastVectorSize = 2;
555 template <typename T>
556 using SubpassVector = angle::FastVector<T, kSubpassFastVectorSize>;
557
InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescription2> & subpassDesc,bool unresolveColor,bool unresolveDepthStencil,std::vector<VkSubpassDependency2> * subpassDependencies)558 void InitializeUnresolveSubpassDependencies(const SubpassVector<VkSubpassDescription2> &subpassDesc,
559 bool unresolveColor,
560 bool unresolveDepthStencil,
561 std::vector<VkSubpassDependency2> *subpassDependencies)
562 {
563 ASSERT(subpassDesc.size() >= 2);
564 ASSERT(unresolveColor || unresolveDepthStencil);
565
566 // The unresolve subpass is the first subpass. The application draw subpass is the next one.
567 constexpr uint32_t kUnresolveSubpassIndex = 0;
568 constexpr uint32_t kDrawSubpassIndex = 1;
569
570 // A subpass dependency is needed between the unresolve and draw subpasses. There are two
571 // hazards here:
572 //
573 // - Subpass 0 writes to color/depth/stencil attachments, subpass 1 writes to the same
574 // attachments. This is a WaW hazard (color/depth/stencil write -> color/depth/stencil write)
575 // similar to when two subsequent render passes write to the same images.
576 // - Subpass 0 reads from resolve attachments, subpass 1 writes to the same resolve attachments.
577 // This is a WaR hazard (fragment shader read -> color write) which only requires an execution
578 // barrier.
579 //
580 // Note: the DEPENDENCY_BY_REGION flag is necessary to create a "framebuffer-local" dependency,
581 // as opposed to "framebuffer-global". The latter is effectively a render pass break. The
582 // former creates a dependency per framebuffer region. If dependency scopes correspond to
583 // attachments with:
584 //
585 // - Same sample count: dependency is at sample granularity
586 // - Different sample count: dependency is at pixel granularity
587 //
588 // The latter is clarified by the spec as such:
589 //
590 // > Practically, the pixel vs sample granularity dependency means that if an input attachment
591 // > has a different number of samples than the pipeline's rasterizationSamples, then a fragment
592 // > can access any sample in the input attachment's pixel even if it only uses
593 // > framebuffer-local dependencies.
594 //
595 // The dependency for the first hazard above (attachment write -> attachment write) is on
596 // same-sample attachments, so it will not allow the use of input attachments as required by the
597 // unresolve subpass. As a result, even though the second hazard seems to be subsumed by the
598 // first (its src stage is earlier and its dst stage is the same), a separate dependency is
599 // created for it just to obtain a pixel granularity dependency.
600 //
601 // Note: depth/stencil resolve is considered to be done in the color write stage:
602 //
603 // > Moving to the next subpass automatically performs any multisample resolve operations in the
604 // > subpass being ended. End-of-subpass multisample resolves are treated as color attachment
605 // > writes for the purposes of synchronization. This applies to resolve operations for both
606 // > color and depth/stencil attachments. That is, they are considered to execute in the
607 // > VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT pipeline stage and their writes are
608 // > synchronized with VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT.
609
610 subpassDependencies->push_back({});
611 VkSubpassDependency2 *dependency = &subpassDependencies->back();
612
613 constexpr VkPipelineStageFlags kColorWriteStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
614 constexpr VkPipelineStageFlags kColorReadWriteStage =
615 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
616 constexpr VkAccessFlags kColorWriteFlags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
617 constexpr VkAccessFlags kColorReadWriteFlags =
618 kColorWriteFlags | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
619
620 constexpr VkPipelineStageFlags kDepthStencilWriteStage =
621 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
622 constexpr VkPipelineStageFlags kDepthStencilReadWriteStage =
623 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
624 constexpr VkAccessFlags kDepthStencilWriteFlags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
625 constexpr VkAccessFlags kDepthStencilReadWriteFlags =
626 kDepthStencilWriteFlags | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
627
628 VkPipelineStageFlags attachmentWriteStages = 0;
629 VkPipelineStageFlags attachmentReadWriteStages = 0;
630 VkAccessFlags attachmentWriteFlags = 0;
631 VkAccessFlags attachmentReadWriteFlags = 0;
632
633 if (unresolveColor)
634 {
635 attachmentWriteStages |= kColorWriteStage;
636 attachmentReadWriteStages |= kColorReadWriteStage;
637 attachmentWriteFlags |= kColorWriteFlags;
638 attachmentReadWriteFlags |= kColorReadWriteFlags;
639 }
640
641 if (unresolveDepthStencil)
642 {
643 attachmentWriteStages |= kDepthStencilWriteStage;
644 attachmentReadWriteStages |= kDepthStencilReadWriteStage;
645 attachmentWriteFlags |= kDepthStencilWriteFlags;
646 attachmentReadWriteFlags |= kDepthStencilReadWriteFlags;
647 }
648
649 dependency->sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
650 dependency->srcSubpass = kUnresolveSubpassIndex;
651 dependency->dstSubpass = kDrawSubpassIndex;
652 dependency->srcStageMask = attachmentWriteStages;
653 dependency->dstStageMask = attachmentReadWriteStages;
654 dependency->srcAccessMask = attachmentWriteFlags;
655 dependency->dstAccessMask = attachmentReadWriteFlags;
656 dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
657
658 subpassDependencies->push_back({});
659 dependency = &subpassDependencies->back();
660
661 // Note again that depth/stencil resolve is considered to be done in the color output stage.
662 dependency->sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
663 dependency->srcSubpass = kUnresolveSubpassIndex;
664 dependency->dstSubpass = kDrawSubpassIndex;
665 dependency->srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
666 dependency->dstStageMask = kColorWriteStage;
667 dependency->srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
668 dependency->dstAccessMask = kColorWriteFlags;
669 dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
670 }
671
672 // glFramebufferFetchBarrierEXT and glBlendBarrierKHR require a pipeline barrier to be inserted in
673 // the render pass. This requires a subpass self-dependency.
674 //
675 // For framebuffer fetch:
676 //
677 // srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
678 // dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
679 // srcAccess = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
680 // dstAccess = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
681 //
682 // For advanced blend:
683 //
684 // srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
685 // dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
686 // srcAccess = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
687 // dstAccess = VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT
688 //
689 // Subpass dependencies cannot be added after the fact at the end of the render pass due to render
690 // pass compatibility rules. ANGLE specifies a subpass self-dependency with the above stage/access
691 // masks in preparation of potential framebuffer fetch and advanced blend barriers. This is known
692 // not to add any overhead on any hardware we have been able to gather information from.
InitializeDefaultSubpassSelfDependencies(Context * context,const RenderPassDesc & desc,uint32_t subpassIndex,std::vector<VkSubpassDependency2> * subpassDependencies)693 void InitializeDefaultSubpassSelfDependencies(
694 Context *context,
695 const RenderPassDesc &desc,
696 uint32_t subpassIndex,
697 std::vector<VkSubpassDependency2> *subpassDependencies)
698 {
699 RendererVk *renderer = context->getRenderer();
700 const bool hasRasterizationOrderAttachmentAccess =
701 renderer->getFeatures().supportsRasterizationOrderAttachmentAccess.enabled;
702 const bool hasBlendOperationAdvanced =
703 renderer->getFeatures().supportsBlendOperationAdvanced.enabled;
704
705 if (hasRasterizationOrderAttachmentAccess && !hasBlendOperationAdvanced)
706 {
707 // No need to specify a subpass dependency if VK_EXT_rasterization_order_attachment_access
708 // is enabled, as that extension makes this subpass dependency implicit.
709 return;
710 }
711
712 subpassDependencies->push_back({});
713 VkSubpassDependency2 *dependency = &subpassDependencies->back();
714
715 dependency->sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
716 dependency->srcSubpass = subpassIndex;
717 dependency->dstSubpass = subpassIndex;
718 dependency->srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
719 dependency->dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
720 dependency->srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
721 dependency->dstAccessMask = 0;
722 if (!hasRasterizationOrderAttachmentAccess)
723 {
724 dependency->dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
725 dependency->dstAccessMask |= VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
726 }
727 if (renderer->getFeatures().supportsBlendOperationAdvanced.enabled)
728 {
729 dependency->dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT;
730 }
731 dependency->dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
732 if (desc.viewCount() > 0)
733 {
734 dependency->dependencyFlags |= VK_DEPENDENCY_VIEW_LOCAL_BIT;
735 }
736 }
737
InitializeMSRTSS(Context * context,uint8_t renderToTextureSamples,VkSubpassDescription2 * subpass,VkSubpassDescriptionDepthStencilResolve * msrtssResolve,VkMultisampledRenderToSingleSampledInfoEXT * msrtss,VkMultisampledRenderToSingleSampledInfoGOOGLEX * msrtssGOOGLEX)738 void InitializeMSRTSS(Context *context,
739 uint8_t renderToTextureSamples,
740 VkSubpassDescription2 *subpass,
741 VkSubpassDescriptionDepthStencilResolve *msrtssResolve,
742 VkMultisampledRenderToSingleSampledInfoEXT *msrtss,
743 VkMultisampledRenderToSingleSampledInfoGOOGLEX *msrtssGOOGLEX)
744 {
745 RendererVk *renderer = context->getRenderer();
746
747 ASSERT(renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled ||
748 renderer->getFeatures().supportsMultisampledRenderToSingleSampledGOOGLEX.enabled);
749
750 *msrtssResolve = {};
751 msrtssResolve->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
752 msrtssResolve->depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
753 msrtssResolve->stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
754
755 *msrtss = {};
756 msrtss->sType = VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT;
757 msrtss->pNext = msrtssResolve;
758 msrtss->multisampledRenderToSingleSampledEnable = true;
759 msrtss->rasterizationSamples = gl_vk::GetSamples(
760 renderToTextureSamples, context->getFeatures().limitSampleCountTo2.enabled);
761
762 *msrtssGOOGLEX = {};
763 msrtssGOOGLEX->sType = VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_GOOGLEX;
764 msrtssGOOGLEX->multisampledRenderToSingleSampledEnable = true;
765 msrtssGOOGLEX->rasterizationSamples = msrtss->rasterizationSamples;
766 msrtssGOOGLEX->depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
767 msrtssGOOGLEX->stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
768
769 if (renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled)
770 {
771 // msrtss->pNext is not null so can't use AddToPNextChain
772 AppendToPNextChain(subpass, msrtss);
773 }
774 else
775 {
776 AddToPNextChain(subpass, msrtssGOOGLEX);
777 }
778 }
779
SetRenderPassViewMask(Context * context,const uint32_t * viewMask,VkRenderPassCreateInfo2 * createInfo,SubpassVector<VkSubpassDescription2> * subpassDesc)780 void SetRenderPassViewMask(Context *context,
781 const uint32_t *viewMask,
782 VkRenderPassCreateInfo2 *createInfo,
783 SubpassVector<VkSubpassDescription2> *subpassDesc)
784 {
785 for (VkSubpassDescription2 &subpass : *subpassDesc)
786 {
787 subpass.viewMask = *viewMask;
788 }
789
790 // For VR, the views are correlated, so this would be an optimization. However, an
791 // application can also use multiview for example to render to all 6 faces of a cubemap, in
792 // which case the views are actually not so correlated. In the absence of any hints from
793 // the application, we have to decide on one or the other. Since VR is more expensive, the
794 // views are marked as correlated to optimize that use case.
795 createInfo->correlatedViewMaskCount = 1;
796 createInfo->pCorrelatedViewMasks = viewMask;
797 }
798
ToAttachmentDesciption1(const VkAttachmentDescription2 & desc,VkAttachmentDescription * desc1Out)799 void ToAttachmentDesciption1(const VkAttachmentDescription2 &desc,
800 VkAttachmentDescription *desc1Out)
801 {
802 ASSERT(desc.pNext == nullptr);
803
804 *desc1Out = {};
805 desc1Out->flags = desc.flags;
806 desc1Out->format = desc.format;
807 desc1Out->samples = desc.samples;
808 desc1Out->loadOp = desc.loadOp;
809 desc1Out->storeOp = desc.storeOp;
810 desc1Out->stencilLoadOp = desc.stencilLoadOp;
811 desc1Out->stencilStoreOp = desc.stencilStoreOp;
812 desc1Out->initialLayout = desc.initialLayout;
813 desc1Out->finalLayout = desc.finalLayout;
814 }
815
ToAttachmentReference1(const VkAttachmentReference2 & ref,VkAttachmentReference * ref1Out)816 void ToAttachmentReference1(const VkAttachmentReference2 &ref, VkAttachmentReference *ref1Out)
817 {
818 ASSERT(ref.pNext == nullptr);
819
820 *ref1Out = {};
821 ref1Out->attachment = ref.attachment;
822 ref1Out->layout = ref.layout;
823 }
824
ToSubpassDescription1(const VkSubpassDescription2 & desc,const FramebufferAttachmentsVector<VkAttachmentReference> & inputRefs,const gl::DrawBuffersVector<VkAttachmentReference> & colorRefs,const gl::DrawBuffersVector<VkAttachmentReference> & resolveRefs,const VkAttachmentReference & depthStencilRef,VkSubpassDescription * desc1Out)825 void ToSubpassDescription1(const VkSubpassDescription2 &desc,
826 const FramebufferAttachmentsVector<VkAttachmentReference> &inputRefs,
827 const gl::DrawBuffersVector<VkAttachmentReference> &colorRefs,
828 const gl::DrawBuffersVector<VkAttachmentReference> &resolveRefs,
829 const VkAttachmentReference &depthStencilRef,
830 VkSubpassDescription *desc1Out)
831 {
832 ASSERT(desc.pNext == nullptr);
833
834 *desc1Out = {};
835 desc1Out->flags = desc.flags;
836 desc1Out->pipelineBindPoint = desc.pipelineBindPoint;
837 desc1Out->inputAttachmentCount = static_cast<uint32_t>(inputRefs.size());
838 desc1Out->pInputAttachments = !inputRefs.empty() ? inputRefs.data() : nullptr;
839 desc1Out->colorAttachmentCount = static_cast<uint32_t>(colorRefs.size());
840 desc1Out->pColorAttachments = !colorRefs.empty() ? colorRefs.data() : nullptr;
841 desc1Out->pResolveAttachments = !resolveRefs.empty() ? resolveRefs.data() : nullptr;
842 desc1Out->pDepthStencilAttachment = desc.pDepthStencilAttachment ? &depthStencilRef : nullptr;
843 desc1Out->preserveAttachmentCount = desc.preserveAttachmentCount;
844 desc1Out->pPreserveAttachments = desc.pPreserveAttachments;
845 }
846
ToSubpassDependency1(const VkSubpassDependency2 & dep,VkSubpassDependency * dep1Out)847 void ToSubpassDependency1(const VkSubpassDependency2 &dep, VkSubpassDependency *dep1Out)
848 {
849 ASSERT(dep.pNext == nullptr);
850
851 *dep1Out = {};
852 dep1Out->srcSubpass = dep.srcSubpass;
853 dep1Out->dstSubpass = dep.dstSubpass;
854 dep1Out->srcStageMask = dep.srcStageMask;
855 dep1Out->dstStageMask = dep.dstStageMask;
856 dep1Out->srcAccessMask = dep.srcAccessMask;
857 dep1Out->dstAccessMask = dep.dstAccessMask;
858 dep1Out->dependencyFlags = dep.dependencyFlags;
859 }
860
ToRenderPassMultiviewCreateInfo(const VkRenderPassCreateInfo2 & createInfo,VkRenderPassCreateInfo * createInfo1,SubpassVector<uint32_t> * viewMasks,VkRenderPassMultiviewCreateInfo * multiviewInfo)861 void ToRenderPassMultiviewCreateInfo(const VkRenderPassCreateInfo2 &createInfo,
862 VkRenderPassCreateInfo *createInfo1,
863 SubpassVector<uint32_t> *viewMasks,
864 VkRenderPassMultiviewCreateInfo *multiviewInfo)
865 {
866 ASSERT(createInfo.correlatedViewMaskCount == 1);
867 const uint32_t viewMask = createInfo.pCorrelatedViewMasks[0];
868
869 viewMasks->resize(createInfo.subpassCount, viewMask);
870
871 multiviewInfo->sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
872 multiviewInfo->subpassCount = createInfo.subpassCount;
873 multiviewInfo->pViewMasks = viewMasks->data();
874 multiviewInfo->correlationMaskCount = createInfo.correlatedViewMaskCount;
875 multiviewInfo->pCorrelationMasks = createInfo.pCorrelatedViewMasks;
876
877 AddToPNextChain(createInfo1, multiviewInfo);
878 }
879
CreateRenderPass1(Context * context,const VkRenderPassCreateInfo2 & createInfo,uint8_t viewCount,RenderPass * renderPass)880 angle::Result CreateRenderPass1(Context *context,
881 const VkRenderPassCreateInfo2 &createInfo,
882 uint8_t viewCount,
883 RenderPass *renderPass)
884 {
885 // Convert the attachments to VkAttachmentDescription.
886 FramebufferAttachmentArray<VkAttachmentDescription> attachmentDescs;
887 for (uint32_t index = 0; index < createInfo.attachmentCount; ++index)
888 {
889 ToAttachmentDesciption1(createInfo.pAttachments[index], &attachmentDescs[index]);
890 }
891
892 // Convert subpass attachments to VkAttachmentReference and the subpass description to
893 // VkSubpassDescription.
894 SubpassVector<FramebufferAttachmentsVector<VkAttachmentReference>> subpassInputAttachmentRefs(
895 createInfo.subpassCount);
896 SubpassVector<gl::DrawBuffersVector<VkAttachmentReference>> subpassColorAttachmentRefs(
897 createInfo.subpassCount);
898 SubpassVector<gl::DrawBuffersVector<VkAttachmentReference>> subpassResolveAttachmentRefs(
899 createInfo.subpassCount);
900 SubpassVector<VkAttachmentReference> subpassDepthStencilAttachmentRefs(createInfo.subpassCount);
901 SubpassVector<VkSubpassDescription> subpassDescriptions(createInfo.subpassCount);
902 for (uint32_t subpass = 0; subpass < createInfo.subpassCount; ++subpass)
903 {
904 const VkSubpassDescription2 &desc = createInfo.pSubpasses[subpass];
905 FramebufferAttachmentsVector<VkAttachmentReference> &inputRefs =
906 subpassInputAttachmentRefs[subpass];
907 gl::DrawBuffersVector<VkAttachmentReference> &colorRefs =
908 subpassColorAttachmentRefs[subpass];
909 gl::DrawBuffersVector<VkAttachmentReference> &resolveRefs =
910 subpassResolveAttachmentRefs[subpass];
911 VkAttachmentReference &depthStencilRef = subpassDepthStencilAttachmentRefs[subpass];
912
913 inputRefs.resize(desc.inputAttachmentCount);
914 colorRefs.resize(desc.colorAttachmentCount);
915
916 for (uint32_t index = 0; index < desc.inputAttachmentCount; ++index)
917 {
918 ToAttachmentReference1(desc.pInputAttachments[index], &inputRefs[index]);
919 }
920
921 for (uint32_t index = 0; index < desc.colorAttachmentCount; ++index)
922 {
923 ToAttachmentReference1(desc.pColorAttachments[index], &colorRefs[index]);
924 }
925 if (desc.pResolveAttachments)
926 {
927 resolveRefs.resize(desc.colorAttachmentCount);
928 for (uint32_t index = 0; index < desc.colorAttachmentCount; ++index)
929 {
930 ToAttachmentReference1(desc.pResolveAttachments[index], &resolveRefs[index]);
931 }
932 }
933 if (desc.pDepthStencilAttachment)
934 {
935 ToAttachmentReference1(*desc.pDepthStencilAttachment, &depthStencilRef);
936 }
937
938 // Convert subpass itself.
939 ToSubpassDescription1(desc, inputRefs, colorRefs, resolveRefs, depthStencilRef,
940 &subpassDescriptions[subpass]);
941 }
942
943 // Convert subpass dependencies to VkSubpassDependency.
944 std::vector<VkSubpassDependency> subpassDependencies(createInfo.dependencyCount);
945 for (uint32_t index = 0; index < createInfo.dependencyCount; ++index)
946 {
947 ToSubpassDependency1(createInfo.pDependencies[index], &subpassDependencies[index]);
948 }
949
950 // Convert CreateInfo itself
951 VkRenderPassCreateInfo createInfo1 = {};
952 createInfo1.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
953 createInfo1.flags = createInfo.flags;
954 createInfo1.attachmentCount = createInfo.attachmentCount;
955 createInfo1.pAttachments = attachmentDescs.data();
956 createInfo1.subpassCount = createInfo.subpassCount;
957 createInfo1.pSubpasses = subpassDescriptions.data();
958 createInfo1.dependencyCount = static_cast<uint32_t>(subpassDependencies.size());
959 createInfo1.pDependencies = !subpassDependencies.empty() ? subpassDependencies.data() : nullptr;
960
961 SubpassVector<uint32_t> viewMasks;
962 VkRenderPassMultiviewCreateInfo multiviewInfo = {};
963 if (viewCount > 0)
964 {
965 ToRenderPassMultiviewCreateInfo(createInfo, &createInfo1, &viewMasks, &multiviewInfo);
966 }
967
968 // Initialize the render pass.
969 ANGLE_VK_TRY(context, renderPass->init(context->getDevice(), createInfo1));
970
971 return angle::Result::Continue;
972 }
973
UpdateRenderPassColorPerfCounters(const VkRenderPassCreateInfo2 & createInfo,FramebufferAttachmentMask depthStencilAttachmentIndices,RenderPassPerfCounters * countersOut)974 void UpdateRenderPassColorPerfCounters(const VkRenderPassCreateInfo2 &createInfo,
975 FramebufferAttachmentMask depthStencilAttachmentIndices,
976 RenderPassPerfCounters *countersOut)
977 {
978 for (uint32_t index = 0; index < createInfo.attachmentCount; index++)
979 {
980 if (depthStencilAttachmentIndices.test(index))
981 {
982 continue;
983 }
984
985 VkAttachmentLoadOp loadOp = createInfo.pAttachments[index].loadOp;
986 VkAttachmentStoreOp storeOp = createInfo.pAttachments[index].storeOp;
987 countersOut->colorLoadOpClears += loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
988 countersOut->colorLoadOpLoads += loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
989 countersOut->colorLoadOpNones += loadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT ? 1 : 0;
990 countersOut->colorStoreOpStores += storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
991 countersOut->colorStoreOpNones += storeOp == VK_ATTACHMENT_STORE_OP_NONE_EXT ? 1 : 0;
992 }
993 }
994
UpdateSubpassColorPerfCounters(const VkRenderPassCreateInfo2 & createInfo,const VkSubpassDescription2 & subpass,RenderPassPerfCounters * countersOut)995 void UpdateSubpassColorPerfCounters(const VkRenderPassCreateInfo2 &createInfo,
996 const VkSubpassDescription2 &subpass,
997 RenderPassPerfCounters *countersOut)
998 {
999 // Color resolve counters.
1000 if (subpass.pResolveAttachments == nullptr)
1001 {
1002 return;
1003 }
1004
1005 for (uint32_t colorSubpassIndex = 0; colorSubpassIndex < subpass.colorAttachmentCount;
1006 ++colorSubpassIndex)
1007 {
1008 uint32_t resolveRenderPassIndex = subpass.pResolveAttachments[colorSubpassIndex].attachment;
1009
1010 if (resolveRenderPassIndex == VK_ATTACHMENT_UNUSED)
1011 {
1012 continue;
1013 }
1014
1015 ++countersOut->colorAttachmentResolves;
1016 }
1017 }
1018
UpdateRenderPassDepthStencilPerfCounters(const VkRenderPassCreateInfo2 & createInfo,size_t renderPassIndex,RenderPassPerfCounters * countersOut)1019 void UpdateRenderPassDepthStencilPerfCounters(const VkRenderPassCreateInfo2 &createInfo,
1020 size_t renderPassIndex,
1021 RenderPassPerfCounters *countersOut)
1022 {
1023 ASSERT(renderPassIndex != VK_ATTACHMENT_UNUSED);
1024
1025 // Depth/stencil ops counters.
1026 const VkAttachmentDescription2 &ds = createInfo.pAttachments[renderPassIndex];
1027
1028 countersOut->depthLoadOpClears += ds.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
1029 countersOut->depthLoadOpLoads += ds.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
1030 countersOut->depthLoadOpNones += ds.loadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT ? 1 : 0;
1031 countersOut->depthStoreOpStores += ds.storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
1032 countersOut->depthStoreOpNones += ds.storeOp == VK_ATTACHMENT_STORE_OP_NONE_EXT ? 1 : 0;
1033
1034 countersOut->stencilLoadOpClears += ds.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
1035 countersOut->stencilLoadOpLoads += ds.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
1036 countersOut->stencilLoadOpNones += ds.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_NONE_EXT ? 1 : 0;
1037 countersOut->stencilStoreOpStores += ds.stencilStoreOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
1038 countersOut->stencilStoreOpNones +=
1039 ds.stencilStoreOp == VK_ATTACHMENT_STORE_OP_NONE_EXT ? 1 : 0;
1040
1041 // Depth/stencil read-only mode.
1042 countersOut->readOnlyDepthStencil +=
1043 ds.finalLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL ? 1 : 0;
1044 }
1045
UpdateRenderPassDepthStencilResolvePerfCounters(const VkRenderPassCreateInfo2 & createInfo,const VkSubpassDescriptionDepthStencilResolve & depthStencilResolve,RenderPassPerfCounters * countersOut)1046 void UpdateRenderPassDepthStencilResolvePerfCounters(
1047 const VkRenderPassCreateInfo2 &createInfo,
1048 const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve,
1049 RenderPassPerfCounters *countersOut)
1050 {
1051 if (depthStencilResolve.pDepthStencilResolveAttachment == nullptr)
1052 {
1053 return;
1054 }
1055
1056 uint32_t resolveRenderPassIndex =
1057 depthStencilResolve.pDepthStencilResolveAttachment->attachment;
1058
1059 if (resolveRenderPassIndex == VK_ATTACHMENT_UNUSED)
1060 {
1061 return;
1062 }
1063
1064 const VkAttachmentDescription2 &dsResolve = createInfo.pAttachments[resolveRenderPassIndex];
1065
1066 // Resolve depth/stencil ops counters.
1067 countersOut->depthLoadOpClears += dsResolve.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
1068 countersOut->depthLoadOpLoads += dsResolve.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
1069 countersOut->depthStoreOpStores +=
1070 dsResolve.storeOp == static_cast<uint16_t>(RenderPassStoreOp::Store) ? 1 : 0;
1071
1072 countersOut->stencilLoadOpClears +=
1073 dsResolve.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
1074 countersOut->stencilLoadOpLoads +=
1075 dsResolve.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
1076 countersOut->stencilStoreOpStores +=
1077 dsResolve.stencilStoreOp == static_cast<uint16_t>(RenderPassStoreOp::Store) ? 1 : 0;
1078
1079 // Depth/stencil resolve counters.
1080 countersOut->depthAttachmentResolves +=
1081 depthStencilResolve.depthResolveMode != VK_RESOLVE_MODE_NONE ? 1 : 0;
1082 countersOut->stencilAttachmentResolves +=
1083 depthStencilResolve.stencilResolveMode != VK_RESOLVE_MODE_NONE ? 1 : 0;
1084 }
1085
UpdateRenderPassPerfCounters(const RenderPassDesc & desc,const VkRenderPassCreateInfo2 & createInfo,const VkSubpassDescriptionDepthStencilResolve & depthStencilResolve,RenderPassPerfCounters * countersOut)1086 void UpdateRenderPassPerfCounters(
1087 const RenderPassDesc &desc,
1088 const VkRenderPassCreateInfo2 &createInfo,
1089 const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve,
1090 RenderPassPerfCounters *countersOut)
1091 {
1092 // Accumulate depth/stencil attachment indices in all subpasses to avoid double-counting
1093 // counters.
1094 FramebufferAttachmentMask depthStencilAttachmentIndices;
1095
1096 for (uint32_t subpassIndex = 0; subpassIndex < createInfo.subpassCount; ++subpassIndex)
1097 {
1098 const VkSubpassDescription2 &subpass = createInfo.pSubpasses[subpassIndex];
1099
1100 // Color counters.
1101 // NOTE: For simplicity, this will accumulate counts for all subpasses in the renderpass.
1102 UpdateSubpassColorPerfCounters(createInfo, subpass, countersOut);
1103
1104 // Record index of depth/stencil attachment.
1105 if (subpass.pDepthStencilAttachment != nullptr)
1106 {
1107 uint32_t attachmentRenderPassIndex = subpass.pDepthStencilAttachment->attachment;
1108 if (attachmentRenderPassIndex != VK_ATTACHMENT_UNUSED)
1109 {
1110 depthStencilAttachmentIndices.set(attachmentRenderPassIndex);
1111 }
1112 }
1113 }
1114
1115 UpdateRenderPassColorPerfCounters(createInfo, depthStencilAttachmentIndices, countersOut);
1116
1117 // Depth/stencil counters. Currently, both subpasses use the same depth/stencil attachment (if
1118 // any).
1119 ASSERT(depthStencilAttachmentIndices.count() <= 1);
1120 for (size_t attachmentRenderPassIndex : depthStencilAttachmentIndices)
1121 {
1122 UpdateRenderPassDepthStencilPerfCounters(createInfo, attachmentRenderPassIndex,
1123 countersOut);
1124 }
1125
1126 UpdateRenderPassDepthStencilResolvePerfCounters(createInfo, depthStencilResolve, countersOut);
1127
1128 // Determine unresolve counters from the render pass desc, to avoid making guesses from subpass
1129 // count etc.
1130 countersOut->colorAttachmentUnresolves += desc.getColorUnresolveAttachmentMask().count();
1131 countersOut->depthAttachmentUnresolves += desc.hasDepthUnresolveAttachment() ? 1 : 0;
1132 countersOut->stencilAttachmentUnresolves += desc.hasStencilUnresolveAttachment() ? 1 : 0;
1133 }
1134
InitializeRenderPassFromDesc(ContextVk * contextVk,const RenderPassDesc & desc,const AttachmentOpsArray & ops,RenderPassHelper * renderPassHelper)1135 angle::Result InitializeRenderPassFromDesc(ContextVk *contextVk,
1136 const RenderPassDesc &desc,
1137 const AttachmentOpsArray &ops,
1138 RenderPassHelper *renderPassHelper)
1139 {
1140 constexpr VkAttachmentReference2 kUnusedAttachment = {VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
1141 nullptr, VK_ATTACHMENT_UNUSED,
1142 VK_IMAGE_LAYOUT_UNDEFINED, 0};
1143
1144 const bool needInputAttachments = desc.hasFramebufferFetch();
1145 const bool isRenderToTextureThroughExtension =
1146 desc.isRenderToTexture() &&
1147 (contextVk->getFeatures().supportsMultisampledRenderToSingleSampled.enabled ||
1148 contextVk->getFeatures().supportsMultisampledRenderToSingleSampledGOOGLEX.enabled);
1149 const bool isRenderToTextureThroughEmulation =
1150 desc.isRenderToTexture() && !isRenderToTextureThroughExtension;
1151
1152 const uint8_t descSamples = desc.samples();
1153 const uint8_t attachmentSamples = isRenderToTextureThroughExtension ? 1 : descSamples;
1154 const uint8_t renderToTextureSamples = isRenderToTextureThroughExtension ? descSamples : 1;
1155
1156 // Unpack the packed and split representation into the format required by Vulkan.
1157 gl::DrawBuffersVector<VkAttachmentReference2> colorAttachmentRefs;
1158 gl::DrawBuffersVector<VkAttachmentReference2> colorResolveAttachmentRefs;
1159 VkAttachmentReference2 depthStencilAttachmentRef = kUnusedAttachment;
1160 VkAttachmentReference2 depthStencilResolveAttachmentRef = kUnusedAttachment;
1161
1162 // The list of attachments includes all non-resolve and resolve attachments.
1163 FramebufferAttachmentArray<VkAttachmentDescription2> attachmentDescs;
1164
1165 // Track invalidated attachments so their resolve attachments can be invalidated as well.
1166 // Resolve attachments can be removed in that case if the render pass has only one subpass
1167 // (which is the case if there are no unresolve attachments).
1168 gl::DrawBufferMask isColorInvalidated;
1169 bool isDepthInvalidated = false;
1170 bool isStencilInvalidated = false;
1171 const bool hasUnresolveAttachments =
1172 desc.getColorUnresolveAttachmentMask().any() || desc.hasDepthStencilUnresolveAttachment();
1173 const bool canRemoveResolveAttachments =
1174 isRenderToTextureThroughEmulation && !hasUnresolveAttachments;
1175
1176 // Pack color attachments
1177 PackedAttachmentIndex attachmentCount(0);
1178 for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
1179 {
1180 // Vulkan says:
1181 //
1182 // > Each element of the pColorAttachments array corresponds to an output location in the
1183 // > shader, i.e. if the shader declares an output variable decorated with a Location value
1184 // > of X, then it uses the attachment provided in pColorAttachments[X].
1185 //
1186 // This means that colorAttachmentRefs is indexed by colorIndexGL. Where the color
1187 // attachment is disabled, a reference with VK_ATTACHMENT_UNUSED is given.
1188
1189 if (!desc.isColorAttachmentEnabled(colorIndexGL))
1190 {
1191 colorAttachmentRefs.push_back(kUnusedAttachment);
1192 continue;
1193 }
1194
1195 angle::FormatID attachmentFormatID = desc[colorIndexGL];
1196 ASSERT(attachmentFormatID != angle::FormatID::NONE);
1197
1198 VkAttachmentReference2 colorRef = {};
1199 colorRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
1200 colorRef.attachment = attachmentCount.get();
1201 colorRef.layout =
1202 needInputAttachments
1203 ? VK_IMAGE_LAYOUT_GENERAL
1204 : ConvertImageLayoutToVkImageLayout(
1205 contextVk, static_cast<ImageLayout>(ops[attachmentCount].initialLayout));
1206 colorRef.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1207 colorAttachmentRefs.push_back(colorRef);
1208
1209 UnpackAttachmentDesc(contextVk, &attachmentDescs[attachmentCount.get()], attachmentFormatID,
1210 attachmentSamples, ops[attachmentCount]);
1211
1212 // If this renderpass uses EXT_srgb_write_control, we need to override the format to its
1213 // linear counterpart. Formats that cannot be reinterpreted are exempt from this
1214 // requirement.
1215 angle::FormatID linearFormat = rx::ConvertToLinear(attachmentFormatID);
1216 if (linearFormat != angle::FormatID::NONE)
1217 {
1218 if (desc.getSRGBWriteControlMode() == gl::SrgbWriteControlMode::Linear)
1219 {
1220 attachmentFormatID = linearFormat;
1221 }
1222 }
1223 attachmentDescs[attachmentCount.get()].format = GetVkFormatFromFormatID(attachmentFormatID);
1224 ASSERT(attachmentDescs[attachmentCount.get()].format != VK_FORMAT_UNDEFINED);
1225
1226 isColorInvalidated.set(colorIndexGL, ops[attachmentCount].isInvalidated);
1227
1228 ++attachmentCount;
1229 }
1230
1231 // Pack depth/stencil attachment, if any
1232 if (desc.hasDepthStencilAttachment())
1233 {
1234 uint32_t depthStencilIndexGL = static_cast<uint32_t>(desc.depthStencilAttachmentIndex());
1235
1236 angle::FormatID attachmentFormatID = desc[depthStencilIndexGL];
1237 ASSERT(attachmentFormatID != angle::FormatID::NONE);
1238
1239 depthStencilAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
1240 depthStencilAttachmentRef.attachment = attachmentCount.get();
1241 depthStencilAttachmentRef.layout = ConvertImageLayoutToVkImageLayout(
1242 contextVk, static_cast<ImageLayout>(ops[attachmentCount].initialLayout));
1243 depthStencilAttachmentRef.aspectMask =
1244 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1245
1246 UnpackAttachmentDesc(contextVk, &attachmentDescs[attachmentCount.get()], attachmentFormatID,
1247 attachmentSamples, ops[attachmentCount]);
1248
1249 isDepthInvalidated = ops[attachmentCount].isInvalidated;
1250 isStencilInvalidated = ops[attachmentCount].isStencilInvalidated;
1251
1252 ++attachmentCount;
1253 }
1254
1255 // Pack color resolve attachments
1256 const uint32_t nonResolveAttachmentCount = attachmentCount.get();
1257 for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
1258 {
1259 if (!desc.hasColorResolveAttachment(colorIndexGL))
1260 {
1261 colorResolveAttachmentRefs.push_back(kUnusedAttachment);
1262 continue;
1263 }
1264
1265 ASSERT(desc.isColorAttachmentEnabled(colorIndexGL));
1266
1267 angle::FormatID attachmentFormatID = desc[colorIndexGL];
1268
1269 VkAttachmentReference2 colorRef = {};
1270 colorRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
1271 colorRef.attachment = attachmentCount.get();
1272 colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1273 colorRef.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1274
1275 // If color attachment is invalidated, try to remove its resolve attachment altogether.
1276 if (canRemoveResolveAttachments && isColorInvalidated.test(colorIndexGL))
1277 {
1278 colorResolveAttachmentRefs.push_back(kUnusedAttachment);
1279 }
1280 else
1281 {
1282 colorResolveAttachmentRefs.push_back(colorRef);
1283 }
1284
1285 // When multisampled-render-to-texture is used, invalidating an attachment invalidates both
1286 // the multisampled and the resolve attachments. Otherwise, the resolve attachment is
1287 // independent of the multisampled attachment, and is never invalidated.
1288 UnpackColorResolveAttachmentDesc(
1289 &attachmentDescs[attachmentCount.get()], attachmentFormatID,
1290 desc.hasColorUnresolveAttachment(colorIndexGL),
1291 isColorInvalidated.test(colorIndexGL) && isRenderToTextureThroughEmulation);
1292
1293 ++attachmentCount;
1294 }
1295
1296 // Pack depth/stencil resolve attachment, if any
1297 if (desc.hasDepthStencilResolveAttachment())
1298 {
1299 ASSERT(desc.hasDepthStencilAttachment());
1300
1301 uint32_t depthStencilIndexGL = static_cast<uint32_t>(desc.depthStencilAttachmentIndex());
1302
1303 angle::FormatID attachmentFormatID = desc[depthStencilIndexGL];
1304 const angle::Format &angleFormat = angle::Format::Get(attachmentFormatID);
1305
1306 // Treat missing aspect as invalidated for the purpose of the resolve attachment.
1307 if (angleFormat.depthBits == 0)
1308 {
1309 isDepthInvalidated = true;
1310 }
1311 if (angleFormat.stencilBits == 0)
1312 {
1313 isStencilInvalidated = true;
1314 }
1315
1316 depthStencilResolveAttachmentRef.attachment = attachmentCount.get();
1317 depthStencilResolveAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1318 depthStencilResolveAttachmentRef.aspectMask = 0;
1319
1320 if (!isDepthInvalidated)
1321 {
1322 depthStencilResolveAttachmentRef.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
1323 }
1324 if (!isStencilInvalidated)
1325 {
1326 depthStencilResolveAttachmentRef.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
1327 }
1328
1329 UnpackDepthStencilResolveAttachmentDesc(
1330 &attachmentDescs[attachmentCount.get()], attachmentFormatID,
1331 desc.hasDepthUnresolveAttachment(), desc.hasStencilUnresolveAttachment(),
1332 isDepthInvalidated, isStencilInvalidated);
1333
1334 ++attachmentCount;
1335 }
1336
1337 SubpassVector<VkSubpassDescription2> subpassDesc;
1338
1339 // If any attachment needs to be unresolved, create an initial subpass for this purpose. Note
1340 // that the following arrays are used in initializing a VkSubpassDescription2 in subpassDesc,
1341 // which is in turn used in VkRenderPassCreateInfo below. That is why they are declared in the
1342 // same scope.
1343 gl::DrawBuffersVector<VkAttachmentReference2> unresolveColorAttachmentRefs;
1344 VkAttachmentReference2 unresolveDepthStencilAttachmentRef = kUnusedAttachment;
1345 FramebufferAttachmentsVector<VkAttachmentReference2> unresolveInputAttachmentRefs;
1346 FramebufferAttachmentsVector<uint32_t> unresolvePreserveAttachmentRefs;
1347 if (hasUnresolveAttachments)
1348 {
1349 subpassDesc.push_back({});
1350 InitializeUnresolveSubpass(
1351 desc, colorAttachmentRefs, colorResolveAttachmentRefs, depthStencilAttachmentRef,
1352 depthStencilResolveAttachmentRef, &unresolveColorAttachmentRefs,
1353 &unresolveDepthStencilAttachmentRef, &unresolveInputAttachmentRefs,
1354 &unresolvePreserveAttachmentRefs, &subpassDesc.back());
1355 }
1356
1357 subpassDesc.push_back({});
1358 VkSubpassDescription2 *applicationSubpass = &subpassDesc.back();
1359
1360 applicationSubpass->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
1361 applicationSubpass->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1362 applicationSubpass->inputAttachmentCount =
1363 needInputAttachments ? static_cast<uint32_t>(colorAttachmentRefs.size()) : 0;
1364 applicationSubpass->pInputAttachments =
1365 needInputAttachments ? colorAttachmentRefs.data() : nullptr;
1366 applicationSubpass->colorAttachmentCount = static_cast<uint32_t>(colorAttachmentRefs.size());
1367 applicationSubpass->pColorAttachments = colorAttachmentRefs.data();
1368 applicationSubpass->pResolveAttachments = attachmentCount.get() > nonResolveAttachmentCount
1369 ? colorResolveAttachmentRefs.data()
1370 : nullptr;
1371 applicationSubpass->pDepthStencilAttachment =
1372 (depthStencilAttachmentRef.attachment != VK_ATTACHMENT_UNUSED ? &depthStencilAttachmentRef
1373 : nullptr);
1374
1375 // Specify rasterization order for color on the subpass when available and
1376 // there is framebuffer fetch. This is required when the corresponding
1377 // flag is set on the pipeline.
1378 if (contextVk->getFeatures().supportsRasterizationOrderAttachmentAccess.enabled &&
1379 desc.hasFramebufferFetch())
1380 {
1381 for (VkSubpassDescription2 &subpass : subpassDesc)
1382 {
1383 subpass.flags |=
1384 VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT;
1385 }
1386 }
1387
1388 if (contextVk->getFeatures().supportsLegacyDithering.enabled && desc.isLegacyDitherEnabled())
1389 {
1390 subpassDesc.back().flags |= VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT;
1391 }
1392
1393 // If depth/stencil is to be resolved, add a VkSubpassDescriptionDepthStencilResolve to the
1394 // pNext chain of the subpass description.
1395 VkSubpassDescriptionDepthStencilResolve depthStencilResolve = {};
1396 VkSubpassDescriptionDepthStencilResolve msrtssResolve = {};
1397 VkMultisampledRenderToSingleSampledInfoEXT msrtss = {};
1398 VkMultisampledRenderToSingleSampledInfoGOOGLEX msrtssGOOGLEX = {};
1399 if (desc.hasDepthStencilResolveAttachment())
1400 {
1401 ASSERT(!isRenderToTextureThroughExtension);
1402
1403 depthStencilResolve.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
1404 depthStencilResolve.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1405 depthStencilResolve.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
1406
1407 // If depth/stencil attachment is invalidated, try to remove its resolve attachment
1408 // altogether.
1409 const bool removeDepthStencilResolve =
1410 canRemoveResolveAttachments && isDepthInvalidated && isStencilInvalidated;
1411 if (!removeDepthStencilResolve)
1412 {
1413 depthStencilResolve.pDepthStencilResolveAttachment = &depthStencilResolveAttachmentRef;
1414 AddToPNextChain(&subpassDesc.back(), &depthStencilResolve);
1415 }
1416 }
1417 else if (isRenderToTextureThroughExtension)
1418 {
1419 ASSERT(subpassDesc.size() == 1);
1420 InitializeMSRTSS(contextVk, renderToTextureSamples, &subpassDesc.back(), &msrtssResolve,
1421 &msrtss, &msrtssGOOGLEX);
1422 }
1423
1424 std::vector<VkSubpassDependency2> subpassDependencies;
1425 if (hasUnresolveAttachments)
1426 {
1427 InitializeUnresolveSubpassDependencies(
1428 subpassDesc, desc.getColorUnresolveAttachmentMask().any(),
1429 desc.hasDepthStencilUnresolveAttachment(), &subpassDependencies);
1430 }
1431
1432 const uint32_t drawSubpassIndex = static_cast<uint32_t>(subpassDesc.size()) - 1;
1433 InitializeDefaultSubpassSelfDependencies(contextVk, desc, drawSubpassIndex,
1434 &subpassDependencies);
1435
1436 VkRenderPassCreateInfo2 createInfo = {};
1437 createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2;
1438 createInfo.attachmentCount = attachmentCount.get();
1439 createInfo.pAttachments = attachmentDescs.data();
1440 createInfo.subpassCount = static_cast<uint32_t>(subpassDesc.size());
1441 createInfo.pSubpasses = subpassDesc.data();
1442
1443 if (!subpassDependencies.empty())
1444 {
1445 createInfo.dependencyCount = static_cast<uint32_t>(subpassDependencies.size());
1446 createInfo.pDependencies = subpassDependencies.data();
1447 }
1448
1449 const uint32_t viewMask = angle::BitMask<uint32_t>(desc.viewCount());
1450 if (desc.viewCount() > 0)
1451 {
1452 SetRenderPassViewMask(contextVk, &viewMask, &createInfo, &subpassDesc);
1453 }
1454
1455 // If VK_KHR_create_renderpass2 is not supported, we must use core Vulkan 1.0. This is
1456 // increasingly uncommon. Note that extensions that require chaining information to subpasses
1457 // are automatically not used when this extension is not available.
1458 if (!contextVk->getFeatures().supportsRenderpass2.enabled)
1459 {
1460 ANGLE_TRY(CreateRenderPass1(contextVk, createInfo, desc.viewCount(),
1461 &renderPassHelper->getRenderPass()));
1462 }
1463 else
1464 {
1465 ANGLE_VK_TRY(contextVk,
1466 renderPassHelper->getRenderPass().init2(contextVk->getDevice(), createInfo));
1467 }
1468
1469 // Calculate perf counters associated with this render pass, such as load/store ops, unresolve
1470 // and resolve operations etc. This information is taken out of the render pass create info.
1471 // Depth/stencil resolve attachment uses RenderPass2 structures, so it's passed in separately.
1472 UpdateRenderPassPerfCounters(desc, createInfo, depthStencilResolve,
1473 &renderPassHelper->getPerfCounters());
1474
1475 return angle::Result::Continue;
1476 }
1477
GetRenderPassAndUpdateCounters(ContextVk * contextVk,bool updatePerfCounters,RenderPassHelper * renderPassHelper,const RenderPass ** renderPassOut)1478 void GetRenderPassAndUpdateCounters(ContextVk *contextVk,
1479 bool updatePerfCounters,
1480 RenderPassHelper *renderPassHelper,
1481 const RenderPass **renderPassOut)
1482 {
1483 *renderPassOut = &renderPassHelper->getRenderPass();
1484 if (updatePerfCounters)
1485 {
1486 angle::VulkanPerfCounters &counters = contextVk->getPerfCounters();
1487 const RenderPassPerfCounters &rpCounters = renderPassHelper->getPerfCounters();
1488
1489 counters.colorLoadOpClears += rpCounters.colorLoadOpClears;
1490 counters.colorLoadOpLoads += rpCounters.colorLoadOpLoads;
1491 counters.colorLoadOpNones += rpCounters.colorLoadOpNones;
1492 counters.colorStoreOpStores += rpCounters.colorStoreOpStores;
1493 counters.colorStoreOpNones += rpCounters.colorStoreOpNones;
1494 counters.depthLoadOpClears += rpCounters.depthLoadOpClears;
1495 counters.depthLoadOpLoads += rpCounters.depthLoadOpLoads;
1496 counters.depthLoadOpNones += rpCounters.depthLoadOpNones;
1497 counters.depthStoreOpStores += rpCounters.depthStoreOpStores;
1498 counters.depthStoreOpNones += rpCounters.depthStoreOpNones;
1499 counters.stencilLoadOpClears += rpCounters.stencilLoadOpClears;
1500 counters.stencilLoadOpLoads += rpCounters.stencilLoadOpLoads;
1501 counters.stencilLoadOpNones += rpCounters.stencilLoadOpNones;
1502 counters.stencilStoreOpStores += rpCounters.stencilStoreOpStores;
1503 counters.stencilStoreOpNones += rpCounters.stencilStoreOpNones;
1504 counters.colorAttachmentUnresolves += rpCounters.colorAttachmentUnresolves;
1505 counters.colorAttachmentResolves += rpCounters.colorAttachmentResolves;
1506 counters.depthAttachmentUnresolves += rpCounters.depthAttachmentUnresolves;
1507 counters.depthAttachmentResolves += rpCounters.depthAttachmentResolves;
1508 counters.stencilAttachmentUnresolves += rpCounters.stencilAttachmentUnresolves;
1509 counters.stencilAttachmentResolves += rpCounters.stencilAttachmentResolves;
1510 counters.readOnlyDepthStencilRenderPasses += rpCounters.readOnlyDepthStencil;
1511 }
1512 }
1513
InitializeSpecializationInfo(const SpecializationConstants & specConsts,SpecializationConstantMap<VkSpecializationMapEntry> * specializationEntriesOut,VkSpecializationInfo * specializationInfoOut)1514 void InitializeSpecializationInfo(
1515 const SpecializationConstants &specConsts,
1516 SpecializationConstantMap<VkSpecializationMapEntry> *specializationEntriesOut,
1517 VkSpecializationInfo *specializationInfoOut)
1518 {
1519 // Collect specialization constants.
1520 for (const sh::vk::SpecializationConstantId id :
1521 angle::AllEnums<sh::vk::SpecializationConstantId>())
1522 {
1523 (*specializationEntriesOut)[id].constantID = static_cast<uint32_t>(id);
1524 switch (id)
1525 {
1526 case sh::vk::SpecializationConstantId::SurfaceRotation:
1527 (*specializationEntriesOut)[id].offset =
1528 offsetof(SpecializationConstants, surfaceRotation);
1529 (*specializationEntriesOut)[id].size = sizeof(specConsts.surfaceRotation);
1530 break;
1531 case sh::vk::SpecializationConstantId::Dither:
1532 (*specializationEntriesOut)[id].offset =
1533 offsetof(vk::SpecializationConstants, dither);
1534 (*specializationEntriesOut)[id].size = sizeof(specConsts.dither);
1535 break;
1536 default:
1537 UNREACHABLE();
1538 break;
1539 }
1540 }
1541
1542 specializationInfoOut->mapEntryCount = static_cast<uint32_t>(specializationEntriesOut->size());
1543 specializationInfoOut->pMapEntries = specializationEntriesOut->data();
1544 specializationInfoOut->dataSize = sizeof(specConsts);
1545 specializationInfoOut->pData = &specConsts;
1546 }
1547
1548 // Utility for setting a value on a packed 4-bit integer array.
1549 template <typename SrcT>
Int4Array_Set(uint8_t * arrayBytes,uint32_t arrayIndex,SrcT value)1550 void Int4Array_Set(uint8_t *arrayBytes, uint32_t arrayIndex, SrcT value)
1551 {
1552 uint32_t byteIndex = arrayIndex >> 1;
1553 ASSERT(value < 16);
1554
1555 if ((arrayIndex & 1) == 0)
1556 {
1557 arrayBytes[byteIndex] &= 0xF0;
1558 arrayBytes[byteIndex] |= static_cast<uint8_t>(value);
1559 }
1560 else
1561 {
1562 arrayBytes[byteIndex] &= 0x0F;
1563 arrayBytes[byteIndex] |= static_cast<uint8_t>(value) << 4;
1564 }
1565 }
1566
1567 // Utility for getting a value from a packed 4-bit integer array.
1568 template <typename DestT>
Int4Array_Get(const uint8_t * arrayBytes,uint32_t arrayIndex)1569 DestT Int4Array_Get(const uint8_t *arrayBytes, uint32_t arrayIndex)
1570 {
1571 uint32_t byteIndex = arrayIndex >> 1;
1572
1573 if ((arrayIndex & 1) == 0)
1574 {
1575 return static_cast<DestT>(arrayBytes[byteIndex] & 0xF);
1576 }
1577 else
1578 {
1579 return static_cast<DestT>(arrayBytes[byteIndex] >> 4);
1580 }
1581 }
1582
1583 // When converting a byte number to a transition bit index we can shift instead of divide.
1584 constexpr size_t kTransitionByteShift = Log2(kGraphicsPipelineDirtyBitBytes);
1585
1586 // When converting a number of bits offset to a transition bit index we can also shift.
1587 constexpr size_t kBitsPerByte = 8;
1588 constexpr size_t kTransitionBitShift = kTransitionByteShift + Log2(kBitsPerByte);
1589
1590 // Helper macro to map from a PipelineDesc struct and field to a dirty bit index.
1591 // Uses the 'offsetof' macro to compute the offset 'Member' within the PipelineDesc.
1592 // We can optimize the dirty bit setting by computing the shifted dirty bit at compile time instead
1593 // of calling "set".
1594 #define ANGLE_GET_TRANSITION_BIT(Member) \
1595 (offsetof(GraphicsPipelineDesc, Member) >> kTransitionByteShift)
1596
1597 // Indexed dirty bits cannot be entirely computed at compile time since the index is passed to
1598 // the update function.
1599 #define ANGLE_GET_INDEXED_TRANSITION_BIT(Member, Index, BitWidth) \
1600 (((BitWidth * Index) >> kTransitionBitShift) + ANGLE_GET_TRANSITION_BIT(Member))
1601
1602 constexpr char kDescriptorTypeNameMap[][30] = {"sampler",
1603 "combined image sampler",
1604 "sampled image",
1605 "storage image",
1606 "uniform texel buffer",
1607 "storage texel buffer",
1608 "uniform buffer",
1609 "storage buffer",
1610 "uniform buffer dynamic",
1611 "storage buffer dynamic",
1612 "input attachment"};
1613
1614 // Helpers for creating a readable dump of the graphics pipeline graph. Each program generates a
1615 // group of nodes. The group's description is the common state among all nodes. Each node contains
1616 // the diff with the shared state. Arrows between nodes indicate the GraphicsPipelineTransitionBits
1617 // that have caused the transition. State that is 0 is not output for brevity.
1618 enum class PipelineState
1619 {
1620 VertexAttribFormat,
1621 VertexAttribDivisor = VertexAttribFormat + gl::MAX_VERTEX_ATTRIBS,
1622 VertexAttribOffset = VertexAttribDivisor + gl::MAX_VERTEX_ATTRIBS,
1623 VertexAttribStride = VertexAttribOffset + gl::MAX_VERTEX_ATTRIBS,
1624 VertexAttribCompressed = VertexAttribStride + gl::MAX_VERTEX_ATTRIBS,
1625 VertexAttribShaderComponentType = VertexAttribCompressed + gl::MAX_VERTEX_ATTRIBS,
1626 RenderPassSamples = VertexAttribShaderComponentType + gl::MAX_VERTEX_ATTRIBS,
1627 RenderPassColorAttachmentRange,
1628 RenderPassViewCount,
1629 RenderPassSrgbWriteControl,
1630 RenderPassHasFramebufferFetch,
1631 RenderPassIsRenderToTexture,
1632 RenderPassResolveDepthStencil,
1633 RenderPassUnresolveDepth,
1634 RenderPassUnresolveStencil,
1635 RenderPassColorResolveMask,
1636 RenderPassColorUnresolveMask,
1637 RenderPassColorFormat,
1638 RenderPassDepthStencilFormat = RenderPassColorFormat + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1639 Subpass,
1640 Topology,
1641 PatchVertices,
1642 PrimitiveRestartEnable,
1643 PolygonMode,
1644 CullMode,
1645 FrontFace,
1646 SurfaceRotation,
1647 ViewportNegativeOneToOne,
1648 SampleShadingEnable,
1649 RasterizationSamples,
1650 MinSampleShading,
1651 SampleMask,
1652 AlphaToCoverageEnable,
1653 AlphaToOneEnable,
1654 LogicOpEnable,
1655 LogicOp,
1656 RasterizerDiscardEnable,
1657 ColorWriteMask,
1658 BlendEnableMask = ColorWriteMask + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1659 MissingOutputsMask,
1660 SrcColorBlendFactor,
1661 DstColorBlendFactor = SrcColorBlendFactor + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1662 ColorBlendOp = DstColorBlendFactor + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1663 SrcAlphaBlendFactor = ColorBlendOp + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1664 DstAlphaBlendFactor = SrcAlphaBlendFactor + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1665 AlphaBlendOp = DstAlphaBlendFactor + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1666 EmulatedDitherControl = AlphaBlendOp + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
1667 DepthClampEnable,
1668 DepthBoundsTest,
1669 DepthCompareOp,
1670 DepthTest,
1671 DepthWrite,
1672 StencilTest,
1673 DepthBiasEnable,
1674 StencilOpFailFront,
1675 StencilOpPassFront,
1676 StencilOpDepthFailFront,
1677 StencilCompareFront,
1678 StencilOpFailBack,
1679 StencilOpPassBack,
1680 StencilOpDepthFailBack,
1681 StencilCompareBack,
1682
1683 InvalidEnum,
1684 EnumCount = InvalidEnum,
1685 };
1686
1687 using UnpackedPipelineState = angle::PackedEnumMap<PipelineState, uint32_t>;
1688 using PipelineStateBitSet = angle::BitSetArray<angle::EnumSize<PipelineState>()>;
1689
UnpackPipelineState(const GraphicsPipelineDesc & state,GraphicsPipelineSubset subset,UnpackedPipelineState * valuesOut)1690 [[maybe_unused]] void UnpackPipelineState(const GraphicsPipelineDesc &state,
1691 GraphicsPipelineSubset subset,
1692 UnpackedPipelineState *valuesOut)
1693 {
1694 const bool hasVertexInput = GraphicsPipelineHasVertexInput(subset);
1695 const bool hasShaders = GraphicsPipelineHasShaders(subset);
1696 const bool hasShadersOrFragmentOutput = GraphicsPipelineHasShadersOrFragmentOutput(subset);
1697 const bool hasFragmentOutput = GraphicsPipelineHasFragmentOutput(subset);
1698
1699 valuesOut->fill(0);
1700
1701 if (hasVertexInput)
1702 {
1703 const PipelineVertexInputState &vertexInputState = state.getVertexInputStateForLog();
1704
1705 const PackedVertexInputAttributes &vertex = vertexInputState.vertex;
1706 uint32_t *vaFormats = &(*valuesOut)[PipelineState::VertexAttribFormat];
1707 uint32_t *vaDivisors = &(*valuesOut)[PipelineState::VertexAttribDivisor];
1708 uint32_t *vaOffsets = &(*valuesOut)[PipelineState::VertexAttribOffset];
1709 uint32_t *vaStrides = &(*valuesOut)[PipelineState::VertexAttribStride];
1710 uint32_t *vaCompressed = &(*valuesOut)[PipelineState::VertexAttribCompressed];
1711 uint32_t *vaShaderComponentType =
1712 &(*valuesOut)[PipelineState::VertexAttribShaderComponentType];
1713 for (uint32_t attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
1714 {
1715 vaFormats[attribIndex] = vertex.attribs[attribIndex].format;
1716 vaDivisors[attribIndex] = vertex.attribs[attribIndex].divisor;
1717 vaOffsets[attribIndex] = vertex.attribs[attribIndex].offset;
1718 vaStrides[attribIndex] = vertex.strides[attribIndex];
1719 vaCompressed[attribIndex] = vertex.attribs[attribIndex].compressed;
1720
1721 gl::ComponentType componentType = gl::GetComponentTypeMask(
1722 gl::ComponentTypeMask(vertex.shaderAttribComponentType), attribIndex);
1723 vaShaderComponentType[attribIndex] = componentType == gl::ComponentType::InvalidEnum
1724 ? 0
1725 : static_cast<uint32_t>(componentType);
1726 }
1727
1728 const PackedInputAssemblyState &inputAssembly = vertexInputState.inputAssembly;
1729 (*valuesOut)[PipelineState::Topology] = inputAssembly.bits.topology;
1730 (*valuesOut)[PipelineState::PrimitiveRestartEnable] =
1731 inputAssembly.bits.primitiveRestartEnable;
1732 }
1733
1734 if (hasShaders)
1735 {
1736 const PipelineShadersState &shadersState = state.getShadersStateForLog();
1737
1738 const PackedPreRasterizationAndFragmentStates &shaders = shadersState.shaders;
1739 (*valuesOut)[PipelineState::ViewportNegativeOneToOne] =
1740 shaders.bits.viewportNegativeOneToOne;
1741 (*valuesOut)[PipelineState::DepthClampEnable] = shaders.bits.depthClampEnable;
1742 (*valuesOut)[PipelineState::PolygonMode] = shaders.bits.polygonMode;
1743 (*valuesOut)[PipelineState::CullMode] = shaders.bits.cullMode;
1744 (*valuesOut)[PipelineState::FrontFace] = shaders.bits.frontFace;
1745 (*valuesOut)[PipelineState::RasterizerDiscardEnable] = shaders.bits.rasterizerDiscardEnable;
1746 (*valuesOut)[PipelineState::DepthBiasEnable] = shaders.bits.depthBiasEnable;
1747 (*valuesOut)[PipelineState::PatchVertices] = shaders.bits.patchVertices;
1748 (*valuesOut)[PipelineState::DepthBoundsTest] = shaders.bits.depthBoundsTest;
1749 (*valuesOut)[PipelineState::DepthTest] = shaders.bits.depthTest;
1750 (*valuesOut)[PipelineState::DepthWrite] = shaders.bits.depthWrite;
1751 (*valuesOut)[PipelineState::StencilTest] = shaders.bits.stencilTest;
1752 (*valuesOut)[PipelineState::DepthCompareOp] = shaders.bits.depthCompareOp;
1753 (*valuesOut)[PipelineState::SurfaceRotation] = shaders.bits.surfaceRotation;
1754 (*valuesOut)[PipelineState::EmulatedDitherControl] = shaders.emulatedDitherControl;
1755 (*valuesOut)[PipelineState::StencilOpFailFront] = shaders.front.fail;
1756 (*valuesOut)[PipelineState::StencilOpPassFront] = shaders.front.pass;
1757 (*valuesOut)[PipelineState::StencilOpDepthFailFront] = shaders.front.depthFail;
1758 (*valuesOut)[PipelineState::StencilCompareFront] = shaders.front.compare;
1759 (*valuesOut)[PipelineState::StencilOpFailBack] = shaders.back.fail;
1760 (*valuesOut)[PipelineState::StencilOpPassBack] = shaders.back.pass;
1761 (*valuesOut)[PipelineState::StencilOpDepthFailBack] = shaders.back.depthFail;
1762 (*valuesOut)[PipelineState::StencilCompareBack] = shaders.back.compare;
1763 }
1764
1765 if (hasShadersOrFragmentOutput)
1766 {
1767 const PipelineSharedNonVertexInputState &sharedNonVertexInputState =
1768 state.getSharedNonVertexInputStateForLog();
1769
1770 const PackedMultisampleAndSubpassState &multisample = sharedNonVertexInputState.multisample;
1771 (*valuesOut)[PipelineState::SampleMask] = multisample.bits.sampleMask;
1772 (*valuesOut)[PipelineState::RasterizationSamples] =
1773 multisample.bits.rasterizationSamplesMinusOne + 1;
1774 (*valuesOut)[PipelineState::SampleShadingEnable] = multisample.bits.sampleShadingEnable;
1775 (*valuesOut)[PipelineState::AlphaToCoverageEnable] = multisample.bits.alphaToCoverageEnable;
1776 (*valuesOut)[PipelineState::AlphaToOneEnable] = multisample.bits.alphaToOneEnable;
1777 (*valuesOut)[PipelineState::Subpass] = multisample.bits.subpass;
1778 (*valuesOut)[PipelineState::MinSampleShading] = multisample.bits.minSampleShading;
1779
1780 const RenderPassDesc renderPass = sharedNonVertexInputState.renderPass;
1781 (*valuesOut)[PipelineState::RenderPassSamples] = renderPass.samples();
1782 (*valuesOut)[PipelineState::RenderPassColorAttachmentRange] =
1783 static_cast<uint32_t>(renderPass.colorAttachmentRange());
1784 (*valuesOut)[PipelineState::RenderPassViewCount] = renderPass.viewCount();
1785 (*valuesOut)[PipelineState::RenderPassSrgbWriteControl] =
1786 static_cast<uint32_t>(renderPass.getSRGBWriteControlMode());
1787 (*valuesOut)[PipelineState::RenderPassHasFramebufferFetch] =
1788 renderPass.hasFramebufferFetch();
1789 (*valuesOut)[PipelineState::RenderPassIsRenderToTexture] = renderPass.isRenderToTexture();
1790 (*valuesOut)[PipelineState::RenderPassResolveDepthStencil] =
1791 renderPass.hasDepthStencilResolveAttachment();
1792 (*valuesOut)[PipelineState::RenderPassUnresolveDepth] =
1793 renderPass.hasDepthUnresolveAttachment();
1794 (*valuesOut)[PipelineState::RenderPassUnresolveStencil] =
1795 renderPass.hasStencilUnresolveAttachment();
1796 (*valuesOut)[PipelineState::RenderPassColorResolveMask] =
1797 renderPass.getColorResolveAttachmentMask().bits();
1798 (*valuesOut)[PipelineState::RenderPassColorUnresolveMask] =
1799 renderPass.getColorUnresolveAttachmentMask().bits();
1800
1801 uint32_t *colorFormats = &(*valuesOut)[PipelineState::RenderPassColorFormat];
1802 for (uint32_t colorIndex = 0; colorIndex < renderPass.colorAttachmentRange(); ++colorIndex)
1803 {
1804 colorFormats[colorIndex] = static_cast<uint32_t>(renderPass[colorIndex]);
1805 }
1806 (*valuesOut)[PipelineState::RenderPassDepthStencilFormat] =
1807 static_cast<uint32_t>(renderPass[renderPass.depthStencilAttachmentIndex()]);
1808 }
1809
1810 if (hasFragmentOutput)
1811 {
1812 const PipelineFragmentOutputState &fragmentOutputState =
1813 state.getFragmentOutputStateForLog();
1814
1815 const PackedColorBlendState &blend = fragmentOutputState.blend;
1816 uint32_t *colorWriteMasks = &(*valuesOut)[PipelineState::ColorWriteMask];
1817 uint32_t *srcColorBlendFactors = &(*valuesOut)[PipelineState::SrcColorBlendFactor];
1818 uint32_t *dstColorBlendFactors = &(*valuesOut)[PipelineState::DstColorBlendFactor];
1819 uint32_t *colorBlendOps = &(*valuesOut)[PipelineState::ColorBlendOp];
1820 uint32_t *srcAlphaBlendFactors = &(*valuesOut)[PipelineState::SrcAlphaBlendFactor];
1821 uint32_t *dstAlphaBlendFactors = &(*valuesOut)[PipelineState::DstAlphaBlendFactor];
1822 uint32_t *alphaBlendOps = &(*valuesOut)[PipelineState::AlphaBlendOp];
1823 for (uint32_t colorIndex = 0; colorIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
1824 ++colorIndex)
1825 {
1826 colorWriteMasks[colorIndex] =
1827 Int4Array_Get<VkColorComponentFlags>(blend.colorWriteMaskBits, colorIndex);
1828
1829 srcColorBlendFactors[colorIndex] = blend.attachments[colorIndex].srcColorBlendFactor;
1830 dstColorBlendFactors[colorIndex] = blend.attachments[colorIndex].dstColorBlendFactor;
1831 colorBlendOps[colorIndex] = blend.attachments[colorIndex].colorBlendOp;
1832 srcAlphaBlendFactors[colorIndex] = blend.attachments[colorIndex].srcAlphaBlendFactor;
1833 dstAlphaBlendFactors[colorIndex] = blend.attachments[colorIndex].dstAlphaBlendFactor;
1834 alphaBlendOps[colorIndex] = blend.attachments[colorIndex].alphaBlendOp;
1835 }
1836
1837 const PackedBlendMaskAndLogicOpState &blendMaskAndLogic =
1838 fragmentOutputState.blendMaskAndLogic;
1839 (*valuesOut)[PipelineState::BlendEnableMask] = blendMaskAndLogic.bits.blendEnableMask;
1840 (*valuesOut)[PipelineState::LogicOpEnable] = blendMaskAndLogic.bits.logicOpEnable;
1841 (*valuesOut)[PipelineState::LogicOp] = blendMaskAndLogic.bits.logicOp;
1842 (*valuesOut)[PipelineState::MissingOutputsMask] = blendMaskAndLogic.bits.missingOutputsMask;
1843 }
1844 }
1845
GetCommonPipelineState(const std::vector<UnpackedPipelineState> & pipelines)1846 [[maybe_unused]] PipelineStateBitSet GetCommonPipelineState(
1847 const std::vector<UnpackedPipelineState> &pipelines)
1848 {
1849 PipelineStateBitSet commonState;
1850 commonState.set();
1851
1852 ASSERT(!pipelines.empty());
1853 const UnpackedPipelineState &firstPipeline = pipelines[0];
1854
1855 for (const UnpackedPipelineState &pipeline : pipelines)
1856 {
1857 for (size_t stateIndex = 0; stateIndex < firstPipeline.size(); ++stateIndex)
1858 {
1859 if (pipeline.data()[stateIndex] != firstPipeline.data()[stateIndex])
1860 {
1861 commonState.reset(stateIndex);
1862 }
1863 }
1864 }
1865
1866 return commonState;
1867 }
1868
IsPipelineState(size_t stateIndex,PipelineState pipelineState,size_t range)1869 bool IsPipelineState(size_t stateIndex, PipelineState pipelineState, size_t range)
1870 {
1871 size_t pipelineStateAsInt = static_cast<size_t>(pipelineState);
1872
1873 return stateIndex >= pipelineStateAsInt && stateIndex < pipelineStateAsInt + range;
1874 }
1875
GetPipelineStateSubIndex(size_t stateIndex,PipelineState pipelineState)1876 size_t GetPipelineStateSubIndex(size_t stateIndex, PipelineState pipelineState)
1877 {
1878 return stateIndex - static_cast<size_t>(pipelineState);
1879 }
1880
GetPipelineState(size_t stateIndex,bool * isRangedOut,size_t * subIndexOut)1881 PipelineState GetPipelineState(size_t stateIndex, bool *isRangedOut, size_t *subIndexOut)
1882 {
1883 constexpr PipelineState kRangedStates[] = {
1884 PipelineState::VertexAttribFormat, PipelineState::VertexAttribDivisor,
1885 PipelineState::VertexAttribOffset, PipelineState::VertexAttribStride,
1886 PipelineState::VertexAttribCompressed, PipelineState::VertexAttribShaderComponentType,
1887 PipelineState::RenderPassColorFormat, PipelineState::ColorWriteMask,
1888 PipelineState::SrcColorBlendFactor, PipelineState::DstColorBlendFactor,
1889 PipelineState::ColorBlendOp, PipelineState::SrcAlphaBlendFactor,
1890 PipelineState::DstAlphaBlendFactor, PipelineState::AlphaBlendOp,
1891 };
1892
1893 for (PipelineState ps : kRangedStates)
1894 {
1895 size_t range;
1896 switch (ps)
1897 {
1898 case PipelineState::VertexAttribFormat:
1899 case PipelineState::VertexAttribDivisor:
1900 case PipelineState::VertexAttribOffset:
1901 case PipelineState::VertexAttribStride:
1902 case PipelineState::VertexAttribCompressed:
1903 case PipelineState::VertexAttribShaderComponentType:
1904 range = gl::MAX_VERTEX_ATTRIBS;
1905 break;
1906 default:
1907 range = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
1908 break;
1909 }
1910
1911 if (IsPipelineState(stateIndex, ps, range))
1912 {
1913 *subIndexOut = GetPipelineStateSubIndex(stateIndex, ps);
1914 *isRangedOut = true;
1915 return ps;
1916 }
1917 }
1918
1919 *isRangedOut = false;
1920 return static_cast<PipelineState>(stateIndex);
1921 }
1922
OutputPipelineState(std::ostream & out,size_t stateIndex,uint32_t state)1923 [[maybe_unused]] void OutputPipelineState(std::ostream &out, size_t stateIndex, uint32_t state)
1924 {
1925 size_t subIndex = 0;
1926 bool isRanged = false;
1927 PipelineState pipelineState = GetPipelineState(stateIndex, &isRanged, &subIndex);
1928
1929 constexpr angle::PackedEnumMap<PipelineState, const char *> kStateNames = {{
1930 {PipelineState::VertexAttribFormat, "va_format"},
1931 {PipelineState::VertexAttribDivisor, "va_divisor"},
1932 {PipelineState::VertexAttribOffset, "va_offset"},
1933 {PipelineState::VertexAttribStride, "va_stride"},
1934 {PipelineState::VertexAttribCompressed, "va_compressed"},
1935 {PipelineState::VertexAttribShaderComponentType, "va_shader_component_type"},
1936 {PipelineState::RenderPassSamples, "rp_samples"},
1937 {PipelineState::RenderPassColorAttachmentRange, "rp_color_range"},
1938 {PipelineState::RenderPassViewCount, "rp_views"},
1939 {PipelineState::RenderPassSrgbWriteControl, "rp_srgb"},
1940 {PipelineState::RenderPassHasFramebufferFetch, "rp_has_framebuffer_fetch"},
1941 {PipelineState::RenderPassIsRenderToTexture, "rp_is_msrtt"},
1942 {PipelineState::RenderPassResolveDepthStencil, "rp_resolve_depth_stencil"},
1943 {PipelineState::RenderPassUnresolveDepth, "rp_unresolve_depth"},
1944 {PipelineState::RenderPassUnresolveStencil, "rp_unresolve_stencil"},
1945 {PipelineState::RenderPassColorResolveMask, "rp_resolve_color"},
1946 {PipelineState::RenderPassColorUnresolveMask, "rp_unresolve_color"},
1947 {PipelineState::RenderPassColorFormat, "rp_color"},
1948 {PipelineState::RenderPassDepthStencilFormat, "rp_depth_stencil"},
1949 {PipelineState::Subpass, "subpass"},
1950 {PipelineState::Topology, "topology"},
1951 {PipelineState::PatchVertices, "patch_vertices"},
1952 {PipelineState::PrimitiveRestartEnable, "primitive_restart"},
1953 {PipelineState::PolygonMode, "polygon_mode"},
1954 {PipelineState::CullMode, "cull_mode"},
1955 {PipelineState::FrontFace, "front_face"},
1956 {PipelineState::SurfaceRotation, "rotated_surface"},
1957 {PipelineState::ViewportNegativeOneToOne, "viewport_depth_[-1,1]"},
1958 {PipelineState::SampleShadingEnable, "sample_shading"},
1959 {PipelineState::RasterizationSamples, "rasterization_samples"},
1960 {PipelineState::MinSampleShading, "min_sample_shading"},
1961 {PipelineState::SampleMask, "sample_mask"},
1962 {PipelineState::AlphaToCoverageEnable, "alpha_to_coverage"},
1963 {PipelineState::AlphaToOneEnable, "alpha_to_one"},
1964 {PipelineState::LogicOpEnable, "logic_op_enable"},
1965 {PipelineState::LogicOp, "logic_op"},
1966 {PipelineState::RasterizerDiscardEnable, "rasterization_discard"},
1967 {PipelineState::ColorWriteMask, "color_write"},
1968 {PipelineState::BlendEnableMask, "blend_mask"},
1969 {PipelineState::MissingOutputsMask, "missing_outputs_mask"},
1970 {PipelineState::SrcColorBlendFactor, "src_color_blend"},
1971 {PipelineState::DstColorBlendFactor, "dst_color_blend"},
1972 {PipelineState::ColorBlendOp, "color_blend"},
1973 {PipelineState::SrcAlphaBlendFactor, "src_alpha_blend"},
1974 {PipelineState::DstAlphaBlendFactor, "dst_alpha_blend"},
1975 {PipelineState::AlphaBlendOp, "alpha_blend"},
1976 {PipelineState::EmulatedDitherControl, "dither"},
1977 {PipelineState::DepthClampEnable, "depth_clamp"},
1978 {PipelineState::DepthBoundsTest, "depth_bounds_test"},
1979 {PipelineState::DepthCompareOp, "depth_compare"},
1980 {PipelineState::DepthTest, "depth_test"},
1981 {PipelineState::DepthWrite, "depth_write"},
1982 {PipelineState::StencilTest, "stencil_test"},
1983 {PipelineState::DepthBiasEnable, "depth_bias"},
1984 {PipelineState::StencilOpFailFront, "stencil_front_fail"},
1985 {PipelineState::StencilOpPassFront, "stencil_front_pass"},
1986 {PipelineState::StencilOpDepthFailFront, "stencil_front_depth_fail"},
1987 {PipelineState::StencilCompareFront, "stencil_front_compare"},
1988 {PipelineState::StencilOpFailBack, "stencil_back_fail"},
1989 {PipelineState::StencilOpPassBack, "stencil_back_pass"},
1990 {PipelineState::StencilOpDepthFailBack, "stencil_back_depth_fail"},
1991 {PipelineState::StencilCompareBack, "stencil_back_compare"},
1992 }};
1993
1994 out << kStateNames[pipelineState];
1995 if (isRanged)
1996 {
1997 out << "_" << subIndex;
1998 }
1999
2000 switch (pipelineState)
2001 {
2002 // Given that state == 0 produces no output, binary state doesn't require anything but
2003 // its name specified, as it being enabled would be implied.
2004 case PipelineState::VertexAttribCompressed:
2005 case PipelineState::RenderPassSrgbWriteControl:
2006 case PipelineState::RenderPassHasFramebufferFetch:
2007 case PipelineState::RenderPassIsRenderToTexture:
2008 case PipelineState::RenderPassResolveDepthStencil:
2009 case PipelineState::RenderPassUnresolveDepth:
2010 case PipelineState::RenderPassUnresolveStencil:
2011 case PipelineState::PrimitiveRestartEnable:
2012 case PipelineState::SurfaceRotation:
2013 case PipelineState::ViewportNegativeOneToOne:
2014 case PipelineState::SampleShadingEnable:
2015 case PipelineState::AlphaToCoverageEnable:
2016 case PipelineState::AlphaToOneEnable:
2017 case PipelineState::LogicOpEnable:
2018 case PipelineState::RasterizerDiscardEnable:
2019 case PipelineState::DepthClampEnable:
2020 case PipelineState::DepthBoundsTest:
2021 case PipelineState::DepthTest:
2022 case PipelineState::DepthWrite:
2023 case PipelineState::StencilTest:
2024 case PipelineState::DepthBiasEnable:
2025 break;
2026
2027 // Special formatting for some state
2028 case PipelineState::VertexAttribShaderComponentType:
2029 out << "=";
2030 switch (state)
2031 {
2032 case 0:
2033 static_assert(static_cast<uint32_t>(gl::ComponentType::Float) == 0);
2034 out << "float";
2035 break;
2036 case 1:
2037 static_assert(static_cast<uint32_t>(gl::ComponentType::Int) == 1);
2038 out << "int";
2039 break;
2040 case 2:
2041 static_assert(static_cast<uint32_t>(gl::ComponentType::UnsignedInt) == 2);
2042 out << "uint";
2043 break;
2044 case 3:
2045 static_assert(static_cast<uint32_t>(gl::ComponentType::NoType) == 3);
2046 out << "none";
2047 break;
2048 default:
2049 UNREACHABLE();
2050 }
2051 break;
2052 case PipelineState::Topology:
2053 out << "=";
2054 switch (state)
2055 {
2056 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
2057 out << "points";
2058 break;
2059 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
2060 out << "lines";
2061 break;
2062 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
2063 out << "line_strip";
2064 break;
2065 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
2066 out << "tris";
2067 break;
2068 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
2069 out << "tri_strip";
2070 break;
2071 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
2072 out << "tri_fan";
2073 break;
2074 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
2075 out << "lines_with_adj";
2076 break;
2077 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
2078 out << "line_strip_with_adj";
2079 break;
2080 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
2081 out << "tris_with_adj";
2082 break;
2083 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
2084 out << "tri_strip_with_adj";
2085 break;
2086 case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
2087 out << "patches";
2088 break;
2089 default:
2090 UNREACHABLE();
2091 }
2092 break;
2093 case PipelineState::PolygonMode:
2094 out << "=";
2095 switch (state)
2096 {
2097 case VK_POLYGON_MODE_FILL:
2098 out << "fill";
2099 break;
2100 case VK_POLYGON_MODE_LINE:
2101 out << "line";
2102 break;
2103 case VK_POLYGON_MODE_POINT:
2104 out << "point";
2105 break;
2106 default:
2107 UNREACHABLE();
2108 }
2109 break;
2110 case PipelineState::CullMode:
2111 out << "=";
2112 if ((state & VK_CULL_MODE_FRONT_BIT) != 0)
2113 {
2114 out << "front";
2115 }
2116 if (state == VK_CULL_MODE_FRONT_AND_BACK)
2117 {
2118 out << "+";
2119 }
2120 if ((state & VK_CULL_MODE_BACK_BIT) != 0)
2121 {
2122 out << "back";
2123 }
2124 break;
2125 case PipelineState::FrontFace:
2126 out << "=" << (state == VK_FRONT_FACE_COUNTER_CLOCKWISE ? "ccw" : "cw");
2127 break;
2128 case PipelineState::MinSampleShading:
2129 out << "=" << (static_cast<float>(state) / kMinSampleShadingScale);
2130 break;
2131 case PipelineState::SrcColorBlendFactor:
2132 case PipelineState::DstColorBlendFactor:
2133 case PipelineState::SrcAlphaBlendFactor:
2134 case PipelineState::DstAlphaBlendFactor:
2135 out << "=";
2136 switch (state)
2137 {
2138 case VK_BLEND_FACTOR_ZERO:
2139 out << "0";
2140 break;
2141 case VK_BLEND_FACTOR_ONE:
2142 out << "1";
2143 break;
2144 case VK_BLEND_FACTOR_SRC_COLOR:
2145 out << "sc";
2146 break;
2147 case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
2148 out << "1-sc";
2149 break;
2150 case VK_BLEND_FACTOR_DST_COLOR:
2151 out << "dc";
2152 break;
2153 case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
2154 out << "1-dc";
2155 break;
2156 case VK_BLEND_FACTOR_SRC_ALPHA:
2157 out << "sa";
2158 break;
2159 case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
2160 out << "1-sa";
2161 break;
2162 case VK_BLEND_FACTOR_DST_ALPHA:
2163 out << "da";
2164 break;
2165 case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
2166 out << "1-da";
2167 break;
2168 case VK_BLEND_FACTOR_CONSTANT_COLOR:
2169 out << "const_color";
2170 break;
2171 case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
2172 out << "1-const_color";
2173 break;
2174 case VK_BLEND_FACTOR_CONSTANT_ALPHA:
2175 out << "const_alpha";
2176 break;
2177 case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
2178 out << "1-const_alpha";
2179 break;
2180 case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE:
2181 out << "sat(sa)";
2182 break;
2183 case VK_BLEND_FACTOR_SRC1_COLOR:
2184 out << "sc1";
2185 break;
2186 case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
2187 out << "1-sc1";
2188 break;
2189 case VK_BLEND_FACTOR_SRC1_ALPHA:
2190 out << "sa1";
2191 break;
2192 case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
2193 out << "1-sa1";
2194 break;
2195 default:
2196 UNREACHABLE();
2197 }
2198 break;
2199 case PipelineState::ColorBlendOp:
2200 case PipelineState::AlphaBlendOp:
2201 out << "=";
2202 switch (UnpackBlendOp(static_cast<uint8_t>(state)))
2203 {
2204 case VK_BLEND_OP_ADD:
2205 out << "add";
2206 break;
2207 case VK_BLEND_OP_SUBTRACT:
2208 out << "sub";
2209 break;
2210 case VK_BLEND_OP_REVERSE_SUBTRACT:
2211 out << "reverse_sub";
2212 break;
2213 case VK_BLEND_OP_MIN:
2214 out << "min";
2215 break;
2216 case VK_BLEND_OP_MAX:
2217 out << "max";
2218 break;
2219 case VK_BLEND_OP_MULTIPLY_EXT:
2220 out << "multiply";
2221 break;
2222 case VK_BLEND_OP_SCREEN_EXT:
2223 out << "screen";
2224 break;
2225 case VK_BLEND_OP_OVERLAY_EXT:
2226 out << "overlay";
2227 break;
2228 case VK_BLEND_OP_DARKEN_EXT:
2229 out << "darken";
2230 break;
2231 case VK_BLEND_OP_LIGHTEN_EXT:
2232 out << "lighten";
2233 break;
2234 case VK_BLEND_OP_COLORDODGE_EXT:
2235 out << "dodge";
2236 break;
2237 case VK_BLEND_OP_COLORBURN_EXT:
2238 out << "burn";
2239 break;
2240 case VK_BLEND_OP_HARDLIGHT_EXT:
2241 out << "hardlight";
2242 break;
2243 case VK_BLEND_OP_SOFTLIGHT_EXT:
2244 out << "softlight";
2245 break;
2246 case VK_BLEND_OP_DIFFERENCE_EXT:
2247 out << "difference";
2248 break;
2249 case VK_BLEND_OP_EXCLUSION_EXT:
2250 out << "exclusion";
2251 break;
2252 case VK_BLEND_OP_HSL_HUE_EXT:
2253 out << "hsl_hue";
2254 break;
2255 case VK_BLEND_OP_HSL_SATURATION_EXT:
2256 out << "hsl_sat";
2257 break;
2258 case VK_BLEND_OP_HSL_COLOR_EXT:
2259 out << "hsl_color";
2260 break;
2261 case VK_BLEND_OP_HSL_LUMINOSITY_EXT:
2262 out << "hsl_lum";
2263 break;
2264 default:
2265 UNREACHABLE();
2266 }
2267 break;
2268 case PipelineState::DepthCompareOp:
2269 case PipelineState::StencilCompareFront:
2270 case PipelineState::StencilCompareBack:
2271 out << "=";
2272 switch (state)
2273 {
2274 case VK_COMPARE_OP_NEVER:
2275 out << "never";
2276 break;
2277 case VK_COMPARE_OP_LESS:
2278 out << "'<'";
2279 break;
2280 case VK_COMPARE_OP_EQUAL:
2281 out << "'='";
2282 break;
2283 case VK_COMPARE_OP_LESS_OR_EQUAL:
2284 out << "'<='";
2285 break;
2286 case VK_COMPARE_OP_GREATER:
2287 out << "'>'";
2288 break;
2289 case VK_COMPARE_OP_NOT_EQUAL:
2290 out << "'!='";
2291 break;
2292 case VK_COMPARE_OP_GREATER_OR_EQUAL:
2293 out << "'>='";
2294 break;
2295 case VK_COMPARE_OP_ALWAYS:
2296 out << "always";
2297 break;
2298 default:
2299 UNREACHABLE();
2300 }
2301 break;
2302 case PipelineState::StencilOpFailFront:
2303 case PipelineState::StencilOpPassFront:
2304 case PipelineState::StencilOpDepthFailFront:
2305 case PipelineState::StencilOpFailBack:
2306 case PipelineState::StencilOpPassBack:
2307 case PipelineState::StencilOpDepthFailBack:
2308 out << "=";
2309 switch (state)
2310 {
2311 case VK_STENCIL_OP_KEEP:
2312 out << "keep";
2313 break;
2314 case VK_STENCIL_OP_ZERO:
2315 out << "0";
2316 break;
2317 case VK_STENCIL_OP_REPLACE:
2318 out << "replace";
2319 break;
2320 case VK_STENCIL_OP_INCREMENT_AND_CLAMP:
2321 out << "clamp++";
2322 break;
2323 case VK_STENCIL_OP_DECREMENT_AND_CLAMP:
2324 out << "clamp--";
2325 break;
2326 case VK_STENCIL_OP_INVERT:
2327 out << "'~'";
2328 break;
2329 case VK_STENCIL_OP_INCREMENT_AND_WRAP:
2330 out << "wrap++";
2331 break;
2332 case VK_STENCIL_OP_DECREMENT_AND_WRAP:
2333 out << "wrap--";
2334 break;
2335 default:
2336 UNREACHABLE();
2337 }
2338 break;
2339
2340 // Some state output the value as hex because they are bitmasks
2341 case PipelineState::RenderPassColorResolveMask:
2342 case PipelineState::RenderPassColorUnresolveMask:
2343 case PipelineState::SampleMask:
2344 case PipelineState::ColorWriteMask:
2345 case PipelineState::BlendEnableMask:
2346 case PipelineState::MissingOutputsMask:
2347 case PipelineState::EmulatedDitherControl:
2348 out << "=0x" << std::hex << state << std::dec;
2349 break;
2350
2351 // The rest will simply output the state value
2352 default:
2353 out << "=" << state;
2354 break;
2355 }
2356
2357 out << "\\n";
2358 }
2359
OutputAllPipelineState(ContextVk * contextVk,std::ostream & out,const UnpackedPipelineState & pipeline,GraphicsPipelineSubset subset,const PipelineStateBitSet & include,bool isCommonState)2360 [[maybe_unused]] void OutputAllPipelineState(ContextVk *contextVk,
2361 std::ostream &out,
2362 const UnpackedPipelineState &pipeline,
2363 GraphicsPipelineSubset subset,
2364 const PipelineStateBitSet &include,
2365 bool isCommonState)
2366 {
2367 // Default non-existing state to 0, so they are automatically not output as
2368 // UnpackedPipelineState also sets them to 0.
2369 const bool hasVertexInput = GraphicsPipelineHasVertexInput(subset);
2370 const bool hasShaders = GraphicsPipelineHasShaders(subset);
2371 const bool hasShadersOrFragmentOutput = GraphicsPipelineHasShadersOrFragmentOutput(subset);
2372 const bool hasFragmentOutput = GraphicsPipelineHasFragmentOutput(subset);
2373
2374 const angle::PackedEnumMap<PipelineState, uint32_t> kDefaultState = {{
2375 // Vertex input state
2376 {PipelineState::VertexAttribFormat,
2377 hasVertexInput
2378 ? static_cast<uint32_t>(GetCurrentValueFormatID(gl::VertexAttribType::Float))
2379 : 0},
2380 {PipelineState::VertexAttribDivisor, 0},
2381 {PipelineState::VertexAttribOffset, 0},
2382 {PipelineState::VertexAttribStride, 0},
2383 {PipelineState::VertexAttribCompressed, 0},
2384 {PipelineState::VertexAttribShaderComponentType, 0},
2385 {PipelineState::Topology, hasVertexInput ? VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST : 0},
2386 {PipelineState::PrimitiveRestartEnable, 0},
2387
2388 // Shaders state
2389 {PipelineState::ViewportNegativeOneToOne,
2390 hasShaders && contextVk->getFeatures().supportsDepthClipControl.enabled},
2391 {PipelineState::DepthClampEnable, 0},
2392 {PipelineState::PolygonMode, hasShaders ? VK_POLYGON_MODE_FILL : 0},
2393 {PipelineState::CullMode, hasShaders ? VK_CULL_MODE_NONE : 0},
2394 {PipelineState::FrontFace, hasShaders ? VK_FRONT_FACE_COUNTER_CLOCKWISE : 0},
2395 {PipelineState::RasterizerDiscardEnable, 0},
2396 {PipelineState::DepthBiasEnable, 0},
2397 {PipelineState::PatchVertices, hasShaders ? 3 : 0},
2398 {PipelineState::DepthBoundsTest, 0},
2399 {PipelineState::DepthTest, 0},
2400 {PipelineState::DepthWrite, 0},
2401 {PipelineState::StencilTest, 0},
2402 {PipelineState::DepthCompareOp, hasShaders ? VK_COMPARE_OP_LESS : 0},
2403 {PipelineState::SurfaceRotation, 0},
2404 {PipelineState::EmulatedDitherControl, 0},
2405 {PipelineState::StencilOpFailFront, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2406 {PipelineState::StencilOpPassFront, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2407 {PipelineState::StencilOpDepthFailFront, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2408 {PipelineState::StencilCompareFront, hasShaders ? VK_COMPARE_OP_ALWAYS : 0},
2409 {PipelineState::StencilOpFailBack, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2410 {PipelineState::StencilOpPassBack, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2411 {PipelineState::StencilOpDepthFailBack, hasShaders ? VK_STENCIL_OP_KEEP : 0},
2412 {PipelineState::StencilCompareBack, hasShaders ? VK_COMPARE_OP_ALWAYS : 0},
2413
2414 // Shared shaders and fragment output state
2415 {PipelineState::SampleMask,
2416 hasShadersOrFragmentOutput ? std::numeric_limits<uint16_t>::max() : 0},
2417 {PipelineState::RasterizationSamples, hasShadersOrFragmentOutput ? 1 : 0},
2418 {PipelineState::SampleShadingEnable, 0},
2419 {PipelineState::MinSampleShading, hasShadersOrFragmentOutput ? kMinSampleShadingScale : 0},
2420 {PipelineState::AlphaToCoverageEnable, 0},
2421 {PipelineState::AlphaToOneEnable, 0},
2422 {PipelineState::RenderPassSamples, hasShadersOrFragmentOutput ? 1 : 0},
2423 {PipelineState::RenderPassColorAttachmentRange, 0},
2424 {PipelineState::RenderPassViewCount, 0},
2425 {PipelineState::RenderPassSrgbWriteControl, 0},
2426 {PipelineState::RenderPassHasFramebufferFetch, 0},
2427 {PipelineState::RenderPassIsRenderToTexture, 0},
2428 {PipelineState::RenderPassResolveDepthStencil, 0},
2429 {PipelineState::RenderPassUnresolveDepth, 0},
2430 {PipelineState::RenderPassUnresolveStencil, 0},
2431 {PipelineState::RenderPassColorResolveMask, 0},
2432 {PipelineState::RenderPassColorUnresolveMask, 0},
2433 {PipelineState::RenderPassColorFormat, 0},
2434 {PipelineState::RenderPassDepthStencilFormat, 0},
2435 {PipelineState::Subpass, 0},
2436
2437 // Fragment output state
2438 {PipelineState::ColorWriteMask, 0},
2439 {PipelineState::SrcColorBlendFactor, hasFragmentOutput ? VK_BLEND_FACTOR_ONE : 0},
2440 {PipelineState::DstColorBlendFactor, hasFragmentOutput ? VK_BLEND_FACTOR_ZERO : 0},
2441 {PipelineState::ColorBlendOp, hasFragmentOutput ? VK_BLEND_OP_ADD : 0},
2442 {PipelineState::SrcAlphaBlendFactor, hasFragmentOutput ? VK_BLEND_FACTOR_ONE : 0},
2443 {PipelineState::DstAlphaBlendFactor, hasFragmentOutput ? VK_BLEND_FACTOR_ZERO : 0},
2444 {PipelineState::AlphaBlendOp, hasFragmentOutput ? VK_BLEND_OP_ADD : 0},
2445 {PipelineState::BlendEnableMask, 0},
2446 {PipelineState::LogicOpEnable, 0},
2447 {PipelineState::LogicOp, hasFragmentOutput ? VK_LOGIC_OP_COPY : 0},
2448 {PipelineState::MissingOutputsMask, 0},
2449 }};
2450
2451 bool anyStateOutput = false;
2452 for (size_t stateIndex : include)
2453 {
2454 size_t subIndex = 0;
2455 bool isRanged = false;
2456 PipelineState pipelineState = GetPipelineState(stateIndex, &isRanged, &subIndex);
2457
2458 const uint32_t state = pipeline.data()[stateIndex];
2459 if (state != kDefaultState[pipelineState])
2460 {
2461 OutputPipelineState(out, stateIndex, state);
2462 anyStateOutput = true;
2463 }
2464 }
2465
2466 if (!isCommonState)
2467 {
2468 out << "(" << (anyStateOutput ? "+" : "") << "common state)\\n";
2469 }
2470 }
2471
2472 template <typename Hash>
DumpPipelineCacheGraph(ContextVk * contextVk,const std::unordered_map<GraphicsPipelineDesc,PipelineHelper,Hash,typename GraphicsPipelineCacheTypeHelper<Hash>::KeyEqual> & cache)2473 void DumpPipelineCacheGraph(
2474 ContextVk *contextVk,
2475 const std::unordered_map<GraphicsPipelineDesc,
2476 PipelineHelper,
2477 Hash,
2478 typename GraphicsPipelineCacheTypeHelper<Hash>::KeyEqual> &cache)
2479 {
2480 constexpr GraphicsPipelineSubset kSubset = GraphicsPipelineCacheTypeHelper<Hash>::kSubset;
2481
2482 std::ostream &out = contextVk->getPipelineCacheGraphStream();
2483
2484 static std::atomic<uint32_t> sCacheSerial(0);
2485 angle::HashMap<GraphicsPipelineDesc, uint32_t, Hash,
2486 typename GraphicsPipelineCacheTypeHelper<Hash>::KeyEqual>
2487 descToId;
2488
2489 uint32_t cacheSerial = sCacheSerial.fetch_add(1);
2490 uint32_t descId = 0;
2491
2492 // Unpack pipeline states
2493 std::vector<UnpackedPipelineState> pipelines(cache.size());
2494 for (const auto &descAndPipeline : cache)
2495 {
2496 UnpackPipelineState(descAndPipeline.first, kSubset, &pipelines[descId++]);
2497 }
2498
2499 // Extract common state between all pipelines.
2500 PipelineStateBitSet commonState = GetCommonPipelineState(pipelines);
2501 PipelineStateBitSet nodeState = ~commonState;
2502
2503 const char *subsetDescription = "";
2504 const char *subsetTag = "";
2505 switch (kSubset)
2506 {
2507 case GraphicsPipelineSubset::VertexInput:
2508 subsetDescription = "(vertex input)\\n";
2509 subsetTag = "VI_";
2510 break;
2511 case GraphicsPipelineSubset::Shaders:
2512 subsetDescription = "(shaders)\\n";
2513 subsetTag = "S_";
2514 break;
2515 case GraphicsPipelineSubset::FragmentOutput:
2516 subsetDescription = "(fragment output)\\n";
2517 subsetTag = "FO_";
2518 break;
2519 default:
2520 break;
2521 }
2522
2523 out << " subgraph cluster_" << subsetTag << cacheSerial << "{\n";
2524 out << " label=\"Program " << cacheSerial << "\\n"
2525 << subsetDescription << "\\nCommon state:\\n";
2526 OutputAllPipelineState(contextVk, out, pipelines[0], kSubset, commonState, true);
2527 out << "\";\n";
2528
2529 descId = 0;
2530 for (const auto &descAndPipeline : cache)
2531 {
2532 const GraphicsPipelineDesc &desc = descAndPipeline.first;
2533
2534 const char *style = "";
2535 const char *feedbackDesc = "";
2536 switch (descAndPipeline.second.getCacheLookUpFeedback())
2537 {
2538 case CacheLookUpFeedback::Hit:
2539 // Default is green already
2540 break;
2541 case CacheLookUpFeedback::Miss:
2542 style = "[color=red]";
2543 break;
2544 case CacheLookUpFeedback::LinkedDrawHit:
2545 // Default is green already
2546 style = "[style=dotted]";
2547 feedbackDesc = "(linked)\\n";
2548 break;
2549 case CacheLookUpFeedback::LinkedDrawMiss:
2550 style = "[style=dotted,color=red]";
2551 feedbackDesc = "(linked)\\n";
2552 break;
2553 case CacheLookUpFeedback::WarmUpHit:
2554 // Default is green already
2555 style = "[style=dashed]";
2556 feedbackDesc = "(warm up)\\n";
2557 break;
2558 case CacheLookUpFeedback::WarmUpMiss:
2559 style = "[style=dashed,color=red]";
2560 feedbackDesc = "(warm up)\\n";
2561 break;
2562 case CacheLookUpFeedback::UtilsHit:
2563 style = "[color=yellow]";
2564 feedbackDesc = "(utils)\\n";
2565 break;
2566 case CacheLookUpFeedback::UtilsMiss:
2567 style = "[color=purple]";
2568 feedbackDesc = "(utils)\\n";
2569 break;
2570 default:
2571 // No feedback available
2572 break;
2573 }
2574
2575 out << " p" << subsetTag << cacheSerial << "_" << descId << "[label=\"Pipeline " << descId
2576 << "\\n"
2577 << feedbackDesc << "\\n";
2578 OutputAllPipelineState(contextVk, out, pipelines[descId], kSubset, nodeState, false);
2579 out << "\"]" << style << ";\n";
2580
2581 descToId[desc] = descId++;
2582 }
2583 for (const auto &descAndPipeline : cache)
2584 {
2585 const GraphicsPipelineDesc &desc = descAndPipeline.first;
2586 const PipelineHelper &pipelineHelper = descAndPipeline.second;
2587 const std::vector<GraphicsPipelineTransition> &transitions =
2588 pipelineHelper.getTransitions();
2589
2590 for (const GraphicsPipelineTransition &transition : transitions)
2591 {
2592 #if defined(ANGLE_IS_64_BIT_CPU)
2593 const uint64_t transitionBits = transition.bits.bits();
2594 #else
2595 const uint64_t transitionBits =
2596 static_cast<uint64_t>(transition.bits.bits(1)) << 32 | transition.bits.bits(0);
2597 #endif
2598 out << " p" << subsetTag << cacheSerial << "_" << descToId[desc] << " -> p"
2599 << subsetTag << cacheSerial << "_" << descToId[*transition.desc] << " [label=\"'0x"
2600 << std::hex << transitionBits << std::dec << "'\"];\n";
2601 }
2602 }
2603 out << " }\n";
2604 }
2605
2606 // Used by SharedCacheKeyManager
ReleaseCachedObject(ContextVk * contextVk,const FramebufferDesc & desc)2607 void ReleaseCachedObject(ContextVk *contextVk, const FramebufferDesc &desc)
2608 {
2609 contextVk->getShareGroup()->getFramebufferCache().erase(contextVk, desc);
2610 }
2611
ReleaseCachedObject(ContextVk * contextVk,const DescriptorSetDescAndPool & descAndPool)2612 void ReleaseCachedObject(ContextVk *contextVk, const DescriptorSetDescAndPool &descAndPool)
2613 {
2614 ASSERT(descAndPool.mPool != nullptr);
2615 descAndPool.mPool->releaseCachedDescriptorSet(contextVk, descAndPool.mDesc);
2616 }
2617
DestroyCachedObject(RendererVk * renderer,const FramebufferDesc & desc)2618 void DestroyCachedObject(RendererVk *renderer, const FramebufferDesc &desc)
2619 {
2620 // Framebuffer cache are implemented in a way that each cache entry tracks GPU progress and we
2621 // always guarantee cache entries are released before calling destroy.
2622 }
2623
DestroyCachedObject(RendererVk * renderer,const DescriptorSetDescAndPool & descAndPool)2624 void DestroyCachedObject(RendererVk *renderer, const DescriptorSetDescAndPool &descAndPool)
2625 {
2626 ASSERT(descAndPool.mPool != nullptr);
2627 descAndPool.mPool->destroyCachedDescriptorSet(renderer, descAndPool.mDesc);
2628 }
2629
InitializePipelineFromLibraries(Context * context,PipelineCacheAccess * pipelineCache,const vk::PipelineLayout & pipelineLayout,const vk::PipelineHelper & vertexInputPipeline,const vk::PipelineHelper & shadersPipeline,const vk::PipelineHelper & fragmentOutputPipeline,Pipeline * pipelineOut,CacheLookUpFeedback * feedbackOut)2630 angle::Result InitializePipelineFromLibraries(Context *context,
2631 PipelineCacheAccess *pipelineCache,
2632 const vk::PipelineLayout &pipelineLayout,
2633 const vk::PipelineHelper &vertexInputPipeline,
2634 const vk::PipelineHelper &shadersPipeline,
2635 const vk::PipelineHelper &fragmentOutputPipeline,
2636 Pipeline *pipelineOut,
2637 CacheLookUpFeedback *feedbackOut)
2638 {
2639 // Nothing in the create info, everything comes from the libraries.
2640 VkGraphicsPipelineCreateInfo createInfo = {};
2641 createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
2642 createInfo.layout = pipelineLayout.getHandle();
2643
2644 const std::array<VkPipeline, 3> pipelines = {
2645 vertexInputPipeline.getPipeline().getHandle(),
2646 shadersPipeline.getPipeline().getHandle(),
2647 fragmentOutputPipeline.getPipeline().getHandle(),
2648 };
2649
2650 // Specify the three subsets as input libraries.
2651 VkPipelineLibraryCreateInfoKHR libraryInfo = {};
2652 libraryInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR;
2653 libraryInfo.libraryCount = 3;
2654 libraryInfo.pLibraries = pipelines.data();
2655
2656 AddToPNextChain(&createInfo, &libraryInfo);
2657
2658 // If supported, get feedback.
2659 VkPipelineCreationFeedback feedback = {};
2660 VkPipelineCreationFeedbackCreateInfo feedbackInfo = {};
2661 feedbackInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO;
2662
2663 const bool supportsFeedback = context->getFeatures().supportsPipelineCreationFeedback.enabled;
2664 if (supportsFeedback)
2665 {
2666 feedbackInfo.pPipelineCreationFeedback = &feedback;
2667 AddToPNextChain(&createInfo, &feedbackInfo);
2668 }
2669
2670 // Create the pipeline
2671 ANGLE_VK_TRY(context, pipelineCache->createGraphicsPipeline(context, createInfo, pipelineOut));
2672
2673 if (supportsFeedback)
2674 {
2675 const bool cacheHit =
2676 (feedback.flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT) !=
2677 0;
2678
2679 *feedbackOut = cacheHit ? CacheLookUpFeedback::Hit : CacheLookUpFeedback::Miss;
2680 ApplyPipelineCreationFeedback(context, feedback);
2681 }
2682
2683 return angle::Result::Continue;
2684 }
2685 } // anonymous namespace
2686
GetGraphicsPipelineTransitionBitsMask(GraphicsPipelineSubset subset)2687 GraphicsPipelineTransitionBits GetGraphicsPipelineTransitionBitsMask(GraphicsPipelineSubset subset)
2688 {
2689 switch (subset)
2690 {
2691 case GraphicsPipelineSubset::VertexInput:
2692 return kPipelineVertexInputTransitionBitsMask;
2693 case GraphicsPipelineSubset::Shaders:
2694 return kPipelineShadersTransitionBitsMask;
2695 case GraphicsPipelineSubset::FragmentOutput:
2696 return kPipelineFragmentOutputTransitionBitsMask;
2697 default:
2698 break;
2699 }
2700
2701 ASSERT(subset == GraphicsPipelineSubset::Complete);
2702
2703 GraphicsPipelineTransitionBits allBits;
2704 allBits.set();
2705
2706 return allBits;
2707 }
2708
2709 // RenderPassDesc implementation.
RenderPassDesc()2710 RenderPassDesc::RenderPassDesc()
2711 {
2712 memset(this, 0, sizeof(RenderPassDesc));
2713 }
2714
2715 RenderPassDesc::~RenderPassDesc() = default;
2716
RenderPassDesc(const RenderPassDesc & other)2717 RenderPassDesc::RenderPassDesc(const RenderPassDesc &other)
2718 {
2719 memcpy(this, &other, sizeof(RenderPassDesc));
2720 }
2721
packColorAttachment(size_t colorIndexGL,angle::FormatID formatID)2722 void RenderPassDesc::packColorAttachment(size_t colorIndexGL, angle::FormatID formatID)
2723 {
2724 ASSERT(colorIndexGL < mAttachmentFormats.size());
2725 static_assert(angle::kNumANGLEFormats < std::numeric_limits<uint8_t>::max(),
2726 "Too many ANGLE formats to fit in uint8_t");
2727 // Force the user to pack the depth/stencil attachment last.
2728 ASSERT(!hasDepthStencilAttachment());
2729 // This function should only be called for enabled GL color attachments.
2730 ASSERT(formatID != angle::FormatID::NONE);
2731
2732 uint8_t &packedFormat = mAttachmentFormats[colorIndexGL];
2733 SetBitField(packedFormat, formatID);
2734
2735 // Set color attachment range such that it covers the range from index 0 through last active
2736 // index. This is the reasons why we need depth/stencil to be packed last.
2737 SetBitField(mColorAttachmentRange, std::max<size_t>(mColorAttachmentRange, colorIndexGL + 1));
2738 }
2739
packColorAttachmentGap(size_t colorIndexGL)2740 void RenderPassDesc::packColorAttachmentGap(size_t colorIndexGL)
2741 {
2742 ASSERT(colorIndexGL < mAttachmentFormats.size());
2743 static_assert(angle::kNumANGLEFormats < std::numeric_limits<uint8_t>::max(),
2744 "Too many ANGLE formats to fit in uint8_t");
2745 // Force the user to pack the depth/stencil attachment last.
2746 ASSERT(!hasDepthStencilAttachment());
2747
2748 // Use NONE as a flag for gaps in GL color attachments.
2749 uint8_t &packedFormat = mAttachmentFormats[colorIndexGL];
2750 SetBitField(packedFormat, angle::FormatID::NONE);
2751 }
2752
packDepthStencilAttachment(angle::FormatID formatID)2753 void RenderPassDesc::packDepthStencilAttachment(angle::FormatID formatID)
2754 {
2755 ASSERT(!hasDepthStencilAttachment());
2756
2757 size_t index = depthStencilAttachmentIndex();
2758 ASSERT(index < mAttachmentFormats.size());
2759
2760 uint8_t &packedFormat = mAttachmentFormats[index];
2761 SetBitField(packedFormat, formatID);
2762 }
2763
packColorResolveAttachment(size_t colorIndexGL)2764 void RenderPassDesc::packColorResolveAttachment(size_t colorIndexGL)
2765 {
2766 ASSERT(isColorAttachmentEnabled(colorIndexGL));
2767 ASSERT(!mColorResolveAttachmentMask.test(colorIndexGL));
2768 ASSERT(mSamples > 1);
2769 mColorResolveAttachmentMask.set(colorIndexGL);
2770 }
2771
removeColorResolveAttachment(size_t colorIndexGL)2772 void RenderPassDesc::removeColorResolveAttachment(size_t colorIndexGL)
2773 {
2774 ASSERT(mColorResolveAttachmentMask.test(colorIndexGL));
2775 mColorResolveAttachmentMask.reset(colorIndexGL);
2776 }
2777
packColorUnresolveAttachment(size_t colorIndexGL)2778 void RenderPassDesc::packColorUnresolveAttachment(size_t colorIndexGL)
2779 {
2780 mColorUnresolveAttachmentMask.set(colorIndexGL);
2781 }
2782
removeColorUnresolveAttachment(size_t colorIndexGL)2783 void RenderPassDesc::removeColorUnresolveAttachment(size_t colorIndexGL)
2784 {
2785 mColorUnresolveAttachmentMask.reset(colorIndexGL);
2786 }
2787
packDepthStencilResolveAttachment()2788 void RenderPassDesc::packDepthStencilResolveAttachment()
2789 {
2790 ASSERT(hasDepthStencilAttachment());
2791 ASSERT(!hasDepthStencilResolveAttachment());
2792
2793 mResolveDepthStencil = true;
2794 }
2795
packDepthStencilUnresolveAttachment(bool unresolveDepth,bool unresolveStencil)2796 void RenderPassDesc::packDepthStencilUnresolveAttachment(bool unresolveDepth, bool unresolveStencil)
2797 {
2798 ASSERT(hasDepthStencilAttachment());
2799
2800 mUnresolveDepth = unresolveDepth;
2801 mUnresolveStencil = unresolveStencil;
2802 }
2803
removeDepthStencilUnresolveAttachment()2804 void RenderPassDesc::removeDepthStencilUnresolveAttachment()
2805 {
2806 mUnresolveDepth = false;
2807 mUnresolveStencil = false;
2808 }
2809
operator =(const RenderPassDesc & other)2810 RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other)
2811 {
2812 memcpy(this, &other, sizeof(RenderPassDesc));
2813 return *this;
2814 }
2815
setWriteControlMode(gl::SrgbWriteControlMode mode)2816 void RenderPassDesc::setWriteControlMode(gl::SrgbWriteControlMode mode)
2817 {
2818 SetBitField(mSrgbWriteControl, mode);
2819 }
2820
hash() const2821 size_t RenderPassDesc::hash() const
2822 {
2823 return angle::ComputeGenericHash(*this);
2824 }
2825
isColorAttachmentEnabled(size_t colorIndexGL) const2826 bool RenderPassDesc::isColorAttachmentEnabled(size_t colorIndexGL) const
2827 {
2828 angle::FormatID formatID = operator[](colorIndexGL);
2829 return formatID != angle::FormatID::NONE;
2830 }
2831
hasDepthStencilAttachment() const2832 bool RenderPassDesc::hasDepthStencilAttachment() const
2833 {
2834 angle::FormatID formatID = operator[](depthStencilAttachmentIndex());
2835 return formatID != angle::FormatID::NONE;
2836 }
2837
attachmentCount() const2838 size_t RenderPassDesc::attachmentCount() const
2839 {
2840 size_t colorAttachmentCount = 0;
2841 for (size_t i = 0; i < mColorAttachmentRange; ++i)
2842 {
2843 colorAttachmentCount += isColorAttachmentEnabled(i);
2844 }
2845
2846 // Note that there are no gaps in depth/stencil attachments. In fact there is a maximum of 1 of
2847 // it + 1 for its resolve attachment.
2848 size_t depthStencilCount = hasDepthStencilAttachment() ? 1 : 0;
2849 size_t depthStencilResolveCount = hasDepthStencilResolveAttachment() ? 1 : 0;
2850 return colorAttachmentCount + mColorResolveAttachmentMask.count() + depthStencilCount +
2851 depthStencilResolveCount;
2852 }
2853
setLegacyDither(bool enabled)2854 void RenderPassDesc::setLegacyDither(bool enabled)
2855 {
2856 SetBitField(mLegacyDitherEnabled, enabled ? 1 : 0);
2857 }
2858
operator ==(const RenderPassDesc & lhs,const RenderPassDesc & rhs)2859 bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs)
2860 {
2861 return memcmp(&lhs, &rhs, sizeof(RenderPassDesc)) == 0;
2862 }
2863
2864 // GraphicsPipelineDesc implementation.
2865 // Use aligned allocation and free so we can use the alignas keyword.
operator new(std::size_t size)2866 void *GraphicsPipelineDesc::operator new(std::size_t size)
2867 {
2868 return angle::AlignedAlloc(size, 32);
2869 }
2870
operator delete(void * ptr)2871 void GraphicsPipelineDesc::operator delete(void *ptr)
2872 {
2873 return angle::AlignedFree(ptr);
2874 }
2875
GraphicsPipelineDesc()2876 GraphicsPipelineDesc::GraphicsPipelineDesc()
2877 {
2878 memset(this, 0, sizeof(GraphicsPipelineDesc));
2879 }
2880
2881 GraphicsPipelineDesc::~GraphicsPipelineDesc() = default;
2882
GraphicsPipelineDesc(const GraphicsPipelineDesc & other)2883 GraphicsPipelineDesc::GraphicsPipelineDesc(const GraphicsPipelineDesc &other)
2884 {
2885 *this = other;
2886 }
2887
operator =(const GraphicsPipelineDesc & other)2888 GraphicsPipelineDesc &GraphicsPipelineDesc::operator=(const GraphicsPipelineDesc &other)
2889 {
2890 memcpy(this, &other, sizeof(*this));
2891 return *this;
2892 }
2893
getPipelineSubsetMemory(GraphicsPipelineSubset subset,size_t * sizeOut) const2894 const void *GraphicsPipelineDesc::getPipelineSubsetMemory(GraphicsPipelineSubset subset,
2895 size_t *sizeOut) const
2896 {
2897 // GraphicsPipelineDesc must be laid out such that the three subsets are contiguous. The layout
2898 // is:
2899 //
2900 // Shaders State \
2901 // )--> Pre-rasterization + fragment subset
2902 // Shared Non-Vertex-Input State / \
2903 // )--> fragment output subset
2904 // Fragment Output State /
2905 //
2906 // Vertex Input State ----> Vertex input subset
2907 static_assert(offsetof(GraphicsPipelineDesc, mShaders) == kPipelineShadersDescOffset);
2908 static_assert(offsetof(GraphicsPipelineDesc, mSharedNonVertexInput) ==
2909 kPipelineShadersDescOffset + kGraphicsPipelineShadersStateSize);
2910 static_assert(offsetof(GraphicsPipelineDesc, mSharedNonVertexInput) ==
2911 kPipelineFragmentOutputDescOffset);
2912 static_assert(offsetof(GraphicsPipelineDesc, mFragmentOutput) ==
2913 kPipelineFragmentOutputDescOffset +
2914 kGraphicsPipelineSharedNonVertexInputStateSize);
2915 static_assert(offsetof(GraphicsPipelineDesc, mVertexInput) == kPipelineVertexInputDescOffset);
2916
2917 // Exclude vertex strides from the hash. It's conveniently placed last, so it would be easy to
2918 // exclude it from hash.
2919 static_assert(offsetof(GraphicsPipelineDesc, mVertexInput.vertex.strides) +
2920 sizeof(PackedVertexInputAttributes::strides) ==
2921 sizeof(GraphicsPipelineDesc));
2922
2923 size_t vertexInputReduceSize = 0;
2924 if (mVertexInput.inputAssembly.bits.useVertexInputBindingStrideDynamicState)
2925 {
2926 vertexInputReduceSize = sizeof(PackedVertexInputAttributes::strides);
2927 }
2928
2929 switch (subset)
2930 {
2931 case GraphicsPipelineSubset::VertexInput:
2932 *sizeOut = kPipelineVertexInputDescSize - vertexInputReduceSize;
2933 return &mVertexInput;
2934
2935 case GraphicsPipelineSubset::Shaders:
2936 *sizeOut = kPipelineShadersDescSize;
2937 return &mShaders;
2938
2939 case GraphicsPipelineSubset::FragmentOutput:
2940 *sizeOut = kPipelineFragmentOutputDescSize;
2941 return &mSharedNonVertexInput;
2942
2943 case GraphicsPipelineSubset::Complete:
2944 default:
2945 *sizeOut = sizeof(*this) - vertexInputReduceSize;
2946 return this;
2947 }
2948 }
2949
hash(GraphicsPipelineSubset subset) const2950 size_t GraphicsPipelineDesc::hash(GraphicsPipelineSubset subset) const
2951 {
2952 size_t keySize = 0;
2953 const void *key = getPipelineSubsetMemory(subset, &keySize);
2954
2955 return angle::ComputeGenericHash(key, keySize);
2956 }
2957
keyEqual(const GraphicsPipelineDesc & other,GraphicsPipelineSubset subset) const2958 bool GraphicsPipelineDesc::keyEqual(const GraphicsPipelineDesc &other,
2959 GraphicsPipelineSubset subset) const
2960 {
2961 size_t keySize = 0;
2962 const void *key = getPipelineSubsetMemory(subset, &keySize);
2963
2964 size_t otherKeySize = 0;
2965 const void *otherKey = other.getPipelineSubsetMemory(subset, &otherKeySize);
2966
2967 // Compare the relevant part of the desc memory. Note that due to workarounds (e.g.
2968 // useVertexInputBindingStrideDynamicState), |this| or |other| may produce different key sizes.
2969 // In that case, comparing the minimum of the two is sufficient; if the workarounds are
2970 // different, the comparison would fail anyway.
2971 return memcmp(key, otherKey, std::min(keySize, otherKeySize)) == 0;
2972 }
2973
2974 // Initialize PSO states, it is consistent with initial value of gl::State.
2975 //
2976 // Some states affect the pipeline, but they are not derived from the GL state, but rather the
2977 // properties of the Vulkan device or the context itself; such as whether a workaround is in
2978 // effect, or the context is robust. For VK_EXT_graphics_pipeline_library, such state that affects
2979 // multiple subsets of the pipeline is duplicated in each subset (for example, there are two
2980 // copies of isRobustContext, one for vertex input and one for shader stages).
initDefaults(const ContextVk * contextVk,GraphicsPipelineSubset subset)2981 void GraphicsPipelineDesc::initDefaults(const ContextVk *contextVk, GraphicsPipelineSubset subset)
2982 {
2983 if (GraphicsPipelineHasVertexInput(subset))
2984 {
2985 // Set all vertex input attributes to default, the default format is Float
2986 angle::FormatID defaultFormat = GetCurrentValueFormatID(gl::VertexAttribType::Float);
2987 for (PackedAttribDesc &packedAttrib : mVertexInput.vertex.attribs)
2988 {
2989 SetBitField(packedAttrib.divisor, 0);
2990 SetBitField(packedAttrib.format, defaultFormat);
2991 SetBitField(packedAttrib.compressed, 0);
2992 SetBitField(packedAttrib.offset, 0);
2993 }
2994 mVertexInput.vertex.shaderAttribComponentType = 0;
2995 memset(mVertexInput.vertex.strides, 0, sizeof(mVertexInput.vertex.strides));
2996
2997 SetBitField(mVertexInput.inputAssembly.bits.topology, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
2998 mVertexInput.inputAssembly.bits.primitiveRestartEnable = 0;
2999 mVertexInput.inputAssembly.bits.useVertexInputBindingStrideDynamicState =
3000 contextVk->getRenderer()->useVertexInputBindingStrideDynamicState();
3001 mVertexInput.inputAssembly.bits.padding = 0;
3002 }
3003
3004 if (GraphicsPipelineHasShaders(subset))
3005 {
3006 mShaders.shaders.bits.viewportNegativeOneToOne =
3007 contextVk->getFeatures().supportsDepthClipControl.enabled;
3008 mShaders.shaders.bits.depthClampEnable = 0;
3009 SetBitField(mShaders.shaders.bits.polygonMode, VK_POLYGON_MODE_FILL);
3010 SetBitField(mShaders.shaders.bits.cullMode, VK_CULL_MODE_NONE);
3011 SetBitField(mShaders.shaders.bits.frontFace, VK_FRONT_FACE_COUNTER_CLOCKWISE);
3012 mShaders.shaders.bits.rasterizerDiscardEnable = 0;
3013 mShaders.shaders.bits.depthBiasEnable = 0;
3014 SetBitField(mShaders.shaders.bits.patchVertices, 3);
3015 mShaders.shaders.bits.depthBoundsTest = 0;
3016 mShaders.shaders.bits.depthTest = 0;
3017 mShaders.shaders.bits.depthWrite = 0;
3018 mShaders.shaders.bits.stencilTest = 0;
3019 mShaders.shaders.bits.nonZeroStencilWriteMaskWorkaround = 0;
3020 SetBitField(mShaders.shaders.bits.depthCompareOp, VK_COMPARE_OP_LESS);
3021 mShaders.shaders.bits.surfaceRotation = 0;
3022 mShaders.shaders.emulatedDitherControl = 0;
3023 mShaders.shaders.padding = 0;
3024 SetBitField(mShaders.shaders.front.fail, VK_STENCIL_OP_KEEP);
3025 SetBitField(mShaders.shaders.front.pass, VK_STENCIL_OP_KEEP);
3026 SetBitField(mShaders.shaders.front.depthFail, VK_STENCIL_OP_KEEP);
3027 SetBitField(mShaders.shaders.front.compare, VK_COMPARE_OP_ALWAYS);
3028 SetBitField(mShaders.shaders.back.fail, VK_STENCIL_OP_KEEP);
3029 SetBitField(mShaders.shaders.back.pass, VK_STENCIL_OP_KEEP);
3030 SetBitField(mShaders.shaders.back.depthFail, VK_STENCIL_OP_KEEP);
3031 SetBitField(mShaders.shaders.back.compare, VK_COMPARE_OP_ALWAYS);
3032 }
3033
3034 if (GraphicsPipelineHasShadersOrFragmentOutput(subset))
3035 {
3036 mSharedNonVertexInput.multisample.bits.sampleMask = std::numeric_limits<uint16_t>::max();
3037 mSharedNonVertexInput.multisample.bits.rasterizationSamplesMinusOne = 0;
3038 mSharedNonVertexInput.multisample.bits.sampleShadingEnable = 0;
3039 mSharedNonVertexInput.multisample.bits.alphaToCoverageEnable = 0;
3040 mSharedNonVertexInput.multisample.bits.alphaToOneEnable = 0;
3041 mSharedNonVertexInput.multisample.bits.subpass = 0;
3042 mSharedNonVertexInput.multisample.bits.minSampleShading = kMinSampleShadingScale;
3043 }
3044
3045 if (GraphicsPipelineHasFragmentOutput(subset))
3046 {
3047 constexpr VkFlags kAllColorBits = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
3048 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
3049
3050 for (uint32_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
3051 ++colorIndexGL)
3052 {
3053 Int4Array_Set(mFragmentOutput.blend.colorWriteMaskBits, colorIndexGL, kAllColorBits);
3054 }
3055
3056 PackedColorBlendAttachmentState blendAttachmentState;
3057 SetBitField(blendAttachmentState.srcColorBlendFactor, VK_BLEND_FACTOR_ONE);
3058 SetBitField(blendAttachmentState.dstColorBlendFactor, VK_BLEND_FACTOR_ZERO);
3059 SetBitField(blendAttachmentState.colorBlendOp, VK_BLEND_OP_ADD);
3060 SetBitField(blendAttachmentState.srcAlphaBlendFactor, VK_BLEND_FACTOR_ONE);
3061 SetBitField(blendAttachmentState.dstAlphaBlendFactor, VK_BLEND_FACTOR_ZERO);
3062 SetBitField(blendAttachmentState.alphaBlendOp, VK_BLEND_OP_ADD);
3063
3064 std::fill(&mFragmentOutput.blend.attachments[0],
3065 &mFragmentOutput.blend.attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS],
3066 blendAttachmentState);
3067
3068 mFragmentOutput.blendMaskAndLogic.bits.blendEnableMask = 0;
3069 mFragmentOutput.blendMaskAndLogic.bits.logicOpEnable = 0;
3070 SetBitField(mFragmentOutput.blendMaskAndLogic.bits.logicOp, VK_LOGIC_OP_COPY);
3071 mFragmentOutput.blendMaskAndLogic.bits.padding = 0;
3072 }
3073
3074 // Context robustness affects vertex input and shader stages.
3075 mVertexInput.inputAssembly.bits.isRobustContext = mShaders.shaders.bits.isRobustContext =
3076 contextVk->shouldUsePipelineRobustness();
3077
3078 // Context protected-ness affects all subsets.
3079 mVertexInput.inputAssembly.bits.isProtectedContext = mShaders.shaders.bits.isProtectedContext =
3080 mFragmentOutput.blendMaskAndLogic.bits.isProtectedContext =
3081 contextVk->shouldRestrictPipelineToProtectedAccess();
3082 }
3083
initializePipeline(Context * context,PipelineCacheAccess * pipelineCache,GraphicsPipelineSubset subset,const RenderPass & compatibleRenderPass,const PipelineLayout & pipelineLayout,const ShaderModuleMap & shaders,const SpecializationConstants & specConsts,Pipeline * pipelineOut,CacheLookUpFeedback * feedbackOut) const3084 VkResult GraphicsPipelineDesc::initializePipeline(Context *context,
3085 PipelineCacheAccess *pipelineCache,
3086 GraphicsPipelineSubset subset,
3087 const RenderPass &compatibleRenderPass,
3088 const PipelineLayout &pipelineLayout,
3089 const ShaderModuleMap &shaders,
3090 const SpecializationConstants &specConsts,
3091 Pipeline *pipelineOut,
3092 CacheLookUpFeedback *feedbackOut) const
3093 {
3094 GraphicsPipelineVertexInputVulkanStructs vertexInputState;
3095 GraphicsPipelineShadersVulkanStructs shadersState;
3096 GraphicsPipelineSharedNonVertexInputVulkanStructs sharedNonVertexInputState;
3097 GraphicsPipelineFragmentOutputVulkanStructs fragmentOutputState;
3098 GraphicsPipelineDynamicStateList dynamicStateList;
3099
3100 VkGraphicsPipelineCreateInfo createInfo = {};
3101 createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
3102 createInfo.flags = 0;
3103 createInfo.renderPass = compatibleRenderPass.getHandle();
3104 createInfo.subpass = mSharedNonVertexInput.multisample.bits.subpass;
3105
3106 const bool hasVertexInput = GraphicsPipelineHasVertexInput(subset);
3107 const bool hasShaders = GraphicsPipelineHasShaders(subset);
3108 const bool hasShadersOrFragmentOutput = GraphicsPipelineHasShadersOrFragmentOutput(subset);
3109 const bool hasFragmentOutput = GraphicsPipelineHasFragmentOutput(subset);
3110
3111 if (hasVertexInput)
3112 {
3113 initializePipelineVertexInputState(context, &vertexInputState, &dynamicStateList);
3114
3115 createInfo.pVertexInputState = &vertexInputState.vertexInputState;
3116 createInfo.pInputAssemblyState = &vertexInputState.inputAssemblyState;
3117 }
3118
3119 if (hasShaders)
3120 {
3121 initializePipelineShadersState(context, shaders, specConsts, &shadersState,
3122 &dynamicStateList);
3123
3124 createInfo.stageCount = static_cast<uint32_t>(shadersState.shaderStages.size());
3125 createInfo.pStages = shadersState.shaderStages.data();
3126 createInfo.pTessellationState = &shadersState.tessellationState;
3127 createInfo.pViewportState = &shadersState.viewportState;
3128 createInfo.pRasterizationState = &shadersState.rasterState;
3129 createInfo.pDepthStencilState = &shadersState.depthStencilState;
3130 createInfo.layout = pipelineLayout.getHandle();
3131 }
3132
3133 if (hasShadersOrFragmentOutput)
3134 {
3135 initializePipelineSharedNonVertexInputState(context, &sharedNonVertexInputState,
3136 &dynamicStateList);
3137
3138 createInfo.pMultisampleState = &sharedNonVertexInputState.multisampleState;
3139 }
3140
3141 if (hasFragmentOutput)
3142 {
3143 initializePipelineFragmentOutputState(context, &fragmentOutputState, &dynamicStateList);
3144
3145 createInfo.pColorBlendState = &fragmentOutputState.blendState;
3146 }
3147
3148 VkPipelineDynamicStateCreateInfo dynamicState = {};
3149 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
3150 dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStateList.size());
3151 dynamicState.pDynamicStates = dynamicStateList.data();
3152 createInfo.pDynamicState = dynamicStateList.empty() ? nullptr : &dynamicState;
3153
3154 // If not a complete pipeline, specify which subset is being created
3155 VkGraphicsPipelineLibraryCreateInfoEXT libraryInfo = {};
3156 libraryInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT;
3157
3158 if (subset != GraphicsPipelineSubset::Complete)
3159 {
3160 switch (subset)
3161 {
3162 case GraphicsPipelineSubset::VertexInput:
3163 libraryInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT;
3164 break;
3165 case GraphicsPipelineSubset::Shaders:
3166 libraryInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
3167 VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
3168 break;
3169 case GraphicsPipelineSubset::FragmentOutput:
3170 libraryInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT;
3171 break;
3172 default:
3173 UNREACHABLE();
3174 break;
3175 }
3176
3177 createInfo.flags |= VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
3178
3179 AddToPNextChain(&createInfo, &libraryInfo);
3180 }
3181
3182 VkPipelineRobustnessCreateInfoEXT robustness = {};
3183 robustness.sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT;
3184
3185 // Enable robustness on the pipeline if needed. Note that the global robustBufferAccess feature
3186 // must be disabled by default.
3187 if ((hasVertexInput && mVertexInput.inputAssembly.bits.isRobustContext) ||
3188 (hasShaders && mShaders.shaders.bits.isRobustContext))
3189 {
3190 ASSERT(context->getFeatures().supportsPipelineRobustness.enabled);
3191
3192 robustness.storageBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
3193 robustness.uniformBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
3194 robustness.vertexInputs = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
3195 robustness.images = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT;
3196
3197 AddToPNextChain(&createInfo, &robustness);
3198 }
3199
3200 if ((hasVertexInput && mVertexInput.inputAssembly.bits.isProtectedContext) ||
3201 (hasShaders && mShaders.shaders.bits.isProtectedContext) ||
3202 (hasFragmentOutput && mFragmentOutput.blendMaskAndLogic.bits.isProtectedContext))
3203 {
3204 ASSERT(context->getFeatures().supportsPipelineProtectedAccess.enabled);
3205 createInfo.flags |= VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT;
3206 }
3207 else if (context->getFeatures().supportsPipelineProtectedAccess.enabled)
3208 {
3209 createInfo.flags |= VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT;
3210 }
3211
3212 VkPipelineCreationFeedback feedback = {};
3213 gl::ShaderMap<VkPipelineCreationFeedback> perStageFeedback;
3214
3215 VkPipelineCreationFeedbackCreateInfo feedbackInfo = {};
3216 feedbackInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO;
3217
3218 const bool supportsFeedback = context->getFeatures().supportsPipelineCreationFeedback.enabled;
3219 if (supportsFeedback)
3220 {
3221 feedbackInfo.pPipelineCreationFeedback = &feedback;
3222 // Provide some storage for per-stage data, even though it's not used. This first works
3223 // around a VVL bug that doesn't allow `pipelineStageCreationFeedbackCount=0` despite the
3224 // spec (See https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/4161). Even
3225 // with fixed VVL, several drivers crash when this storage is missing too.
3226 feedbackInfo.pipelineStageCreationFeedbackCount = createInfo.stageCount;
3227 feedbackInfo.pPipelineStageCreationFeedbacks = perStageFeedback.data();
3228
3229 AddToPNextChain(&createInfo, &feedbackInfo);
3230 }
3231
3232 VkResult result = pipelineCache->createGraphicsPipeline(context, createInfo, pipelineOut);
3233
3234 if (supportsFeedback)
3235 {
3236 const bool cacheHit =
3237 (feedback.flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT) !=
3238 0;
3239
3240 *feedbackOut = cacheHit ? CacheLookUpFeedback::Hit : CacheLookUpFeedback::Miss;
3241 ApplyPipelineCreationFeedback(context, feedback);
3242 }
3243
3244 return result;
3245 }
3246
patchVertexAttribComponentType(angle::FormatID format,gl::ComponentType vsInputType)3247 angle::FormatID patchVertexAttribComponentType(angle::FormatID format,
3248 gl::ComponentType vsInputType)
3249 {
3250 const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromID(format);
3251 // For normalized format, keep the same ?
3252 EGLBoolean normalized = vertexFormat.normalized;
3253 if (normalized)
3254 {
3255 return format;
3256 }
3257 gl::VertexAttribType attribType = gl::FromGLenum<gl::VertexAttribType>(vertexFormat.type);
3258 if (vsInputType != gl::ComponentType::Float)
3259 {
3260 ASSERT(vsInputType == gl::ComponentType::Int ||
3261 vsInputType == gl::ComponentType::UnsignedInt);
3262 switch (attribType)
3263 {
3264 case gl::VertexAttribType::Float:
3265 case gl::VertexAttribType::Fixed:
3266 case gl::VertexAttribType::UnsignedInt:
3267 case gl::VertexAttribType::Int:
3268 attribType = vsInputType == gl::ComponentType::Int
3269 ? gl::VertexAttribType::Int
3270 : gl::VertexAttribType::UnsignedInt;
3271 break;
3272 case gl::VertexAttribType::HalfFloat:
3273 case gl::VertexAttribType::HalfFloatOES:
3274 case gl::VertexAttribType::Short:
3275 case gl::VertexAttribType::UnsignedShort:
3276 attribType = vsInputType == gl::ComponentType::Int
3277 ? gl::VertexAttribType::Short
3278 : gl::VertexAttribType::UnsignedShort;
3279 break;
3280 case gl::VertexAttribType::Byte:
3281 case gl::VertexAttribType::UnsignedByte:
3282 attribType = vsInputType == gl::ComponentType::Int
3283 ? gl::VertexAttribType::Byte
3284 : gl::VertexAttribType::UnsignedByte;
3285 break;
3286 case gl::VertexAttribType::UnsignedInt2101010:
3287 case gl::VertexAttribType::Int2101010:
3288 attribType = vsInputType == gl::ComponentType::Int
3289 ? gl::VertexAttribType::Int2101010
3290 : gl::VertexAttribType::UnsignedInt2101010;
3291 break;
3292 case gl::VertexAttribType::UnsignedInt1010102:
3293 case gl::VertexAttribType::Int1010102:
3294 attribType = vsInputType == gl::ComponentType::Int
3295 ? gl::VertexAttribType::Int1010102
3296 : gl::VertexAttribType::UnsignedInt1010102;
3297 break;
3298 default:
3299 ASSERT(0);
3300 break;
3301 }
3302 }
3303 return gl::GetVertexFormatID(attribType, vertexFormat.normalized, vertexFormat.components,
3304 !vertexFormat.pureInteger);
3305 }
3306
initializePipelineVertexInputState(Context * context,GraphicsPipelineVertexInputVulkanStructs * stateOut,GraphicsPipelineDynamicStateList * dynamicStateListOut) const3307 void GraphicsPipelineDesc::initializePipelineVertexInputState(
3308 Context *context,
3309 GraphicsPipelineVertexInputVulkanStructs *stateOut,
3310 GraphicsPipelineDynamicStateList *dynamicStateListOut) const
3311 {
3312 // TODO(jmadill): Possibly use different path for ES 3.1 split bindings/attribs.
3313 uint32_t vertexAttribCount = 0;
3314
3315 stateOut->divisorState.sType =
3316 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
3317 stateOut->divisorState.pVertexBindingDivisors = stateOut->divisorDesc.data();
3318 for (size_t attribIndexSizeT :
3319 gl::AttributesMask(mVertexInput.inputAssembly.bits.programActiveAttributeLocations))
3320 {
3321 const uint32_t attribIndex = static_cast<uint32_t>(attribIndexSizeT);
3322
3323 VkVertexInputBindingDescription &bindingDesc = stateOut->bindingDescs[vertexAttribCount];
3324 VkVertexInputAttributeDescription &attribDesc = stateOut->attributeDescs[vertexAttribCount];
3325 const PackedAttribDesc &packedAttrib = mVertexInput.vertex.attribs[attribIndex];
3326
3327 bindingDesc.binding = attribIndex;
3328 bindingDesc.stride = static_cast<uint32_t>(mVertexInput.vertex.strides[attribIndex]);
3329 if (packedAttrib.divisor != 0)
3330 {
3331 bindingDesc.inputRate = static_cast<VkVertexInputRate>(VK_VERTEX_INPUT_RATE_INSTANCE);
3332 stateOut->divisorDesc[stateOut->divisorState.vertexBindingDivisorCount].binding =
3333 bindingDesc.binding;
3334 stateOut->divisorDesc[stateOut->divisorState.vertexBindingDivisorCount].divisor =
3335 packedAttrib.divisor;
3336 ++stateOut->divisorState.vertexBindingDivisorCount;
3337 }
3338 else
3339 {
3340 bindingDesc.inputRate = static_cast<VkVertexInputRate>(VK_VERTEX_INPUT_RATE_VERTEX);
3341 }
3342
3343 // Get the corresponding VkFormat for the attrib's format.
3344 angle::FormatID formatID = static_cast<angle::FormatID>(packedAttrib.format);
3345 const Format &format = context->getRenderer()->getFormat(formatID);
3346 const angle::Format &intendedFormat = format.getIntendedFormat();
3347 VkFormat vkFormat = format.getActualBufferVkFormat(packedAttrib.compressed);
3348
3349 const gl::ComponentType attribType = GetVertexAttributeComponentType(
3350 intendedFormat.isPureInt(), intendedFormat.vertexAttribType);
3351 const gl::ComponentType programAttribType = gl::GetComponentTypeMask(
3352 gl::ComponentTypeMask(mVertexInput.vertex.shaderAttribComponentType), attribIndex);
3353
3354 // If using dynamic state for stride, the value for stride is unconditionally 0 here.
3355 // |ContextVk::handleDirtyGraphicsVertexBuffers| implements the same fix when setting stride
3356 // dynamically.
3357 ASSERT(!context->getRenderer()->useVertexInputBindingStrideDynamicState() ||
3358 bindingDesc.stride == 0);
3359
3360 if (attribType != programAttribType)
3361 {
3362 VkFormat origVkFormat = vkFormat;
3363 if (attribType == gl::ComponentType::Float ||
3364 programAttribType == gl::ComponentType::Float)
3365 {
3366 angle::FormatID patchFormatID =
3367 patchVertexAttribComponentType(formatID, programAttribType);
3368 vkFormat = context->getRenderer()
3369 ->getFormat(patchFormatID)
3370 .getActualBufferVkFormat(packedAttrib.compressed);
3371 }
3372 else
3373 {
3374 // When converting from an unsigned to a signed format or vice versa, attempt to
3375 // match the bit width.
3376 angle::FormatID convertedFormatID = gl::ConvertFormatSignedness(intendedFormat);
3377 const Format &convertedFormat =
3378 context->getRenderer()->getFormat(convertedFormatID);
3379 ASSERT(intendedFormat.channelCount ==
3380 convertedFormat.getIntendedFormat().channelCount);
3381 ASSERT(intendedFormat.redBits == convertedFormat.getIntendedFormat().redBits);
3382 ASSERT(intendedFormat.greenBits == convertedFormat.getIntendedFormat().greenBits);
3383 ASSERT(intendedFormat.blueBits == convertedFormat.getIntendedFormat().blueBits);
3384 ASSERT(intendedFormat.alphaBits == convertedFormat.getIntendedFormat().alphaBits);
3385
3386 vkFormat = convertedFormat.getActualBufferVkFormat(packedAttrib.compressed);
3387 }
3388 const Format &origFormat =
3389 context->getRenderer()->getFormat(GetFormatIDFromVkFormat(origVkFormat));
3390 const Format &patchFormat =
3391 context->getRenderer()->getFormat(GetFormatIDFromVkFormat(vkFormat));
3392 ASSERT(origFormat.getIntendedFormat().pixelBytes ==
3393 patchFormat.getIntendedFormat().pixelBytes);
3394 ASSERT(context->getRenderer()->getNativeExtensions().relaxedVertexAttributeTypeANGLE);
3395 }
3396
3397 attribDesc.binding = attribIndex;
3398 attribDesc.format = vkFormat;
3399 attribDesc.location = static_cast<uint32_t>(attribIndex);
3400 attribDesc.offset = packedAttrib.offset;
3401
3402 vertexAttribCount++;
3403 }
3404
3405 // The binding descriptions are filled in at draw time.
3406 stateOut->vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
3407 stateOut->vertexInputState.flags = 0;
3408 stateOut->vertexInputState.vertexBindingDescriptionCount = vertexAttribCount;
3409 stateOut->vertexInputState.pVertexBindingDescriptions = stateOut->bindingDescs.data();
3410 stateOut->vertexInputState.vertexAttributeDescriptionCount = vertexAttribCount;
3411 stateOut->vertexInputState.pVertexAttributeDescriptions = stateOut->attributeDescs.data();
3412 if (stateOut->divisorState.vertexBindingDivisorCount)
3413 {
3414 stateOut->vertexInputState.pNext = &stateOut->divisorState;
3415 }
3416
3417 const PackedInputAssemblyState &inputAssembly = mVertexInput.inputAssembly;
3418
3419 // Primitive topology is filled in at draw time.
3420 stateOut->inputAssemblyState.sType =
3421 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
3422 stateOut->inputAssemblyState.flags = 0;
3423 stateOut->inputAssemblyState.topology =
3424 static_cast<VkPrimitiveTopology>(inputAssembly.bits.topology);
3425 stateOut->inputAssemblyState.primitiveRestartEnable =
3426 static_cast<VkBool32>(inputAssembly.bits.primitiveRestartEnable);
3427
3428 // Dynamic state
3429 if (context->getRenderer()->useVertexInputBindingStrideDynamicState() && vertexAttribCount > 0)
3430 {
3431 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE);
3432 }
3433 if (context->getRenderer()->usePrimitiveRestartEnableDynamicState())
3434 {
3435 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE);
3436 }
3437 }
3438
initializePipelineShadersState(Context * context,const ShaderModuleMap & shaders,const SpecializationConstants & specConsts,GraphicsPipelineShadersVulkanStructs * stateOut,GraphicsPipelineDynamicStateList * dynamicStateListOut) const3439 void GraphicsPipelineDesc::initializePipelineShadersState(
3440 Context *context,
3441 const ShaderModuleMap &shaders,
3442 const SpecializationConstants &specConsts,
3443 GraphicsPipelineShadersVulkanStructs *stateOut,
3444 GraphicsPipelineDynamicStateList *dynamicStateListOut) const
3445 {
3446 InitializeSpecializationInfo(specConsts, &stateOut->specializationEntries,
3447 &stateOut->specializationInfo);
3448
3449 // Vertex shader is always expected to be present.
3450 const ShaderModule &vertexModule = shaders[gl::ShaderType::Vertex].get();
3451 ASSERT(vertexModule.valid());
3452 VkPipelineShaderStageCreateInfo vertexStage = {};
3453 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3454 VK_SHADER_STAGE_VERTEX_BIT, vertexModule.getHandle(),
3455 stateOut->specializationInfo, &vertexStage);
3456 stateOut->shaderStages.push_back(vertexStage);
3457
3458 const ShaderModulePointer &tessControlPointer = shaders[gl::ShaderType::TessControl];
3459 if (tessControlPointer.valid())
3460 {
3461 const ShaderModule &tessControlModule = tessControlPointer.get();
3462 VkPipelineShaderStageCreateInfo tessControlStage = {};
3463 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3464 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
3465 tessControlModule.getHandle(), stateOut->specializationInfo,
3466 &tessControlStage);
3467 stateOut->shaderStages.push_back(tessControlStage);
3468 }
3469
3470 const ShaderModulePointer &tessEvaluationPointer = shaders[gl::ShaderType::TessEvaluation];
3471 if (tessEvaluationPointer.valid())
3472 {
3473 const ShaderModule &tessEvaluationModule = tessEvaluationPointer.get();
3474 VkPipelineShaderStageCreateInfo tessEvaluationStage = {};
3475 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3476 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
3477 tessEvaluationModule.getHandle(), stateOut->specializationInfo,
3478 &tessEvaluationStage);
3479 stateOut->shaderStages.push_back(tessEvaluationStage);
3480 }
3481
3482 const ShaderModulePointer &geometryPointer = shaders[gl::ShaderType::Geometry];
3483 if (geometryPointer.valid())
3484 {
3485 const ShaderModule &geometryModule = geometryPointer.get();
3486 VkPipelineShaderStageCreateInfo geometryStage = {};
3487 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3488 VK_SHADER_STAGE_GEOMETRY_BIT, geometryModule.getHandle(),
3489 stateOut->specializationInfo, &geometryStage);
3490 stateOut->shaderStages.push_back(geometryStage);
3491 }
3492
3493 // Fragment shader is optional.
3494 const ShaderModulePointer &fragmentPointer = shaders[gl::ShaderType::Fragment];
3495 if (fragmentPointer.valid() && !mShaders.shaders.bits.rasterizerDiscardEnable)
3496 {
3497 const ShaderModule &fragmentModule = fragmentPointer.get();
3498 VkPipelineShaderStageCreateInfo fragmentStage = {};
3499 SetPipelineShaderStageInfo(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3500 VK_SHADER_STAGE_FRAGMENT_BIT, fragmentModule.getHandle(),
3501 stateOut->specializationInfo, &fragmentStage);
3502 stateOut->shaderStages.push_back(fragmentStage);
3503 }
3504
3505 // Set initial viewport and scissor state.
3506 stateOut->viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
3507 stateOut->viewportState.flags = 0;
3508 stateOut->viewportState.viewportCount = 1;
3509 stateOut->viewportState.pViewports = nullptr;
3510 stateOut->viewportState.scissorCount = 1;
3511 stateOut->viewportState.pScissors = nullptr;
3512
3513 if (context->getFeatures().supportsDepthClipControl.enabled)
3514 {
3515 stateOut->depthClipControl.sType =
3516 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT;
3517 stateOut->depthClipControl.negativeOneToOne =
3518 static_cast<VkBool32>(mShaders.shaders.bits.viewportNegativeOneToOne);
3519
3520 stateOut->viewportState.pNext = &stateOut->depthClipControl;
3521 }
3522
3523 // Rasterizer state.
3524 stateOut->rasterState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
3525 stateOut->rasterState.flags = 0;
3526 stateOut->rasterState.depthClampEnable =
3527 static_cast<VkBool32>(mShaders.shaders.bits.depthClampEnable);
3528 stateOut->rasterState.rasterizerDiscardEnable =
3529 static_cast<VkBool32>(mShaders.shaders.bits.rasterizerDiscardEnable);
3530 stateOut->rasterState.polygonMode =
3531 static_cast<VkPolygonMode>(mShaders.shaders.bits.polygonMode);
3532 stateOut->rasterState.cullMode = static_cast<VkCullModeFlags>(mShaders.shaders.bits.cullMode);
3533 stateOut->rasterState.frontFace = static_cast<VkFrontFace>(mShaders.shaders.bits.frontFace);
3534 stateOut->rasterState.depthBiasEnable =
3535 static_cast<VkBool32>(mShaders.shaders.bits.depthBiasEnable);
3536 stateOut->rasterState.lineWidth = 0;
3537 const void **pNextPtr = &stateOut->rasterState.pNext;
3538
3539 const PackedMultisampleAndSubpassState &multisample = mSharedNonVertexInput.multisample;
3540
3541 stateOut->rasterLineState.sType =
3542 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
3543 // Enable Bresenham line rasterization if available and the following conditions are met:
3544 // 1.) not multisampling
3545 // 2.) VUID-VkGraphicsPipelineCreateInfo-lineRasterizationMode-02766:
3546 // The Vulkan spec states: If the lineRasterizationMode member of a
3547 // VkPipelineRasterizationLineStateCreateInfoEXT structure included in the pNext chain of
3548 // pRasterizationState is VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT or
3549 // VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT and if rasterization is enabled, then the
3550 // alphaToCoverageEnable, alphaToOneEnable, and sampleShadingEnable members of pMultisampleState
3551 // must all be VK_FALSE.
3552 if (multisample.bits.rasterizationSamplesMinusOne == 0 &&
3553 !mShaders.shaders.bits.rasterizerDiscardEnable && !multisample.bits.alphaToCoverageEnable &&
3554 !multisample.bits.alphaToOneEnable && !multisample.bits.sampleShadingEnable &&
3555 context->getFeatures().bresenhamLineRasterization.enabled)
3556 {
3557 stateOut->rasterLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
3558 *pNextPtr = &stateOut->rasterLineState;
3559 pNextPtr = &stateOut->rasterLineState.pNext;
3560 }
3561
3562 // Always set provoking vertex mode to last if available.
3563 if (context->getFeatures().provokingVertex.enabled)
3564 {
3565 stateOut->provokingVertexState.sType =
3566 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT;
3567 stateOut->provokingVertexState.provokingVertexMode =
3568 VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
3569 *pNextPtr = &stateOut->provokingVertexState;
3570 pNextPtr = &stateOut->provokingVertexState.pNext;
3571 }
3572
3573 if (context->getFeatures().supportsGeometryStreamsCapability.enabled)
3574 {
3575 stateOut->rasterStreamState.sType =
3576 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT;
3577 stateOut->rasterStreamState.rasterizationStream = 0;
3578 *pNextPtr = &stateOut->rasterStreamState;
3579 pNextPtr = &stateOut->rasterStreamState.pNext;
3580 }
3581
3582 // Depth/stencil state.
3583 stateOut->depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
3584 stateOut->depthStencilState.flags = 0;
3585 stateOut->depthStencilState.depthTestEnable =
3586 static_cast<VkBool32>(mShaders.shaders.bits.depthTest);
3587 stateOut->depthStencilState.depthWriteEnable =
3588 static_cast<VkBool32>(mShaders.shaders.bits.depthWrite);
3589 stateOut->depthStencilState.depthCompareOp =
3590 static_cast<VkCompareOp>(mShaders.shaders.bits.depthCompareOp);
3591 stateOut->depthStencilState.depthBoundsTestEnable =
3592 static_cast<VkBool32>(mShaders.shaders.bits.depthBoundsTest);
3593 stateOut->depthStencilState.stencilTestEnable =
3594 static_cast<VkBool32>(mShaders.shaders.bits.stencilTest);
3595 UnpackStencilState(mShaders.shaders.front, &stateOut->depthStencilState.front,
3596 mShaders.shaders.bits.nonZeroStencilWriteMaskWorkaround);
3597 UnpackStencilState(mShaders.shaders.back, &stateOut->depthStencilState.back,
3598 mShaders.shaders.bits.nonZeroStencilWriteMaskWorkaround);
3599 stateOut->depthStencilState.minDepthBounds = 0;
3600 stateOut->depthStencilState.maxDepthBounds = 0;
3601
3602 // tessellation State
3603 if (tessControlPointer.valid() && tessEvaluationPointer.valid())
3604 {
3605 stateOut->domainOriginState.sType =
3606 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO;
3607 stateOut->domainOriginState.pNext = NULL;
3608 stateOut->domainOriginState.domainOrigin = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
3609
3610 stateOut->tessellationState.sType =
3611 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
3612 stateOut->tessellationState.flags = 0;
3613 stateOut->tessellationState.pNext = &stateOut->domainOriginState;
3614 stateOut->tessellationState.patchControlPoints =
3615 static_cast<uint32_t>(mShaders.shaders.bits.patchVertices);
3616 }
3617
3618 // Dynamic state
3619 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_VIEWPORT);
3620 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_SCISSOR);
3621 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_LINE_WIDTH);
3622 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
3623 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
3624 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
3625 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
3626 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
3627 if (context->getRenderer()->useCullModeDynamicState())
3628 {
3629 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_CULL_MODE_EXT);
3630 }
3631 if (context->getRenderer()->useFrontFaceDynamicState())
3632 {
3633 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_FRONT_FACE_EXT);
3634 }
3635 if (context->getRenderer()->useDepthTestEnableDynamicState())
3636 {
3637 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE);
3638 }
3639 if (context->getRenderer()->useDepthWriteEnableDynamicState())
3640 {
3641 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE);
3642 }
3643 if (context->getRenderer()->useDepthCompareOpDynamicState())
3644 {
3645 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_COMPARE_OP);
3646 }
3647 if (context->getRenderer()->useStencilTestEnableDynamicState())
3648 {
3649 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE);
3650 }
3651 if (context->getRenderer()->useStencilOpDynamicState())
3652 {
3653 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_STENCIL_OP);
3654 }
3655 if (context->getRenderer()->useRasterizerDiscardEnableDynamicState())
3656 {
3657 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE);
3658 }
3659 if (context->getRenderer()->useDepthBiasEnableDynamicState())
3660 {
3661 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE);
3662 }
3663 if (context->getFeatures().supportsFragmentShadingRate.enabled)
3664 {
3665 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR);
3666 }
3667 }
3668
initializePipelineSharedNonVertexInputState(Context * context,GraphicsPipelineSharedNonVertexInputVulkanStructs * stateOut,GraphicsPipelineDynamicStateList * dynamicStateListOut) const3669 void GraphicsPipelineDesc::initializePipelineSharedNonVertexInputState(
3670 Context *context,
3671 GraphicsPipelineSharedNonVertexInputVulkanStructs *stateOut,
3672 GraphicsPipelineDynamicStateList *dynamicStateListOut) const
3673 {
3674 const PackedMultisampleAndSubpassState &multisample = mSharedNonVertexInput.multisample;
3675
3676 stateOut->sampleMask = multisample.bits.sampleMask;
3677
3678 // Multisample state.
3679 stateOut->multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
3680 stateOut->multisampleState.flags = 0;
3681 stateOut->multisampleState.rasterizationSamples =
3682 gl_vk::GetSamples(multisample.bits.rasterizationSamplesMinusOne + 1,
3683 context->getFeatures().limitSampleCountTo2.enabled);
3684 stateOut->multisampleState.sampleShadingEnable =
3685 static_cast<VkBool32>(multisample.bits.sampleShadingEnable);
3686 stateOut->multisampleState.minSampleShading =
3687 static_cast<float>(multisample.bits.minSampleShading) / kMinSampleShadingScale;
3688 stateOut->multisampleState.pSampleMask = &stateOut->sampleMask;
3689 stateOut->multisampleState.alphaToCoverageEnable =
3690 static_cast<VkBool32>(multisample.bits.alphaToCoverageEnable);
3691 stateOut->multisampleState.alphaToOneEnable =
3692 static_cast<VkBool32>(multisample.bits.alphaToOneEnable);
3693 }
3694
initializePipelineFragmentOutputState(Context * context,GraphicsPipelineFragmentOutputVulkanStructs * stateOut,GraphicsPipelineDynamicStateList * dynamicStateListOut) const3695 void GraphicsPipelineDesc::initializePipelineFragmentOutputState(
3696 Context *context,
3697 GraphicsPipelineFragmentOutputVulkanStructs *stateOut,
3698 GraphicsPipelineDynamicStateList *dynamicStateListOut) const
3699 {
3700 stateOut->blendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
3701 stateOut->blendState.flags = 0;
3702 stateOut->blendState.logicOpEnable =
3703 static_cast<VkBool32>(mFragmentOutput.blendMaskAndLogic.bits.logicOpEnable);
3704 stateOut->blendState.logicOp =
3705 static_cast<VkLogicOp>(mFragmentOutput.blendMaskAndLogic.bits.logicOp);
3706 stateOut->blendState.attachmentCount =
3707 static_cast<uint32_t>(mSharedNonVertexInput.renderPass.colorAttachmentRange());
3708 stateOut->blendState.pAttachments = stateOut->blendAttachmentState.data();
3709
3710 // If this graphics pipeline is for the unresolve operation, correct the color attachment count
3711 // for that subpass.
3712 if ((mSharedNonVertexInput.renderPass.getColorUnresolveAttachmentMask().any() ||
3713 mSharedNonVertexInput.renderPass.hasDepthStencilUnresolveAttachment()) &&
3714 mSharedNonVertexInput.multisample.bits.subpass == 0)
3715 {
3716 stateOut->blendState.attachmentCount = static_cast<uint32_t>(
3717 mSharedNonVertexInput.renderPass.getColorUnresolveAttachmentMask().count());
3718 }
3719
3720 // Specify rasterization order for color when available and there is
3721 // framebuffer fetch. This allows implementation of coherent framebuffer
3722 // fetch / advanced blend.
3723 //
3724 // We can do better by setting the bit only when there is coherent
3725 // framebuffer fetch, but getRenderPassFramebufferFetchMode does not
3726 // distinguish coherent / non-coherent yet. Also, once an app uses
3727 // framebufer fetch, we treat all render passes as if they use framebuffer
3728 // fetch. This check is not very effective.
3729 if (context->getFeatures().supportsRasterizationOrderAttachmentAccess.enabled &&
3730 getRenderPassFramebufferFetchMode())
3731 {
3732 stateOut->blendState.flags |=
3733 VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT;
3734 }
3735
3736 const gl::DrawBufferMask blendEnableMask(
3737 mFragmentOutput.blendMaskAndLogic.bits.blendEnableMask);
3738
3739 // Zero-init all states.
3740 stateOut->blendAttachmentState = {};
3741
3742 const PackedColorBlendState &colorBlend = mFragmentOutput.blend;
3743
3744 for (uint32_t colorIndexGL = 0; colorIndexGL < stateOut->blendState.attachmentCount;
3745 ++colorIndexGL)
3746 {
3747 VkPipelineColorBlendAttachmentState &state = stateOut->blendAttachmentState[colorIndexGL];
3748
3749 if (blendEnableMask[colorIndexGL])
3750 {
3751 // To avoid triggering valid usage error, blending must be disabled for formats that do
3752 // not have VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT feature bit set.
3753 // From OpenGL ES clients, this means disabling blending for integer formats.
3754 if (!angle::Format::Get(mSharedNonVertexInput.renderPass[colorIndexGL]).isInt())
3755 {
3756 ASSERT(!context->getRenderer()
3757 ->getFormat(mSharedNonVertexInput.renderPass[colorIndexGL])
3758 .getActualRenderableImageFormat()
3759 .isInt());
3760
3761 // The blend fixed-function is enabled with normal blend as well as advanced blend
3762 // when the Vulkan extension is present. When emulating advanced blend in the
3763 // shader, the blend fixed-function must be disabled.
3764 const PackedColorBlendAttachmentState &packedBlendState =
3765 colorBlend.attachments[colorIndexGL];
3766 if (packedBlendState.colorBlendOp <= static_cast<uint8_t>(VK_BLEND_OP_MAX) ||
3767 context->getFeatures().supportsBlendOperationAdvanced.enabled)
3768 {
3769 state.blendEnable = VK_TRUE;
3770 UnpackBlendAttachmentState(packedBlendState, &state);
3771 }
3772 }
3773 }
3774
3775 ASSERT(context->getRenderer()->getNativeExtensions().robustFragmentShaderOutputANGLE);
3776 if ((mFragmentOutput.blendMaskAndLogic.bits.missingOutputsMask >> colorIndexGL & 1) != 0)
3777 {
3778 state.colorWriteMask = 0;
3779 }
3780 else
3781 {
3782 state.colorWriteMask =
3783 Int4Array_Get<VkColorComponentFlags>(colorBlend.colorWriteMaskBits, colorIndexGL);
3784 }
3785 }
3786
3787 // Dynamic state
3788 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
3789 if (context->getRenderer()->useLogicOpDynamicState())
3790 {
3791 dynamicStateListOut->push_back(VK_DYNAMIC_STATE_LOGIC_OP_EXT);
3792 }
3793 }
3794
updateVertexInput(ContextVk * contextVk,GraphicsPipelineTransitionBits * transition,uint32_t attribIndex,GLuint stride,GLuint divisor,angle::FormatID format,bool compressed,GLuint relativeOffset)3795 void GraphicsPipelineDesc::updateVertexInput(ContextVk *contextVk,
3796 GraphicsPipelineTransitionBits *transition,
3797 uint32_t attribIndex,
3798 GLuint stride,
3799 GLuint divisor,
3800 angle::FormatID format,
3801 bool compressed,
3802 GLuint relativeOffset)
3803 {
3804 PackedAttribDesc &packedAttrib = mVertexInput.vertex.attribs[attribIndex];
3805
3806 SetBitField(packedAttrib.divisor, divisor);
3807
3808 if (format == angle::FormatID::NONE)
3809 {
3810 UNIMPLEMENTED();
3811 }
3812
3813 SetBitField(packedAttrib.format, format);
3814 SetBitField(packedAttrib.compressed, compressed);
3815 SetBitField(packedAttrib.offset, relativeOffset);
3816
3817 constexpr size_t kAttribBits = kPackedAttribDescSize * kBitsPerByte;
3818 const size_t kBit =
3819 ANGLE_GET_INDEXED_TRANSITION_BIT(mVertexInput.vertex.attribs, attribIndex, kAttribBits);
3820
3821 // Each attribute is 4 bytes, so only one transition bit needs to be set.
3822 static_assert(kPackedAttribDescSize == kGraphicsPipelineDirtyBitBytes,
3823 "Adjust transition bits");
3824 transition->set(kBit);
3825
3826 if (!contextVk->getRenderer()->useVertexInputBindingStrideDynamicState())
3827 {
3828 SetBitField(mVertexInput.vertex.strides[attribIndex], stride);
3829 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(
3830 mVertexInput.vertex.strides, attribIndex,
3831 sizeof(mVertexInput.vertex.strides[0]) * kBitsPerByte));
3832 }
3833 }
3834
setVertexShaderComponentTypes(gl::AttributesMask activeAttribLocations,gl::ComponentTypeMask componentTypeMask)3835 void GraphicsPipelineDesc::setVertexShaderComponentTypes(gl::AttributesMask activeAttribLocations,
3836 gl::ComponentTypeMask componentTypeMask)
3837 {
3838 SetBitField(mVertexInput.inputAssembly.bits.programActiveAttributeLocations,
3839 activeAttribLocations.bits());
3840
3841 const gl::ComponentTypeMask activeComponentTypeMask =
3842 componentTypeMask & gl::GetActiveComponentTypeMask(activeAttribLocations);
3843
3844 SetBitField(mVertexInput.vertex.shaderAttribComponentType, activeComponentTypeMask.bits());
3845 }
3846
updateVertexShaderComponentTypes(GraphicsPipelineTransitionBits * transition,gl::AttributesMask activeAttribLocations,gl::ComponentTypeMask componentTypeMask)3847 void GraphicsPipelineDesc::updateVertexShaderComponentTypes(
3848 GraphicsPipelineTransitionBits *transition,
3849 gl::AttributesMask activeAttribLocations,
3850 gl::ComponentTypeMask componentTypeMask)
3851 {
3852 if (mVertexInput.inputAssembly.bits.programActiveAttributeLocations !=
3853 activeAttribLocations.bits())
3854 {
3855 SetBitField(mVertexInput.inputAssembly.bits.programActiveAttributeLocations,
3856 activeAttribLocations.bits());
3857 transition->set(ANGLE_GET_TRANSITION_BIT(mVertexInput.inputAssembly.bits));
3858 }
3859
3860 const gl::ComponentTypeMask activeComponentTypeMask =
3861 componentTypeMask & gl::GetActiveComponentTypeMask(activeAttribLocations);
3862
3863 if (mVertexInput.vertex.shaderAttribComponentType != activeComponentTypeMask.bits())
3864 {
3865 SetBitField(mVertexInput.vertex.shaderAttribComponentType, activeComponentTypeMask.bits());
3866 transition->set(ANGLE_GET_TRANSITION_BIT(mVertexInput.vertex.shaderAttribComponentType));
3867 }
3868 }
3869
setTopology(gl::PrimitiveMode drawMode)3870 void GraphicsPipelineDesc::setTopology(gl::PrimitiveMode drawMode)
3871 {
3872 VkPrimitiveTopology vkTopology = gl_vk::GetPrimitiveTopology(drawMode);
3873 SetBitField(mVertexInput.inputAssembly.bits.topology, vkTopology);
3874 }
3875
updateTopology(GraphicsPipelineTransitionBits * transition,gl::PrimitiveMode drawMode)3876 void GraphicsPipelineDesc::updateTopology(GraphicsPipelineTransitionBits *transition,
3877 gl::PrimitiveMode drawMode)
3878 {
3879 setTopology(drawMode);
3880 transition->set(ANGLE_GET_TRANSITION_BIT(mVertexInput.inputAssembly.bits));
3881 }
3882
updateDepthClipControl(GraphicsPipelineTransitionBits * transition,bool negativeOneToOne)3883 void GraphicsPipelineDesc::updateDepthClipControl(GraphicsPipelineTransitionBits *transition,
3884 bool negativeOneToOne)
3885 {
3886 SetBitField(mShaders.shaders.bits.viewportNegativeOneToOne, negativeOneToOne);
3887 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
3888 }
3889
updatePrimitiveRestartEnabled(GraphicsPipelineTransitionBits * transition,bool primitiveRestartEnabled)3890 void GraphicsPipelineDesc::updatePrimitiveRestartEnabled(GraphicsPipelineTransitionBits *transition,
3891 bool primitiveRestartEnabled)
3892 {
3893 mVertexInput.inputAssembly.bits.primitiveRestartEnable =
3894 static_cast<uint16_t>(primitiveRestartEnabled);
3895 transition->set(ANGLE_GET_TRANSITION_BIT(mVertexInput.inputAssembly.bits));
3896 }
3897
updatePolygonMode(GraphicsPipelineTransitionBits * transition,gl::PolygonMode polygonMode)3898 void GraphicsPipelineDesc::updatePolygonMode(GraphicsPipelineTransitionBits *transition,
3899 gl::PolygonMode polygonMode)
3900 {
3901 mShaders.shaders.bits.polygonMode = gl_vk::GetPolygonMode(polygonMode);
3902 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
3903 }
3904
updateCullMode(GraphicsPipelineTransitionBits * transition,const gl::RasterizerState & rasterState)3905 void GraphicsPipelineDesc::updateCullMode(GraphicsPipelineTransitionBits *transition,
3906 const gl::RasterizerState &rasterState)
3907 {
3908 SetBitField(mShaders.shaders.bits.cullMode, gl_vk::GetCullMode(rasterState));
3909 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
3910 }
3911
updateFrontFace(GraphicsPipelineTransitionBits * transition,const gl::RasterizerState & rasterState,bool invertFrontFace)3912 void GraphicsPipelineDesc::updateFrontFace(GraphicsPipelineTransitionBits *transition,
3913 const gl::RasterizerState &rasterState,
3914 bool invertFrontFace)
3915 {
3916 SetBitField(mShaders.shaders.bits.frontFace,
3917 gl_vk::GetFrontFace(rasterState.frontFace, invertFrontFace));
3918 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
3919 }
3920
updateRasterizerDiscardEnabled(GraphicsPipelineTransitionBits * transition,bool rasterizerDiscardEnabled)3921 void GraphicsPipelineDesc::updateRasterizerDiscardEnabled(
3922 GraphicsPipelineTransitionBits *transition,
3923 bool rasterizerDiscardEnabled)
3924 {
3925 mShaders.shaders.bits.rasterizerDiscardEnable = static_cast<uint32_t>(rasterizerDiscardEnabled);
3926 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
3927 }
3928
getRasterizationSamples() const3929 uint32_t GraphicsPipelineDesc::getRasterizationSamples() const
3930 {
3931 return mSharedNonVertexInput.multisample.bits.rasterizationSamplesMinusOne + 1;
3932 }
3933
setRasterizationSamples(uint32_t rasterizationSamples)3934 void GraphicsPipelineDesc::setRasterizationSamples(uint32_t rasterizationSamples)
3935 {
3936 ASSERT(rasterizationSamples > 0);
3937 mSharedNonVertexInput.multisample.bits.rasterizationSamplesMinusOne = rasterizationSamples - 1;
3938 }
3939
updateRasterizationSamples(GraphicsPipelineTransitionBits * transition,uint32_t rasterizationSamples)3940 void GraphicsPipelineDesc::updateRasterizationSamples(GraphicsPipelineTransitionBits *transition,
3941 uint32_t rasterizationSamples)
3942 {
3943 setRasterizationSamples(rasterizationSamples);
3944 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
3945 }
3946
updateAlphaToCoverageEnable(GraphicsPipelineTransitionBits * transition,bool enable)3947 void GraphicsPipelineDesc::updateAlphaToCoverageEnable(GraphicsPipelineTransitionBits *transition,
3948 bool enable)
3949 {
3950 mSharedNonVertexInput.multisample.bits.alphaToCoverageEnable = enable;
3951 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
3952 }
3953
updateAlphaToOneEnable(GraphicsPipelineTransitionBits * transition,bool enable)3954 void GraphicsPipelineDesc::updateAlphaToOneEnable(GraphicsPipelineTransitionBits *transition,
3955 bool enable)
3956 {
3957 mSharedNonVertexInput.multisample.bits.alphaToOneEnable = enable;
3958 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
3959 }
3960
updateSampleMask(GraphicsPipelineTransitionBits * transition,uint32_t maskNumber,uint32_t mask)3961 void GraphicsPipelineDesc::updateSampleMask(GraphicsPipelineTransitionBits *transition,
3962 uint32_t maskNumber,
3963 uint32_t mask)
3964 {
3965 ASSERT(maskNumber == 0);
3966 SetBitField(mSharedNonVertexInput.multisample.bits.sampleMask, mask);
3967
3968 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
3969 }
3970
updateSampleShading(GraphicsPipelineTransitionBits * transition,bool enable,float value)3971 void GraphicsPipelineDesc::updateSampleShading(GraphicsPipelineTransitionBits *transition,
3972 bool enable,
3973 float value)
3974 {
3975 mSharedNonVertexInput.multisample.bits.sampleShadingEnable = enable;
3976 if (enable)
3977 {
3978 SetBitField(mSharedNonVertexInput.multisample.bits.minSampleShading,
3979 static_cast<uint16_t>(value * kMinSampleShadingScale));
3980 }
3981 else
3982 {
3983 mSharedNonVertexInput.multisample.bits.minSampleShading = kMinSampleShadingScale;
3984 }
3985
3986 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
3987 }
3988
setSingleBlend(uint32_t colorIndexGL,bool enabled,VkBlendOp op,VkBlendFactor srcFactor,VkBlendFactor dstFactor)3989 void GraphicsPipelineDesc::setSingleBlend(uint32_t colorIndexGL,
3990 bool enabled,
3991 VkBlendOp op,
3992 VkBlendFactor srcFactor,
3993 VkBlendFactor dstFactor)
3994 {
3995 mFragmentOutput.blendMaskAndLogic.bits.blendEnableMask |=
3996 static_cast<uint8_t>(1 << colorIndexGL);
3997
3998 PackedColorBlendAttachmentState &blendAttachmentState =
3999 mFragmentOutput.blend.attachments[colorIndexGL];
4000
4001 SetBitField(blendAttachmentState.colorBlendOp, op);
4002 SetBitField(blendAttachmentState.alphaBlendOp, op);
4003
4004 SetBitField(blendAttachmentState.srcColorBlendFactor, srcFactor);
4005 SetBitField(blendAttachmentState.dstColorBlendFactor, dstFactor);
4006 SetBitField(blendAttachmentState.srcAlphaBlendFactor, VK_BLEND_FACTOR_ZERO);
4007 SetBitField(blendAttachmentState.dstAlphaBlendFactor, VK_BLEND_FACTOR_ONE);
4008 }
4009
updateBlendEnabled(GraphicsPipelineTransitionBits * transition,gl::DrawBufferMask blendEnabledMask)4010 void GraphicsPipelineDesc::updateBlendEnabled(GraphicsPipelineTransitionBits *transition,
4011 gl::DrawBufferMask blendEnabledMask)
4012 {
4013 SetBitField(mFragmentOutput.blendMaskAndLogic.bits.blendEnableMask, blendEnabledMask.bits());
4014 transition->set(ANGLE_GET_TRANSITION_BIT(mFragmentOutput.blendMaskAndLogic.bits));
4015 }
4016
updateBlendEquations(GraphicsPipelineTransitionBits * transition,const gl::BlendStateExt & blendStateExt,gl::DrawBufferMask attachmentMask)4017 void GraphicsPipelineDesc::updateBlendEquations(GraphicsPipelineTransitionBits *transition,
4018 const gl::BlendStateExt &blendStateExt,
4019 gl::DrawBufferMask attachmentMask)
4020 {
4021 constexpr size_t kSizeBits = sizeof(PackedColorBlendAttachmentState) * 8;
4022
4023 for (size_t attachmentIndex : attachmentMask)
4024 {
4025 PackedColorBlendAttachmentState &blendAttachmentState =
4026 mFragmentOutput.blend.attachments[attachmentIndex];
4027 blendAttachmentState.colorBlendOp =
4028 PackGLBlendOp(blendStateExt.getEquationColorIndexed(attachmentIndex));
4029 blendAttachmentState.alphaBlendOp =
4030 PackGLBlendOp(blendStateExt.getEquationAlphaIndexed(attachmentIndex));
4031 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mFragmentOutput.blend.attachments,
4032 attachmentIndex, kSizeBits));
4033 }
4034 }
4035
updateBlendFuncs(GraphicsPipelineTransitionBits * transition,const gl::BlendStateExt & blendStateExt,gl::DrawBufferMask attachmentMask)4036 void GraphicsPipelineDesc::updateBlendFuncs(GraphicsPipelineTransitionBits *transition,
4037 const gl::BlendStateExt &blendStateExt,
4038 gl::DrawBufferMask attachmentMask)
4039 {
4040 constexpr size_t kSizeBits = sizeof(PackedColorBlendAttachmentState) * 8;
4041 for (size_t attachmentIndex : attachmentMask)
4042 {
4043 PackedColorBlendAttachmentState &blendAttachmentState =
4044 mFragmentOutput.blend.attachments[attachmentIndex];
4045 blendAttachmentState.srcColorBlendFactor =
4046 PackGLBlendFactor(blendStateExt.getSrcColorIndexed(attachmentIndex));
4047 blendAttachmentState.dstColorBlendFactor =
4048 PackGLBlendFactor(blendStateExt.getDstColorIndexed(attachmentIndex));
4049 blendAttachmentState.srcAlphaBlendFactor =
4050 PackGLBlendFactor(blendStateExt.getSrcAlphaIndexed(attachmentIndex));
4051 blendAttachmentState.dstAlphaBlendFactor =
4052 PackGLBlendFactor(blendStateExt.getDstAlphaIndexed(attachmentIndex));
4053 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mFragmentOutput.blend.attachments,
4054 attachmentIndex, kSizeBits));
4055 }
4056 }
4057
resetBlendFuncsAndEquations(GraphicsPipelineTransitionBits * transition,const gl::BlendStateExt & blendStateExt,gl::DrawBufferMask previousAttachmentsMask,gl::DrawBufferMask newAttachmentsMask)4058 void GraphicsPipelineDesc::resetBlendFuncsAndEquations(GraphicsPipelineTransitionBits *transition,
4059 const gl::BlendStateExt &blendStateExt,
4060 gl::DrawBufferMask previousAttachmentsMask,
4061 gl::DrawBufferMask newAttachmentsMask)
4062 {
4063 // A framebuffer with attachments in P was bound, and now one with attachments in N is bound.
4064 // We need to clear blend funcs and equations for attachments in P that are not in N. That is
4065 // attachments in P&~N.
4066 const gl::DrawBufferMask attachmentsToClear = previousAttachmentsMask & ~newAttachmentsMask;
4067 // We also need to restore blend funcs and equations for attachments in N that are not in P.
4068 const gl::DrawBufferMask attachmentsToAdd = newAttachmentsMask & ~previousAttachmentsMask;
4069 constexpr size_t kSizeBits = sizeof(PackedColorBlendAttachmentState) * 8;
4070
4071 for (size_t attachmentIndex : attachmentsToClear)
4072 {
4073 PackedColorBlendAttachmentState &blendAttachmentState =
4074 mFragmentOutput.blend.attachments[attachmentIndex];
4075
4076 blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
4077 blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
4078 blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
4079 blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
4080 blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
4081 blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
4082
4083 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mFragmentOutput.blend.attachments,
4084 attachmentIndex, kSizeBits));
4085 }
4086
4087 if (attachmentsToAdd.any())
4088 {
4089 updateBlendFuncs(transition, blendStateExt, attachmentsToAdd);
4090 updateBlendEquations(transition, blendStateExt, attachmentsToAdd);
4091 }
4092 }
4093
setColorWriteMasks(gl::BlendStateExt::ColorMaskStorage::Type colorMasks,const gl::DrawBufferMask & alphaMask,const gl::DrawBufferMask & enabledDrawBuffers)4094 void GraphicsPipelineDesc::setColorWriteMasks(gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
4095 const gl::DrawBufferMask &alphaMask,
4096 const gl::DrawBufferMask &enabledDrawBuffers)
4097 {
4098 for (uint32_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
4099 colorIndexGL++)
4100 {
4101 uint8_t colorMask =
4102 gl::BlendStateExt::ColorMaskStorage::GetValueIndexed(colorIndexGL, colorMasks);
4103
4104 uint8_t mask = 0;
4105 if (enabledDrawBuffers.test(colorIndexGL))
4106 {
4107 mask = alphaMask[colorIndexGL] ? (colorMask & ~VK_COLOR_COMPONENT_A_BIT) : colorMask;
4108 }
4109 Int4Array_Set(mFragmentOutput.blend.colorWriteMaskBits, colorIndexGL, mask);
4110 }
4111 }
4112
setSingleColorWriteMask(uint32_t colorIndexGL,VkColorComponentFlags colorComponentFlags)4113 void GraphicsPipelineDesc::setSingleColorWriteMask(uint32_t colorIndexGL,
4114 VkColorComponentFlags colorComponentFlags)
4115 {
4116 uint8_t colorMask = static_cast<uint8_t>(colorComponentFlags);
4117 Int4Array_Set(mFragmentOutput.blend.colorWriteMaskBits, colorIndexGL, colorMask);
4118 }
4119
updateColorWriteMasks(GraphicsPipelineTransitionBits * transition,gl::BlendStateExt::ColorMaskStorage::Type colorMasks,const gl::DrawBufferMask & alphaMask,const gl::DrawBufferMask & enabledDrawBuffers)4120 void GraphicsPipelineDesc::updateColorWriteMasks(
4121 GraphicsPipelineTransitionBits *transition,
4122 gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
4123 const gl::DrawBufferMask &alphaMask,
4124 const gl::DrawBufferMask &enabledDrawBuffers)
4125 {
4126 setColorWriteMasks(colorMasks, alphaMask, enabledDrawBuffers);
4127
4128 for (size_t colorIndexGL = 0; colorIndexGL < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
4129 colorIndexGL++)
4130 {
4131 transition->set(ANGLE_GET_INDEXED_TRANSITION_BIT(mFragmentOutput.blend.colorWriteMaskBits,
4132 colorIndexGL, 4));
4133 }
4134 }
4135
updateMissingOutputsMask(GraphicsPipelineTransitionBits * transition,gl::DrawBufferMask missingOutputsMask)4136 void GraphicsPipelineDesc::updateMissingOutputsMask(GraphicsPipelineTransitionBits *transition,
4137 gl::DrawBufferMask missingOutputsMask)
4138 {
4139 if (mFragmentOutput.blendMaskAndLogic.bits.missingOutputsMask != missingOutputsMask.bits())
4140 {
4141 SetBitField(mFragmentOutput.blendMaskAndLogic.bits.missingOutputsMask,
4142 missingOutputsMask.bits());
4143 transition->set(ANGLE_GET_TRANSITION_BIT(mFragmentOutput.blendMaskAndLogic.bits));
4144 }
4145 }
4146
updateLogicOpEnabled(GraphicsPipelineTransitionBits * transition,bool enable)4147 void GraphicsPipelineDesc::updateLogicOpEnabled(GraphicsPipelineTransitionBits *transition,
4148 bool enable)
4149 {
4150 mFragmentOutput.blendMaskAndLogic.bits.logicOpEnable = enable;
4151 transition->set(ANGLE_GET_TRANSITION_BIT(mFragmentOutput.blendMaskAndLogic.bits));
4152 }
4153
updateLogicOp(GraphicsPipelineTransitionBits * transition,VkLogicOp logicOp)4154 void GraphicsPipelineDesc::updateLogicOp(GraphicsPipelineTransitionBits *transition,
4155 VkLogicOp logicOp)
4156 {
4157 SetBitField(mFragmentOutput.blendMaskAndLogic.bits.logicOp, logicOp);
4158 transition->set(ANGLE_GET_TRANSITION_BIT(mFragmentOutput.blendMaskAndLogic.bits));
4159 }
4160
setDepthTestEnabled(bool enabled)4161 void GraphicsPipelineDesc::setDepthTestEnabled(bool enabled)
4162 {
4163 mShaders.shaders.bits.depthTest = enabled;
4164 }
4165
setDepthWriteEnabled(bool enabled)4166 void GraphicsPipelineDesc::setDepthWriteEnabled(bool enabled)
4167 {
4168 mShaders.shaders.bits.depthWrite = enabled;
4169 }
4170
setDepthFunc(VkCompareOp op)4171 void GraphicsPipelineDesc::setDepthFunc(VkCompareOp op)
4172 {
4173 SetBitField(mShaders.shaders.bits.depthCompareOp, op);
4174 }
4175
setDepthClampEnabled(bool enabled)4176 void GraphicsPipelineDesc::setDepthClampEnabled(bool enabled)
4177 {
4178 mShaders.shaders.bits.depthClampEnable = enabled;
4179 }
4180
setStencilTestEnabled(bool enabled)4181 void GraphicsPipelineDesc::setStencilTestEnabled(bool enabled)
4182 {
4183 mShaders.shaders.bits.stencilTest = enabled;
4184 }
4185
setStencilFrontFuncs(VkCompareOp compareOp)4186 void GraphicsPipelineDesc::setStencilFrontFuncs(VkCompareOp compareOp)
4187 {
4188 SetBitField(mShaders.shaders.front.compare, compareOp);
4189 }
4190
setStencilBackFuncs(VkCompareOp compareOp)4191 void GraphicsPipelineDesc::setStencilBackFuncs(VkCompareOp compareOp)
4192 {
4193 SetBitField(mShaders.shaders.back.compare, compareOp);
4194 }
4195
setStencilFrontOps(VkStencilOp failOp,VkStencilOp passOp,VkStencilOp depthFailOp)4196 void GraphicsPipelineDesc::setStencilFrontOps(VkStencilOp failOp,
4197 VkStencilOp passOp,
4198 VkStencilOp depthFailOp)
4199 {
4200 SetBitField(mShaders.shaders.front.fail, failOp);
4201 SetBitField(mShaders.shaders.front.pass, passOp);
4202 SetBitField(mShaders.shaders.front.depthFail, depthFailOp);
4203 }
4204
setStencilBackOps(VkStencilOp failOp,VkStencilOp passOp,VkStencilOp depthFailOp)4205 void GraphicsPipelineDesc::setStencilBackOps(VkStencilOp failOp,
4206 VkStencilOp passOp,
4207 VkStencilOp depthFailOp)
4208 {
4209 SetBitField(mShaders.shaders.back.fail, failOp);
4210 SetBitField(mShaders.shaders.back.pass, passOp);
4211 SetBitField(mShaders.shaders.back.depthFail, depthFailOp);
4212 }
4213
updateDepthTestEnabled(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState,const gl::Framebuffer * drawFramebuffer)4214 void GraphicsPipelineDesc::updateDepthTestEnabled(GraphicsPipelineTransitionBits *transition,
4215 const gl::DepthStencilState &depthStencilState,
4216 const gl::Framebuffer *drawFramebuffer)
4217 {
4218 // Only enable the depth test if the draw framebuffer has a depth buffer. It's possible that
4219 // we're emulating a stencil-only buffer with a depth-stencil buffer
4220 setDepthTestEnabled(depthStencilState.depthTest && drawFramebuffer->hasDepth());
4221 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4222 }
4223
updateDepthFunc(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4224 void GraphicsPipelineDesc::updateDepthFunc(GraphicsPipelineTransitionBits *transition,
4225 const gl::DepthStencilState &depthStencilState)
4226 {
4227 setDepthFunc(gl_vk::GetCompareOp(depthStencilState.depthFunc));
4228 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4229 }
4230
updateDepthClampEnabled(GraphicsPipelineTransitionBits * transition,bool enabled)4231 void GraphicsPipelineDesc::updateDepthClampEnabled(GraphicsPipelineTransitionBits *transition,
4232 bool enabled)
4233 {
4234 setDepthClampEnabled(enabled);
4235 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4236 }
4237
updateSurfaceRotation(GraphicsPipelineTransitionBits * transition,bool isRotatedAspectRatio)4238 void GraphicsPipelineDesc::updateSurfaceRotation(GraphicsPipelineTransitionBits *transition,
4239 bool isRotatedAspectRatio)
4240 {
4241 SetBitField(mShaders.shaders.bits.surfaceRotation, isRotatedAspectRatio);
4242 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4243 }
4244
updateDepthWriteEnabled(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState,const gl::Framebuffer * drawFramebuffer)4245 void GraphicsPipelineDesc::updateDepthWriteEnabled(GraphicsPipelineTransitionBits *transition,
4246 const gl::DepthStencilState &depthStencilState,
4247 const gl::Framebuffer *drawFramebuffer)
4248 {
4249 // Don't write to depth buffers that should not exist
4250 const bool depthWriteEnabled =
4251 drawFramebuffer->hasDepth() && depthStencilState.depthTest && depthStencilState.depthMask;
4252 if (static_cast<bool>(mShaders.shaders.bits.depthWrite) != depthWriteEnabled)
4253 {
4254 setDepthWriteEnabled(depthWriteEnabled);
4255 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4256 }
4257 }
4258
updateStencilTestEnabled(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState,const gl::Framebuffer * drawFramebuffer)4259 void GraphicsPipelineDesc::updateStencilTestEnabled(GraphicsPipelineTransitionBits *transition,
4260 const gl::DepthStencilState &depthStencilState,
4261 const gl::Framebuffer *drawFramebuffer)
4262 {
4263 // Only enable the stencil test if the draw framebuffer has a stencil buffer. It's possible
4264 // that we're emulating a depth-only buffer with a depth-stencil buffer
4265 setStencilTestEnabled(depthStencilState.stencilTest && drawFramebuffer->hasStencil());
4266 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4267 }
4268
updateStencilFrontFuncs(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4269 void GraphicsPipelineDesc::updateStencilFrontFuncs(GraphicsPipelineTransitionBits *transition,
4270 const gl::DepthStencilState &depthStencilState)
4271 {
4272 setStencilFrontFuncs(gl_vk::GetCompareOp(depthStencilState.stencilFunc));
4273 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.front));
4274 }
4275
updateStencilBackFuncs(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4276 void GraphicsPipelineDesc::updateStencilBackFuncs(GraphicsPipelineTransitionBits *transition,
4277 const gl::DepthStencilState &depthStencilState)
4278 {
4279 setStencilBackFuncs(gl_vk::GetCompareOp(depthStencilState.stencilBackFunc));
4280 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.back));
4281 }
4282
updateStencilFrontOps(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4283 void GraphicsPipelineDesc::updateStencilFrontOps(GraphicsPipelineTransitionBits *transition,
4284 const gl::DepthStencilState &depthStencilState)
4285 {
4286 setStencilFrontOps(gl_vk::GetStencilOp(depthStencilState.stencilFail),
4287 gl_vk::GetStencilOp(depthStencilState.stencilPassDepthPass),
4288 gl_vk::GetStencilOp(depthStencilState.stencilPassDepthFail));
4289 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.front));
4290 }
4291
updateStencilBackOps(GraphicsPipelineTransitionBits * transition,const gl::DepthStencilState & depthStencilState)4292 void GraphicsPipelineDesc::updateStencilBackOps(GraphicsPipelineTransitionBits *transition,
4293 const gl::DepthStencilState &depthStencilState)
4294 {
4295 setStencilBackOps(gl_vk::GetStencilOp(depthStencilState.stencilBackFail),
4296 gl_vk::GetStencilOp(depthStencilState.stencilBackPassDepthPass),
4297 gl_vk::GetStencilOp(depthStencilState.stencilBackPassDepthFail));
4298 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.back));
4299 }
4300
updatePolygonOffsetEnabled(GraphicsPipelineTransitionBits * transition,bool enabled)4301 void GraphicsPipelineDesc::updatePolygonOffsetEnabled(GraphicsPipelineTransitionBits *transition,
4302 bool enabled)
4303 {
4304 mShaders.shaders.bits.depthBiasEnable = enabled;
4305 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4306 }
4307
setRenderPassDesc(const RenderPassDesc & renderPassDesc)4308 void GraphicsPipelineDesc::setRenderPassDesc(const RenderPassDesc &renderPassDesc)
4309 {
4310 mSharedNonVertexInput.renderPass = renderPassDesc;
4311 }
4312
updateSubpass(GraphicsPipelineTransitionBits * transition,uint32_t subpass)4313 void GraphicsPipelineDesc::updateSubpass(GraphicsPipelineTransitionBits *transition,
4314 uint32_t subpass)
4315 {
4316 if (mSharedNonVertexInput.multisample.bits.subpass != subpass)
4317 {
4318 SetBitField(mSharedNonVertexInput.multisample.bits.subpass, subpass);
4319 transition->set(ANGLE_GET_TRANSITION_BIT(mSharedNonVertexInput.multisample.bits));
4320 }
4321 }
4322
updatePatchVertices(GraphicsPipelineTransitionBits * transition,GLuint value)4323 void GraphicsPipelineDesc::updatePatchVertices(GraphicsPipelineTransitionBits *transition,
4324 GLuint value)
4325 {
4326 SetBitField(mShaders.shaders.bits.patchVertices, value);
4327 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4328 }
4329
resetSubpass(GraphicsPipelineTransitionBits * transition)4330 void GraphicsPipelineDesc::resetSubpass(GraphicsPipelineTransitionBits *transition)
4331 {
4332 updateSubpass(transition, 0);
4333 }
4334
nextSubpass(GraphicsPipelineTransitionBits * transition)4335 void GraphicsPipelineDesc::nextSubpass(GraphicsPipelineTransitionBits *transition)
4336 {
4337 updateSubpass(transition, mSharedNonVertexInput.multisample.bits.subpass + 1);
4338 }
4339
setSubpass(uint32_t subpass)4340 void GraphicsPipelineDesc::setSubpass(uint32_t subpass)
4341 {
4342 SetBitField(mSharedNonVertexInput.multisample.bits.subpass, subpass);
4343 }
4344
getSubpass() const4345 uint32_t GraphicsPipelineDesc::getSubpass() const
4346 {
4347 return mSharedNonVertexInput.multisample.bits.subpass;
4348 }
4349
updateEmulatedDitherControl(GraphicsPipelineTransitionBits * transition,uint16_t value)4350 void GraphicsPipelineDesc::updateEmulatedDitherControl(GraphicsPipelineTransitionBits *transition,
4351 uint16_t value)
4352 {
4353 // Make sure we don't waste time resetting this to zero in the common no-dither case.
4354 ASSERT(value != 0 || mShaders.shaders.emulatedDitherControl != 0);
4355
4356 mShaders.shaders.emulatedDitherControl = value;
4357 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.emulatedDitherControl));
4358 }
4359
updateNonZeroStencilWriteMaskWorkaround(GraphicsPipelineTransitionBits * transition,bool enabled)4360 void GraphicsPipelineDesc::updateNonZeroStencilWriteMaskWorkaround(
4361 GraphicsPipelineTransitionBits *transition,
4362 bool enabled)
4363 {
4364 mShaders.shaders.bits.nonZeroStencilWriteMaskWorkaround = enabled;
4365 transition->set(ANGLE_GET_TRANSITION_BIT(mShaders.shaders.bits));
4366 }
4367
updateRenderPassDesc(GraphicsPipelineTransitionBits * transition,const RenderPassDesc & renderPassDesc)4368 void GraphicsPipelineDesc::updateRenderPassDesc(GraphicsPipelineTransitionBits *transition,
4369 const RenderPassDesc &renderPassDesc)
4370 {
4371 setRenderPassDesc(renderPassDesc);
4372
4373 // The RenderPass is a special case where it spans multiple bits but has no member.
4374 constexpr size_t kFirstBit =
4375 offsetof(GraphicsPipelineDesc, mSharedNonVertexInput.renderPass) >> kTransitionByteShift;
4376 constexpr size_t kBitCount = kRenderPassDescSize >> kTransitionByteShift;
4377 for (size_t bit = 0; bit < kBitCount; ++bit)
4378 {
4379 transition->set(kFirstBit + bit);
4380 }
4381 }
4382
setRenderPassSampleCount(GLint samples)4383 void GraphicsPipelineDesc::setRenderPassSampleCount(GLint samples)
4384 {
4385 mSharedNonVertexInput.renderPass.setSamples(samples);
4386 }
4387
setRenderPassFramebufferFetchMode(bool hasFramebufferFetch)4388 void GraphicsPipelineDesc::setRenderPassFramebufferFetchMode(bool hasFramebufferFetch)
4389 {
4390 mSharedNonVertexInput.renderPass.setFramebufferFetchMode(hasFramebufferFetch);
4391 }
4392
setRenderPassColorAttachmentFormat(size_t colorIndexGL,angle::FormatID formatID)4393 void GraphicsPipelineDesc::setRenderPassColorAttachmentFormat(size_t colorIndexGL,
4394 angle::FormatID formatID)
4395 {
4396 mSharedNonVertexInput.renderPass.packColorAttachment(colorIndexGL, formatID);
4397 }
4398
4399 // AttachmentOpsArray implementation.
AttachmentOpsArray()4400 AttachmentOpsArray::AttachmentOpsArray()
4401 {
4402 memset(&mOps, 0, sizeof(PackedAttachmentOpsDesc) * mOps.size());
4403 }
4404
4405 AttachmentOpsArray::~AttachmentOpsArray() = default;
4406
AttachmentOpsArray(const AttachmentOpsArray & other)4407 AttachmentOpsArray::AttachmentOpsArray(const AttachmentOpsArray &other)
4408 {
4409 memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
4410 }
4411
operator =(const AttachmentOpsArray & other)4412 AttachmentOpsArray &AttachmentOpsArray::operator=(const AttachmentOpsArray &other)
4413 {
4414 memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
4415 return *this;
4416 }
4417
operator [](PackedAttachmentIndex index) const4418 const PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](PackedAttachmentIndex index) const
4419 {
4420 return mOps[index.get()];
4421 }
4422
operator [](PackedAttachmentIndex index)4423 PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](PackedAttachmentIndex index)
4424 {
4425 return mOps[index.get()];
4426 }
4427
initWithLoadStore(PackedAttachmentIndex index,ImageLayout initialLayout,ImageLayout finalLayout)4428 void AttachmentOpsArray::initWithLoadStore(PackedAttachmentIndex index,
4429 ImageLayout initialLayout,
4430 ImageLayout finalLayout)
4431 {
4432 setLayouts(index, initialLayout, finalLayout);
4433 setOps(index, RenderPassLoadOp::Load, RenderPassStoreOp::Store);
4434 setStencilOps(index, RenderPassLoadOp::Load, RenderPassStoreOp::Store);
4435 }
4436
setLayouts(PackedAttachmentIndex index,ImageLayout initialLayout,ImageLayout finalLayout)4437 void AttachmentOpsArray::setLayouts(PackedAttachmentIndex index,
4438 ImageLayout initialLayout,
4439 ImageLayout finalLayout)
4440 {
4441 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4442 SetBitField(ops.initialLayout, initialLayout);
4443 SetBitField(ops.finalLayout, finalLayout);
4444 }
4445
setOps(PackedAttachmentIndex index,RenderPassLoadOp loadOp,RenderPassStoreOp storeOp)4446 void AttachmentOpsArray::setOps(PackedAttachmentIndex index,
4447 RenderPassLoadOp loadOp,
4448 RenderPassStoreOp storeOp)
4449 {
4450 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4451 SetBitField(ops.loadOp, loadOp);
4452 SetBitField(ops.storeOp, storeOp);
4453 ops.isInvalidated = false;
4454 }
4455
setStencilOps(PackedAttachmentIndex index,RenderPassLoadOp loadOp,RenderPassStoreOp storeOp)4456 void AttachmentOpsArray::setStencilOps(PackedAttachmentIndex index,
4457 RenderPassLoadOp loadOp,
4458 RenderPassStoreOp storeOp)
4459 {
4460 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4461 SetBitField(ops.stencilLoadOp, loadOp);
4462 SetBitField(ops.stencilStoreOp, storeOp);
4463 ops.isStencilInvalidated = false;
4464 }
4465
setClearOp(PackedAttachmentIndex index)4466 void AttachmentOpsArray::setClearOp(PackedAttachmentIndex index)
4467 {
4468 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4469 SetBitField(ops.loadOp, RenderPassLoadOp::Clear);
4470 }
4471
setClearStencilOp(PackedAttachmentIndex index)4472 void AttachmentOpsArray::setClearStencilOp(PackedAttachmentIndex index)
4473 {
4474 PackedAttachmentOpsDesc &ops = mOps[index.get()];
4475 SetBitField(ops.stencilLoadOp, RenderPassLoadOp::Clear);
4476 }
4477
hash() const4478 size_t AttachmentOpsArray::hash() const
4479 {
4480 return angle::ComputeGenericHash(mOps);
4481 }
4482
operator ==(const AttachmentOpsArray & lhs,const AttachmentOpsArray & rhs)4483 bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs)
4484 {
4485 return memcmp(&lhs, &rhs, sizeof(AttachmentOpsArray)) == 0;
4486 }
4487
4488 // DescriptorSetLayoutDesc implementation.
DescriptorSetLayoutDesc()4489 DescriptorSetLayoutDesc::DescriptorSetLayoutDesc() : mPackedDescriptorSetLayout{} {}
4490
4491 DescriptorSetLayoutDesc::~DescriptorSetLayoutDesc() = default;
4492
4493 DescriptorSetLayoutDesc::DescriptorSetLayoutDesc(const DescriptorSetLayoutDesc &other) = default;
4494
4495 DescriptorSetLayoutDesc &DescriptorSetLayoutDesc::operator=(const DescriptorSetLayoutDesc &other) =
4496 default;
4497
hash() const4498 size_t DescriptorSetLayoutDesc::hash() const
4499 {
4500 return angle::ComputeGenericHash(mPackedDescriptorSetLayout);
4501 }
4502
operator ==(const DescriptorSetLayoutDesc & other) const4503 bool DescriptorSetLayoutDesc::operator==(const DescriptorSetLayoutDesc &other) const
4504 {
4505 return memcmp(&mPackedDescriptorSetLayout, &other.mPackedDescriptorSetLayout,
4506 sizeof(mPackedDescriptorSetLayout)) == 0;
4507 }
4508
update(uint32_t bindingIndex,VkDescriptorType descriptorType,uint32_t count,VkShaderStageFlags stages,const Sampler * immutableSampler)4509 void DescriptorSetLayoutDesc::update(uint32_t bindingIndex,
4510 VkDescriptorType descriptorType,
4511 uint32_t count,
4512 VkShaderStageFlags stages,
4513 const Sampler *immutableSampler)
4514 {
4515 ASSERT(static_cast<size_t>(descriptorType) < std::numeric_limits<uint16_t>::max());
4516 ASSERT(count < std::numeric_limits<uint16_t>::max());
4517
4518 PackedDescriptorSetBinding &packedBinding = mPackedDescriptorSetLayout[bindingIndex];
4519
4520 SetBitField(packedBinding.type, descriptorType);
4521 SetBitField(packedBinding.count, count);
4522 SetBitField(packedBinding.stages, stages);
4523 packedBinding.immutableSampler = VK_NULL_HANDLE;
4524 packedBinding.pad = 0;
4525
4526 if (immutableSampler)
4527 {
4528 ASSERT(count == 1);
4529 packedBinding.immutableSampler = immutableSampler->getHandle();
4530 }
4531 }
4532
unpackBindings(DescriptorSetLayoutBindingVector * bindings,std::vector<VkSampler> * immutableSamplers) const4533 void DescriptorSetLayoutDesc::unpackBindings(DescriptorSetLayoutBindingVector *bindings,
4534 std::vector<VkSampler> *immutableSamplers) const
4535 {
4536 for (uint32_t bindingIndex = 0; bindingIndex < kMaxDescriptorSetLayoutBindings; ++bindingIndex)
4537 {
4538 const PackedDescriptorSetBinding &packedBinding = mPackedDescriptorSetLayout[bindingIndex];
4539 if (packedBinding.count == 0)
4540 continue;
4541
4542 VkDescriptorSetLayoutBinding binding = {};
4543 binding.binding = bindingIndex;
4544 binding.descriptorCount = packedBinding.count;
4545 binding.descriptorType = static_cast<VkDescriptorType>(packedBinding.type);
4546 binding.stageFlags = static_cast<VkShaderStageFlags>(packedBinding.stages);
4547 if (packedBinding.immutableSampler != VK_NULL_HANDLE)
4548 {
4549 ASSERT(packedBinding.count == 1);
4550 immutableSamplers->push_back(packedBinding.immutableSampler);
4551 binding.pImmutableSamplers = reinterpret_cast<const VkSampler *>(angle::DirtyPointer);
4552 }
4553
4554 bindings->push_back(binding);
4555 }
4556 if (!immutableSamplers->empty())
4557 {
4558 // Patch up pImmutableSampler addresses now that the vector is stable
4559 int immutableIndex = 0;
4560 for (VkDescriptorSetLayoutBinding &binding : *bindings)
4561 {
4562 if (binding.pImmutableSamplers)
4563 {
4564 binding.pImmutableSamplers = &(*immutableSamplers)[immutableIndex];
4565 immutableIndex++;
4566 }
4567 }
4568 }
4569 }
4570
4571 // PipelineLayoutDesc implementation.
PipelineLayoutDesc()4572 PipelineLayoutDesc::PipelineLayoutDesc()
4573 : mDescriptorSetLayouts{}, mPushConstantRange{}, mPadding(0)
4574 {}
4575
4576 PipelineLayoutDesc::~PipelineLayoutDesc() = default;
4577
4578 PipelineLayoutDesc::PipelineLayoutDesc(const PipelineLayoutDesc &other) = default;
4579
operator =(const PipelineLayoutDesc & rhs)4580 PipelineLayoutDesc &PipelineLayoutDesc::operator=(const PipelineLayoutDesc &rhs)
4581 {
4582 mDescriptorSetLayouts = rhs.mDescriptorSetLayouts;
4583 mPushConstantRange = rhs.mPushConstantRange;
4584 return *this;
4585 }
4586
hash() const4587 size_t PipelineLayoutDesc::hash() const
4588 {
4589 return angle::ComputeGenericHash(*this);
4590 }
4591
operator ==(const PipelineLayoutDesc & other) const4592 bool PipelineLayoutDesc::operator==(const PipelineLayoutDesc &other) const
4593 {
4594 return memcmp(this, &other, sizeof(PipelineLayoutDesc)) == 0;
4595 }
4596
updateDescriptorSetLayout(DescriptorSetIndex setIndex,const DescriptorSetLayoutDesc & desc)4597 void PipelineLayoutDesc::updateDescriptorSetLayout(DescriptorSetIndex setIndex,
4598 const DescriptorSetLayoutDesc &desc)
4599 {
4600 mDescriptorSetLayouts[setIndex] = desc;
4601 }
4602
updatePushConstantRange(VkShaderStageFlags stageMask,uint32_t offset,uint32_t size)4603 void PipelineLayoutDesc::updatePushConstantRange(VkShaderStageFlags stageMask,
4604 uint32_t offset,
4605 uint32_t size)
4606 {
4607 SetBitField(mPushConstantRange.offset, offset);
4608 SetBitField(mPushConstantRange.size, size);
4609 SetBitField(mPushConstantRange.stageMask, stageMask);
4610 }
4611
4612 // CreateMonolithicPipelineTask implementation.
CreateMonolithicPipelineTask(RendererVk * renderer,const PipelineCacheAccess & pipelineCache,const PipelineLayout & pipelineLayout,const ShaderModuleMap & shaders,const SpecializationConstants & specConsts,const GraphicsPipelineDesc & desc)4613 CreateMonolithicPipelineTask::CreateMonolithicPipelineTask(
4614 RendererVk *renderer,
4615 const PipelineCacheAccess &pipelineCache,
4616 const PipelineLayout &pipelineLayout,
4617 const ShaderModuleMap &shaders,
4618 const SpecializationConstants &specConsts,
4619 const GraphicsPipelineDesc &desc)
4620 : Context(renderer),
4621 mPipelineCache(pipelineCache),
4622 mCompatibleRenderPass(nullptr),
4623 mPipelineLayout(pipelineLayout),
4624 mShaders(shaders),
4625 mSpecConsts(specConsts),
4626 mDesc(desc),
4627 mResult(VK_NOT_READY),
4628 mFeedback(CacheLookUpFeedback::None)
4629 {
4630 // Make sure the given pipeline cache has an associated mutex as this task will be running
4631 // asynchronously.
4632 ASSERT(pipelineCache.isThreadSafe());
4633 }
4634
setCompatibleRenderPass(const RenderPass * compatibleRenderPass)4635 void CreateMonolithicPipelineTask::setCompatibleRenderPass(const RenderPass *compatibleRenderPass)
4636 {
4637 mCompatibleRenderPass = compatibleRenderPass;
4638 }
4639
operator ()()4640 void CreateMonolithicPipelineTask::operator()()
4641 {
4642 ANGLE_TRACE_EVENT0("gpu.angle", "CreateMonolithicPipelineTask");
4643 mResult = mDesc.initializePipeline(this, &mPipelineCache, vk::GraphicsPipelineSubset::Complete,
4644 *mCompatibleRenderPass, mPipelineLayout, mShaders,
4645 mSpecConsts, &mPipeline, &mFeedback);
4646
4647 if (mRenderer->getFeatures().slowDownMonolithicPipelineCreationForTesting.enabled)
4648 {
4649 constexpr double kSlowdownTime = 0.05;
4650
4651 double startTime = angle::GetCurrentSystemTime();
4652 while (angle::GetCurrentSystemTime() - startTime < kSlowdownTime)
4653 {
4654 // Busy waiting
4655 }
4656 }
4657 }
4658
handleError(VkResult result,const char * file,const char * function,unsigned int line)4659 void CreateMonolithicPipelineTask::handleError(VkResult result,
4660 const char *file,
4661 const char *function,
4662 unsigned int line)
4663 {
4664 UNREACHABLE();
4665 }
4666
4667 // WaitableMonolithicPipelineCreationTask implementation
~WaitableMonolithicPipelineCreationTask()4668 WaitableMonolithicPipelineCreationTask::~WaitableMonolithicPipelineCreationTask()
4669 {
4670 ASSERT(!mWaitableEvent);
4671 ASSERT(!mTask);
4672 }
4673
4674 // PipelineHelper implementation.
4675 PipelineHelper::PipelineHelper() = default;
4676
4677 PipelineHelper::~PipelineHelper() = default;
4678
destroy(VkDevice device)4679 void PipelineHelper::destroy(VkDevice device)
4680 {
4681 mPipeline.destroy(device);
4682 mLinkedPipelineToRelease.destroy(device);
4683
4684 // If there is a pending task, wait for it before destruction.
4685 if (mMonolithicPipelineCreationTask.isValid())
4686 {
4687 if (mMonolithicPipelineCreationTask.isPosted())
4688 {
4689 mMonolithicPipelineCreationTask.wait();
4690 mMonolithicPipelineCreationTask.getTask()->getPipeline().destroy(device);
4691 }
4692 mMonolithicPipelineCreationTask.reset();
4693 }
4694
4695 reset();
4696 }
4697
release(ContextVk * contextVk)4698 void PipelineHelper::release(ContextVk *contextVk)
4699 {
4700 contextVk->getRenderer()->collectGarbage(mUse, &mPipeline);
4701 contextVk->getRenderer()->collectGarbage(mUse, &mLinkedPipelineToRelease);
4702
4703 // If there is a pending task, wait for it before release.
4704 if (mMonolithicPipelineCreationTask.isValid())
4705 {
4706 if (mMonolithicPipelineCreationTask.isPosted())
4707 {
4708 mMonolithicPipelineCreationTask.wait();
4709 contextVk->getRenderer()->collectGarbage(
4710 mUse, &mMonolithicPipelineCreationTask.getTask()->getPipeline());
4711 }
4712 mMonolithicPipelineCreationTask.reset();
4713 }
4714
4715 reset();
4716 }
4717
reset()4718 void PipelineHelper::reset()
4719 {
4720 mCacheLookUpFeedback = CacheLookUpFeedback::None;
4721 mMonolithicCacheLookUpFeedback = CacheLookUpFeedback::None;
4722
4723 mLinkedShaders = nullptr;
4724 }
4725
getPreferredPipeline(ContextVk * contextVk,const Pipeline ** pipelineOut)4726 angle::Result PipelineHelper::getPreferredPipeline(ContextVk *contextVk,
4727 const Pipeline **pipelineOut)
4728 {
4729 if (mMonolithicPipelineCreationTask.isValid())
4730 {
4731 // If there is a monolithic task pending, attempt to post it if not already. Once the task
4732 // is done, retrieve the results and replace the pipeline.
4733 if (!mMonolithicPipelineCreationTask.isPosted())
4734 {
4735 ANGLE_TRY(contextVk->getShareGroup()->scheduleMonolithicPipelineCreationTask(
4736 contextVk, &mMonolithicPipelineCreationTask));
4737 }
4738 else if (mMonolithicPipelineCreationTask.isReady())
4739 {
4740 CreateMonolithicPipelineTask *task = &*mMonolithicPipelineCreationTask.getTask();
4741 ANGLE_VK_TRY(contextVk, task->getResult());
4742
4743 mMonolithicCacheLookUpFeedback = task->getFeedback();
4744
4745 // The pipeline will not be used anymore. Every context that has used this pipeline has
4746 // already updated the serial.
4747 mLinkedPipelineToRelease = std::move(mPipeline);
4748
4749 // Replace it with the monolithic one.
4750 mPipeline = std::move(task->getPipeline());
4751
4752 mLinkedShaders = nullptr;
4753
4754 mMonolithicPipelineCreationTask.reset();
4755
4756 ++contextVk->getPerfCounters().monolithicPipelineCreation;
4757 }
4758 }
4759
4760 *pipelineOut = &mPipeline;
4761
4762 return angle::Result::Continue;
4763 }
4764
addTransition(GraphicsPipelineTransitionBits bits,const GraphicsPipelineDesc * desc,PipelineHelper * pipeline)4765 void PipelineHelper::addTransition(GraphicsPipelineTransitionBits bits,
4766 const GraphicsPipelineDesc *desc,
4767 PipelineHelper *pipeline)
4768 {
4769 mTransitions.emplace_back(bits, desc, pipeline);
4770 }
4771
setLinkedLibraryReferences(vk::PipelineHelper * shadersPipeline)4772 void PipelineHelper::setLinkedLibraryReferences(vk::PipelineHelper *shadersPipeline)
4773 {
4774 mLinkedShaders = shadersPipeline;
4775 }
4776
retainInRenderPass(RenderPassCommandBufferHelper * renderPassCommands)4777 void PipelineHelper::retainInRenderPass(RenderPassCommandBufferHelper *renderPassCommands)
4778 {
4779 renderPassCommands->retainResource(this);
4780
4781 // Keep references to the linked libraries alive. Note that currently only need to do this for
4782 // the shaders library, as the vertex and fragment libraries live in the context until
4783 // destruction.
4784 if (mLinkedShaders != nullptr)
4785 {
4786 renderPassCommands->retainResource(mLinkedShaders);
4787 }
4788 }
4789
4790 // FramebufferHelper implementation.
4791 FramebufferHelper::FramebufferHelper() = default;
4792
4793 FramebufferHelper::~FramebufferHelper() = default;
4794
FramebufferHelper(FramebufferHelper && other)4795 FramebufferHelper::FramebufferHelper(FramebufferHelper &&other) : Resource(std::move(other))
4796 {
4797 mFramebuffer = std::move(other.mFramebuffer);
4798 }
4799
operator =(FramebufferHelper && other)4800 FramebufferHelper &FramebufferHelper::operator=(FramebufferHelper &&other)
4801 {
4802 Resource::operator=(std::move(other));
4803 std::swap(mFramebuffer, other.mFramebuffer);
4804 return *this;
4805 }
4806
init(ContextVk * contextVk,const VkFramebufferCreateInfo & createInfo)4807 angle::Result FramebufferHelper::init(ContextVk *contextVk,
4808 const VkFramebufferCreateInfo &createInfo)
4809 {
4810 ANGLE_VK_TRY(contextVk, mFramebuffer.init(contextVk->getDevice(), createInfo));
4811 return angle::Result::Continue;
4812 }
4813
destroy(RendererVk * rendererVk)4814 void FramebufferHelper::destroy(RendererVk *rendererVk)
4815 {
4816 mFramebuffer.destroy(rendererVk->getDevice());
4817 }
4818
release(ContextVk * contextVk)4819 void FramebufferHelper::release(ContextVk *contextVk)
4820 {
4821 contextVk->addGarbage(&mFramebuffer);
4822 }
4823
4824 // DescriptorSetDesc implementation.
hash() const4825 size_t DescriptorSetDesc::hash() const
4826 {
4827 if (mDescriptorInfos.empty())
4828 {
4829 return 0;
4830 }
4831
4832 return angle::ComputeGenericHash(mDescriptorInfos.data(),
4833 sizeof(mDescriptorInfos[0]) * mDescriptorInfos.size());
4834 }
4835
4836 // FramebufferDesc implementation.
4837
FramebufferDesc()4838 FramebufferDesc::FramebufferDesc()
4839 {
4840 reset();
4841 }
4842
4843 FramebufferDesc::~FramebufferDesc() = default;
4844 FramebufferDesc::FramebufferDesc(const FramebufferDesc &other) = default;
4845 FramebufferDesc &FramebufferDesc::operator=(const FramebufferDesc &other) = default;
4846
update(uint32_t index,ImageOrBufferViewSubresourceSerial serial)4847 void FramebufferDesc::update(uint32_t index, ImageOrBufferViewSubresourceSerial serial)
4848 {
4849 static_assert(kMaxFramebufferAttachments + 1 < std::numeric_limits<uint8_t>::max(),
4850 "mMaxIndex size is too small");
4851 ASSERT(index < kMaxFramebufferAttachments);
4852 mSerials[index] = serial;
4853 if (serial.viewSerial.valid())
4854 {
4855 SetBitField(mMaxIndex, std::max(mMaxIndex, static_cast<uint16_t>(index + 1)));
4856 }
4857 }
4858
updateColor(uint32_t index,ImageOrBufferViewSubresourceSerial serial)4859 void FramebufferDesc::updateColor(uint32_t index, ImageOrBufferViewSubresourceSerial serial)
4860 {
4861 update(kFramebufferDescColorIndexOffset + index, serial);
4862 }
4863
updateColorResolve(uint32_t index,ImageOrBufferViewSubresourceSerial serial)4864 void FramebufferDesc::updateColorResolve(uint32_t index, ImageOrBufferViewSubresourceSerial serial)
4865 {
4866 update(kFramebufferDescColorResolveIndexOffset + index, serial);
4867 }
4868
updateUnresolveMask(FramebufferNonResolveAttachmentMask unresolveMask)4869 void FramebufferDesc::updateUnresolveMask(FramebufferNonResolveAttachmentMask unresolveMask)
4870 {
4871 SetBitField(mUnresolveAttachmentMask, unresolveMask.bits());
4872 }
4873
updateDepthStencil(ImageOrBufferViewSubresourceSerial serial)4874 void FramebufferDesc::updateDepthStencil(ImageOrBufferViewSubresourceSerial serial)
4875 {
4876 update(kFramebufferDescDepthStencilIndex, serial);
4877 }
4878
updateDepthStencilResolve(ImageOrBufferViewSubresourceSerial serial)4879 void FramebufferDesc::updateDepthStencilResolve(ImageOrBufferViewSubresourceSerial serial)
4880 {
4881 update(kFramebufferDescDepthStencilResolveIndexOffset, serial);
4882 }
4883
hash() const4884 size_t FramebufferDesc::hash() const
4885 {
4886 return angle::ComputeGenericHash(&mSerials, sizeof(mSerials[0]) * mMaxIndex) ^
4887 mHasFramebufferFetch << 26 ^ mIsRenderToTexture << 25 ^ mLayerCount << 16 ^
4888 mUnresolveAttachmentMask;
4889 }
4890
reset()4891 void FramebufferDesc::reset()
4892 {
4893 mMaxIndex = 0;
4894 mHasFramebufferFetch = false;
4895 mLayerCount = 0;
4896 mSrgbWriteControlMode = 0;
4897 mUnresolveAttachmentMask = 0;
4898 mIsRenderToTexture = 0;
4899 memset(&mSerials, 0, sizeof(mSerials));
4900 }
4901
operator ==(const FramebufferDesc & other) const4902 bool FramebufferDesc::operator==(const FramebufferDesc &other) const
4903 {
4904 if (mMaxIndex != other.mMaxIndex || mLayerCount != other.mLayerCount ||
4905 mUnresolveAttachmentMask != other.mUnresolveAttachmentMask ||
4906 mHasFramebufferFetch != other.mHasFramebufferFetch ||
4907 mSrgbWriteControlMode != other.mSrgbWriteControlMode ||
4908 mIsRenderToTexture != other.mIsRenderToTexture)
4909 {
4910 return false;
4911 }
4912
4913 size_t validRegionSize = sizeof(mSerials[0]) * mMaxIndex;
4914 return memcmp(&mSerials, &other.mSerials, validRegionSize) == 0;
4915 }
4916
attachmentCount() const4917 uint32_t FramebufferDesc::attachmentCount() const
4918 {
4919 uint32_t count = 0;
4920 for (const ImageOrBufferViewSubresourceSerial &serial : mSerials)
4921 {
4922 if (serial.viewSerial.valid())
4923 {
4924 count++;
4925 }
4926 }
4927 return count;
4928 }
4929
getUnresolveAttachmentMask() const4930 FramebufferNonResolveAttachmentMask FramebufferDesc::getUnresolveAttachmentMask() const
4931 {
4932 return FramebufferNonResolveAttachmentMask(mUnresolveAttachmentMask);
4933 }
4934
updateLayerCount(uint32_t layerCount)4935 void FramebufferDesc::updateLayerCount(uint32_t layerCount)
4936 {
4937 SetBitField(mLayerCount, layerCount);
4938 }
4939
setFramebufferFetchMode(bool hasFramebufferFetch)4940 void FramebufferDesc::setFramebufferFetchMode(bool hasFramebufferFetch)
4941 {
4942 SetBitField(mHasFramebufferFetch, hasFramebufferFetch);
4943 }
4944
updateRenderToTexture(bool isRenderToTexture)4945 void FramebufferDesc::updateRenderToTexture(bool isRenderToTexture)
4946 {
4947 SetBitField(mIsRenderToTexture, isRenderToTexture);
4948 }
4949
4950 // YcbcrConversionDesc implementation
YcbcrConversionDesc()4951 YcbcrConversionDesc::YcbcrConversionDesc()
4952 {
4953 reset();
4954 }
4955
4956 YcbcrConversionDesc::~YcbcrConversionDesc() = default;
4957
4958 YcbcrConversionDesc::YcbcrConversionDesc(const YcbcrConversionDesc &other) = default;
4959
4960 YcbcrConversionDesc &YcbcrConversionDesc::operator=(const YcbcrConversionDesc &rhs) = default;
4961
hash() const4962 size_t YcbcrConversionDesc::hash() const
4963 {
4964 return angle::ComputeGenericHash(*this);
4965 }
4966
operator ==(const YcbcrConversionDesc & other) const4967 bool YcbcrConversionDesc::operator==(const YcbcrConversionDesc &other) const
4968 {
4969 return memcmp(this, &other, sizeof(YcbcrConversionDesc)) == 0;
4970 }
4971
reset()4972 void YcbcrConversionDesc::reset()
4973 {
4974 mExternalOrVkFormat = 0;
4975 mIsExternalFormat = 0;
4976 mConversionModel = 0;
4977 mColorRange = 0;
4978 mXChromaOffset = 0;
4979 mYChromaOffset = 0;
4980 mChromaFilter = 0;
4981 mRSwizzle = 0;
4982 mGSwizzle = 0;
4983 mBSwizzle = 0;
4984 mASwizzle = 0;
4985 mPadding = 0;
4986 mReserved = 0;
4987 }
4988
update(RendererVk * rendererVk,uint64_t externalFormat,VkSamplerYcbcrModelConversion conversionModel,VkSamplerYcbcrRange colorRange,VkChromaLocation xChromaOffset,VkChromaLocation yChromaOffset,VkFilter chromaFilter,VkComponentMapping components,angle::FormatID intendedFormatID)4989 void YcbcrConversionDesc::update(RendererVk *rendererVk,
4990 uint64_t externalFormat,
4991 VkSamplerYcbcrModelConversion conversionModel,
4992 VkSamplerYcbcrRange colorRange,
4993 VkChromaLocation xChromaOffset,
4994 VkChromaLocation yChromaOffset,
4995 VkFilter chromaFilter,
4996 VkComponentMapping components,
4997 angle::FormatID intendedFormatID)
4998 {
4999 const vk::Format &vkFormat = rendererVk->getFormat(intendedFormatID);
5000 ASSERT(externalFormat != 0 || vkFormat.getIntendedFormat().isYUV);
5001
5002 SetBitField(mIsExternalFormat, (externalFormat) ? 1 : 0);
5003 mExternalOrVkFormat = (externalFormat)
5004 ? externalFormat
5005 : vkFormat.getActualImageVkFormat(vk::ImageAccess::SampleOnly);
5006
5007 updateChromaFilter(rendererVk, chromaFilter);
5008
5009 SetBitField(mConversionModel, conversionModel);
5010 SetBitField(mColorRange, colorRange);
5011 SetBitField(mXChromaOffset, xChromaOffset);
5012 SetBitField(mYChromaOffset, yChromaOffset);
5013 SetBitField(mRSwizzle, components.r);
5014 SetBitField(mGSwizzle, components.g);
5015 SetBitField(mBSwizzle, components.b);
5016 SetBitField(mASwizzle, components.a);
5017 }
5018
updateChromaFilter(RendererVk * rendererVk,VkFilter filter)5019 bool YcbcrConversionDesc::updateChromaFilter(RendererVk *rendererVk, VkFilter filter)
5020 {
5021 // The app has requested a specific min/mag filter, reconcile that with the filter
5022 // requested by preferLinearFilterForYUV feature.
5023 //
5024 // preferLinearFilterForYUV enforces linear filter while forceNearestFiltering and
5025 // forceNearestMipFiltering enforces nearest filter, enabling one precludes the other.
5026 ASSERT(!rendererVk->getFeatures().preferLinearFilterForYUV.enabled ||
5027 (!rendererVk->getFeatures().forceNearestFiltering.enabled &&
5028 !rendererVk->getFeatures().forceNearestMipFiltering.enabled));
5029
5030 VkFilter preferredChromaFilter = rendererVk->getPreferredFilterForYUV(filter);
5031 ASSERT(preferredChromaFilter == VK_FILTER_LINEAR || preferredChromaFilter == VK_FILTER_NEAREST);
5032
5033 if (preferredChromaFilter == VK_FILTER_LINEAR && mIsExternalFormat == 0)
5034 {
5035 // Vulkan ICDs are allowed to not support LINEAR filter.
5036 angle::FormatID formatId =
5037 vk::GetFormatIDFromVkFormat(static_cast<VkFormat>(mExternalOrVkFormat));
5038 if (!rendererVk->hasImageFormatFeatureBits(
5039 formatId, VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT))
5040 {
5041 preferredChromaFilter = VK_FILTER_NEAREST;
5042 }
5043 }
5044
5045 if (getChromaFilter() != preferredChromaFilter)
5046 {
5047 SetBitField(mChromaFilter, preferredChromaFilter);
5048 return true;
5049 }
5050 return false;
5051 }
5052
updateConversionModel(VkSamplerYcbcrModelConversion conversionModel)5053 void YcbcrConversionDesc::updateConversionModel(VkSamplerYcbcrModelConversion conversionModel)
5054 {
5055 SetBitField(mConversionModel, conversionModel);
5056 }
5057
init(Context * context,SamplerYcbcrConversion * conversionOut) const5058 angle::Result YcbcrConversionDesc::init(Context *context,
5059 SamplerYcbcrConversion *conversionOut) const
5060 {
5061 // Create the VkSamplerYcbcrConversion
5062 VkSamplerYcbcrConversionCreateInfo samplerYcbcrConversionInfo = {};
5063 samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO;
5064 samplerYcbcrConversionInfo.format =
5065 getExternalFormat() == 0 ? static_cast<VkFormat>(mExternalOrVkFormat) : VK_FORMAT_UNDEFINED;
5066 samplerYcbcrConversionInfo.xChromaOffset = static_cast<VkChromaLocation>(mXChromaOffset);
5067 samplerYcbcrConversionInfo.yChromaOffset = static_cast<VkChromaLocation>(mYChromaOffset);
5068 samplerYcbcrConversionInfo.ycbcrModel =
5069 static_cast<VkSamplerYcbcrModelConversion>(mConversionModel);
5070 samplerYcbcrConversionInfo.ycbcrRange = static_cast<VkSamplerYcbcrRange>(mColorRange);
5071 samplerYcbcrConversionInfo.chromaFilter = static_cast<VkFilter>(mChromaFilter);
5072 samplerYcbcrConversionInfo.components = {
5073 static_cast<VkComponentSwizzle>(mRSwizzle), static_cast<VkComponentSwizzle>(mGSwizzle),
5074 static_cast<VkComponentSwizzle>(mBSwizzle), static_cast<VkComponentSwizzle>(mASwizzle)};
5075
5076 #ifdef VK_USE_PLATFORM_ANDROID_KHR
5077 VkExternalFormatANDROID externalFormat = {};
5078 if (getExternalFormat() != 0)
5079 {
5080 externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
5081 externalFormat.externalFormat = mExternalOrVkFormat;
5082 samplerYcbcrConversionInfo.pNext = &externalFormat;
5083 }
5084 #else
5085 // We do not support external format for any platform other than Android.
5086 ASSERT(mIsExternalFormat == 0);
5087 #endif // VK_USE_PLATFORM_ANDROID_KHR
5088
5089 ANGLE_VK_TRY(context, conversionOut->init(context->getDevice(), samplerYcbcrConversionInfo));
5090 return angle::Result::Continue;
5091 }
5092
5093 // SamplerDesc implementation.
SamplerDesc()5094 SamplerDesc::SamplerDesc()
5095 {
5096 reset();
5097 }
5098
5099 SamplerDesc::~SamplerDesc() = default;
5100
5101 SamplerDesc::SamplerDesc(const SamplerDesc &other) = default;
5102
5103 SamplerDesc &SamplerDesc::operator=(const SamplerDesc &rhs) = default;
5104
SamplerDesc(ContextVk * contextVk,const gl::SamplerState & samplerState,bool stencilMode,const YcbcrConversionDesc * ycbcrConversionDesc,angle::FormatID intendedFormatID)5105 SamplerDesc::SamplerDesc(ContextVk *contextVk,
5106 const gl::SamplerState &samplerState,
5107 bool stencilMode,
5108 const YcbcrConversionDesc *ycbcrConversionDesc,
5109 angle::FormatID intendedFormatID)
5110 {
5111 update(contextVk, samplerState, stencilMode, ycbcrConversionDesc, intendedFormatID);
5112 }
5113
reset()5114 void SamplerDesc::reset()
5115 {
5116 mMipLodBias = 0.0f;
5117 mMaxAnisotropy = 0.0f;
5118 mMinLod = 0.0f;
5119 mMaxLod = 0.0f;
5120 mYcbcrConversionDesc.reset();
5121 mMagFilter = 0;
5122 mMinFilter = 0;
5123 mMipmapMode = 0;
5124 mAddressModeU = 0;
5125 mAddressModeV = 0;
5126 mAddressModeW = 0;
5127 mCompareEnabled = 0;
5128 mCompareOp = 0;
5129 mPadding = 0;
5130 mBorderColorType = 0;
5131 mBorderColor.red = 0.0f;
5132 mBorderColor.green = 0.0f;
5133 mBorderColor.blue = 0.0f;
5134 mBorderColor.alpha = 0.0f;
5135 mReserved = 0;
5136 }
5137
update(ContextVk * contextVk,const gl::SamplerState & samplerState,bool stencilMode,const YcbcrConversionDesc * ycbcrConversionDesc,angle::FormatID intendedFormatID)5138 void SamplerDesc::update(ContextVk *contextVk,
5139 const gl::SamplerState &samplerState,
5140 bool stencilMode,
5141 const YcbcrConversionDesc *ycbcrConversionDesc,
5142 angle::FormatID intendedFormatID)
5143 {
5144 const angle::FeaturesVk &featuresVk = contextVk->getFeatures();
5145 mMipLodBias = 0.0f;
5146 if (featuresVk.forceTextureLodOffset1.enabled)
5147 {
5148 mMipLodBias = 1.0f;
5149 }
5150 else if (featuresVk.forceTextureLodOffset2.enabled)
5151 {
5152 mMipLodBias = 2.0f;
5153 }
5154 else if (featuresVk.forceTextureLodOffset3.enabled)
5155 {
5156 mMipLodBias = 3.0f;
5157 }
5158 else if (featuresVk.forceTextureLodOffset4.enabled)
5159 {
5160 mMipLodBias = 4.0f;
5161 }
5162
5163 mMaxAnisotropy = samplerState.getMaxAnisotropy();
5164 mMinLod = samplerState.getMinLod();
5165 mMaxLod = samplerState.getMaxLod();
5166
5167 GLenum minFilter = samplerState.getMinFilter();
5168 GLenum magFilter = samplerState.getMagFilter();
5169 if (ycbcrConversionDesc && ycbcrConversionDesc->valid())
5170 {
5171 // Update the SamplerYcbcrConversionCache key
5172 mYcbcrConversionDesc = *ycbcrConversionDesc;
5173
5174 // Reconcile chroma filter and min/mag filters.
5175 //
5176 // VUID-VkSamplerCreateInfo-minFilter-01645
5177 // If sampler YCBCR conversion is enabled and the potential format features of the
5178 // sampler YCBCR conversion do not support
5179 // VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT,
5180 // minFilter and magFilter must be equal to the sampler YCBCR conversions chromaFilter.
5181 //
5182 // For simplicity assume external formats do not support that feature bit.
5183 ASSERT((mYcbcrConversionDesc.getExternalFormat() != 0) ||
5184 (angle::Format::Get(intendedFormatID).isYUV));
5185 const bool filtersMustMatch =
5186 (mYcbcrConversionDesc.getExternalFormat() != 0) ||
5187 !contextVk->getRenderer()->hasImageFormatFeatureBits(
5188 intendedFormatID,
5189 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT);
5190 if (filtersMustMatch)
5191 {
5192 GLenum glFilter = (mYcbcrConversionDesc.getChromaFilter() == VK_FILTER_LINEAR)
5193 ? GL_LINEAR
5194 : GL_NEAREST;
5195 minFilter = glFilter;
5196 magFilter = glFilter;
5197 }
5198 }
5199
5200 bool compareEnable = samplerState.getCompareMode() == GL_COMPARE_REF_TO_TEXTURE;
5201 VkCompareOp compareOp = gl_vk::GetCompareOp(samplerState.getCompareFunc());
5202 // When sampling from stencil, deqp tests expect texture compare to have no effect
5203 // dEQP - GLES31.functional.stencil_texturing.misc.compare_mode_effect
5204 // states: NOTE: Texture compare mode has no effect when reading stencil values.
5205 if (stencilMode)
5206 {
5207 compareEnable = VK_FALSE;
5208 compareOp = VK_COMPARE_OP_ALWAYS;
5209 }
5210
5211 if (featuresVk.forceNearestFiltering.enabled)
5212 {
5213 magFilter = gl::ConvertToNearestFilterMode(magFilter);
5214 minFilter = gl::ConvertToNearestFilterMode(minFilter);
5215 }
5216 if (featuresVk.forceNearestMipFiltering.enabled)
5217 {
5218 minFilter = gl::ConvertToNearestMipFilterMode(minFilter);
5219 }
5220
5221 SetBitField(mMagFilter, gl_vk::GetFilter(magFilter));
5222 SetBitField(mMinFilter, gl_vk::GetFilter(minFilter));
5223 SetBitField(mMipmapMode, gl_vk::GetSamplerMipmapMode(samplerState.getMinFilter()));
5224 SetBitField(mAddressModeU, gl_vk::GetSamplerAddressMode(samplerState.getWrapS()));
5225 SetBitField(mAddressModeV, gl_vk::GetSamplerAddressMode(samplerState.getWrapT()));
5226 SetBitField(mAddressModeW, gl_vk::GetSamplerAddressMode(samplerState.getWrapR()));
5227 SetBitField(mCompareEnabled, compareEnable);
5228 SetBitField(mCompareOp, compareOp);
5229
5230 if (!gl::IsMipmapFiltered(minFilter))
5231 {
5232 // Per the Vulkan spec, GL_NEAREST and GL_LINEAR do not map directly to Vulkan, so
5233 // they must be emulated (See "Mapping of OpenGL to Vulkan filter modes")
5234 SetBitField(mMipmapMode, VK_SAMPLER_MIPMAP_MODE_NEAREST);
5235 mMinLod = 0.0f;
5236 mMaxLod = 0.25f;
5237 }
5238
5239 mPadding = 0;
5240
5241 mBorderColorType =
5242 (samplerState.getBorderColor().type == angle::ColorGeneric::Type::Float) ? 0 : 1;
5243
5244 // Adjust border color according to intended format
5245 const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(intendedFormatID);
5246 gl::ColorGeneric adjustedBorderColor =
5247 AdjustBorderColor(samplerState.getBorderColor(), vkFormat.getIntendedFormat(), stencilMode);
5248 mBorderColor = adjustedBorderColor.colorF;
5249
5250 mReserved = 0;
5251 }
5252
init(ContextVk * contextVk,Sampler * sampler) const5253 angle::Result SamplerDesc::init(ContextVk *contextVk, Sampler *sampler) const
5254 {
5255 const gl::Extensions &extensions = contextVk->getExtensions();
5256
5257 bool anisotropyEnable = extensions.textureFilterAnisotropicEXT && mMaxAnisotropy > 1.0f;
5258
5259 VkSamplerCreateInfo createInfo = {};
5260 createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
5261 createInfo.flags = 0;
5262 createInfo.magFilter = static_cast<VkFilter>(mMagFilter);
5263 createInfo.minFilter = static_cast<VkFilter>(mMinFilter);
5264 createInfo.mipmapMode = static_cast<VkSamplerMipmapMode>(mMipmapMode);
5265 createInfo.addressModeU = static_cast<VkSamplerAddressMode>(mAddressModeU);
5266 createInfo.addressModeV = static_cast<VkSamplerAddressMode>(mAddressModeV);
5267 createInfo.addressModeW = static_cast<VkSamplerAddressMode>(mAddressModeW);
5268 createInfo.mipLodBias = mMipLodBias;
5269 createInfo.anisotropyEnable = anisotropyEnable;
5270 createInfo.maxAnisotropy = mMaxAnisotropy;
5271 createInfo.compareEnable = mCompareEnabled ? VK_TRUE : VK_FALSE;
5272 createInfo.compareOp = static_cast<VkCompareOp>(mCompareOp);
5273 createInfo.minLod = mMinLod;
5274 createInfo.maxLod = mMaxLod;
5275 createInfo.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
5276 createInfo.unnormalizedCoordinates = VK_FALSE;
5277
5278 // Note: because we don't detect changes to this hint (no dirty bit), if a sampler is created
5279 // with the hint enabled, and then the hint gets disabled, the next render will do so with the
5280 // hint enabled.
5281 VkSamplerFilteringPrecisionGOOGLE filteringInfo = {};
5282 GLenum hint = contextVk->getState().getTextureFilteringHint();
5283 if (hint == GL_NICEST)
5284 {
5285 ASSERT(extensions.textureFilteringHintCHROMIUM);
5286 filteringInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_FILTERING_PRECISION_GOOGLE;
5287 filteringInfo.samplerFilteringPrecisionMode =
5288 VK_SAMPLER_FILTERING_PRECISION_MODE_HIGH_GOOGLE;
5289 AddToPNextChain(&createInfo, &filteringInfo);
5290 }
5291
5292 VkSamplerYcbcrConversionInfo samplerYcbcrConversionInfo = {};
5293 if (mYcbcrConversionDesc.valid())
5294 {
5295 ASSERT((contextVk->getRenderer()->getFeatures().supportsYUVSamplerConversion.enabled));
5296 samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
5297 samplerYcbcrConversionInfo.pNext = nullptr;
5298 ANGLE_TRY(contextVk->getRenderer()->getYuvConversionCache().getSamplerYcbcrConversion(
5299 contextVk, mYcbcrConversionDesc, &samplerYcbcrConversionInfo.conversion));
5300 AddToPNextChain(&createInfo, &samplerYcbcrConversionInfo);
5301
5302 // Vulkan spec requires these settings:
5303 createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5304 createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5305 createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5306 createInfo.anisotropyEnable = VK_FALSE;
5307 createInfo.unnormalizedCoordinates = VK_FALSE;
5308 }
5309
5310 VkSamplerCustomBorderColorCreateInfoEXT customBorderColorInfo = {};
5311 if (createInfo.addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
5312 createInfo.addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
5313 createInfo.addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER)
5314 {
5315 ASSERT((contextVk->getRenderer()->getFeatures().supportsCustomBorderColor.enabled));
5316 customBorderColorInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT;
5317
5318 customBorderColorInfo.customBorderColor.float32[0] = mBorderColor.red;
5319 customBorderColorInfo.customBorderColor.float32[1] = mBorderColor.green;
5320 customBorderColorInfo.customBorderColor.float32[2] = mBorderColor.blue;
5321 customBorderColorInfo.customBorderColor.float32[3] = mBorderColor.alpha;
5322
5323 if (mBorderColorType == static_cast<uint32_t>(angle::ColorGeneric::Type::Float))
5324 {
5325 createInfo.borderColor = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT;
5326 }
5327 else
5328 {
5329 createInfo.borderColor = VK_BORDER_COLOR_INT_CUSTOM_EXT;
5330 }
5331
5332 vk::AddToPNextChain(&createInfo, &customBorderColorInfo);
5333 }
5334 ANGLE_VK_TRY(contextVk, sampler->init(contextVk->getDevice(), createInfo));
5335
5336 return angle::Result::Continue;
5337 }
5338
hash() const5339 size_t SamplerDesc::hash() const
5340 {
5341 return angle::ComputeGenericHash(*this);
5342 }
5343
operator ==(const SamplerDesc & other) const5344 bool SamplerDesc::operator==(const SamplerDesc &other) const
5345 {
5346 return memcmp(this, &other, sizeof(SamplerDesc)) == 0;
5347 }
5348
5349 // SamplerHelper implementation.
SamplerHelper(ContextVk * contextVk)5350 SamplerHelper::SamplerHelper(ContextVk *contextVk)
5351 : mSamplerSerial(contextVk->getRenderer()->getResourceSerialFactory().generateSamplerSerial())
5352 {}
5353
~SamplerHelper()5354 SamplerHelper::~SamplerHelper() {}
5355
SamplerHelper(SamplerHelper && samplerHelper)5356 SamplerHelper::SamplerHelper(SamplerHelper &&samplerHelper)
5357 {
5358 *this = std::move(samplerHelper);
5359 }
5360
operator =(SamplerHelper && rhs)5361 SamplerHelper &SamplerHelper::operator=(SamplerHelper &&rhs)
5362 {
5363 std::swap(mSampler, rhs.mSampler);
5364 std::swap(mSamplerSerial, rhs.mSamplerSerial);
5365 return *this;
5366 }
5367
5368 // RenderPassHelper implementation.
RenderPassHelper()5369 RenderPassHelper::RenderPassHelper() : mPerfCounters{} {}
5370
5371 RenderPassHelper::~RenderPassHelper() = default;
5372
RenderPassHelper(RenderPassHelper && other)5373 RenderPassHelper::RenderPassHelper(RenderPassHelper &&other)
5374 {
5375 *this = std::move(other);
5376 }
5377
operator =(RenderPassHelper && other)5378 RenderPassHelper &RenderPassHelper::operator=(RenderPassHelper &&other)
5379 {
5380 mRenderPass = std::move(other.mRenderPass);
5381 mPerfCounters = std::move(other.mPerfCounters);
5382 return *this;
5383 }
5384
destroy(VkDevice device)5385 void RenderPassHelper::destroy(VkDevice device)
5386 {
5387 mRenderPass.destroy(device);
5388 }
5389
release(ContextVk * contextVk)5390 void RenderPassHelper::release(ContextVk *contextVk)
5391 {
5392 contextVk->addGarbage(&mRenderPass);
5393 }
5394
getRenderPass() const5395 const RenderPass &RenderPassHelper::getRenderPass() const
5396 {
5397 return mRenderPass;
5398 }
5399
getRenderPass()5400 RenderPass &RenderPassHelper::getRenderPass()
5401 {
5402 return mRenderPass;
5403 }
5404
getPerfCounters() const5405 const RenderPassPerfCounters &RenderPassHelper::getPerfCounters() const
5406 {
5407 return mPerfCounters;
5408 }
5409
getPerfCounters()5410 RenderPassPerfCounters &RenderPassHelper::getPerfCounters()
5411 {
5412 return mPerfCounters;
5413 }
5414
5415 // WriteDescriptorDescs implementation.
updateWriteDesc(uint32_t bindingIndex,VkDescriptorType descriptorType,uint32_t descriptorCount)5416 void WriteDescriptorDescs::updateWriteDesc(uint32_t bindingIndex,
5417 VkDescriptorType descriptorType,
5418 uint32_t descriptorCount)
5419 {
5420 if (hasWriteDescAtIndex(bindingIndex))
5421 {
5422 uint32_t infoIndex = mDescs[bindingIndex].descriptorInfoIndex;
5423 uint32_t oldDescriptorCount = mDescs[bindingIndex].descriptorCount;
5424 if (descriptorCount != oldDescriptorCount)
5425 {
5426 ASSERT(infoIndex + oldDescriptorCount == mCurrentInfoIndex);
5427 ASSERT(descriptorCount > oldDescriptorCount);
5428 uint32_t additionalDescriptors = descriptorCount - oldDescriptorCount;
5429 incrementDescriptorCount(bindingIndex, additionalDescriptors);
5430 mCurrentInfoIndex += additionalDescriptors;
5431 }
5432 }
5433 else
5434 {
5435 WriteDescriptorDesc &writeDesc = mDescs[bindingIndex];
5436 SetBitField(writeDesc.binding, bindingIndex);
5437 SetBitField(writeDesc.descriptorCount, descriptorCount);
5438 SetBitField(writeDesc.descriptorType, descriptorType);
5439 SetBitField(writeDesc.descriptorInfoIndex, mCurrentInfoIndex);
5440 mCurrentInfoIndex += descriptorCount;
5441 ASSERT(writeDesc.descriptorCount > 0);
5442 }
5443 }
5444
updateShaderBuffers(const ShaderInterfaceVariableInfoMap & variableInfoMap,const std::vector<gl::InterfaceBlock> & blocks,VkDescriptorType descriptorType)5445 void WriteDescriptorDescs::updateShaderBuffers(
5446 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5447 const std::vector<gl::InterfaceBlock> &blocks,
5448 VkDescriptorType descriptorType)
5449 {
5450 // Initialize the descriptor writes in a first pass. This ensures we can pack the structures
5451 // corresponding to array elements tightly.
5452 for (uint32_t blockIndex = 0; blockIndex < blocks.size(); ++blockIndex)
5453 {
5454 const gl::InterfaceBlock &block = blocks[blockIndex];
5455
5456 if (block.activeShaders().none())
5457 {
5458 continue;
5459 }
5460
5461 const gl::ShaderType firstShaderType = block.getFirstActiveShaderType();
5462 const ShaderInterfaceVariableInfo &info =
5463 variableInfoMap.getVariableById(firstShaderType, block.getId(firstShaderType));
5464
5465 if (block.isArray && block.arrayElement > 0)
5466 {
5467 incrementDescriptorCount(info.binding, 1);
5468 mCurrentInfoIndex++;
5469 }
5470 else
5471 {
5472 updateWriteDesc(info.binding, descriptorType, 1);
5473 }
5474 }
5475 }
5476
updateAtomicCounters(const ShaderInterfaceVariableInfoMap & variableInfoMap,const std::vector<gl::AtomicCounterBuffer> & atomicCounterBuffers)5477 void WriteDescriptorDescs::updateAtomicCounters(
5478 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5479 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers)
5480 {
5481 if (atomicCounterBuffers.empty())
5482 {
5483 return;
5484 }
5485
5486 static_assert(!IsDynamicDescriptor(kStorageBufferDescriptorType),
5487 "This method needs an update to handle dynamic descriptors");
5488
5489 uint32_t binding = variableInfoMap.getAtomicCounterBufferBinding(
5490 atomicCounterBuffers[0].getFirstActiveShaderType(), 0);
5491
5492 updateWriteDesc(binding, kStorageBufferDescriptorType,
5493 gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS);
5494 }
5495
updateImages(const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap)5496 void WriteDescriptorDescs::updateImages(const gl::ProgramExecutable &executable,
5497 const ShaderInterfaceVariableInfoMap &variableInfoMap)
5498 {
5499 const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings();
5500 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
5501
5502 if (imageBindings.empty())
5503 {
5504 return;
5505 }
5506
5507 for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
5508 {
5509 const gl::ImageBinding &imageBinding = imageBindings[imageIndex];
5510 uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex);
5511 const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
5512
5513 if (imageUniform.activeShaders().none())
5514 {
5515 continue;
5516 }
5517
5518 const gl::ShaderType firstShaderType = imageUniform.getFirstActiveShaderType();
5519 const ShaderInterfaceVariableInfo &info =
5520 variableInfoMap.getVariableById(firstShaderType, imageUniform.getId(firstShaderType));
5521
5522 uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
5523 uint32_t descriptorCount = arraySize * imageUniform.getOuterArraySizeProduct();
5524 VkDescriptorType descriptorType = (imageBinding.textureType == gl::TextureType::Buffer)
5525 ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
5526 : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
5527
5528 updateWriteDesc(info.binding, descriptorType, descriptorCount);
5529 }
5530 }
5531
updateInputAttachments(const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,FramebufferVk * framebufferVk)5532 void WriteDescriptorDescs::updateInputAttachments(
5533 const gl::ProgramExecutable &executable,
5534 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5535 FramebufferVk *framebufferVk)
5536 {
5537 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
5538
5539 if (!executable.usesFramebufferFetch())
5540 {
5541 return;
5542 }
5543
5544 const uint32_t baseUniformIndex = executable.getFragmentInoutRange().low();
5545 const gl::LinkedUniform &baseInputAttachment = uniforms.at(baseUniformIndex);
5546
5547 const ShaderInterfaceVariableInfo &baseInfo = variableInfoMap.getVariableById(
5548 gl::ShaderType::Fragment, baseInputAttachment.getId(gl::ShaderType::Fragment));
5549
5550 uint32_t baseBinding = baseInfo.binding - baseInputAttachment.getLocation();
5551
5552 for (size_t colorIndex : framebufferVk->getState().getColorAttachmentsMask())
5553 {
5554 uint32_t binding = baseBinding + static_cast<uint32_t>(colorIndex);
5555 updateWriteDesc(binding, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1);
5556 }
5557 }
5558
updateExecutableActiveTextures(const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ProgramExecutable & executable)5559 void WriteDescriptorDescs::updateExecutableActiveTextures(
5560 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5561 const gl::ProgramExecutable &executable)
5562 {
5563 const std::vector<gl::SamplerBinding> &samplerBindings = executable.getSamplerBindings();
5564 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
5565
5566 for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
5567 {
5568 const gl::SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
5569 uint32_t uniformIndex = executable.getUniformIndexFromSamplerIndex(samplerIndex);
5570 const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
5571
5572 if (samplerUniform.activeShaders().none())
5573 {
5574 continue;
5575 }
5576
5577 const gl::ShaderType firstShaderType = samplerUniform.getFirstActiveShaderType();
5578 const ShaderInterfaceVariableInfo &info =
5579 variableInfoMap.getVariableById(firstShaderType, samplerUniform.getId(firstShaderType));
5580
5581 uint32_t arraySize = static_cast<uint32_t>(samplerBinding.boundTextureUnits.size());
5582 uint32_t descriptorCount = arraySize * samplerUniform.getOuterArraySizeProduct();
5583 VkDescriptorType descriptorType = (samplerBinding.textureType == gl::TextureType::Buffer)
5584 ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
5585 : VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
5586
5587 updateWriteDesc(info.binding, descriptorType, descriptorCount);
5588 }
5589 }
5590
updateDefaultUniform(gl::ShaderBitSet shaderTypes,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ProgramExecutable & executable)5591 void WriteDescriptorDescs::updateDefaultUniform(
5592 gl::ShaderBitSet shaderTypes,
5593 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5594 const gl::ProgramExecutable &executable)
5595 {
5596 for (const gl::ShaderType shaderType : shaderTypes)
5597 {
5598 uint32_t binding = variableInfoMap.getDefaultUniformBinding(shaderType);
5599 updateWriteDesc(binding, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1);
5600 }
5601 }
5602
updateTransformFeedbackWrite(const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ProgramExecutable & executable)5603 void WriteDescriptorDescs::updateTransformFeedbackWrite(
5604 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5605 const gl::ProgramExecutable &executable)
5606 {
5607 uint32_t xfbBufferCount = static_cast<uint32_t>(executable.getTransformFeedbackBufferCount());
5608 updateWriteDesc(variableInfoMap.getEmulatedXfbBufferBinding(0),
5609 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, xfbBufferCount);
5610 }
5611
updateDynamicDescriptorsCount()5612 void WriteDescriptorDescs::updateDynamicDescriptorsCount()
5613 {
5614 mDynamicDescriptorSetCount = 0;
5615 for (uint32_t index = 0; index < mDescs.size(); ++index)
5616 {
5617 const WriteDescriptorDesc &writeDesc = mDescs[index];
5618 if (IsDynamicDescriptor(static_cast<VkDescriptorType>(writeDesc.descriptorType)))
5619 {
5620 mDynamicDescriptorSetCount += writeDesc.descriptorCount;
5621 }
5622 }
5623 }
5624
streamOut(std::ostream & ostr) const5625 void WriteDescriptorDescs::streamOut(std::ostream &ostr) const
5626 {
5627 ostr << mDescs.size() << " write descriptor descs:\n";
5628
5629 for (uint32_t index = 0; index < mDescs.size(); ++index)
5630 {
5631 const WriteDescriptorDesc &writeDesc = mDescs[index];
5632 ostr << static_cast<int>(writeDesc.binding) << ": "
5633 << static_cast<int>(writeDesc.descriptorCount) << " "
5634 << kDescriptorTypeNameMap[writeDesc.descriptorType] << " descriptors: ";
5635 ostr << "\n";
5636 }
5637 }
5638
5639 // DescriptorSetDesc implementation.
updateDescriptorSet(Context * context,const WriteDescriptorDescs & writeDescriptorDescs,UpdateDescriptorSetsBuilder * updateBuilder,const DescriptorDescHandles * handles,VkDescriptorSet descriptorSet) const5640 void DescriptorSetDesc::updateDescriptorSet(Context *context,
5641 const WriteDescriptorDescs &writeDescriptorDescs,
5642 UpdateDescriptorSetsBuilder *updateBuilder,
5643 const DescriptorDescHandles *handles,
5644 VkDescriptorSet descriptorSet) const
5645 {
5646 for (uint32_t writeIndex = 0; writeIndex < writeDescriptorDescs.size(); ++writeIndex)
5647 {
5648 const WriteDescriptorDesc &writeDesc = writeDescriptorDescs[writeIndex];
5649
5650 if (writeDesc.descriptorCount == 0)
5651 {
5652 continue;
5653 }
5654
5655 VkWriteDescriptorSet &writeSet = updateBuilder->allocWriteDescriptorSet();
5656
5657 writeSet.descriptorCount = writeDesc.descriptorCount;
5658 writeSet.descriptorType = static_cast<VkDescriptorType>(writeDesc.descriptorType);
5659 writeSet.dstArrayElement = 0;
5660 writeSet.dstBinding = writeIndex;
5661 writeSet.dstSet = descriptorSet;
5662 writeSet.pBufferInfo = nullptr;
5663 writeSet.pImageInfo = nullptr;
5664 writeSet.pNext = nullptr;
5665 writeSet.pTexelBufferView = nullptr;
5666 writeSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
5667
5668 uint32_t infoDescIndex = writeDesc.descriptorInfoIndex;
5669
5670 switch (writeSet.descriptorType)
5671 {
5672 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
5673 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
5674 {
5675 ASSERT(writeDesc.descriptorCount == 1);
5676 VkBufferView &bufferView = updateBuilder->allocBufferView();
5677 bufferView = handles[infoDescIndex].bufferView;
5678 writeSet.pTexelBufferView = &bufferView;
5679 break;
5680 }
5681 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
5682 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
5683 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
5684 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
5685 {
5686 VkDescriptorBufferInfo *writeBuffers =
5687 updateBuilder->allocDescriptorBufferInfos(writeSet.descriptorCount);
5688 for (uint32_t arrayElement = 0; arrayElement < writeSet.descriptorCount;
5689 ++arrayElement)
5690 {
5691 const DescriptorInfoDesc &infoDesc =
5692 mDescriptorInfos[infoDescIndex + arrayElement];
5693 VkDescriptorBufferInfo &bufferInfo = writeBuffers[arrayElement];
5694 bufferInfo.buffer = handles[infoDescIndex + arrayElement].buffer;
5695 bufferInfo.offset = infoDesc.imageViewSerialOrOffset;
5696 bufferInfo.range = infoDesc.imageLayoutOrRange;
5697 }
5698 writeSet.pBufferInfo = writeBuffers;
5699 break;
5700 }
5701 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
5702 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
5703 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
5704 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
5705 {
5706 VkDescriptorImageInfo *writeImages =
5707 updateBuilder->allocDescriptorImageInfos(writeSet.descriptorCount);
5708 for (uint32_t arrayElement = 0; arrayElement < writeSet.descriptorCount;
5709 ++arrayElement)
5710 {
5711 const DescriptorInfoDesc &infoDesc =
5712 mDescriptorInfos[infoDescIndex + arrayElement];
5713 VkDescriptorImageInfo &imageInfo = writeImages[arrayElement];
5714
5715 ImageLayout imageLayout = static_cast<ImageLayout>(infoDesc.imageLayoutOrRange);
5716
5717 imageInfo.imageLayout = ConvertImageLayoutToVkImageLayout(context, imageLayout);
5718 imageInfo.imageView = handles[infoDescIndex + arrayElement].imageView;
5719 imageInfo.sampler = handles[infoDescIndex + arrayElement].sampler;
5720 }
5721 writeSet.pImageInfo = writeImages;
5722 break;
5723 }
5724
5725 default:
5726 UNREACHABLE();
5727 break;
5728 }
5729 }
5730 }
5731
streamOut(std::ostream & ostr) const5732 void DescriptorSetDesc::streamOut(std::ostream &ostr) const
5733 {
5734 ostr << mDescriptorInfos.size() << " descriptor descs:\n";
5735
5736 for (uint32_t index = 0; index < mDescriptorInfos.size(); ++index)
5737 {
5738 const DescriptorInfoDesc &infoDesc = mDescriptorInfos[index];
5739 ostr << "{" << infoDesc.imageLayoutOrRange << ", " << infoDesc.imageSubresourceRange << ", "
5740 << infoDesc.imageViewSerialOrOffset << ", " << infoDesc.samplerOrBufferSerial << "}";
5741 ostr << "\n";
5742 }
5743 }
5744
5745 // DescriptorSetDescBuilder implementation.
5746 DescriptorSetDescBuilder::DescriptorSetDescBuilder() = default;
DescriptorSetDescBuilder(size_t descriptorCount)5747 DescriptorSetDescBuilder::DescriptorSetDescBuilder(size_t descriptorCount)
5748 {
5749 resize(descriptorCount);
5750 }
5751
~DescriptorSetDescBuilder()5752 DescriptorSetDescBuilder::~DescriptorSetDescBuilder() {}
5753
DescriptorSetDescBuilder(const DescriptorSetDescBuilder & other)5754 DescriptorSetDescBuilder::DescriptorSetDescBuilder(const DescriptorSetDescBuilder &other)
5755 : mDesc(other.mDesc), mHandles(other.mHandles), mDynamicOffsets(other.mDynamicOffsets)
5756 {}
5757
operator =(const DescriptorSetDescBuilder & other)5758 DescriptorSetDescBuilder &DescriptorSetDescBuilder::operator=(const DescriptorSetDescBuilder &other)
5759 {
5760 mDesc = other.mDesc;
5761 mHandles = other.mHandles;
5762 mDynamicOffsets = other.mDynamicOffsets;
5763 return *this;
5764 }
5765
updateUniformBuffer(uint32_t bindingIndex,const WriteDescriptorDescs & writeDescriptorDescs,const BufferHelper & bufferHelper,VkDeviceSize bufferRange)5766 void DescriptorSetDescBuilder::updateUniformBuffer(uint32_t bindingIndex,
5767 const WriteDescriptorDescs &writeDescriptorDescs,
5768 const BufferHelper &bufferHelper,
5769 VkDeviceSize bufferRange)
5770 {
5771 uint32_t infoIndex = writeDescriptorDescs[bindingIndex].descriptorInfoIndex;
5772 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
5773
5774 infoDesc.samplerOrBufferSerial = bufferHelper.getBlockSerial().getValue();
5775 infoDesc.imageViewSerialOrOffset = 0;
5776 SetBitField(infoDesc.imageLayoutOrRange, bufferRange);
5777 infoDesc.imageSubresourceRange = 0;
5778 infoDesc.binding = 0;
5779
5780 mHandles[infoIndex].buffer = bufferHelper.getBuffer().getHandle();
5781 }
5782
updateTransformFeedbackBuffer(const Context * context,const ShaderInterfaceVariableInfoMap & variableInfoMap,const WriteDescriptorDescs & writeDescriptorDescs,uint32_t xfbBufferIndex,const BufferHelper & bufferHelper,VkDeviceSize bufferOffset,VkDeviceSize bufferRange)5783 void DescriptorSetDescBuilder::updateTransformFeedbackBuffer(
5784 const Context *context,
5785 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5786 const WriteDescriptorDescs &writeDescriptorDescs,
5787 uint32_t xfbBufferIndex,
5788 const BufferHelper &bufferHelper,
5789 VkDeviceSize bufferOffset,
5790 VkDeviceSize bufferRange)
5791 {
5792 const uint32_t baseBinding = variableInfoMap.getEmulatedXfbBufferBinding(0);
5793
5794 RendererVk *renderer = context->getRenderer();
5795 VkDeviceSize offsetAlignment =
5796 renderer->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
5797 // Set the offset as close as possible to the requested offset while remaining aligned.
5798 VkDeviceSize alignedOffset = (bufferOffset / offsetAlignment) * offsetAlignment;
5799 VkDeviceSize adjustedRange = bufferRange + (bufferOffset - alignedOffset);
5800
5801 uint32_t infoIndex = writeDescriptorDescs[baseBinding].descriptorInfoIndex + xfbBufferIndex;
5802 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
5803 infoDesc.samplerOrBufferSerial = bufferHelper.getBlockSerial().getValue();
5804 SetBitField(infoDesc.imageViewSerialOrOffset, alignedOffset);
5805 SetBitField(infoDesc.imageLayoutOrRange, adjustedRange);
5806 infoDesc.imageSubresourceRange = 0;
5807 infoDesc.binding = 0;
5808
5809 mHandles[infoIndex].buffer = bufferHelper.getBuffer().getHandle();
5810 }
5811
updateUniformsAndXfb(Context * context,const gl::ProgramExecutable & executable,const ProgramExecutableVk & executableVk,const WriteDescriptorDescs & writeDescriptorDescs,const BufferHelper * currentUniformBuffer,const BufferHelper & emptyBuffer,bool activeUnpaused,TransformFeedbackVk * transformFeedbackVk)5812 void DescriptorSetDescBuilder::updateUniformsAndXfb(
5813 Context *context,
5814 const gl::ProgramExecutable &executable,
5815 const ProgramExecutableVk &executableVk,
5816 const WriteDescriptorDescs &writeDescriptorDescs,
5817 const BufferHelper *currentUniformBuffer,
5818 const BufferHelper &emptyBuffer,
5819 bool activeUnpaused,
5820 TransformFeedbackVk *transformFeedbackVk)
5821 {
5822 gl::ShaderBitSet linkedStages = executable.getLinkedShaderStages();
5823
5824 const ShaderInterfaceVariableInfoMap &variableInfoMap = executableVk.getVariableInfoMap();
5825
5826 for (const gl::ShaderType shaderType : linkedStages)
5827 {
5828 uint32_t binding = variableInfoMap.getDefaultUniformBinding(shaderType);
5829 VkDeviceSize bufferRange = executableVk.getDefaultUniformAlignedSize(context, shaderType);
5830 if (bufferRange == 0)
5831 {
5832 updateUniformBuffer(binding, writeDescriptorDescs, emptyBuffer, emptyBuffer.getSize());
5833 }
5834 else
5835 {
5836 ASSERT(currentUniformBuffer);
5837 updateUniformBuffer(binding, writeDescriptorDescs, *currentUniformBuffer, bufferRange);
5838 }
5839
5840 if (transformFeedbackVk && shaderType == gl::ShaderType::Vertex &&
5841 context->getRenderer()->getFeatures().emulateTransformFeedback.enabled)
5842 {
5843 transformFeedbackVk->updateTransformFeedbackDescriptorDesc(
5844 context, executable, variableInfoMap, writeDescriptorDescs, emptyBuffer,
5845 activeUnpaused, this);
5846 }
5847 }
5848 }
5849
UpdatePreCacheActiveTextures(const gl::ProgramExecutable & executable,const ProgramExecutableVk & executableVk,const std::vector<gl::SamplerBinding> & samplerBindings,const gl::ActiveTextureMask & activeTextures,const gl::ActiveTextureArray<TextureVk * > & textures,const gl::SamplerBindingVector & samplers,DescriptorSetDesc * desc)5850 void UpdatePreCacheActiveTextures(const gl::ProgramExecutable &executable,
5851 const ProgramExecutableVk &executableVk,
5852 const std::vector<gl::SamplerBinding> &samplerBindings,
5853 const gl::ActiveTextureMask &activeTextures,
5854 const gl::ActiveTextureArray<TextureVk *> &textures,
5855 const gl::SamplerBindingVector &samplers,
5856 DescriptorSetDesc *desc)
5857 {
5858 desc->resize(executableVk.getTextureWriteDescriptorDescs().getTotalDescriptorCount());
5859 const WriteDescriptorDescs &writeDescriptorDescs =
5860 executableVk.getTextureWriteDescriptorDescs();
5861
5862 const ShaderInterfaceVariableInfoMap &variableInfoMap = executableVk.getVariableInfoMap();
5863 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
5864
5865 for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
5866 {
5867 const gl::SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
5868 uint32_t arraySize = static_cast<uint32_t>(samplerBinding.boundTextureUnits.size());
5869 bool isSamplerExternalY2Y = samplerBinding.samplerType == GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT;
5870
5871 uint32_t uniformIndex = executable.getUniformIndexFromSamplerIndex(samplerIndex);
5872 const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
5873
5874 if (samplerUniform.activeShaders().none())
5875 {
5876 continue;
5877 }
5878
5879 const gl::ShaderType firstShaderType = samplerUniform.getFirstActiveShaderType();
5880 const ShaderInterfaceVariableInfo &info =
5881 variableInfoMap.getVariableById(firstShaderType, samplerUniform.getId(firstShaderType));
5882
5883 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
5884 {
5885 GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement];
5886 if (!activeTextures.test(textureUnit))
5887 continue;
5888 TextureVk *textureVk = textures[textureUnit];
5889
5890 uint32_t infoIndex = writeDescriptorDescs[info.binding].descriptorInfoIndex +
5891 arrayElement + samplerUniform.getOuterArrayOffset();
5892 DescriptorInfoDesc &infoDesc = desc->getInfoDesc(infoIndex);
5893 infoDesc.binding = info.binding;
5894
5895 if (textureVk->getState().getType() == gl::TextureType::Buffer)
5896 {
5897 ImageOrBufferViewSubresourceSerial imageViewSerial =
5898 textureVk->getBufferViewSerial();
5899 infoDesc.imageViewSerialOrOffset = imageViewSerial.viewSerial.getValue();
5900 infoDesc.imageLayoutOrRange = 0;
5901 infoDesc.samplerOrBufferSerial = 0;
5902 infoDesc.imageSubresourceRange = 0;
5903 }
5904 else
5905 {
5906 gl::Sampler *sampler = samplers[textureUnit].get();
5907 const SamplerVk *samplerVk = sampler ? vk::GetImpl(sampler) : nullptr;
5908
5909 const SamplerHelper &samplerHelper =
5910 samplerVk ? samplerVk->getSampler()
5911 : textureVk->getSampler(isSamplerExternalY2Y);
5912 const gl::SamplerState &samplerState =
5913 sampler ? sampler->getSamplerState() : textureVk->getState().getSamplerState();
5914
5915 ImageOrBufferViewSubresourceSerial imageViewSerial =
5916 textureVk->getImageViewSubresourceSerial(samplerState);
5917
5918 ImageLayout imageLayout = textureVk->getImage().getCurrentImageLayout();
5919 SetBitField(infoDesc.imageLayoutOrRange, imageLayout);
5920 infoDesc.imageViewSerialOrOffset = imageViewSerial.viewSerial.getValue();
5921 infoDesc.samplerOrBufferSerial = samplerHelper.getSamplerSerial().getValue();
5922 memcpy(&infoDesc.imageSubresourceRange, &imageViewSerial.subresource,
5923 sizeof(uint32_t));
5924 }
5925 }
5926 }
5927 }
5928
updateFullActiveTextures(Context * context,const ShaderInterfaceVariableInfoMap & variableInfoMap,const WriteDescriptorDescs & writeDescriptorDescs,const gl::ProgramExecutable & executable,const gl::ActiveTextureArray<TextureVk * > & textures,const gl::SamplerBindingVector & samplers,bool emulateSeamfulCubeMapSampling,PipelineType pipelineType,const SharedDescriptorSetCacheKey & sharedCacheKey)5929 angle::Result DescriptorSetDescBuilder::updateFullActiveTextures(
5930 Context *context,
5931 const ShaderInterfaceVariableInfoMap &variableInfoMap,
5932 const WriteDescriptorDescs &writeDescriptorDescs,
5933 const gl::ProgramExecutable &executable,
5934 const gl::ActiveTextureArray<TextureVk *> &textures,
5935 const gl::SamplerBindingVector &samplers,
5936 bool emulateSeamfulCubeMapSampling,
5937 PipelineType pipelineType,
5938 const SharedDescriptorSetCacheKey &sharedCacheKey)
5939 {
5940 const std::vector<gl::SamplerBinding> &samplerBindings = executable.getSamplerBindings();
5941 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
5942 const gl::ActiveTextureTypeArray &textureTypes = executable.getActiveSamplerTypes();
5943
5944 for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
5945 {
5946 const gl::SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
5947 uint32_t uniformIndex = executable.getUniformIndexFromSamplerIndex(samplerIndex);
5948 const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
5949
5950 if (samplerUniform.activeShaders().none())
5951 {
5952 continue;
5953 }
5954
5955 const gl::ShaderType firstShaderType = samplerUniform.getFirstActiveShaderType();
5956 const ShaderInterfaceVariableInfo &info =
5957 variableInfoMap.getVariableById(firstShaderType, samplerUniform.getId(firstShaderType));
5958
5959 uint32_t arraySize = static_cast<uint32_t>(samplerBinding.boundTextureUnits.size());
5960 bool isSamplerExternalY2Y = samplerBinding.samplerType == GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT;
5961
5962 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
5963 {
5964 GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement];
5965 TextureVk *textureVk = textures[textureUnit];
5966
5967 uint32_t infoIndex = writeDescriptorDescs[info.binding].descriptorInfoIndex +
5968 arrayElement + samplerUniform.getOuterArrayOffset();
5969 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
5970 infoDesc.binding = info.binding;
5971
5972 if (textureTypes[textureUnit] == gl::TextureType::Buffer)
5973 {
5974 ImageOrBufferViewSubresourceSerial imageViewSerial =
5975 textureVk->getBufferViewSerial();
5976 infoDesc.imageViewSerialOrOffset = imageViewSerial.viewSerial.getValue();
5977 infoDesc.imageLayoutOrRange = 0;
5978 infoDesc.samplerOrBufferSerial = 0;
5979 infoDesc.imageSubresourceRange = 0;
5980
5981 textureVk->onNewDescriptorSet(sharedCacheKey);
5982
5983 const BufferView *view = nullptr;
5984 ANGLE_TRY(textureVk->getBufferViewAndRecordUse(context, nullptr, false, &view));
5985 mHandles[infoIndex].bufferView = view->getHandle();
5986 }
5987 else
5988 {
5989 gl::Sampler *sampler = samplers[textureUnit].get();
5990 const SamplerVk *samplerVk = sampler ? vk::GetImpl(sampler) : nullptr;
5991
5992 const SamplerHelper &samplerHelper =
5993 samplerVk ? samplerVk->getSampler()
5994 : textureVk->getSampler(isSamplerExternalY2Y);
5995 const gl::SamplerState &samplerState =
5996 sampler ? sampler->getSamplerState() : textureVk->getState().getSamplerState();
5997
5998 ImageOrBufferViewSubresourceSerial imageViewSerial =
5999 textureVk->getImageViewSubresourceSerial(samplerState);
6000
6001 textureVk->onNewDescriptorSet(sharedCacheKey);
6002
6003 ImageLayout imageLayout = textureVk->getImage().getCurrentImageLayout();
6004 SetBitField(infoDesc.imageLayoutOrRange, imageLayout);
6005 infoDesc.imageViewSerialOrOffset = imageViewSerial.viewSerial.getValue();
6006 infoDesc.samplerOrBufferSerial = samplerHelper.getSamplerSerial().getValue();
6007 memcpy(&infoDesc.imageSubresourceRange, &imageViewSerial.subresource,
6008 sizeof(uint32_t));
6009
6010 mHandles[infoIndex].sampler = samplerHelper.get().getHandle();
6011
6012 // __samplerExternal2DY2YEXT cannot be used with
6013 // emulateSeamfulCubeMapSampling because that's only enabled in GLES == 2.
6014 // Use the read image view here anyway.
6015 if (emulateSeamfulCubeMapSampling && !isSamplerExternalY2Y)
6016 {
6017 // If emulating seamful cube mapping, use the fetch image view. This is
6018 // basically the same image view as read, except it's a 2DArray view for
6019 // cube maps.
6020 const ImageView &imageView =
6021 textureVk->getFetchImageView(context, samplerState.getSRGBDecode(),
6022 samplerUniform.isTexelFetchStaticUse());
6023 mHandles[infoIndex].imageView = imageView.getHandle();
6024 }
6025 else
6026 {
6027 const ImageView &imageView = textureVk->getReadImageView(
6028 context, samplerState.getSRGBDecode(),
6029 samplerUniform.isTexelFetchStaticUse(), isSamplerExternalY2Y);
6030 mHandles[infoIndex].imageView = imageView.getHandle();
6031 }
6032 }
6033 }
6034 }
6035
6036 return angle::Result::Continue;
6037 }
6038
setEmptyBuffer(uint32_t infoDescIndex,VkDescriptorType descriptorType,const BufferHelper & emptyBuffer)6039 void DescriptorSetDescBuilder::setEmptyBuffer(uint32_t infoDescIndex,
6040 VkDescriptorType descriptorType,
6041 const BufferHelper &emptyBuffer)
6042 {
6043 DescriptorInfoDesc &emptyDesc = mDesc.getInfoDesc(infoDescIndex);
6044 SetBitField(emptyDesc.imageLayoutOrRange, emptyBuffer.getSize());
6045 emptyDesc.imageViewSerialOrOffset = 0;
6046 emptyDesc.samplerOrBufferSerial = emptyBuffer.getBlockSerial().getValue();
6047
6048 mHandles[infoDescIndex].buffer = emptyBuffer.getBuffer().getHandle();
6049
6050 if (IsDynamicDescriptor(descriptorType))
6051 {
6052 mDynamicOffsets[infoDescIndex] = 0;
6053 }
6054 }
6055
6056 template <typename CommandBufferT>
updateOneShaderBuffer(ContextVk * contextVk,CommandBufferT * commandBufferHelper,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::BufferVector & buffers,const std::vector<gl::InterfaceBlock> & blocks,uint32_t blockIndex,VkDescriptorType descriptorType,VkDeviceSize maxBoundBufferRange,const BufferHelper & emptyBuffer,const WriteDescriptorDescs & writeDescriptorDescs)6057 void DescriptorSetDescBuilder::updateOneShaderBuffer(
6058 ContextVk *contextVk,
6059 CommandBufferT *commandBufferHelper,
6060 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6061 const gl::BufferVector &buffers,
6062 const std::vector<gl::InterfaceBlock> &blocks,
6063 uint32_t blockIndex,
6064 VkDescriptorType descriptorType,
6065 VkDeviceSize maxBoundBufferRange,
6066 const BufferHelper &emptyBuffer,
6067 const WriteDescriptorDescs &writeDescriptorDescs)
6068 {
6069 const gl::InterfaceBlock &block = blocks[blockIndex];
6070 if (block.activeShaders().none())
6071 {
6072 return;
6073 }
6074
6075 const gl::ShaderType firstShaderType = block.getFirstActiveShaderType();
6076 const ShaderInterfaceVariableInfo &info =
6077 variableInfoMap.getVariableById(firstShaderType, block.getId(firstShaderType));
6078
6079 uint32_t binding = info.binding;
6080 uint32_t arrayElement = block.isArray ? block.arrayElement : 0;
6081 uint32_t infoDescIndex = writeDescriptorDescs[binding].descriptorInfoIndex + arrayElement;
6082
6083 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = buffers[block.binding];
6084 if (bufferBinding.get() == nullptr)
6085 {
6086 setEmptyBuffer(infoDescIndex, descriptorType, emptyBuffer);
6087 return;
6088 }
6089
6090 // Limit bound buffer size to maximum resource binding size.
6091 GLsizeiptr boundBufferSize = gl::GetBoundBufferAvailableSize(bufferBinding);
6092 VkDeviceSize size = std::min<VkDeviceSize>(boundBufferSize, maxBoundBufferRange);
6093
6094 // Make sure there's no possible under/overflow with binding size.
6095 static_assert(sizeof(VkDeviceSize) >= sizeof(bufferBinding.getSize()),
6096 "VkDeviceSize too small");
6097 ASSERT(bufferBinding.getSize() >= 0);
6098
6099 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
6100 BufferHelper &bufferHelper = bufferVk->getBuffer();
6101
6102 const bool isUniformBuffer = descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
6103 descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
6104 if (isUniformBuffer)
6105 {
6106 commandBufferHelper->bufferRead(contextVk, VK_ACCESS_UNIFORM_READ_BIT,
6107 block.activeShaders(), &bufferHelper);
6108 }
6109 else
6110 {
6111 ASSERT(descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
6112 descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
6113 if (block.isReadOnly)
6114 {
6115 // Avoid unnecessary barriers for readonly SSBOs by making sure the buffers are
6116 // marked read-only. This also helps BufferVk make better decisions during
6117 // buffer data uploads and copies by knowing that the buffers are not actually
6118 // being written to.
6119 commandBufferHelper->bufferRead(contextVk, VK_ACCESS_SHADER_READ_BIT,
6120 block.activeShaders(), &bufferHelper);
6121 }
6122 else
6123 {
6124 // We set the SHADER_READ_BIT to be conservative.
6125 VkAccessFlags accessFlags = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
6126 for (const gl::ShaderType shaderType : block.activeShaders())
6127 {
6128 const vk::PipelineStage pipelineStage = vk::GetPipelineStage(shaderType);
6129 commandBufferHelper->bufferWrite(contextVk, accessFlags, pipelineStage,
6130 &bufferHelper);
6131 }
6132 }
6133 }
6134
6135 VkDeviceSize offset = bufferBinding.getOffset() + bufferHelper.getOffset();
6136
6137 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoDescIndex);
6138 infoDesc.samplerOrBufferSerial = bufferHelper.getBlockSerial().getValue();
6139 if (IsDynamicDescriptor(descriptorType))
6140 {
6141 SetBitField(mDynamicOffsets[infoDescIndex], offset);
6142 infoDesc.imageViewSerialOrOffset = 0;
6143 }
6144 else
6145 {
6146 SetBitField(infoDesc.imageViewSerialOrOffset, offset);
6147 }
6148 SetBitField(infoDesc.imageLayoutOrRange, size);
6149 infoDesc.imageSubresourceRange = 0;
6150 infoDesc.binding = 0;
6151
6152 mHandles[infoDescIndex].buffer = bufferHelper.getBuffer().getHandle();
6153 }
6154
6155 template <typename CommandBufferT>
updateShaderBuffers(ContextVk * contextVk,CommandBufferT * commandBufferHelper,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::BufferVector & buffers,const std::vector<gl::InterfaceBlock> & blocks,VkDescriptorType descriptorType,VkDeviceSize maxBoundBufferRange,const BufferHelper & emptyBuffer,const WriteDescriptorDescs & writeDescriptorDescs)6156 void DescriptorSetDescBuilder::updateShaderBuffers(
6157 ContextVk *contextVk,
6158 CommandBufferT *commandBufferHelper,
6159 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6160 const gl::BufferVector &buffers,
6161 const std::vector<gl::InterfaceBlock> &blocks,
6162 VkDescriptorType descriptorType,
6163 VkDeviceSize maxBoundBufferRange,
6164 const BufferHelper &emptyBuffer,
6165 const WriteDescriptorDescs &writeDescriptorDescs)
6166 {
6167 // Now that we have the proper array elements counts, initialize the info structures.
6168 for (uint32_t blockIndex = 0; blockIndex < blocks.size(); ++blockIndex)
6169 {
6170 updateOneShaderBuffer(contextVk, commandBufferHelper, variableInfoMap, buffers, blocks,
6171 blockIndex, descriptorType, maxBoundBufferRange, emptyBuffer,
6172 writeDescriptorDescs);
6173 }
6174 }
6175
6176 template <typename CommandBufferT>
updateAtomicCounters(ContextVk * contextVk,CommandBufferT * commandBufferHelper,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::BufferVector & buffers,const std::vector<gl::AtomicCounterBuffer> & atomicCounterBuffers,const VkDeviceSize requiredOffsetAlignment,const BufferHelper & emptyBuffer,const WriteDescriptorDescs & writeDescriptorDescs)6177 void DescriptorSetDescBuilder::updateAtomicCounters(
6178 ContextVk *contextVk,
6179 CommandBufferT *commandBufferHelper,
6180 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6181 const gl::BufferVector &buffers,
6182 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
6183 const VkDeviceSize requiredOffsetAlignment,
6184 const BufferHelper &emptyBuffer,
6185 const WriteDescriptorDescs &writeDescriptorDescs)
6186 {
6187 ASSERT(!atomicCounterBuffers.empty());
6188 static_assert(!IsDynamicDescriptor(kStorageBufferDescriptorType),
6189 "This method needs an update to handle dynamic descriptors");
6190
6191 if (atomicCounterBuffers.empty())
6192 {
6193 return;
6194 }
6195
6196 uint32_t binding = variableInfoMap.getAtomicCounterBufferBinding(
6197 atomicCounterBuffers[0].getFirstActiveShaderType(), 0);
6198 uint32_t baseInfoIndex = writeDescriptorDescs[binding].descriptorInfoIndex;
6199
6200 // Bind the empty buffer to every array slot that's unused.
6201 for (uint32_t arrayElement = 0;
6202 arrayElement < gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS; ++arrayElement)
6203 {
6204 uint32_t infoIndex = baseInfoIndex + arrayElement;
6205 setEmptyBuffer(infoIndex, kStorageBufferDescriptorType, emptyBuffer);
6206 }
6207
6208 for (const gl::AtomicCounterBuffer &atomicCounterBuffer : atomicCounterBuffers)
6209 {
6210 int arrayElement = atomicCounterBuffer.binding;
6211 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = buffers[arrayElement];
6212
6213 uint32_t infoIndex = baseInfoIndex + arrayElement;
6214
6215 if (bufferBinding.get() == nullptr)
6216 {
6217 setEmptyBuffer(infoIndex, kStorageBufferDescriptorType, emptyBuffer);
6218 continue;
6219 }
6220
6221 BufferVk *bufferVk = vk::GetImpl(bufferBinding.get());
6222 vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
6223
6224 for (const gl::ShaderType shaderType : atomicCounterBuffer.activeShaders())
6225 {
6226 const vk::PipelineStage pipelineStage = vk::GetPipelineStage(shaderType);
6227 commandBufferHelper->bufferWrite(contextVk,
6228 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
6229 pipelineStage, &bufferHelper);
6230 }
6231
6232 VkDeviceSize offset = bufferBinding.getOffset() + bufferHelper.getOffset();
6233
6234 VkDeviceSize alignedOffset = (offset / requiredOffsetAlignment) * requiredOffsetAlignment;
6235 VkDeviceSize offsetDiff = offset - alignedOffset;
6236
6237 offset = alignedOffset;
6238
6239 VkDeviceSize range = gl::GetBoundBufferAvailableSize(bufferBinding) + offsetDiff;
6240
6241 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6242 SetBitField(infoDesc.imageLayoutOrRange, range);
6243 SetBitField(infoDesc.imageViewSerialOrOffset, offset);
6244 infoDesc.samplerOrBufferSerial = bufferHelper.getBlockSerial().getValue();
6245 infoDesc.imageSubresourceRange = 0;
6246 infoDesc.binding = 0;
6247
6248 mHandles[infoIndex].buffer = bufferHelper.getBuffer().getHandle();
6249 }
6250 }
6251
6252 // Explicit instantiation
6253 template void DescriptorSetDescBuilder::updateOneShaderBuffer<vk::RenderPassCommandBufferHelper>(
6254 ContextVk *contextVk,
6255 RenderPassCommandBufferHelper *commandBufferHelper,
6256 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6257 const gl::BufferVector &buffers,
6258 const std::vector<gl::InterfaceBlock> &blocks,
6259 uint32_t blockIndex,
6260 VkDescriptorType descriptorType,
6261 VkDeviceSize maxBoundBufferRange,
6262 const BufferHelper &emptyBuffer,
6263 const WriteDescriptorDescs &writeDescriptorDescs);
6264
6265 template void DescriptorSetDescBuilder::updateOneShaderBuffer<OutsideRenderPassCommandBufferHelper>(
6266 ContextVk *contextVk,
6267 OutsideRenderPassCommandBufferHelper *commandBufferHelper,
6268 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6269 const gl::BufferVector &buffers,
6270 const std::vector<gl::InterfaceBlock> &blocks,
6271 uint32_t blockIndex,
6272 VkDescriptorType descriptorType,
6273 VkDeviceSize maxBoundBufferRange,
6274 const BufferHelper &emptyBuffer,
6275 const WriteDescriptorDescs &writeDescriptorDescs);
6276
6277 template void DescriptorSetDescBuilder::updateShaderBuffers<OutsideRenderPassCommandBufferHelper>(
6278 ContextVk *contextVk,
6279 OutsideRenderPassCommandBufferHelper *commandBufferHelper,
6280 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6281 const gl::BufferVector &buffers,
6282 const std::vector<gl::InterfaceBlock> &blocks,
6283 VkDescriptorType descriptorType,
6284 VkDeviceSize maxBoundBufferRange,
6285 const BufferHelper &emptyBuffer,
6286 const WriteDescriptorDescs &writeDescriptorDescs);
6287
6288 template void DescriptorSetDescBuilder::updateShaderBuffers<RenderPassCommandBufferHelper>(
6289 ContextVk *contextVk,
6290 RenderPassCommandBufferHelper *commandBufferHelper,
6291 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6292 const gl::BufferVector &buffers,
6293 const std::vector<gl::InterfaceBlock> &blocks,
6294 VkDescriptorType descriptorType,
6295 VkDeviceSize maxBoundBufferRange,
6296 const BufferHelper &emptyBuffer,
6297 const WriteDescriptorDescs &writeDescriptorDescs);
6298
6299 template void DescriptorSetDescBuilder::updateAtomicCounters<OutsideRenderPassCommandBufferHelper>(
6300 ContextVk *contextVk,
6301 OutsideRenderPassCommandBufferHelper *commandBufferHelper,
6302 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6303 const gl::BufferVector &buffers,
6304 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
6305 const VkDeviceSize requiredOffsetAlignment,
6306 const BufferHelper &emptyBuffer,
6307 const WriteDescriptorDescs &writeDescriptorDescs);
6308
6309 template void DescriptorSetDescBuilder::updateAtomicCounters<RenderPassCommandBufferHelper>(
6310 ContextVk *contextVk,
6311 RenderPassCommandBufferHelper *commandBufferHelper,
6312 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6313 const gl::BufferVector &buffers,
6314 const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers,
6315 const VkDeviceSize requiredOffsetAlignment,
6316 const BufferHelper &emptyBuffer,
6317 const WriteDescriptorDescs &writeDescriptorDescs);
6318
updateImages(Context * context,const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,const gl::ActiveTextureArray<TextureVk * > & activeImages,const std::vector<gl::ImageUnit> & imageUnits,const WriteDescriptorDescs & writeDescriptorDescs)6319 angle::Result DescriptorSetDescBuilder::updateImages(
6320 Context *context,
6321 const gl::ProgramExecutable &executable,
6322 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6323 const gl::ActiveTextureArray<TextureVk *> &activeImages,
6324 const std::vector<gl::ImageUnit> &imageUnits,
6325 const WriteDescriptorDescs &writeDescriptorDescs)
6326 {
6327 RendererVk *renderer = context->getRenderer();
6328 const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings();
6329 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
6330
6331 if (imageBindings.empty())
6332 {
6333 return angle::Result::Continue;
6334 }
6335
6336 for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
6337 {
6338 const gl::ImageBinding &imageBinding = imageBindings[imageIndex];
6339 uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex);
6340 const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
6341
6342 if (imageUniform.activeShaders().none())
6343 {
6344 continue;
6345 }
6346
6347 const gl::ShaderType firstShaderType = imageUniform.getFirstActiveShaderType();
6348 const ShaderInterfaceVariableInfo &info =
6349 variableInfoMap.getVariableById(firstShaderType, imageUniform.getId(firstShaderType));
6350
6351 uint32_t arraySize = static_cast<uint32_t>(imageBinding.boundImageUnits.size());
6352
6353 // Texture buffers use buffer views, so they are especially handled.
6354 if (imageBinding.textureType == gl::TextureType::Buffer)
6355 {
6356 // Handle format reinterpretation by looking for a view with the format specified in
6357 // the shader (if any, instead of the format specified to glTexBuffer).
6358 const vk::Format *format = nullptr;
6359 if (imageUniform.getImageUnitFormat() != GL_NONE)
6360 {
6361 format = &renderer->getFormat(imageUniform.getImageUnitFormat());
6362 }
6363
6364 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
6365 {
6366 GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
6367 TextureVk *textureVk = activeImages[imageUnit];
6368
6369 uint32_t infoIndex = writeDescriptorDescs[info.binding].descriptorInfoIndex +
6370 arrayElement + imageUniform.getOuterArrayOffset();
6371
6372 const vk::BufferView *view = nullptr;
6373 ANGLE_TRY(textureVk->getBufferViewAndRecordUse(context, format, true, &view));
6374
6375 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6376 infoDesc.imageViewSerialOrOffset =
6377 textureVk->getBufferViewSerial().viewSerial.getValue();
6378 infoDesc.imageLayoutOrRange = 0;
6379 infoDesc.imageSubresourceRange = 0;
6380 infoDesc.samplerOrBufferSerial = 0;
6381 infoDesc.binding = 0;
6382
6383 mHandles[infoIndex].bufferView = view->getHandle();
6384 }
6385 }
6386 else
6387 {
6388 for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
6389 {
6390 GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
6391 const gl::ImageUnit &binding = imageUnits[imageUnit];
6392 TextureVk *textureVk = activeImages[imageUnit];
6393
6394 vk::ImageHelper *image = &textureVk->getImage();
6395 const vk::ImageView *imageView = nullptr;
6396
6397 vk::ImageOrBufferViewSubresourceSerial serial =
6398 textureVk->getStorageImageViewSerial(binding);
6399
6400 ANGLE_TRY(textureVk->getStorageImageView(context, binding, &imageView));
6401
6402 uint32_t infoIndex = writeDescriptorDescs[info.binding].descriptorInfoIndex +
6403 arrayElement + imageUniform.getOuterArrayOffset();
6404
6405 // Note: binding.access is unused because it is implied by the shader.
6406
6407 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6408 SetBitField(infoDesc.imageLayoutOrRange, image->getCurrentImageLayout());
6409 memcpy(&infoDesc.imageSubresourceRange, &serial.subresource, sizeof(uint32_t));
6410 infoDesc.imageViewSerialOrOffset = serial.viewSerial.getValue();
6411 infoDesc.samplerOrBufferSerial = 0;
6412 infoDesc.binding = 0;
6413
6414 mHandles[infoIndex].imageView = imageView->getHandle();
6415 }
6416 }
6417 }
6418
6419 return angle::Result::Continue;
6420 }
6421
updateInputAttachments(vk::Context * context,const gl::ProgramExecutable & executable,const ShaderInterfaceVariableInfoMap & variableInfoMap,FramebufferVk * framebufferVk,const WriteDescriptorDescs & writeDescriptorDescs)6422 angle::Result DescriptorSetDescBuilder::updateInputAttachments(
6423 vk::Context *context,
6424 const gl::ProgramExecutable &executable,
6425 const ShaderInterfaceVariableInfoMap &variableInfoMap,
6426 FramebufferVk *framebufferVk,
6427 const WriteDescriptorDescs &writeDescriptorDescs)
6428 {
6429 const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
6430
6431 if (!executable.usesFramebufferFetch())
6432 {
6433 return angle::Result::Continue;
6434 }
6435
6436 const uint32_t baseUniformIndex = executable.getFragmentInoutRange().low();
6437 const gl::LinkedUniform &baseInputAttachment = uniforms.at(baseUniformIndex);
6438
6439 const ShaderInterfaceVariableInfo &baseInfo = variableInfoMap.getVariableById(
6440 gl::ShaderType::Fragment, baseInputAttachment.getId(gl::ShaderType::Fragment));
6441
6442 uint32_t baseBinding = baseInfo.binding - baseInputAttachment.getLocation();
6443
6444 for (size_t colorIndex : framebufferVk->getState().getColorAttachmentsMask())
6445 {
6446 uint32_t binding = baseBinding + static_cast<uint32_t>(colorIndex);
6447
6448 RenderTargetVk *renderTargetVk = framebufferVk->getColorDrawRenderTarget(colorIndex);
6449 const vk::ImageView *imageView = nullptr;
6450
6451 ANGLE_TRY(renderTargetVk->getImageView(context, &imageView));
6452
6453 uint32_t infoIndex = writeDescriptorDescs[binding].descriptorInfoIndex;
6454
6455 DescriptorInfoDesc &infoDesc = mDesc.getInfoDesc(infoIndex);
6456
6457 // We just need any layout that represents GENERAL. The serial is also not totally precise.
6458 ImageOrBufferViewSubresourceSerial serial = renderTargetVk->getDrawSubresourceSerial();
6459 SetBitField(infoDesc.imageLayoutOrRange, ImageLayout::FragmentShaderWrite);
6460 infoDesc.imageViewSerialOrOffset = serial.viewSerial.getValue();
6461 memcpy(&infoDesc.imageSubresourceRange, &serial.subresource, sizeof(uint32_t));
6462 infoDesc.samplerOrBufferSerial = 0;
6463 infoDesc.binding = 0;
6464
6465 mHandles[infoIndex].imageView = imageView->getHandle();
6466 }
6467
6468 return angle::Result::Continue;
6469 }
6470
updateDescriptorSet(Context * context,const WriteDescriptorDescs & writeDescriptorDescs,UpdateDescriptorSetsBuilder * updateBuilder,VkDescriptorSet descriptorSet) const6471 void DescriptorSetDescBuilder::updateDescriptorSet(Context *context,
6472 const WriteDescriptorDescs &writeDescriptorDescs,
6473 UpdateDescriptorSetsBuilder *updateBuilder,
6474 VkDescriptorSet descriptorSet) const
6475 {
6476 mDesc.updateDescriptorSet(context, writeDescriptorDescs, updateBuilder, mHandles.data(),
6477 descriptorSet);
6478 }
6479
6480 // SharedCacheKeyManager implementation.
6481 template <class SharedCacheKeyT>
addKey(const SharedCacheKeyT & key)6482 void SharedCacheKeyManager<SharedCacheKeyT>::addKey(const SharedCacheKeyT &key)
6483 {
6484 // If there is invalid key in the array, use it instead of keep expanding the array
6485 for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
6486 {
6487 if (*sharedCacheKey.get() == nullptr)
6488 {
6489 sharedCacheKey = key;
6490 return;
6491 }
6492 }
6493 mSharedCacheKeys.emplace_back(key);
6494 }
6495
6496 template <class SharedCacheKeyT>
releaseKeys(ContextVk * contextVk)6497 void SharedCacheKeyManager<SharedCacheKeyT>::releaseKeys(ContextVk *contextVk)
6498 {
6499 for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
6500 {
6501 if (*sharedCacheKey.get() != nullptr)
6502 {
6503 // Immediate destroy the cached object and the key itself when first releaseRef call is
6504 // made
6505 ReleaseCachedObject(contextVk, *(*sharedCacheKey.get()));
6506 *sharedCacheKey.get() = nullptr;
6507 }
6508 }
6509 mSharedCacheKeys.clear();
6510 }
6511
6512 template <class SharedCacheKeyT>
destroyKeys(RendererVk * renderer)6513 void SharedCacheKeyManager<SharedCacheKeyT>::destroyKeys(RendererVk *renderer)
6514 {
6515 for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
6516 {
6517 // destroy the cache key
6518 if (*sharedCacheKey.get() != nullptr)
6519 {
6520 // Immediate destroy the cached object and the key
6521 DestroyCachedObject(renderer, *(*sharedCacheKey.get()));
6522 *sharedCacheKey.get() = nullptr;
6523 }
6524 }
6525 mSharedCacheKeys.clear();
6526 }
6527
6528 template <class SharedCacheKeyT>
clear()6529 void SharedCacheKeyManager<SharedCacheKeyT>::clear()
6530 {
6531 // Caller must have already freed all caches
6532 assertAllEntriesDestroyed();
6533 mSharedCacheKeys.clear();
6534 }
6535
6536 template <class SharedCacheKeyT>
containsKey(const SharedCacheKeyT & key) const6537 bool SharedCacheKeyManager<SharedCacheKeyT>::containsKey(const SharedCacheKeyT &key) const
6538 {
6539 for (const SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
6540 {
6541 if (key == sharedCacheKey)
6542 {
6543 return true;
6544 }
6545 }
6546 return false;
6547 }
6548
6549 template <class SharedCacheKeyT>
assertAllEntriesDestroyed()6550 void SharedCacheKeyManager<SharedCacheKeyT>::assertAllEntriesDestroyed()
6551 {
6552 // Caller must have already freed all caches
6553 for (SharedCacheKeyT &sharedCacheKey : mSharedCacheKeys)
6554 {
6555 ASSERT(*sharedCacheKey.get() == nullptr);
6556 }
6557 }
6558
6559 // Explict instantiate for FramebufferCacheManager
6560 template class SharedCacheKeyManager<SharedFramebufferCacheKey>;
6561 // Explict instantiate for DescriptorSetCacheManager
6562 template class SharedCacheKeyManager<SharedDescriptorSetCacheKey>;
6563
6564 // PipelineCacheAccess implementation.
getLock()6565 std::unique_lock<std::mutex> PipelineCacheAccess::getLock()
6566 {
6567 if (mMutex == nullptr)
6568 {
6569 return std::unique_lock<std::mutex>();
6570 }
6571
6572 return std::unique_lock<std::mutex>(*mMutex);
6573 }
6574
createGraphicsPipeline(vk::Context * context,const VkGraphicsPipelineCreateInfo & createInfo,vk::Pipeline * pipelineOut)6575 VkResult PipelineCacheAccess::createGraphicsPipeline(vk::Context *context,
6576 const VkGraphicsPipelineCreateInfo &createInfo,
6577 vk::Pipeline *pipelineOut)
6578 {
6579 std::unique_lock<std::mutex> lock = getLock();
6580
6581 return pipelineOut->initGraphics(context->getDevice(), createInfo, *mPipelineCache);
6582 }
6583
createComputePipeline(vk::Context * context,const VkComputePipelineCreateInfo & createInfo,vk::Pipeline * pipelineOut)6584 VkResult PipelineCacheAccess::createComputePipeline(vk::Context *context,
6585 const VkComputePipelineCreateInfo &createInfo,
6586 vk::Pipeline *pipelineOut)
6587 {
6588 std::unique_lock<std::mutex> lock = getLock();
6589
6590 return pipelineOut->initCompute(context->getDevice(), createInfo, *mPipelineCache);
6591 }
6592
merge(RendererVk * renderer,const vk::PipelineCache & pipelineCache)6593 void PipelineCacheAccess::merge(RendererVk *renderer, const vk::PipelineCache &pipelineCache)
6594 {
6595 ASSERT(mMutex != nullptr);
6596
6597 std::unique_lock<std::mutex> lock = getLock();
6598
6599 mPipelineCache->merge(renderer->getDevice(), 1, pipelineCache.ptr());
6600 }
6601 } // namespace vk
6602
6603 // FramebufferCache implementation.
destroy(RendererVk * rendererVk)6604 void FramebufferCache::destroy(RendererVk *rendererVk)
6605 {
6606 rendererVk->accumulateCacheStats(VulkanCacheType::Framebuffer, mCacheStats);
6607 for (auto &entry : mPayload)
6608 {
6609 vk::FramebufferHelper &tmpFB = entry.second;
6610 tmpFB.destroy(rendererVk);
6611 }
6612 mPayload.clear();
6613 }
6614
get(ContextVk * contextVk,const vk::FramebufferDesc & desc,vk::Framebuffer & framebuffer)6615 bool FramebufferCache::get(ContextVk *contextVk,
6616 const vk::FramebufferDesc &desc,
6617 vk::Framebuffer &framebuffer)
6618 {
6619 ASSERT(!contextVk->getFeatures().supportsImagelessFramebuffer.enabled);
6620
6621 auto iter = mPayload.find(desc);
6622 if (iter != mPayload.end())
6623 {
6624 framebuffer.setHandle(iter->second.getFramebuffer().getHandle());
6625 mCacheStats.hit();
6626 return true;
6627 }
6628
6629 mCacheStats.miss();
6630 return false;
6631 }
6632
insert(ContextVk * contextVk,const vk::FramebufferDesc & desc,vk::FramebufferHelper && framebufferHelper)6633 void FramebufferCache::insert(ContextVk *contextVk,
6634 const vk::FramebufferDesc &desc,
6635 vk::FramebufferHelper &&framebufferHelper)
6636 {
6637 ASSERT(!contextVk->getFeatures().supportsImagelessFramebuffer.enabled);
6638
6639 mPayload.emplace(desc, std::move(framebufferHelper));
6640 }
6641
erase(ContextVk * contextVk,const vk::FramebufferDesc & desc)6642 void FramebufferCache::erase(ContextVk *contextVk, const vk::FramebufferDesc &desc)
6643 {
6644 ASSERT(!contextVk->getFeatures().supportsImagelessFramebuffer.enabled);
6645
6646 auto iter = mPayload.find(desc);
6647 if (iter != mPayload.end())
6648 {
6649 vk::FramebufferHelper &tmpFB = iter->second;
6650 tmpFB.release(contextVk);
6651 mPayload.erase(desc);
6652 }
6653 }
6654
6655 // RenderPassCache implementation.
6656 RenderPassCache::RenderPassCache() = default;
6657
~RenderPassCache()6658 RenderPassCache::~RenderPassCache()
6659 {
6660 ASSERT(mPayload.empty());
6661 }
6662
destroy(ContextVk * contextVk)6663 void RenderPassCache::destroy(ContextVk *contextVk)
6664 {
6665 RendererVk *renderer = contextVk->getRenderer();
6666
6667 renderer->accumulateCacheStats(VulkanCacheType::CompatibleRenderPass,
6668 mCompatibleRenderPassCacheStats);
6669 renderer->accumulateCacheStats(VulkanCacheType::RenderPassWithOps,
6670 mRenderPassWithOpsCacheStats);
6671
6672 VkDevice device = renderer->getDevice();
6673
6674 // Make sure there are no jobs referencing the render pass cache.
6675 contextVk->getShareGroup()->waitForCurrentMonolithicPipelineCreationTask();
6676
6677 for (auto &outerIt : mPayload)
6678 {
6679 for (auto &innerIt : outerIt.second)
6680 {
6681 innerIt.second.destroy(device);
6682 }
6683 }
6684 mPayload.clear();
6685 }
6686
clear(ContextVk * contextVk)6687 void RenderPassCache::clear(ContextVk *contextVk)
6688 {
6689 // Make sure there are no jobs referencing the render pass cache.
6690 contextVk->getShareGroup()->waitForCurrentMonolithicPipelineCreationTask();
6691
6692 for (auto &outerIt : mPayload)
6693 {
6694 for (auto &innerIt : outerIt.second)
6695 {
6696 innerIt.second.release(contextVk);
6697 }
6698 }
6699 mPayload.clear();
6700 }
6701
addCompatibleRenderPass(ContextVk * contextVk,const vk::RenderPassDesc & desc,const vk::RenderPass ** renderPassOut)6702 angle::Result RenderPassCache::addCompatibleRenderPass(ContextVk *contextVk,
6703 const vk::RenderPassDesc &desc,
6704 const vk::RenderPass **renderPassOut)
6705 {
6706 // This API is only used by getCompatibleRenderPass() to create a compatible render pass. The
6707 // following does not participate in render pass compatibility, so could take any value:
6708 //
6709 // - Load and store ops
6710 // - Attachment layouts
6711 // - Existance of resolve attachment (if single subpass)
6712 //
6713 // The values chosen here are arbitrary.
6714 //
6715 vk::AttachmentOpsArray ops;
6716
6717 vk::PackedAttachmentIndex colorIndexVk(0);
6718 for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
6719 {
6720 if (!desc.isColorAttachmentEnabled(colorIndexGL))
6721 {
6722 continue;
6723 }
6724
6725 const vk::ImageLayout imageLayout = vk::ImageLayout::ColorWrite;
6726 ops.initWithLoadStore(colorIndexVk, imageLayout, imageLayout);
6727 ++colorIndexVk;
6728 }
6729
6730 if (desc.hasDepthStencilAttachment())
6731 {
6732 const vk::ImageLayout imageLayout = vk::ImageLayout::DepthWriteStencilWrite;
6733 ops.initWithLoadStore(colorIndexVk, imageLayout, imageLayout);
6734 }
6735
6736 return getRenderPassWithOpsImpl(contextVk, desc, ops, false, renderPassOut);
6737 }
6738
getRenderPassWithOps(ContextVk * contextVk,const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & attachmentOps,const vk::RenderPass ** renderPassOut)6739 angle::Result RenderPassCache::getRenderPassWithOps(ContextVk *contextVk,
6740 const vk::RenderPassDesc &desc,
6741 const vk::AttachmentOpsArray &attachmentOps,
6742 const vk::RenderPass **renderPassOut)
6743 {
6744 return getRenderPassWithOpsImpl(contextVk, desc, attachmentOps, true, renderPassOut);
6745 }
6746
getRenderPassWithOpsImpl(ContextVk * contextVk,const vk::RenderPassDesc & desc,const vk::AttachmentOpsArray & attachmentOps,bool updatePerfCounters,const vk::RenderPass ** renderPassOut)6747 angle::Result RenderPassCache::getRenderPassWithOpsImpl(ContextVk *contextVk,
6748 const vk::RenderPassDesc &desc,
6749 const vk::AttachmentOpsArray &attachmentOps,
6750 bool updatePerfCounters,
6751 const vk::RenderPass **renderPassOut)
6752 {
6753 auto outerIt = mPayload.find(desc);
6754 if (outerIt != mPayload.end())
6755 {
6756 InnerCache &innerCache = outerIt->second;
6757
6758 auto innerIt = innerCache.find(attachmentOps);
6759 if (innerIt != innerCache.end())
6760 {
6761 // TODO(jmadill): Could possibly use an MRU cache here.
6762 vk::GetRenderPassAndUpdateCounters(contextVk, updatePerfCounters, &innerIt->second,
6763 renderPassOut);
6764 mRenderPassWithOpsCacheStats.hit();
6765 return angle::Result::Continue;
6766 }
6767 }
6768 else
6769 {
6770 auto emplaceResult = mPayload.emplace(desc, InnerCache());
6771 outerIt = emplaceResult.first;
6772 }
6773
6774 mRenderPassWithOpsCacheStats.missAndIncrementSize();
6775 vk::RenderPassHelper newRenderPass;
6776 ANGLE_TRY(vk::InitializeRenderPassFromDesc(contextVk, desc, attachmentOps, &newRenderPass));
6777
6778 InnerCache &innerCache = outerIt->second;
6779 auto insertPos = innerCache.emplace(attachmentOps, std::move(newRenderPass));
6780 vk::GetRenderPassAndUpdateCounters(contextVk, updatePerfCounters, &insertPos.first->second,
6781 renderPassOut);
6782
6783 // TODO(jmadill): Trim cache, and pre-populate with the most common RPs on startup.
6784 return angle::Result::Continue;
6785 }
6786
6787 // GraphicsPipelineCache implementation.
6788 template <typename Hash>
destroy(ContextVk * contextVk)6789 void GraphicsPipelineCache<Hash>::destroy(ContextVk *contextVk)
6790 {
6791 if (kDumpPipelineCacheGraph && !mPayload.empty())
6792 {
6793 vk::DumpPipelineCacheGraph<Hash>(contextVk, mPayload);
6794 }
6795
6796 accumulateCacheStats(contextVk->getRenderer());
6797
6798 VkDevice device = contextVk->getDevice();
6799
6800 for (auto &item : mPayload)
6801 {
6802 vk::PipelineHelper &pipeline = item.second;
6803 pipeline.destroy(device);
6804 }
6805
6806 mPayload.clear();
6807 }
6808
6809 template <typename Hash>
release(ContextVk * contextVk)6810 void GraphicsPipelineCache<Hash>::release(ContextVk *contextVk)
6811 {
6812 if (kDumpPipelineCacheGraph && !mPayload.empty())
6813 {
6814 vk::DumpPipelineCacheGraph<Hash>(contextVk, mPayload);
6815 }
6816
6817 for (auto &item : mPayload)
6818 {
6819 vk::PipelineHelper &pipeline = item.second;
6820 pipeline.release(contextVk);
6821 }
6822
6823 mPayload.clear();
6824 }
6825
6826 template <typename Hash>
createPipeline(ContextVk * contextVk,vk::PipelineCacheAccess * pipelineCache,const vk::RenderPass & compatibleRenderPass,const vk::PipelineLayout & pipelineLayout,const vk::ShaderModuleMap & shaders,const vk::SpecializationConstants & specConsts,PipelineSource source,const vk::GraphicsPipelineDesc & desc,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)6827 angle::Result GraphicsPipelineCache<Hash>::createPipeline(
6828 ContextVk *contextVk,
6829 vk::PipelineCacheAccess *pipelineCache,
6830 const vk::RenderPass &compatibleRenderPass,
6831 const vk::PipelineLayout &pipelineLayout,
6832 const vk::ShaderModuleMap &shaders,
6833 const vk::SpecializationConstants &specConsts,
6834 PipelineSource source,
6835 const vk::GraphicsPipelineDesc &desc,
6836 const vk::GraphicsPipelineDesc **descPtrOut,
6837 vk::PipelineHelper **pipelineOut)
6838 {
6839 vk::Pipeline newPipeline;
6840 vk::CacheLookUpFeedback feedback = vk::CacheLookUpFeedback::None;
6841
6842 // This "if" is left here for the benefit of VulkanPipelineCachePerfTest.
6843 if (contextVk != nullptr)
6844 {
6845 constexpr vk::GraphicsPipelineSubset kSubset =
6846 GraphicsPipelineCacheTypeHelper<Hash>::kSubset;
6847
6848 ANGLE_VK_TRY(contextVk, desc.initializePipeline(
6849 contextVk, pipelineCache, kSubset, compatibleRenderPass,
6850 pipelineLayout, shaders, specConsts, &newPipeline, &feedback));
6851 }
6852
6853 addToCache(source, desc, std::move(newPipeline), feedback, descPtrOut, pipelineOut);
6854 return angle::Result::Continue;
6855 }
6856
6857 template <typename Hash>
linkLibraries(ContextVk * contextVk,vk::PipelineCacheAccess * pipelineCache,const vk::GraphicsPipelineDesc & desc,const vk::PipelineLayout & pipelineLayout,vk::PipelineHelper * vertexInputPipeline,vk::PipelineHelper * shadersPipeline,vk::PipelineHelper * fragmentOutputPipeline,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)6858 angle::Result GraphicsPipelineCache<Hash>::linkLibraries(
6859 ContextVk *contextVk,
6860 vk::PipelineCacheAccess *pipelineCache,
6861 const vk::GraphicsPipelineDesc &desc,
6862 const vk::PipelineLayout &pipelineLayout,
6863 vk::PipelineHelper *vertexInputPipeline,
6864 vk::PipelineHelper *shadersPipeline,
6865 vk::PipelineHelper *fragmentOutputPipeline,
6866 const vk::GraphicsPipelineDesc **descPtrOut,
6867 vk::PipelineHelper **pipelineOut)
6868 {
6869 vk::Pipeline newPipeline;
6870 vk::CacheLookUpFeedback feedback = vk::CacheLookUpFeedback::None;
6871
6872 ANGLE_TRY(vk::InitializePipelineFromLibraries(
6873 contextVk, pipelineCache, pipelineLayout, *vertexInputPipeline, *shadersPipeline,
6874 *fragmentOutputPipeline, &newPipeline, &feedback));
6875
6876 addToCache(PipelineSource::DrawLinked, desc, std::move(newPipeline), feedback, descPtrOut,
6877 pipelineOut);
6878 (*pipelineOut)->setLinkedLibraryReferences(shadersPipeline);
6879
6880 return angle::Result::Continue;
6881 }
6882
6883 template <typename Hash>
addToCache(PipelineSource source,const vk::GraphicsPipelineDesc & desc,vk::Pipeline && pipeline,vk::CacheLookUpFeedback feedback,const vk::GraphicsPipelineDesc ** descPtrOut,vk::PipelineHelper ** pipelineOut)6884 void GraphicsPipelineCache<Hash>::addToCache(PipelineSource source,
6885 const vk::GraphicsPipelineDesc &desc,
6886 vk::Pipeline &&pipeline,
6887 vk::CacheLookUpFeedback feedback,
6888 const vk::GraphicsPipelineDesc **descPtrOut,
6889 vk::PipelineHelper **pipelineOut)
6890 {
6891 ASSERT(mPayload.find(desc) == mPayload.end());
6892
6893 mCacheStats.missAndIncrementSize();
6894
6895 switch (source)
6896 {
6897 case PipelineSource::WarmUp:
6898 feedback = feedback == vk::CacheLookUpFeedback::Hit
6899 ? vk::CacheLookUpFeedback::WarmUpHit
6900 : vk::CacheLookUpFeedback::WarmUpMiss;
6901 break;
6902 case PipelineSource::DrawLinked:
6903 feedback = feedback == vk::CacheLookUpFeedback::Hit
6904 ? vk::CacheLookUpFeedback::LinkedDrawHit
6905 : vk::CacheLookUpFeedback::LinkedDrawMiss;
6906 break;
6907 case PipelineSource::Utils:
6908 feedback = feedback == vk::CacheLookUpFeedback::Hit
6909 ? vk::CacheLookUpFeedback::UtilsHit
6910 : vk::CacheLookUpFeedback::UtilsMiss;
6911 break;
6912 default:
6913 break;
6914 }
6915
6916 auto insertedItem = mPayload.emplace(std::piecewise_construct, std::forward_as_tuple(desc),
6917 std::forward_as_tuple(std::move(pipeline), feedback));
6918 *descPtrOut = &insertedItem.first->first;
6919 *pipelineOut = &insertedItem.first->second;
6920 }
6921
6922 template <typename Hash>
populate(const vk::GraphicsPipelineDesc & desc,vk::Pipeline && pipeline)6923 void GraphicsPipelineCache<Hash>::populate(const vk::GraphicsPipelineDesc &desc,
6924 vk::Pipeline &&pipeline)
6925 {
6926 auto item = mPayload.find(desc);
6927 if (item != mPayload.end())
6928 {
6929 return;
6930 }
6931
6932 // Note: this function is only used for testing.
6933 mPayload.emplace(std::piecewise_construct, std::forward_as_tuple(desc),
6934 std::forward_as_tuple(std::move(pipeline), vk::CacheLookUpFeedback::None));
6935 }
6936
6937 // Instantiate the pipeline cache functions
6938 template void GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>::destroy(
6939 ContextVk *contextVk);
6940 template void GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>::release(
6941 ContextVk *contextVk);
6942 template angle::Result GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>::createPipeline(
6943 ContextVk *contextVk,
6944 vk::PipelineCacheAccess *pipelineCache,
6945 const vk::RenderPass &compatibleRenderPass,
6946 const vk::PipelineLayout &pipelineLayout,
6947 const vk::ShaderModuleMap &shaders,
6948 const vk::SpecializationConstants &specConsts,
6949 PipelineSource source,
6950 const vk::GraphicsPipelineDesc &desc,
6951 const vk::GraphicsPipelineDesc **descPtrOut,
6952 vk::PipelineHelper **pipelineOut);
6953 template angle::Result GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>::linkLibraries(
6954 ContextVk *contextVk,
6955 vk::PipelineCacheAccess *pipelineCache,
6956 const vk::GraphicsPipelineDesc &desc,
6957 const vk::PipelineLayout &pipelineLayout,
6958 vk::PipelineHelper *vertexInputPipeline,
6959 vk::PipelineHelper *shadersPipeline,
6960 vk::PipelineHelper *fragmentOutputPipeline,
6961 const vk::GraphicsPipelineDesc **descPtrOut,
6962 vk::PipelineHelper **pipelineOut);
6963 template void GraphicsPipelineCache<GraphicsPipelineDescCompleteHash>::populate(
6964 const vk::GraphicsPipelineDesc &desc,
6965 vk::Pipeline &&pipeline);
6966
6967 template void GraphicsPipelineCache<GraphicsPipelineDescVertexInputHash>::destroy(
6968 ContextVk *contextVk);
6969 template void GraphicsPipelineCache<GraphicsPipelineDescVertexInputHash>::release(
6970 ContextVk *contextVk);
6971 template angle::Result GraphicsPipelineCache<GraphicsPipelineDescVertexInputHash>::createPipeline(
6972 ContextVk *contextVk,
6973 vk::PipelineCacheAccess *pipelineCache,
6974 const vk::RenderPass &compatibleRenderPass,
6975 const vk::PipelineLayout &pipelineLayout,
6976 const vk::ShaderModuleMap &shaders,
6977 const vk::SpecializationConstants &specConsts,
6978 PipelineSource source,
6979 const vk::GraphicsPipelineDesc &desc,
6980 const vk::GraphicsPipelineDesc **descPtrOut,
6981 vk::PipelineHelper **pipelineOut);
6982 template void GraphicsPipelineCache<GraphicsPipelineDescVertexInputHash>::populate(
6983 const vk::GraphicsPipelineDesc &desc,
6984 vk::Pipeline &&pipeline);
6985
6986 template void GraphicsPipelineCache<GraphicsPipelineDescShadersHash>::destroy(ContextVk *contextVk);
6987 template void GraphicsPipelineCache<GraphicsPipelineDescShadersHash>::release(ContextVk *contextVk);
6988 template angle::Result GraphicsPipelineCache<GraphicsPipelineDescShadersHash>::createPipeline(
6989 ContextVk *contextVk,
6990 vk::PipelineCacheAccess *pipelineCache,
6991 const vk::RenderPass &compatibleRenderPass,
6992 const vk::PipelineLayout &pipelineLayout,
6993 const vk::ShaderModuleMap &shaders,
6994 const vk::SpecializationConstants &specConsts,
6995 PipelineSource source,
6996 const vk::GraphicsPipelineDesc &desc,
6997 const vk::GraphicsPipelineDesc **descPtrOut,
6998 vk::PipelineHelper **pipelineOut);
6999 template void GraphicsPipelineCache<GraphicsPipelineDescShadersHash>::populate(
7000 const vk::GraphicsPipelineDesc &desc,
7001 vk::Pipeline &&pipeline);
7002
7003 template void GraphicsPipelineCache<GraphicsPipelineDescFragmentOutputHash>::destroy(
7004 ContextVk *contextVk);
7005 template void GraphicsPipelineCache<GraphicsPipelineDescFragmentOutputHash>::release(
7006 ContextVk *contextVk);
7007 template angle::Result
7008 GraphicsPipelineCache<GraphicsPipelineDescFragmentOutputHash>::createPipeline(
7009 ContextVk *contextVk,
7010 vk::PipelineCacheAccess *pipelineCache,
7011 const vk::RenderPass &compatibleRenderPass,
7012 const vk::PipelineLayout &pipelineLayout,
7013 const vk::ShaderModuleMap &shaders,
7014 const vk::SpecializationConstants &specConsts,
7015 PipelineSource source,
7016 const vk::GraphicsPipelineDesc &desc,
7017 const vk::GraphicsPipelineDesc **descPtrOut,
7018 vk::PipelineHelper **pipelineOut);
7019 template void GraphicsPipelineCache<GraphicsPipelineDescFragmentOutputHash>::populate(
7020 const vk::GraphicsPipelineDesc &desc,
7021 vk::Pipeline &&pipeline);
7022
7023 // DescriptorSetLayoutCache implementation.
7024 DescriptorSetLayoutCache::DescriptorSetLayoutCache() = default;
7025
~DescriptorSetLayoutCache()7026 DescriptorSetLayoutCache::~DescriptorSetLayoutCache()
7027 {
7028 ASSERT(mPayload.empty());
7029 }
7030
destroy(RendererVk * rendererVk)7031 void DescriptorSetLayoutCache::destroy(RendererVk *rendererVk)
7032 {
7033 rendererVk->accumulateCacheStats(VulkanCacheType::DescriptorSetLayout, mCacheStats);
7034
7035 VkDevice device = rendererVk->getDevice();
7036
7037 for (auto &item : mPayload)
7038 {
7039 vk::RefCountedDescriptorSetLayout &layout = item.second;
7040 ASSERT(!layout.isReferenced());
7041 layout.get().destroy(device);
7042 }
7043
7044 mPayload.clear();
7045 }
7046
getDescriptorSetLayout(vk::Context * context,const vk::DescriptorSetLayoutDesc & desc,vk::BindingPointer<vk::DescriptorSetLayout> * descriptorSetLayoutOut)7047 angle::Result DescriptorSetLayoutCache::getDescriptorSetLayout(
7048 vk::Context *context,
7049 const vk::DescriptorSetLayoutDesc &desc,
7050 vk::BindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut)
7051 {
7052 auto iter = mPayload.find(desc);
7053 if (iter != mPayload.end())
7054 {
7055 vk::RefCountedDescriptorSetLayout &layout = iter->second;
7056 descriptorSetLayoutOut->set(&layout);
7057 mCacheStats.hit();
7058 return angle::Result::Continue;
7059 }
7060
7061 mCacheStats.missAndIncrementSize();
7062 // We must unpack the descriptor set layout description.
7063 vk::DescriptorSetLayoutBindingVector bindingVector;
7064 std::vector<VkSampler> immutableSamplers;
7065 desc.unpackBindings(&bindingVector, &immutableSamplers);
7066
7067 VkDescriptorSetLayoutCreateInfo createInfo = {};
7068 createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
7069 createInfo.flags = 0;
7070 createInfo.bindingCount = static_cast<uint32_t>(bindingVector.size());
7071 createInfo.pBindings = bindingVector.data();
7072
7073 vk::DescriptorSetLayout newLayout;
7074 ANGLE_VK_TRY(context, newLayout.init(context->getDevice(), createInfo));
7075
7076 auto insertedItem =
7077 mPayload.emplace(desc, vk::RefCountedDescriptorSetLayout(std::move(newLayout)));
7078 vk::RefCountedDescriptorSetLayout &insertedLayout = insertedItem.first->second;
7079 descriptorSetLayoutOut->set(&insertedLayout);
7080
7081 return angle::Result::Continue;
7082 }
7083
7084 // PipelineLayoutCache implementation.
7085 PipelineLayoutCache::PipelineLayoutCache() = default;
7086
~PipelineLayoutCache()7087 PipelineLayoutCache::~PipelineLayoutCache()
7088 {
7089 ASSERT(mPayload.empty());
7090 }
7091
destroy(RendererVk * rendererVk)7092 void PipelineLayoutCache::destroy(RendererVk *rendererVk)
7093 {
7094 accumulateCacheStats(rendererVk);
7095
7096 VkDevice device = rendererVk->getDevice();
7097
7098 for (auto &item : mPayload)
7099 {
7100 vk::RefCountedPipelineLayout &layout = item.second;
7101 layout.get().destroy(device);
7102 }
7103
7104 mPayload.clear();
7105 }
7106
getPipelineLayout(vk::Context * context,const vk::PipelineLayoutDesc & desc,const vk::DescriptorSetLayoutPointerArray & descriptorSetLayouts,vk::BindingPointer<vk::PipelineLayout> * pipelineLayoutOut)7107 angle::Result PipelineLayoutCache::getPipelineLayout(
7108 vk::Context *context,
7109 const vk::PipelineLayoutDesc &desc,
7110 const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts,
7111 vk::BindingPointer<vk::PipelineLayout> *pipelineLayoutOut)
7112 {
7113 auto iter = mPayload.find(desc);
7114 if (iter != mPayload.end())
7115 {
7116 vk::RefCountedPipelineLayout &layout = iter->second;
7117 pipelineLayoutOut->set(&layout);
7118 mCacheStats.hit();
7119 return angle::Result::Continue;
7120 }
7121
7122 mCacheStats.missAndIncrementSize();
7123 // Note this does not handle gaps in descriptor set layouts gracefully.
7124 angle::FixedVector<VkDescriptorSetLayout, vk::kMaxDescriptorSetLayouts> setLayoutHandles;
7125 for (const vk::BindingPointer<vk::DescriptorSetLayout> &layoutPtr : descriptorSetLayouts)
7126 {
7127 if (layoutPtr.valid())
7128 {
7129 VkDescriptorSetLayout setLayout = layoutPtr.get().getHandle();
7130 if (setLayout != VK_NULL_HANDLE)
7131 {
7132 setLayoutHandles.push_back(setLayout);
7133 }
7134 }
7135 }
7136
7137 const vk::PackedPushConstantRange &descPushConstantRange = desc.getPushConstantRange();
7138 VkPushConstantRange pushConstantRange;
7139 pushConstantRange.stageFlags = descPushConstantRange.stageMask;
7140 pushConstantRange.offset = descPushConstantRange.offset;
7141 pushConstantRange.size = descPushConstantRange.size;
7142
7143 // No pipeline layout found. We must create a new one.
7144 VkPipelineLayoutCreateInfo createInfo = {};
7145 createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
7146 createInfo.flags = 0;
7147 createInfo.setLayoutCount = static_cast<uint32_t>(setLayoutHandles.size());
7148 createInfo.pSetLayouts = setLayoutHandles.data();
7149 if (pushConstantRange.size > 0)
7150 {
7151 createInfo.pushConstantRangeCount = 1;
7152 createInfo.pPushConstantRanges = &pushConstantRange;
7153 }
7154
7155 vk::PipelineLayout newLayout;
7156 ANGLE_VK_TRY(context, newLayout.init(context->getDevice(), createInfo));
7157
7158 auto insertedItem = mPayload.emplace(desc, vk::RefCountedPipelineLayout(std::move(newLayout)));
7159 vk::RefCountedPipelineLayout &insertedLayout = insertedItem.first->second;
7160 pipelineLayoutOut->set(&insertedLayout);
7161
7162 return angle::Result::Continue;
7163 }
7164
7165 // YuvConversionCache implementation
7166 SamplerYcbcrConversionCache::SamplerYcbcrConversionCache() = default;
7167
~SamplerYcbcrConversionCache()7168 SamplerYcbcrConversionCache::~SamplerYcbcrConversionCache()
7169 {
7170 ASSERT(mExternalFormatPayload.empty() && mVkFormatPayload.empty());
7171 }
7172
destroy(RendererVk * rendererVk)7173 void SamplerYcbcrConversionCache::destroy(RendererVk *rendererVk)
7174 {
7175 rendererVk->accumulateCacheStats(VulkanCacheType::SamplerYcbcrConversion, mCacheStats);
7176
7177 VkDevice device = rendererVk->getDevice();
7178
7179 for (auto &iter : mExternalFormatPayload)
7180 {
7181 vk::SamplerYcbcrConversion &samplerYcbcrConversion = iter.second;
7182 samplerYcbcrConversion.destroy(device);
7183
7184 rendererVk->onDeallocateHandle(vk::HandleType::SamplerYcbcrConversion);
7185 }
7186
7187 for (auto &iter : mVkFormatPayload)
7188 {
7189 vk::SamplerYcbcrConversion &samplerYcbcrConversion = iter.second;
7190 samplerYcbcrConversion.destroy(device);
7191
7192 rendererVk->onDeallocateHandle(vk::HandleType::SamplerYcbcrConversion);
7193 }
7194
7195 mExternalFormatPayload.clear();
7196 mVkFormatPayload.clear();
7197 }
7198
getSamplerYcbcrConversion(vk::Context * context,const vk::YcbcrConversionDesc & ycbcrConversionDesc,VkSamplerYcbcrConversion * vkSamplerYcbcrConversionOut)7199 angle::Result SamplerYcbcrConversionCache::getSamplerYcbcrConversion(
7200 vk::Context *context,
7201 const vk::YcbcrConversionDesc &ycbcrConversionDesc,
7202 VkSamplerYcbcrConversion *vkSamplerYcbcrConversionOut)
7203 {
7204 ASSERT(ycbcrConversionDesc.valid());
7205 ASSERT(vkSamplerYcbcrConversionOut);
7206
7207 SamplerYcbcrConversionMap &payload =
7208 (ycbcrConversionDesc.getExternalFormat() != 0) ? mExternalFormatPayload : mVkFormatPayload;
7209 const auto iter = payload.find(ycbcrConversionDesc);
7210 if (iter != payload.end())
7211 {
7212 vk::SamplerYcbcrConversion &samplerYcbcrConversion = iter->second;
7213 mCacheStats.hit();
7214 *vkSamplerYcbcrConversionOut = samplerYcbcrConversion.getHandle();
7215 return angle::Result::Continue;
7216 }
7217
7218 mCacheStats.missAndIncrementSize();
7219
7220 // Create the VkSamplerYcbcrConversion
7221 vk::SamplerYcbcrConversion wrappedSamplerYcbcrConversion;
7222 ANGLE_TRY(ycbcrConversionDesc.init(context, &wrappedSamplerYcbcrConversion));
7223
7224 auto insertedItem = payload.emplace(
7225 ycbcrConversionDesc, vk::SamplerYcbcrConversion(std::move(wrappedSamplerYcbcrConversion)));
7226 vk::SamplerYcbcrConversion &insertedSamplerYcbcrConversion = insertedItem.first->second;
7227 *vkSamplerYcbcrConversionOut = insertedSamplerYcbcrConversion.getHandle();
7228
7229 context->getRenderer()->onAllocateHandle(vk::HandleType::SamplerYcbcrConversion);
7230
7231 return angle::Result::Continue;
7232 }
7233
7234 // SamplerCache implementation.
7235 SamplerCache::SamplerCache() = default;
7236
~SamplerCache()7237 SamplerCache::~SamplerCache()
7238 {
7239 ASSERT(mPayload.empty());
7240 }
7241
destroy(RendererVk * rendererVk)7242 void SamplerCache::destroy(RendererVk *rendererVk)
7243 {
7244 rendererVk->accumulateCacheStats(VulkanCacheType::Sampler, mCacheStats);
7245
7246 VkDevice device = rendererVk->getDevice();
7247
7248 for (auto &iter : mPayload)
7249 {
7250 vk::RefCountedSampler &sampler = iter.second;
7251 ASSERT(!sampler.isReferenced());
7252 sampler.get().get().destroy(device);
7253
7254 rendererVk->onDeallocateHandle(vk::HandleType::Sampler);
7255 }
7256
7257 mPayload.clear();
7258 }
7259
getSampler(ContextVk * contextVk,const vk::SamplerDesc & desc,vk::SamplerBinding * samplerOut)7260 angle::Result SamplerCache::getSampler(ContextVk *contextVk,
7261 const vk::SamplerDesc &desc,
7262 vk::SamplerBinding *samplerOut)
7263 {
7264 auto iter = mPayload.find(desc);
7265 if (iter != mPayload.end())
7266 {
7267 vk::RefCountedSampler &sampler = iter->second;
7268 samplerOut->set(&sampler);
7269 mCacheStats.hit();
7270 return angle::Result::Continue;
7271 }
7272
7273 mCacheStats.missAndIncrementSize();
7274 vk::SamplerHelper samplerHelper(contextVk);
7275 ANGLE_TRY(desc.init(contextVk, &samplerHelper.get()));
7276
7277 vk::RefCountedSampler newSampler(std::move(samplerHelper));
7278 auto insertedItem = mPayload.emplace(desc, std::move(newSampler));
7279 vk::RefCountedSampler &insertedSampler = insertedItem.first->second;
7280 samplerOut->set(&insertedSampler);
7281
7282 contextVk->getRenderer()->onAllocateHandle(vk::HandleType::Sampler);
7283
7284 return angle::Result::Continue;
7285 }
7286 } // namespace rx
7287