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