• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // UtilsVk.cpp:
7 //    Implements the UtilsVk class.
8 //
9 
10 #include "libANGLE/renderer/vulkan/UtilsVk.h"
11 
12 #include "common/spirv/spirv_instruction_builder_autogen.h"
13 
14 #include "libANGLE/renderer/glslang_wrapper_utils.h"
15 #include "libANGLE/renderer/vulkan/ContextVk.h"
16 #include "libANGLE/renderer/vulkan/DisplayVk.h"
17 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
18 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
19 #include "libANGLE/renderer/vulkan/RendererVk.h"
20 #include "libANGLE/renderer/vulkan/vk_utils.h"
21 
22 namespace rx
23 {
24 
25 namespace ConvertVertex_comp                = vk::InternalShader::ConvertVertex_comp;
26 namespace ImageClear_frag                   = vk::InternalShader::ImageClear_frag;
27 namespace ImageCopy_frag                    = vk::InternalShader::ImageCopy_frag;
28 namespace BlitResolve_frag                  = vk::InternalShader::BlitResolve_frag;
29 namespace BlitResolveStencilNoExport_comp   = vk::InternalShader::BlitResolveStencilNoExport_comp;
30 namespace OverlayCull_comp                  = vk::InternalShader::OverlayCull_comp;
31 namespace OverlayDraw_comp                  = vk::InternalShader::OverlayDraw_comp;
32 namespace ConvertIndexIndirectLineLoop_comp = vk::InternalShader::ConvertIndexIndirectLineLoop_comp;
33 namespace GenerateMipmap_comp               = vk::InternalShader::GenerateMipmap_comp;
34 
35 namespace spirv = angle::spirv;
36 
37 namespace
38 {
39 constexpr uint32_t kConvertIndexDestinationBinding = 0;
40 
41 constexpr uint32_t kConvertVertexDestinationBinding = 0;
42 constexpr uint32_t kConvertVertexSourceBinding      = 1;
43 
44 constexpr uint32_t kImageCopySourceBinding = 0;
45 
46 constexpr uint32_t kBlitResolveColorOrDepthBinding = 0;
47 constexpr uint32_t kBlitResolveStencilBinding      = 1;
48 constexpr uint32_t kBlitResolveSamplerBinding      = 2;
49 
50 constexpr uint32_t kBlitResolveStencilNoExportDestBinding    = 0;
51 constexpr uint32_t kBlitResolveStencilNoExportSrcBinding     = 1;
52 constexpr uint32_t kBlitResolveStencilNoExportSamplerBinding = 2;
53 
54 constexpr uint32_t kOverlayCullCulledWidgetsBinding = 0;
55 constexpr uint32_t kOverlayCullWidgetCoordsBinding  = 1;
56 
57 constexpr uint32_t kOverlayDrawOutputBinding        = 0;
58 constexpr uint32_t kOverlayDrawTextWidgetsBinding   = 1;
59 constexpr uint32_t kOverlayDrawGraphWidgetsBinding  = 2;
60 constexpr uint32_t kOverlayDrawCulledWidgetsBinding = 3;
61 constexpr uint32_t kOverlayDrawFontBinding          = 4;
62 
63 constexpr uint32_t kGenerateMipmapDestinationBinding = 0;
64 constexpr uint32_t kGenerateMipmapSourceBinding      = 1;
65 
ValidateFloatOneAsUint()66 bool ValidateFloatOneAsUint()
67 {
68     union
69     {
70         uint32_t asUint;
71         float asFloat;
72     } one;
73     one.asUint = gl::Float32One;
74     return one.asFloat == 1.0f;
75 }
76 
GetConvertVertexFlags(const UtilsVk::ConvertVertexParameters & params)77 uint32_t GetConvertVertexFlags(const UtilsVk::ConvertVertexParameters &params)
78 {
79     bool srcIsSint      = params.srcFormat->isSint();
80     bool srcIsUint      = params.srcFormat->isUint();
81     bool srcIsSnorm     = params.srcFormat->isSnorm();
82     bool srcIsUnorm     = params.srcFormat->isUnorm();
83     bool srcIsFixed     = params.srcFormat->isFixed;
84     bool srcIsFloat     = params.srcFormat->isFloat();
85     bool srcIsHalfFloat = params.srcFormat->isVertexTypeHalfFloat();
86 
87     bool dstIsSint      = params.dstFormat->isSint();
88     bool dstIsUint      = params.dstFormat->isUint();
89     bool dstIsSnorm     = params.dstFormat->isSnorm();
90     bool dstIsUnorm     = params.dstFormat->isUnorm();
91     bool dstIsFloat     = params.dstFormat->isFloat();
92     bool dstIsHalfFloat = params.dstFormat->isVertexTypeHalfFloat();
93 
94     // Assert on the types to make sure the shader supports its.  These are based on
95     // ConvertVertex_comp::Conversion values.
96     ASSERT(!dstIsSint || srcIsSint);    // If destination is sint, src must be sint too
97     ASSERT(!dstIsUint || srcIsUint);    // If destination is uint, src must be uint too
98     ASSERT(!srcIsFixed || dstIsFloat);  // If source is fixed, dst must be float
99 
100     // One of each bool set must be true
101     ASSERT(srcIsSint || srcIsUint || srcIsSnorm || srcIsUnorm || srcIsFixed || srcIsFloat);
102     ASSERT(dstIsSint || dstIsUint || dstIsSnorm || dstIsUnorm || dstIsFloat || dstIsHalfFloat);
103 
104     // We currently don't have any big-endian devices in the list of supported platforms.  The
105     // shader is capable of supporting big-endian architectures, but the relevant flag (IsBigEndian)
106     // is not added to the build configuration file (to reduce binary size).  If necessary, add
107     // IsBigEndian to ConvertVertex.comp.json and select the appropriate flag based on the
108     // endian-ness test here.
109     ASSERT(IsLittleEndian());
110 
111     uint32_t flags = 0;
112 
113     if (srcIsHalfFloat && dstIsHalfFloat)
114     {
115         // Note that HalfFloat conversion uses the same shader as Uint.
116         flags = ConvertVertex_comp::kUintToUint;
117     }
118     else if ((srcIsSnorm && dstIsSnorm) || (srcIsUnorm && dstIsUnorm))
119     {
120         // Do snorm->snorm and unorm->unorm copies using the uint->uint shader.  Currently only
121         // supported for same-width formats, so it's only used when adding channels.
122         ASSERT(params.srcFormat->redBits == params.dstFormat->redBits);
123         flags = ConvertVertex_comp::kUintToUint;
124     }
125     else if (srcIsSint && dstIsSint)
126     {
127         flags = ConvertVertex_comp::kSintToSint;
128     }
129     else if (srcIsUint && dstIsUint)
130     {
131         flags = ConvertVertex_comp::kUintToUint;
132     }
133     else if (srcIsSint)
134     {
135         flags = ConvertVertex_comp::kSintToFloat;
136     }
137     else if (srcIsUint)
138     {
139         flags = ConvertVertex_comp::kUintToFloat;
140     }
141     else if (srcIsSnorm)
142     {
143         flags = ConvertVertex_comp::kSnormToFloat;
144     }
145     else if (srcIsUnorm)
146     {
147         flags = ConvertVertex_comp::kUnormToFloat;
148     }
149     else if (srcIsFixed)
150     {
151         flags = ConvertVertex_comp::kFixedToFloat;
152     }
153     else if (srcIsFloat)
154     {
155         flags = ConvertVertex_comp::kFloatToFloat;
156     }
157     else
158     {
159         UNREACHABLE();
160     }
161 
162     return flags;
163 }
164 
GetImageClearFlags(const angle::Format & format,uint32_t attachmentIndex,bool clearDepth)165 uint32_t GetImageClearFlags(const angle::Format &format, uint32_t attachmentIndex, bool clearDepth)
166 {
167     constexpr uint32_t kAttachmentFlagStep =
168         ImageClear_frag::kAttachment1 - ImageClear_frag::kAttachment0;
169 
170     static_assert(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS == 8,
171                   "ImageClear shader assumes maximum 8 draw buffers");
172     static_assert(
173         ImageClear_frag::kAttachment0 + 7 * kAttachmentFlagStep == ImageClear_frag::kAttachment7,
174         "ImageClear AttachmentN flag calculation needs correction");
175 
176     uint32_t flags = ImageClear_frag::kAttachment0 + attachmentIndex * kAttachmentFlagStep;
177 
178     if (format.isSint())
179     {
180         flags |= ImageClear_frag::kIsSint;
181     }
182     else if (format.isUint())
183     {
184         flags |= ImageClear_frag::kIsUint;
185     }
186     else
187     {
188         flags |= ImageClear_frag::kIsFloat;
189     }
190 
191     if (clearDepth)
192     {
193         flags |= ImageClear_frag::kClearDepth;
194     }
195 
196     return flags;
197 }
198 
GetFormatFlags(const angle::Format & format,uint32_t intFlag,uint32_t uintFlag,uint32_t floatFlag)199 uint32_t GetFormatFlags(const angle::Format &format,
200                         uint32_t intFlag,
201                         uint32_t uintFlag,
202                         uint32_t floatFlag)
203 {
204     if (format.isSint())
205     {
206         return intFlag;
207     }
208     if (format.isUint())
209     {
210         return uintFlag;
211     }
212     return floatFlag;
213 }
214 
GetImageCopyFlags(const angle::Format & srcIntendedFormat,const angle::Format & dstIntendedFormat)215 uint32_t GetImageCopyFlags(const angle::Format &srcIntendedFormat,
216                            const angle::Format &dstIntendedFormat)
217 {
218     uint32_t flags = 0;
219 
220     flags |= GetFormatFlags(srcIntendedFormat, ImageCopy_frag::kSrcIsSint,
221                             ImageCopy_frag::kSrcIsUint, ImageCopy_frag::kSrcIsFloat);
222     flags |= GetFormatFlags(dstIntendedFormat, ImageCopy_frag::kDestIsSint,
223                             ImageCopy_frag::kDestIsUint, ImageCopy_frag::kDestIsFloat);
224 
225     return flags;
226 }
227 
GetBlitResolveFlags(bool blitColor,bool blitDepth,bool blitStencil,const angle::Format & intendedFormat)228 uint32_t GetBlitResolveFlags(bool blitColor,
229                              bool blitDepth,
230                              bool blitStencil,
231                              const angle::Format &intendedFormat)
232 {
233     if (blitColor)
234     {
235         return GetFormatFlags(intendedFormat, BlitResolve_frag::kBlitColorInt,
236                               BlitResolve_frag::kBlitColorUint, BlitResolve_frag::kBlitColorFloat);
237     }
238 
239     if (blitDepth)
240     {
241         if (blitStencil)
242         {
243             return BlitResolve_frag::kBlitDepthStencil;
244         }
245         else
246         {
247             return BlitResolve_frag::kBlitDepth;
248         }
249     }
250     else
251     {
252         return BlitResolve_frag::kBlitStencil;
253     }
254 }
255 
GetConvertIndexIndirectLineLoopFlag(uint32_t indicesBitsWidth)256 uint32_t GetConvertIndexIndirectLineLoopFlag(uint32_t indicesBitsWidth)
257 {
258     switch (indicesBitsWidth)
259     {
260         case 8:
261             return ConvertIndexIndirectLineLoop_comp::kIs8Bits;
262         case 16:
263             return ConvertIndexIndirectLineLoop_comp::kIs16Bits;
264         case 32:
265             return ConvertIndexIndirectLineLoop_comp::kIs32Bits;
266         default:
267             UNREACHABLE();
268             return 0;
269     }
270 }
271 
GetGenerateMipmapFlags(ContextVk * contextVk,const angle::Format & actualFormat)272 uint32_t GetGenerateMipmapFlags(ContextVk *contextVk, const angle::Format &actualFormat)
273 {
274     uint32_t flags = 0;
275 
276     // Note: If bits-per-component is 8 or 16 and float16 is supported in the shader, use that for
277     // faster math.
278     const bool hasShaderFloat16 =
279         contextVk->getRenderer()->getFeatures().supportsShaderFloat16.enabled;
280 
281     if (actualFormat.redBits <= 8)
282     {
283         flags = hasShaderFloat16 ? GenerateMipmap_comp::kIsRGBA8_UseHalf
284                                  : GenerateMipmap_comp::kIsRGBA8;
285     }
286     else if (actualFormat.redBits <= 16)
287     {
288         flags = hasShaderFloat16 ? GenerateMipmap_comp::kIsRGBA16_UseHalf
289                                  : GenerateMipmap_comp::kIsRGBA16;
290     }
291     else
292     {
293         flags = GenerateMipmap_comp::kIsRGBA32F;
294     }
295 
296     flags |= UtilsVk::GetGenerateMipmapMaxLevels(contextVk) == UtilsVk::kGenerateMipmapMaxLevels
297                  ? GenerateMipmap_comp::kDestSize6
298                  : GenerateMipmap_comp::kDestSize4;
299 
300     return flags;
301 }
302 
303 enum UnresolveColorAttachmentType
304 {
305     kUnresolveTypeUnused = 0,
306     kUnresolveTypeFloat  = 1,
307     kUnresolveTypeSint   = 2,
308     kUnresolveTypeUint   = 3,
309 };
310 
GetUnresolveFlags(uint32_t colorAttachmentCount,const gl::DrawBuffersArray<vk::ImageHelper * > & colorSrc,bool unresolveDepth,bool unresolveStencil,gl::DrawBuffersArray<UnresolveColorAttachmentType> * attachmentTypesOut)311 uint32_t GetUnresolveFlags(uint32_t colorAttachmentCount,
312                            const gl::DrawBuffersArray<vk::ImageHelper *> &colorSrc,
313                            bool unresolveDepth,
314                            bool unresolveStencil,
315                            gl::DrawBuffersArray<UnresolveColorAttachmentType> *attachmentTypesOut)
316 {
317     uint32_t flags = 0;
318 
319     for (uint32_t attachmentIndex = 0; attachmentIndex < colorAttachmentCount; ++attachmentIndex)
320     {
321         const angle::Format &format = colorSrc[attachmentIndex]->getIntendedFormat();
322 
323         UnresolveColorAttachmentType type = kUnresolveTypeFloat;
324         if (format.isSint())
325         {
326             type = kUnresolveTypeSint;
327         }
328         else if (format.isUint())
329         {
330             type = kUnresolveTypeUint;
331         }
332 
333         (*attachmentTypesOut)[attachmentIndex] = type;
334 
335         // |flags| is comprised of |colorAttachmentCount| values from
336         // |UnresolveColorAttachmentType|, each taking up 2 bits.
337         flags |= type << (2 * attachmentIndex);
338     }
339 
340     // Additionally, two bits are used for depth and stencil unresolve.
341     constexpr uint32_t kDepthUnresolveFlagBit   = 2 * gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
342     constexpr uint32_t kStencilUnresolveFlagBit = kDepthUnresolveFlagBit + 1;
343     if (unresolveDepth)
344     {
345         flags |= 1 << kDepthUnresolveFlagBit;
346     }
347 
348     if (unresolveStencil)
349     {
350         flags |= 1 << kStencilUnresolveFlagBit;
351     }
352 
353     return flags;
354 }
355 
GetFormatDefaultChannelMask(const angle::Format & intendedImageFormat,const angle::Format & actualImageFormat)356 uint32_t GetFormatDefaultChannelMask(const angle::Format &intendedImageFormat,
357                                      const angle::Format &actualImageFormat)
358 {
359     uint32_t mask = 0;
360 
361     // Red can never be introduced due to format emulation (except for luma which is handled
362     // especially)
363     ASSERT(((intendedImageFormat.redBits > 0) == (actualImageFormat.redBits > 0)) ||
364            intendedImageFormat.isLUMA());
365     mask |= intendedImageFormat.greenBits == 0 && actualImageFormat.greenBits > 0 ? 2 : 0;
366     mask |= intendedImageFormat.blueBits == 0 && actualImageFormat.blueBits > 0 ? 4 : 0;
367     mask |= intendedImageFormat.alphaBits == 0 && actualImageFormat.alphaBits > 0 ? 8 : 0;
368 
369     return mask;
370 }
371 
372 // Calculate the transformation offset for blit/resolve.  See BlitResolve.frag for details on how
373 // these values are derived.
CalculateBlitOffset(const UtilsVk::BlitResolveParameters & params,float offset[2])374 void CalculateBlitOffset(const UtilsVk::BlitResolveParameters &params, float offset[2])
375 {
376     int srcOffsetFactorX = params.flipX ? -1 : 1;
377     int srcOffsetFactorY = params.flipY ? -1 : 1;
378 
379     offset[0] = params.dstOffset[0] * params.stretch[0] - params.srcOffset[0] * srcOffsetFactorX;
380     offset[1] = params.dstOffset[1] * params.stretch[1] - params.srcOffset[1] * srcOffsetFactorY;
381 }
382 
CalculateResolveOffset(const UtilsVk::BlitResolveParameters & params,int32_t offset[2])383 void CalculateResolveOffset(const UtilsVk::BlitResolveParameters &params, int32_t offset[2])
384 {
385     int srcOffsetFactorX = params.flipX ? -1 : 1;
386     int srcOffsetFactorY = params.flipY ? -1 : 1;
387 
388     // There's no stretching in resolve.
389     offset[0] = params.dstOffset[0] - params.srcOffset[0] * srcOffsetFactorX;
390     offset[1] = params.dstOffset[1] - params.srcOffset[1] * srcOffsetFactorY;
391 }
392 
393 // Sets the appropriate settings in the pipeline for the shader to output stencil.  Requires the
394 // shader stencil export extension.
SetStencilForShaderExport(ContextVk * contextVk,vk::GraphicsPipelineDesc * desc)395 void SetStencilForShaderExport(ContextVk *contextVk, vk::GraphicsPipelineDesc *desc)
396 {
397     ASSERT(contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled);
398 
399     const uint8_t completeMask    = 0xFF;
400     const uint8_t unusedReference = 0x00;
401 
402     desc->setStencilTestEnabled(true);
403     desc->setStencilFrontFuncs(unusedReference, VK_COMPARE_OP_ALWAYS, completeMask);
404     desc->setStencilBackFuncs(unusedReference, VK_COMPARE_OP_ALWAYS, completeMask);
405     desc->setStencilFrontOps(VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE);
406     desc->setStencilBackOps(VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE);
407     desc->setStencilFrontWriteMask(completeMask);
408     desc->setStencilBackWriteMask(completeMask);
409 }
410 
411 namespace unresolve
412 {
413 // The unresolve shader looks like the following, based on the number and types of unresolve
414 // attachments.
415 //
416 //     #version 450 core
417 //     #extension GL_ARB_shader_stencil_export : require
418 //
419 //     layout(location = 0) out vec4 colorOut0;
420 //     layout(location = 1) out ivec4 colorOut1;
421 //     layout(location = 2) out uvec4 colorOut2;
422 //     layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput colorIn0;
423 //     layout(input_attachment_index = 1, set = 0, binding = 1) uniform isubpassInput colorIn1;
424 //     layout(input_attachment_index = 2, set = 0, binding = 2) uniform usubpassInput colorIn2;
425 //     layout(input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput depthIn;
426 //     layout(input_attachment_index = 3, set = 0, binding = 4) uniform usubpassInput stencilIn;
427 //
428 //     void main()
429 //     {
430 //         colorOut0 = subpassLoad(colorIn0);
431 //         colorOut1 = subpassLoad(colorIn1);
432 //         colorOut2 = subpassLoad(colorIn2);
433 //         gl_FragDepth = subpassLoad(depthIn).x;
434 //         gl_FragStencilRefARB = int(subpassLoad(stencilIn).x);
435 //     }
436 //
437 // This shader compiles to the following SPIR-V:
438 //
439 //           OpCapability Shader                              \
440 //           OpCapability InputAttachment                      \
441 //           OpCapability StencilExportEXT                      \   Preamble.  Mostly fixed, except
442 //           OpExtension "SPV_EXT_shader_stencil_export"         \  OpEntryPoint should enumerate
443 //      %1 = OpExtInstImport "GLSL.std.450"                       \ out variables, stencil export
444 //           OpMemoryModel Logical GLSL450                        / is conditional to stencil
445 //           OpEntryPoint Fragment %4 "main" %26 %27 %28 %29 %30 /  unresolve, and depth replacing
446 //           OpExecutionMode %4 OriginUpperLeft                 /   conditional to depth unresolve.
447 //           OpExecutionMode %4 DepthReplacing                 /
448 //           OpSource GLSL 450                                /
449 //
450 //           OpName %4 "main"              \
451 //           OpName %26 "colorOut0"         \
452 //           OpName %27 "colorOut1"          \
453 //           OpName %28 "colorOut2"           \
454 //           OpName %29 "gl_FragDepth"         \ Debug information.  Not generated here.
455 //           OpName %30 "gl_FragStencilRefARB" /
456 //           OpName %31 "colorIn0"            /
457 //           OpName %32 "colorIn1"           /
458 //           OpName %33 "colorIn2"          /
459 //           OpName %34 "depthIn"          /
460 //           OpName %35 "stencilIn"       /
461 //
462 //           OpDecorate %26 Location 0      \
463 //           OpDecorate %27 Location 1       \ Location decoration of out variables.
464 //           OpDecorate %28 Location 2       /
465 //
466 //           OpDecorate %29 BuiltIn FragDepth          \ Builtin outputs, conditional to depth
467 //           OpDecorate %30 BuiltIn FragStencilRefEXT  / and stencil unresolve.
468 //
469 //           OpDecorate %31 DescriptorSet 0        \
470 //           OpDecorate %31 Binding 0               \
471 //           OpDecorate %31 InputAttachmentIndex 0   \
472 //           OpDecorate %32 DescriptorSet 0           \
473 //           OpDecorate %32 Binding 1                  \
474 //           OpDecorate %32 InputAttachmentIndex 1      \
475 //           OpDecorate %33 DescriptorSet 0              \  set, binding and input_attachment
476 //           OpDecorate %33 Binding 2                     \ decorations of the subpassInput
477 //           OpDecorate %33 InputAttachmentIndex 2        / variables.
478 //           OpDecorate %34 DescriptorSet 0              /
479 //           OpDecorate %34 Binding 3                   /
480 //           OpDecorate %34 InputAttachmentIndex 3     /
481 //           OpDecorate %35 DescriptorSet 0           /
482 //           OpDecorate %35 Binding 4                /
483 //           OpDecorate %35 InputAttachmentIndex 3  /
484 //
485 //      %2 = OpTypeVoid         \ Type of main().  Fixed.
486 //      %3 = OpTypeFunction %2  /
487 //
488 //      %6 = OpTypeFloat 32                             \
489 //      %7 = OpTypeVector %6 4                           \
490 //      %8 = OpTypePointer Output %7                      \ Type declaration for "out vec4"
491 //      %9 = OpTypeImage %6 SubpassData 0 0 0 2 Unknown   / and "subpassInput".  Fixed.
492 //     %10 = OpTypePointer UniformConstant %9            /
493 //
494 //     %11 = OpTypeInt 32 1                              \
495 //     %12 = OpTypeVector %11 4                           \
496 //     %13 = OpTypePointer Output %12                      \ Type declaration for "out ivec4"
497 //     %14 = OpTypeImage %11 SubpassData 0 0 0 2 Unknown   / and "isubpassInput".  Fixed.
498 //     %15 = OpTypePointer UniformConstant %14            /
499 //
500 //     %16 = OpTypeInt 32 0                              \
501 //     %17 = OpTypeVector %16 4                           \
502 //     %18 = OpTypePointer Output %17                      \ Type declaration for "out uvec4"
503 //     %19 = OpTypeImage %16 SubpassData 0 0 0 2 Unknown   / and "usubpassInput".  Fixed.
504 //     %20 = OpTypePointer UniformConstant %19            /
505 //
506 //     %21 = OpTypePointer Output %6         \ Type declaraions for depth and stencil. Fixed.
507 //     %22 = OpTypePointer Output %11        /
508 //
509 //     %23 = OpConstant %11 0                \
510 //     %24 = OpTypeVector %11 2               \ ivec2(0) for OpImageRead.  subpassLoad
511 //     %25 = OpConstantComposite %22 %21 %21  / doesn't require coordinates.  Fixed.
512 //
513 //     %26 = OpVariable %8 Output            \
514 //     %27 = OpVariable %13 Output            \
515 //     %28 = OpVariable %18 Output             \
516 //     %29 = OpVariable %21 Output              \
517 //     %30 = OpVariable %22 Output               \ Actual "out" and "*subpassInput"
518 //     %31 = OpVariable %10 UniformConstant      / variable declarations.
519 //     %32 = OpVariable %15 UniformConstant     /
520 //     %33 = OpVariable %20 UniformConstant    /
521 //     %34 = OpVariable %10 UniformConstant   /
522 //     %35 = OpVariable %20 UniformConstant  /
523 //
524 //      %4 = OpFunction %2 None %3   \ Top of main().  Fixed.
525 //      %5 = OpLabel                 /
526 //
527 //     %36 = OpLoad %9 %31           \
528 //     %37 = OpImageRead %7 %36 %23   \ colorOut0 = subpassLoad(colorIn0);
529 //           OpStore %26 %37          /
530 //
531 //     %38 = OpLoad %14 %32          \
532 //     %39 = OpImageRead %12 %38 %23  \ colorOut1 = subpassLoad(colorIn1);
533 //           OpStore %27 %39          /
534 //
535 //     %40 = OpLoad %19 %33          \
536 //     %41 = OpImageRead %17 %40 %23  \ colorOut2 = subpassLoad(colorIn2);
537 //           OpStore %28 %41          /
538 //
539 //     %42 = OpLoad %9 %34              \
540 //     %43 = OpImageRead %7 %42 %23      \ gl_FragDepth = subpassLoad(depthIn).x;
541 //     %44 = OpCompositeExtract %6 %43 0 /
542 //           OpStore %29 %44            /
543 //
544 //     %45 = OpLoad %19 %35              \
545 //     %46 = OpImageRead %17 %45 %23      \
546 //     %47 = OpCompositeExtract %16 %46 0  \ gl_FragStencilRefARB = int(subpassLoad(stencilIn).x);
547 //     %48 = OpBitcast %11 %47             /
548 //           OpStore %30 %48              /
549 //
550 //           OpReturn           \ Bottom of main().  Fixed.
551 //           OpFunctionEnd      /
552 //
553 // What makes the generation of this shader manageable is that the majority of it is constant
554 // between the different variations of the shader.  The rest are repeating patterns with different
555 // ids or indices.
556 
557 enum
558 {
559     // main() ids
560     kIdExtInstImport = 1,
561     kIdVoid,
562     kIdMainType,
563     kIdMain,
564     kIdMainLabel,
565 
566     // Types for "out vec4" and "subpassInput"
567     kIdFloatType,
568     kIdFloat4Type,
569     kIdFloat4OutType,
570     kIdFloatSubpassImageType,
571     kIdFloatSubpassInputType,
572 
573     // Types for "out ivec4" and "isubpassInput"
574     kIdSIntType,
575     kIdSInt4Type,
576     kIdSInt4OutType,
577     kIdSIntSubpassImageType,
578     kIdSIntSubpassInputType,
579 
580     // Types for "out uvec4" and "usubpassInput"
581     kIdUIntType,
582     kIdUInt4Type,
583     kIdUInt4OutType,
584     kIdUIntSubpassImageType,
585     kIdUIntSubpassInputType,
586 
587     // Types for gl_FragDepth && gl_FragStencilRefARB
588     kIdFloatOutType,
589     kIdSIntOutType,
590 
591     // ivec2(0) constant
592     kIdSIntZero,
593     kIdSInt2Type,
594     kIdSInt2Zero,
595 
596     // Output variable ids
597     kIdColor0Out,
598     kIdDepthOut = kIdColor0Out + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
599     kIdStencilOut,
600 
601     // Input variable ids
602     kIdColor0In,
603     kIdDepthIn = kIdColor0In + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
604     kIdStencilIn,
605 
606     // Ids for temp variables
607     kIdColor0Load,
608     // 2 temp ids per color unresolve
609     kIdDepthLoad = kIdColor0Load + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS * 2,
610     // 3 temp ids for depth unresolve
611     kIdStencilLoad = kIdDepthLoad + 3,
612     // Total number of ids used
613     // 4 temp ids for stencil unresolve
614     kIdCount = kIdStencilLoad + 4,
615 };
616 
InsertPreamble(uint32_t colorAttachmentCount,bool unresolveDepth,bool unresolveStencil,angle::spirv::Blob * blobOut)617 void InsertPreamble(uint32_t colorAttachmentCount,
618                     bool unresolveDepth,
619                     bool unresolveStencil,
620                     angle::spirv::Blob *blobOut)
621 {
622     spirv::WriteCapability(blobOut, spv::CapabilityShader);
623     spirv::WriteCapability(blobOut, spv::CapabilityInputAttachment);
624     if (unresolveStencil)
625     {
626         spirv::WriteCapability(blobOut, spv::CapabilityStencilExportEXT);
627         spirv::WriteExtension(blobOut, "SPV_EXT_shader_stencil_export");
628     }
629     // OpExtInstImport is actually not needed by this shader.  We don't use any instructions from
630     // GLSL.std.450.
631     spirv::WriteMemoryModel(blobOut, spv::AddressingModelLogical, spv::MemoryModelGLSL450);
632 
633     // Create the list of entry point ids, including only the out variables.
634     spirv::IdRefList entryPointIds;
635     for (uint32_t colorIndex = 0; colorIndex < colorAttachmentCount; ++colorIndex)
636     {
637         entryPointIds.push_back(spirv::IdRef(kIdColor0Out + colorIndex));
638     }
639     if (unresolveDepth)
640     {
641         entryPointIds.push_back(spirv::IdRef(kIdDepthOut));
642     }
643     if (unresolveStencil)
644     {
645         entryPointIds.push_back(spirv::IdRef(kIdStencilOut));
646     }
647     spirv::WriteEntryPoint(blobOut, spv::ExecutionModelFragment, spirv::IdRef(kIdMain), "main",
648                            entryPointIds);
649 
650     spirv::WriteExecutionMode(blobOut, spirv::IdRef(kIdMain), spv::ExecutionModeOriginUpperLeft,
651                               {});
652     if (unresolveDepth)
653     {
654         spirv::WriteExecutionMode(blobOut, spirv::IdRef(kIdMain), spv::ExecutionModeDepthReplacing,
655                                   {});
656     }
657     spirv::WriteSource(blobOut, spv::SourceLanguageGLSL, spirv::LiteralInteger(450), nullptr,
658                        nullptr);
659 }
660 
InsertInputDecorations(spirv::IdRef id,uint32_t attachmentIndex,uint32_t binding,angle::spirv::Blob * blobOut)661 void InsertInputDecorations(spirv::IdRef id,
662                             uint32_t attachmentIndex,
663                             uint32_t binding,
664                             angle::spirv::Blob *blobOut)
665 {
666     spirv::WriteDecorate(blobOut, id, spv::DecorationDescriptorSet,
667                          {spirv::LiteralInteger(ToUnderlying(DescriptorSetIndex::Internal))});
668     spirv::WriteDecorate(blobOut, id, spv::DecorationBinding, {spirv::LiteralInteger(binding)});
669     spirv::WriteDecorate(blobOut, id, spv::DecorationInputAttachmentIndex,
670                          {spirv::LiteralInteger(attachmentIndex)});
671 }
672 
InsertColorDecorations(uint32_t colorIndex,angle::spirv::Blob * blobOut)673 void InsertColorDecorations(uint32_t colorIndex, angle::spirv::Blob *blobOut)
674 {
675     // Decorate the output color attachment with Location
676     spirv::WriteDecorate(blobOut, spirv::IdRef(kIdColor0Out + colorIndex), spv::DecorationLocation,
677                          {spirv::LiteralInteger(colorIndex)});
678     // Decorate the subpasss input color attachment with Set/Binding/InputAttachmentIndex.
679     InsertInputDecorations(spirv::IdRef(kIdColor0In + colorIndex), colorIndex, colorIndex, blobOut);
680 }
681 
InsertDepthStencilDecorations(uint32_t depthStencilInputIndex,uint32_t depthStencilBindingIndex,bool unresolveDepth,bool unresolveStencil,angle::spirv::Blob * blobOut)682 void InsertDepthStencilDecorations(uint32_t depthStencilInputIndex,
683                                    uint32_t depthStencilBindingIndex,
684                                    bool unresolveDepth,
685                                    bool unresolveStencil,
686                                    angle::spirv::Blob *blobOut)
687 {
688     if (unresolveDepth)
689     {
690         // Decorate the output depth attachment with Location
691         spirv::WriteDecorate(blobOut, spirv::IdRef(kIdDepthOut), spv::DecorationBuiltIn,
692                              {spirv::LiteralInteger(spv::BuiltInFragDepth)});
693         // Decorate the subpasss input depth attachment with Set/Binding/InputAttachmentIndex.
694         InsertInputDecorations(spirv::IdRef(kIdDepthIn), depthStencilInputIndex,
695                                depthStencilBindingIndex, blobOut);
696         // Advance the binding.  Note that the depth/stencil attachment has the same input
697         // attachment index (it's the same attachment in the subpass), but different bindings (one
698         // aspect per image view).
699         ++depthStencilBindingIndex;
700     }
701     if (unresolveStencil)
702     {
703         // Decorate the output stencil attachment with Location
704         spirv::WriteDecorate(blobOut, spirv::IdRef(kIdStencilOut), spv::DecorationBuiltIn,
705                              {spirv::LiteralInteger(spv::BuiltInFragStencilRefEXT)});
706         // Decorate the subpasss input stencil attachment with Set/Binding/InputAttachmentIndex.
707         InsertInputDecorations(spirv::IdRef(kIdStencilIn), depthStencilInputIndex,
708                                depthStencilBindingIndex, blobOut);
709     }
710 }
711 
InsertDerivativeTypes(spirv::IdRef baseId,spirv::IdRef vec4Id,spirv::IdRef vec4OutId,spirv::IdRef imageTypeId,spirv::IdRef inputTypeId,angle::spirv::Blob * blobOut)712 void InsertDerivativeTypes(spirv::IdRef baseId,
713                            spirv::IdRef vec4Id,
714                            spirv::IdRef vec4OutId,
715                            spirv::IdRef imageTypeId,
716                            spirv::IdRef inputTypeId,
717                            angle::spirv::Blob *blobOut)
718 {
719     spirv::WriteTypeVector(blobOut, vec4Id, baseId, spirv::LiteralInteger(4));
720     spirv::WriteTypePointer(blobOut, vec4OutId, spv::StorageClassOutput, vec4Id);
721     spirv::WriteTypeImage(blobOut, imageTypeId, baseId, spv::DimSubpassData,
722                           // Unused with subpass inputs
723                           spirv::LiteralInteger(0),
724                           // Not arrayed
725                           spirv::LiteralInteger(0),
726                           // Not multisampled
727                           spirv::LiteralInteger(0),
728                           // Used without a sampler
729                           spirv::LiteralInteger(2), spv::ImageFormatUnknown, nullptr);
730     spirv::WriteTypePointer(blobOut, inputTypeId, spv::StorageClassUniformConstant, imageTypeId);
731 }
732 
InsertCommonTypes(angle::spirv::Blob * blobOut)733 void InsertCommonTypes(angle::spirv::Blob *blobOut)
734 {
735     // Types to support main().
736     spirv::WriteTypeVoid(blobOut, spirv::IdRef(kIdVoid));
737     spirv::WriteTypeFunction(blobOut, spirv::IdRef(kIdMainType), spirv::IdRef(kIdVoid), {});
738 
739     // Float types
740     spirv::WriteTypeFloat(blobOut, spirv::IdRef(kIdFloatType), spirv::LiteralInteger(32));
741     InsertDerivativeTypes(spirv::IdRef(kIdFloatType), spirv::IdRef(kIdFloat4Type),
742                           spirv::IdRef(kIdFloat4OutType), spirv::IdRef(kIdFloatSubpassImageType),
743                           spirv::IdRef(kIdFloatSubpassInputType), blobOut);
744 
745     // Int types
746     spirv::WriteTypeInt(blobOut, spirv::IdRef(kIdSIntType), spirv::LiteralInteger(32),
747                         spirv::LiteralInteger(1));
748     InsertDerivativeTypes(spirv::IdRef(kIdSIntType), spirv::IdRef(kIdSInt4Type),
749                           spirv::IdRef(kIdSInt4OutType), spirv::IdRef(kIdSIntSubpassImageType),
750                           spirv::IdRef(kIdSIntSubpassInputType), blobOut);
751 
752     // Unsigned int types
753     spirv::WriteTypeInt(blobOut, spirv::IdRef(kIdUIntType), spirv::LiteralInteger(32),
754                         spirv::LiteralInteger(0));
755     InsertDerivativeTypes(spirv::IdRef(kIdUIntType), spirv::IdRef(kIdUInt4Type),
756                           spirv::IdRef(kIdUInt4OutType), spirv::IdRef(kIdUIntSubpassImageType),
757                           spirv::IdRef(kIdUIntSubpassInputType), blobOut);
758 
759     // Types to support depth/stencil
760     spirv::WriteTypePointer(blobOut, spirv::IdRef(kIdFloatOutType), spv::StorageClassOutput,
761                             spirv::IdRef(kIdFloatType));
762     spirv::WriteTypePointer(blobOut, spirv::IdRef(kIdSIntOutType), spv::StorageClassOutput,
763                             spirv::IdRef(kIdSIntType));
764 
765     // Constants used to load from subpass inputs
766     spirv::WriteConstant(blobOut, spirv::IdRef(kIdSIntType), spirv::IdRef(kIdSIntZero),
767                          spirv::LiteralInteger(0));
768     spirv::WriteTypeVector(blobOut, spirv::IdRef(kIdSInt2Type), spirv::IdRef(kIdSIntType),
769                            spirv::LiteralInteger(2));
770     spirv::WriteConstantComposite(blobOut, spirv::IdRef(kIdSInt2Type), spirv::IdRef(kIdSInt2Zero),
771                                   {spirv::IdRef(kIdSIntZero), spirv::IdRef(kIdSIntZero)});
772 }
773 
InsertVariableDecl(spirv::IdRef outType,spirv::IdRef outId,spirv::IdRef inType,spirv::IdRef inId,angle::spirv::Blob * blobOut)774 void InsertVariableDecl(spirv::IdRef outType,
775                         spirv::IdRef outId,
776                         spirv::IdRef inType,
777                         spirv::IdRef inId,
778                         angle::spirv::Blob *blobOut)
779 {
780     // Declare both the output and subpass input variables.
781     spirv::WriteVariable(blobOut, outType, outId, spv::StorageClassOutput, nullptr);
782     spirv::WriteVariable(blobOut, inType, inId, spv::StorageClassUniformConstant, nullptr);
783 }
784 
InsertColorVariableDecl(uint32_t colorIndex,UnresolveColorAttachmentType type,angle::spirv::Blob * blobOut)785 void InsertColorVariableDecl(uint32_t colorIndex,
786                              UnresolveColorAttachmentType type,
787                              angle::spirv::Blob *blobOut)
788 {
789     // Find the correct types for color variable declarations.
790     spirv::IdRef outType(kIdFloat4OutType);
791     spirv::IdRef outId(kIdColor0Out + colorIndex);
792     spirv::IdRef inType(kIdFloatSubpassInputType);
793     spirv::IdRef inId(kIdColor0In + colorIndex);
794     switch (type)
795     {
796         case kUnresolveTypeSint:
797             outType = spirv::IdRef(kIdSInt4OutType);
798             inType  = spirv::IdRef(kIdSIntSubpassInputType);
799             break;
800         case kUnresolveTypeUint:
801             outType = spirv::IdRef(kIdUInt4OutType);
802             inType  = spirv::IdRef(kIdUIntSubpassInputType);
803             break;
804         default:
805             break;
806     }
807     InsertVariableDecl(outType, outId, inType, inId, blobOut);
808 }
809 
InsertDepthStencilVariableDecl(bool unresolveDepth,bool unresolveStencil,angle::spirv::Blob * blobOut)810 void InsertDepthStencilVariableDecl(bool unresolveDepth,
811                                     bool unresolveStencil,
812                                     angle::spirv::Blob *blobOut)
813 {
814     if (unresolveDepth)
815     {
816         InsertVariableDecl(spirv::IdRef(kIdFloatOutType), spirv::IdRef(kIdDepthOut),
817                            spirv::IdRef(kIdFloatSubpassInputType), spirv::IdRef(kIdDepthIn),
818                            blobOut);
819     }
820     if (unresolveStencil)
821     {
822         InsertVariableDecl(spirv::IdRef(kIdSIntOutType), spirv::IdRef(kIdStencilOut),
823                            spirv::IdRef(kIdUIntSubpassInputType), spirv::IdRef(kIdStencilIn),
824                            blobOut);
825     }
826 }
827 
InsertTopOfMain(angle::spirv::Blob * blobOut)828 void InsertTopOfMain(angle::spirv::Blob *blobOut)
829 {
830     spirv::WriteFunction(blobOut, spirv::IdRef(kIdVoid), spirv::IdRef(kIdMain),
831                          spv::FunctionControlMaskNone, spirv::IdRef(kIdMainType));
832     spirv::WriteLabel(blobOut, spirv::IdRef(kIdMainLabel));
833 }
834 
InsertColorUnresolveLoadStore(uint32_t colorIndex,UnresolveColorAttachmentType type,angle::spirv::Blob * blobOut)835 void InsertColorUnresolveLoadStore(uint32_t colorIndex,
836                                    UnresolveColorAttachmentType type,
837                                    angle::spirv::Blob *blobOut)
838 {
839     spirv::IdRef loadResult(kIdColor0Load + colorIndex * 2);
840     spirv::IdRef imageReadResult(loadResult + 1);
841 
842     // Find the correct types for load/store.
843     spirv::IdRef loadType(kIdFloatSubpassImageType);
844     spirv::IdRef readType(kIdFloat4Type);
845     spirv::IdRef inId(kIdColor0In + colorIndex);
846     spirv::IdRef outId(kIdColor0Out + colorIndex);
847     switch (type)
848     {
849         case kUnresolveTypeSint:
850             loadType = spirv::IdRef(kIdSIntSubpassImageType);
851             readType = spirv::IdRef(kIdSInt4Type);
852             break;
853         case kUnresolveTypeUint:
854             loadType = spirv::IdRef(kIdUIntSubpassImageType);
855             readType = spirv::IdRef(kIdUInt4Type);
856             break;
857         default:
858             break;
859     }
860 
861     // Load the subpass input image, read from it, and store in output.
862     spirv::WriteLoad(blobOut, loadType, loadResult, inId, nullptr);
863     spirv::WriteImageRead(blobOut, readType, imageReadResult, loadResult,
864                           spirv::IdRef(kIdSInt2Zero), nullptr, {});
865     spirv::WriteStore(blobOut, outId, imageReadResult, nullptr);
866 }
867 
InsertDepthStencilUnresolveLoadStore(bool unresolveDepth,bool unresolveStencil,angle::spirv::Blob * blobOut)868 void InsertDepthStencilUnresolveLoadStore(bool unresolveDepth,
869                                           bool unresolveStencil,
870                                           angle::spirv::Blob *blobOut)
871 {
872     if (unresolveDepth)
873     {
874         spirv::IdRef loadResult(kIdDepthLoad);
875         spirv::IdRef imageReadResult(loadResult + 1);
876         spirv::IdRef extractResult(imageReadResult + 1);
877 
878         spirv::IdRef loadType(kIdFloatSubpassImageType);
879         spirv::IdRef readType(kIdFloat4Type);
880         spirv::IdRef inId(kIdDepthIn);
881         spirv::IdRef outId(kIdDepthOut);
882 
883         // Load the subpass input image, read from it, select .x, and store in output.
884         spirv::WriteLoad(blobOut, loadType, loadResult, inId, nullptr);
885         spirv::WriteImageRead(blobOut, readType, imageReadResult, loadResult,
886                               spirv::IdRef(kIdSInt2Zero), nullptr, {});
887         spirv::WriteCompositeExtract(blobOut, spirv::IdRef(kIdFloatType), extractResult,
888                                      imageReadResult, {spirv::LiteralInteger(0)});
889         spirv::WriteStore(blobOut, outId, extractResult, nullptr);
890     }
891     if (unresolveStencil)
892     {
893         spirv::IdRef loadResult(kIdStencilLoad);
894         spirv::IdRef imageReadResult(loadResult + 1);
895         spirv::IdRef extractResult(imageReadResult + 1);
896         spirv::IdRef bitcastResult(extractResult + 1);
897 
898         spirv::IdRef loadType(kIdUIntSubpassImageType);
899         spirv::IdRef readType(kIdUInt4Type);
900         spirv::IdRef inId(kIdStencilIn);
901         spirv::IdRef outId(kIdStencilOut);
902 
903         // Load the subpass input image, read from it, select .x, and store in output.  There's a
904         // bitcast involved since the stencil subpass input has unsigned type, while
905         // gl_FragStencilRefARB is signed!
906         spirv::WriteLoad(blobOut, loadType, loadResult, inId, nullptr);
907         spirv::WriteImageRead(blobOut, readType, imageReadResult, loadResult,
908                               spirv::IdRef(kIdSInt2Zero), nullptr, {});
909         spirv::WriteCompositeExtract(blobOut, spirv::IdRef(kIdUIntType), extractResult,
910                                      imageReadResult, {spirv::LiteralInteger(0)});
911         spirv::WriteBitcast(blobOut, spirv::IdRef(kIdSIntType), bitcastResult, extractResult);
912         spirv::WriteStore(blobOut, outId, bitcastResult, nullptr);
913     }
914 }
915 
InsertBottomOfMain(angle::spirv::Blob * blobOut)916 void InsertBottomOfMain(angle::spirv::Blob *blobOut)
917 {
918     spirv::WriteReturn(blobOut);
919     spirv::WriteFunctionEnd(blobOut);
920 }
921 
MakeFragShader(uint32_t colorAttachmentCount,gl::DrawBuffersArray<UnresolveColorAttachmentType> & colorAttachmentTypes,bool unresolveDepth,bool unresolveStencil)922 angle::spirv::Blob MakeFragShader(
923     uint32_t colorAttachmentCount,
924     gl::DrawBuffersArray<UnresolveColorAttachmentType> &colorAttachmentTypes,
925     bool unresolveDepth,
926     bool unresolveStencil)
927 {
928     angle::spirv::Blob code;
929 
930     // Reserve a sensible amount of memory.  A single-attachment shader is 169 words.
931     code.reserve(169);
932 
933     // Header
934     spirv::WriteSpirvHeader(&code, kIdCount);
935 
936     // The preamble
937     InsertPreamble(colorAttachmentCount, unresolveDepth, unresolveStencil, &code);
938 
939     // Color attachment decorations
940     for (uint32_t colorIndex = 0; colorIndex < colorAttachmentCount; ++colorIndex)
941     {
942         InsertColorDecorations(colorIndex, &code);
943     }
944 
945     const uint32_t depthStencilInputIndex = colorAttachmentCount;
946     uint32_t depthStencilBindingIndex     = colorAttachmentCount;
947     InsertDepthStencilDecorations(depthStencilInputIndex, depthStencilBindingIndex, unresolveDepth,
948                                   unresolveStencil, &code);
949 
950     // Common types
951     InsertCommonTypes(&code);
952 
953     // Attachment declarations
954     for (uint32_t colorIndex = 0; colorIndex < colorAttachmentCount; ++colorIndex)
955     {
956         InsertColorVariableDecl(colorIndex, colorAttachmentTypes[colorIndex], &code);
957     }
958     InsertDepthStencilVariableDecl(unresolveDepth, unresolveStencil, &code);
959 
960     // Top of main
961     InsertTopOfMain(&code);
962 
963     // Load and store for each attachment
964     for (uint32_t colorIndex = 0; colorIndex < colorAttachmentCount; ++colorIndex)
965     {
966         InsertColorUnresolveLoadStore(colorIndex, colorAttachmentTypes[colorIndex], &code);
967     }
968     InsertDepthStencilUnresolveLoadStore(unresolveDepth, unresolveStencil, &code);
969 
970     // Bottom of main
971     InsertBottomOfMain(&code);
972 
973     return code;
974 }
975 }  // namespace unresolve
976 
GetUnresolveFrag(vk::Context * context,uint32_t colorAttachmentCount,gl::DrawBuffersArray<UnresolveColorAttachmentType> & colorAttachmentTypes,bool unresolveDepth,bool unresolveStencil,vk::RefCounted<vk::ShaderAndSerial> * shader)977 angle::Result GetUnresolveFrag(
978     vk::Context *context,
979     uint32_t colorAttachmentCount,
980     gl::DrawBuffersArray<UnresolveColorAttachmentType> &colorAttachmentTypes,
981     bool unresolveDepth,
982     bool unresolveStencil,
983     vk::RefCounted<vk::ShaderAndSerial> *shader)
984 {
985     if (shader->get().valid())
986     {
987         return angle::Result::Continue;
988     }
989 
990     angle::spirv::Blob shaderCode = unresolve::MakeFragShader(
991         colorAttachmentCount, colorAttachmentTypes, unresolveDepth, unresolveStencil);
992 
993     ASSERT(spirv::Validate(shaderCode));
994 
995     // Create shader lazily. Access will need to be locked for multi-threading.
996     return vk::InitShaderAndSerial(context, &shader->get(), shaderCode.data(),
997                                    shaderCode.size() * 4);
998 }
999 }  // namespace
1000 
1001 UtilsVk::ConvertVertexShaderParams::ConvertVertexShaderParams() = default;
1002 
1003 UtilsVk::ImageCopyShaderParams::ImageCopyShaderParams() = default;
1004 
GetGenerateMipmapMaxLevels(ContextVk * contextVk)1005 uint32_t UtilsVk::GetGenerateMipmapMaxLevels(ContextVk *contextVk)
1006 {
1007     RendererVk *renderer = contextVk->getRenderer();
1008 
1009     uint32_t maxPerStageDescriptorStorageImages =
1010         renderer->getPhysicalDeviceProperties().limits.maxPerStageDescriptorStorageImages;
1011 
1012     // Vulkan requires that there be support for at least 4 storage images per stage.
1013     constexpr uint32_t kMinimumStorageImagesLimit = 4;
1014     ASSERT(maxPerStageDescriptorStorageImages >= kMinimumStorageImagesLimit);
1015 
1016     // If fewer than max-levels are supported, use 4 levels (which is the minimum required number
1017     // of storage image bindings).
1018     return maxPerStageDescriptorStorageImages < kGenerateMipmapMaxLevels
1019                ? kMinimumStorageImagesLimit
1020                : kGenerateMipmapMaxLevels;
1021 }
1022 
UtilsVk()1023 UtilsVk::UtilsVk() : mPerfCounters{}, mCumulativePerfCounters{} {}
1024 
1025 UtilsVk::~UtilsVk() = default;
1026 
destroy(RendererVk * renderer)1027 void UtilsVk::destroy(RendererVk *renderer)
1028 {
1029     VkDevice device = renderer->getDevice();
1030 
1031     outputCumulativePerfCounters();
1032 
1033     for (Function f : angle::AllEnums<Function>())
1034     {
1035         for (auto &descriptorSetLayout : mDescriptorSetLayouts[f])
1036         {
1037             descriptorSetLayout.reset();
1038         }
1039         mPipelineLayouts[f].reset();
1040         mDescriptorPools[f].destroy(device);
1041     }
1042 
1043     for (vk::ShaderProgramHelper &program : mConvertIndexPrograms)
1044     {
1045         program.destroy(renderer);
1046     }
1047     for (vk::ShaderProgramHelper &program : mConvertIndirectLineLoopPrograms)
1048     {
1049         program.destroy(renderer);
1050     }
1051     for (vk::ShaderProgramHelper &program : mConvertIndexIndirectLineLoopPrograms)
1052     {
1053         program.destroy(renderer);
1054     }
1055     for (vk::ShaderProgramHelper &program : mConvertVertexPrograms)
1056     {
1057         program.destroy(renderer);
1058     }
1059     mImageClearProgramVSOnly.destroy(renderer);
1060     for (vk::ShaderProgramHelper &program : mImageClearPrograms)
1061     {
1062         program.destroy(renderer);
1063     }
1064     for (vk::ShaderProgramHelper &program : mImageCopyPrograms)
1065     {
1066         program.destroy(renderer);
1067     }
1068     for (vk::ShaderProgramHelper &program : mBlitResolvePrograms)
1069     {
1070         program.destroy(renderer);
1071     }
1072     for (vk::ShaderProgramHelper &program : mBlitResolveStencilNoExportPrograms)
1073     {
1074         program.destroy(renderer);
1075     }
1076     for (vk::ShaderProgramHelper &program : mOverlayCullPrograms)
1077     {
1078         program.destroy(renderer);
1079     }
1080     for (vk::ShaderProgramHelper &program : mOverlayDrawPrograms)
1081     {
1082         program.destroy(renderer);
1083     }
1084     for (vk::ShaderProgramHelper &program : mGenerateMipmapPrograms)
1085     {
1086         program.destroy(renderer);
1087     }
1088 
1089     for (auto &programIter : mUnresolvePrograms)
1090     {
1091         vk::ShaderProgramHelper &program = programIter.second;
1092         program.destroy(renderer);
1093     }
1094     mUnresolvePrograms.clear();
1095 
1096     for (auto &shaderIter : mUnresolveFragShaders)
1097     {
1098         vk::RefCounted<vk::ShaderAndSerial> &shader = shaderIter.second;
1099         shader.get().destroy(device);
1100     }
1101     mUnresolveFragShaders.clear();
1102 
1103     mPointSampler.destroy(device);
1104     mLinearSampler.destroy(device);
1105 }
1106 
ensureResourcesInitialized(ContextVk * contextVk,Function function,VkDescriptorPoolSize * setSizes,size_t setSizesCount,size_t pushConstantsSize)1107 angle::Result UtilsVk::ensureResourcesInitialized(ContextVk *contextVk,
1108                                                   Function function,
1109                                                   VkDescriptorPoolSize *setSizes,
1110                                                   size_t setSizesCount,
1111                                                   size_t pushConstantsSize)
1112 {
1113     vk::DescriptorSetLayoutDesc descriptorSetDesc;
1114     bool isCompute = function >= Function::ComputeStartIndex;
1115     const VkShaderStageFlags descStages =
1116         isCompute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
1117 
1118     uint32_t currentBinding = 0;
1119     for (size_t i = 0; i < setSizesCount; ++i)
1120     {
1121         descriptorSetDesc.update(currentBinding, setSizes[i].type, setSizes[i].descriptorCount,
1122                                  descStages, nullptr);
1123         ++currentBinding;
1124     }
1125 
1126     ANGLE_TRY(contextVk->getDescriptorSetLayoutCache().getDescriptorSetLayout(
1127         contextVk, descriptorSetDesc,
1128         &mDescriptorSetLayouts[function][DescriptorSetIndex::Internal]));
1129 
1130     vk::DescriptorSetLayoutBindingVector bindingVector;
1131     std::vector<VkSampler> immutableSamplers;
1132     descriptorSetDesc.unpackBindings(&bindingVector, &immutableSamplers);
1133     std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
1134 
1135     for (const VkDescriptorSetLayoutBinding &binding : bindingVector)
1136     {
1137         if (binding.descriptorCount > 0)
1138         {
1139             VkDescriptorPoolSize poolSize = {};
1140 
1141             poolSize.type            = binding.descriptorType;
1142             poolSize.descriptorCount = binding.descriptorCount;
1143             descriptorPoolSizes.emplace_back(poolSize);
1144         }
1145     }
1146     if (!descriptorPoolSizes.empty())
1147     {
1148         ANGLE_TRY(mDescriptorPools[function].init(
1149             contextVk, descriptorPoolSizes.data(), descriptorPoolSizes.size(),
1150             mDescriptorSetLayouts[function][DescriptorSetIndex::Internal].get().getHandle()));
1151     }
1152 
1153     gl::ShaderType pushConstantsShaderStage =
1154         isCompute ? gl::ShaderType::Compute : gl::ShaderType::Fragment;
1155 
1156     // Corresponding pipeline layouts:
1157     vk::PipelineLayoutDesc pipelineLayoutDesc;
1158 
1159     pipelineLayoutDesc.updateDescriptorSetLayout(DescriptorSetIndex::Internal, descriptorSetDesc);
1160     if (pushConstantsSize)
1161     {
1162         pipelineLayoutDesc.updatePushConstantRange(pushConstantsShaderStage, 0,
1163                                                    static_cast<uint32_t>(pushConstantsSize));
1164     }
1165 
1166     ANGLE_TRY(contextVk->getPipelineLayoutCache().getPipelineLayout(contextVk, pipelineLayoutDesc,
1167                                                                     mDescriptorSetLayouts[function],
1168                                                                     &mPipelineLayouts[function]));
1169 
1170     return angle::Result::Continue;
1171 }
1172 
ensureConvertIndexResourcesInitialized(ContextVk * contextVk)1173 angle::Result UtilsVk::ensureConvertIndexResourcesInitialized(ContextVk *contextVk)
1174 {
1175     if (mPipelineLayouts[Function::ConvertIndexBuffer].valid())
1176     {
1177         return angle::Result::Continue;
1178     }
1179 
1180     VkDescriptorPoolSize setSizes[2] = {
1181         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},
1182         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},
1183     };
1184 
1185     return ensureResourcesInitialized(contextVk, Function::ConvertIndexBuffer, setSizes,
1186                                       ArraySize(setSizes), sizeof(ConvertIndexShaderParams));
1187 }
1188 
ensureConvertIndexIndirectResourcesInitialized(ContextVk * contextVk)1189 angle::Result UtilsVk::ensureConvertIndexIndirectResourcesInitialized(ContextVk *contextVk)
1190 {
1191     if (mPipelineLayouts[Function::ConvertIndexIndirectBuffer].valid())
1192     {
1193         return angle::Result::Continue;
1194     }
1195 
1196     VkDescriptorPoolSize setSizes[4] = {
1197         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // dst index buffer
1198         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // source index buffer
1199         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // src indirect buffer
1200         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // dst indirect buffer
1201     };
1202 
1203     return ensureResourcesInitialized(contextVk, Function::ConvertIndexIndirectBuffer, setSizes,
1204                                       ArraySize(setSizes),
1205                                       sizeof(ConvertIndexIndirectShaderParams));
1206 }
1207 
ensureConvertIndexIndirectLineLoopResourcesInitialized(ContextVk * contextVk)1208 angle::Result UtilsVk::ensureConvertIndexIndirectLineLoopResourcesInitialized(ContextVk *contextVk)
1209 {
1210     if (mPipelineLayouts[Function::ConvertIndexIndirectLineLoopBuffer].valid())
1211     {
1212         return angle::Result::Continue;
1213     }
1214 
1215     VkDescriptorPoolSize setSizes[4] = {
1216         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // cmd buffer
1217         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // dst cmd buffer
1218         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // source index buffer
1219         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // dst index buffer
1220     };
1221 
1222     return ensureResourcesInitialized(contextVk, Function::ConvertIndexIndirectLineLoopBuffer,
1223                                       setSizes, ArraySize(setSizes),
1224                                       sizeof(ConvertIndexIndirectLineLoopShaderParams));
1225 }
1226 
ensureConvertIndirectLineLoopResourcesInitialized(ContextVk * contextVk)1227 angle::Result UtilsVk::ensureConvertIndirectLineLoopResourcesInitialized(ContextVk *contextVk)
1228 {
1229     if (mPipelineLayouts[Function::ConvertIndirectLineLoopBuffer].valid())
1230     {
1231         return angle::Result::Continue;
1232     }
1233 
1234     VkDescriptorPoolSize setSizes[3] = {
1235         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // cmd buffer
1236         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // dst cmd buffer
1237         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},  // dst index buffer
1238     };
1239 
1240     return ensureResourcesInitialized(contextVk, Function::ConvertIndirectLineLoopBuffer, setSizes,
1241                                       ArraySize(setSizes),
1242                                       sizeof(ConvertIndirectLineLoopShaderParams));
1243 }
1244 
ensureConvertVertexResourcesInitialized(ContextVk * contextVk)1245 angle::Result UtilsVk::ensureConvertVertexResourcesInitialized(ContextVk *contextVk)
1246 {
1247     if (mPipelineLayouts[Function::ConvertVertexBuffer].valid())
1248     {
1249         return angle::Result::Continue;
1250     }
1251 
1252     VkDescriptorPoolSize setSizes[2] = {
1253         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},
1254         {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},
1255     };
1256 
1257     return ensureResourcesInitialized(contextVk, Function::ConvertVertexBuffer, setSizes,
1258                                       ArraySize(setSizes), sizeof(ConvertVertexShaderParams));
1259 }
1260 
ensureImageClearResourcesInitialized(ContextVk * contextVk)1261 angle::Result UtilsVk::ensureImageClearResourcesInitialized(ContextVk *contextVk)
1262 {
1263     if (mPipelineLayouts[Function::ImageClear].valid())
1264     {
1265         return angle::Result::Continue;
1266     }
1267 
1268     // The shader does not use any descriptor sets.
1269     return ensureResourcesInitialized(contextVk, Function::ImageClear, nullptr, 0,
1270                                       sizeof(ImageClearShaderParams));
1271 }
1272 
ensureImageCopyResourcesInitialized(ContextVk * contextVk)1273 angle::Result UtilsVk::ensureImageCopyResourcesInitialized(ContextVk *contextVk)
1274 {
1275     if (mPipelineLayouts[Function::ImageCopy].valid())
1276     {
1277         return angle::Result::Continue;
1278     }
1279 
1280     VkDescriptorPoolSize setSizes[1] = {
1281         {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1},
1282     };
1283 
1284     return ensureResourcesInitialized(contextVk, Function::ImageCopy, setSizes, ArraySize(setSizes),
1285                                       sizeof(ImageCopyShaderParams));
1286 }
1287 
ensureBlitResolveResourcesInitialized(ContextVk * contextVk)1288 angle::Result UtilsVk::ensureBlitResolveResourcesInitialized(ContextVk *contextVk)
1289 {
1290     if (!mPipelineLayouts[Function::BlitResolve].valid())
1291     {
1292         VkDescriptorPoolSize setSizes[3] = {
1293             {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1},
1294             {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1},
1295             {VK_DESCRIPTOR_TYPE_SAMPLER, 1},
1296         };
1297 
1298         ANGLE_TRY(ensureResourcesInitialized(contextVk, Function::BlitResolve, setSizes,
1299                                              ArraySize(setSizes), sizeof(BlitResolveShaderParams)));
1300     }
1301 
1302     return ensureSamplersInitialized(contextVk);
1303 }
1304 
ensureBlitResolveStencilNoExportResourcesInitialized(ContextVk * contextVk)1305 angle::Result UtilsVk::ensureBlitResolveStencilNoExportResourcesInitialized(ContextVk *contextVk)
1306 {
1307     if (!mPipelineLayouts[Function::BlitResolveStencilNoExport].valid())
1308     {
1309         VkDescriptorPoolSize setSizes[3] = {
1310             {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},
1311             {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1},
1312             {VK_DESCRIPTOR_TYPE_SAMPLER, 1},
1313         };
1314 
1315         ANGLE_TRY(ensureResourcesInitialized(contextVk, Function::BlitResolveStencilNoExport,
1316                                              setSizes, ArraySize(setSizes),
1317                                              sizeof(BlitResolveStencilNoExportShaderParams)));
1318     }
1319 
1320     return ensureSamplersInitialized(contextVk);
1321 }
1322 
ensureOverlayCullResourcesInitialized(ContextVk * contextVk)1323 angle::Result UtilsVk::ensureOverlayCullResourcesInitialized(ContextVk *contextVk)
1324 {
1325     if (mPipelineLayouts[Function::OverlayCull].valid())
1326     {
1327         return angle::Result::Continue;
1328     }
1329 
1330     VkDescriptorPoolSize setSizes[2] = {
1331         {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1},
1332         {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1},
1333     };
1334 
1335     return ensureResourcesInitialized(contextVk, Function::OverlayCull, setSizes,
1336                                       ArraySize(setSizes), 0);
1337 }
1338 
ensureOverlayDrawResourcesInitialized(ContextVk * contextVk)1339 angle::Result UtilsVk::ensureOverlayDrawResourcesInitialized(ContextVk *contextVk)
1340 {
1341     if (!mPipelineLayouts[Function::OverlayDraw].valid())
1342     {
1343         VkDescriptorPoolSize setSizes[5] = {
1344             {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1},  {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1},
1345             {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1}, {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1},
1346             {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1},
1347         };
1348 
1349         ANGLE_TRY(ensureResourcesInitialized(contextVk, Function::OverlayDraw, setSizes,
1350                                              ArraySize(setSizes), sizeof(OverlayDrawShaderParams)));
1351     }
1352 
1353     return ensureSamplersInitialized(contextVk);
1354 }
1355 
ensureGenerateMipmapResourcesInitialized(ContextVk * contextVk)1356 angle::Result UtilsVk::ensureGenerateMipmapResourcesInitialized(ContextVk *contextVk)
1357 {
1358     if (mPipelineLayouts[Function::GenerateMipmap].valid())
1359     {
1360         return angle::Result::Continue;
1361     }
1362 
1363     VkDescriptorPoolSize setSizes[2] = {
1364         {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, GetGenerateMipmapMaxLevels(contextVk)},
1365         {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1},
1366     };
1367 
1368     return ensureResourcesInitialized(contextVk, Function::GenerateMipmap, setSizes,
1369                                       ArraySize(setSizes), sizeof(GenerateMipmapShaderParams));
1370 }
1371 
ensureUnresolveResourcesInitialized(ContextVk * contextVk,Function function,uint32_t attachmentCount)1372 angle::Result UtilsVk::ensureUnresolveResourcesInitialized(ContextVk *contextVk,
1373                                                            Function function,
1374                                                            uint32_t attachmentCount)
1375 {
1376     ASSERT(static_cast<uint32_t>(function) -
1377                static_cast<uint32_t>(Function::Unresolve1Attachment) ==
1378            attachmentCount - 1);
1379 
1380     if (mPipelineLayouts[function].valid())
1381     {
1382         return angle::Result::Continue;
1383     }
1384 
1385     vk::FramebufferAttachmentArray<VkDescriptorPoolSize> setSizes;
1386     std::fill(setSizes.begin(), setSizes.end(),
1387               VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1});
1388 
1389     return ensureResourcesInitialized(contextVk, function, setSizes.data(), attachmentCount, 0);
1390 }
1391 
ensureSamplersInitialized(ContextVk * contextVk)1392 angle::Result UtilsVk::ensureSamplersInitialized(ContextVk *contextVk)
1393 {
1394     VkSamplerCreateInfo samplerInfo     = {};
1395     samplerInfo.sType                   = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
1396     samplerInfo.flags                   = 0;
1397     samplerInfo.magFilter               = VK_FILTER_NEAREST;
1398     samplerInfo.minFilter               = VK_FILTER_NEAREST;
1399     samplerInfo.mipmapMode              = VK_SAMPLER_MIPMAP_MODE_NEAREST;
1400     samplerInfo.addressModeU            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
1401     samplerInfo.addressModeV            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
1402     samplerInfo.addressModeW            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
1403     samplerInfo.mipLodBias              = 0.0f;
1404     samplerInfo.anisotropyEnable        = VK_FALSE;
1405     samplerInfo.maxAnisotropy           = 1;
1406     samplerInfo.compareEnable           = VK_FALSE;
1407     samplerInfo.compareOp               = VK_COMPARE_OP_ALWAYS;
1408     samplerInfo.minLod                  = 0;
1409     samplerInfo.maxLod                  = 0;
1410     samplerInfo.borderColor             = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
1411     samplerInfo.unnormalizedCoordinates = VK_FALSE;
1412 
1413     if (!mPointSampler.valid())
1414     {
1415         ANGLE_VK_TRY(contextVk, mPointSampler.init(contextVk->getDevice(), samplerInfo));
1416     }
1417 
1418     samplerInfo.magFilter = VK_FILTER_LINEAR;
1419     samplerInfo.minFilter = VK_FILTER_LINEAR;
1420 
1421     if (!mLinearSampler.valid())
1422     {
1423         ANGLE_VK_TRY(contextVk, mLinearSampler.init(contextVk->getDevice(), samplerInfo));
1424     }
1425 
1426     return angle::Result::Continue;
1427 }
1428 
setupProgram(ContextVk * contextVk,Function function,vk::RefCounted<vk::ShaderAndSerial> * fsCsShader,vk::RefCounted<vk::ShaderAndSerial> * vsShader,vk::ShaderProgramHelper * program,const vk::GraphicsPipelineDesc * pipelineDesc,const VkDescriptorSet descriptorSet,const void * pushConstants,size_t pushConstantsSize,vk::CommandBuffer * commandBuffer)1429 angle::Result UtilsVk::setupProgram(ContextVk *contextVk,
1430                                     Function function,
1431                                     vk::RefCounted<vk::ShaderAndSerial> *fsCsShader,
1432                                     vk::RefCounted<vk::ShaderAndSerial> *vsShader,
1433                                     vk::ShaderProgramHelper *program,
1434                                     const vk::GraphicsPipelineDesc *pipelineDesc,
1435                                     const VkDescriptorSet descriptorSet,
1436                                     const void *pushConstants,
1437                                     size_t pushConstantsSize,
1438                                     vk::CommandBuffer *commandBuffer)
1439 {
1440     RendererVk *renderer = contextVk->getRenderer();
1441 
1442     const bool isCompute = function >= Function::ComputeStartIndex;
1443     const VkShaderStageFlags pushConstantsShaderStage =
1444         isCompute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
1445     const VkPipelineBindPoint pipelineBindPoint =
1446         isCompute ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS;
1447 
1448     // If compute, vsShader and pipelineDesc should be nullptr, and if not compute they shouldn't
1449     // be.
1450     ASSERT(isCompute != (vsShader && pipelineDesc));
1451 
1452     const vk::BindingPointer<vk::PipelineLayout> &pipelineLayout = mPipelineLayouts[function];
1453 
1454     if (isCompute)
1455     {
1456         vk::PipelineHelper *pipeline;
1457         program->setShader(gl::ShaderType::Compute, fsCsShader);
1458         ANGLE_TRY(program->getComputePipeline(contextVk, pipelineLayout.get(), &pipeline));
1459         pipeline->retain(&contextVk->getResourceUseList());
1460         commandBuffer->bindComputePipeline(pipeline->getPipeline());
1461 
1462         contextVk->invalidateComputePipelineBinding();
1463     }
1464     else
1465     {
1466         program->setShader(gl::ShaderType::Vertex, vsShader);
1467         if (fsCsShader)
1468         {
1469             program->setShader(gl::ShaderType::Fragment, fsCsShader);
1470         }
1471 
1472         // This value is not used but is passed to getGraphicsPipeline to avoid a nullptr check.
1473         const vk::GraphicsPipelineDesc *descPtr;
1474         vk::PipelineHelper *helper;
1475         vk::PipelineCache *pipelineCache = nullptr;
1476         ANGLE_TRY(renderer->getPipelineCache(&pipelineCache));
1477         ANGLE_TRY(program->getGraphicsPipeline(contextVk, &contextVk->getRenderPassCache(),
1478                                                *pipelineCache, pipelineLayout.get(), *pipelineDesc,
1479                                                gl::AttributesMask(), gl::ComponentTypeMask(),
1480                                                gl::DrawBufferMask(), &descPtr, &helper));
1481         helper->retain(&contextVk->getResourceUseList());
1482         commandBuffer->bindGraphicsPipeline(helper->getPipeline());
1483 
1484         contextVk->invalidateGraphicsPipelineBinding();
1485     }
1486 
1487     if (descriptorSet != VK_NULL_HANDLE)
1488     {
1489         commandBuffer->bindDescriptorSets(pipelineLayout.get(), pipelineBindPoint,
1490                                           DescriptorSetIndex::Internal, 1, &descriptorSet, 0,
1491                                           nullptr);
1492         if (isCompute)
1493         {
1494             contextVk->invalidateComputeDescriptorSet(DescriptorSetIndex::Internal);
1495         }
1496         else
1497         {
1498             contextVk->invalidateGraphicsDescriptorSet(DescriptorSetIndex::Internal);
1499         }
1500     }
1501 
1502     if (pushConstants)
1503     {
1504         commandBuffer->pushConstants(pipelineLayout.get(), pushConstantsShaderStage, 0,
1505                                      static_cast<uint32_t>(pushConstantsSize), pushConstants);
1506     }
1507 
1508     return angle::Result::Continue;
1509 }
1510 
convertIndexBuffer(ContextVk * contextVk,vk::BufferHelper * dst,vk::BufferHelper * src,const ConvertIndexParameters & params)1511 angle::Result UtilsVk::convertIndexBuffer(ContextVk *contextVk,
1512                                           vk::BufferHelper *dst,
1513                                           vk::BufferHelper *src,
1514                                           const ConvertIndexParameters &params)
1515 {
1516     ANGLE_TRY(ensureConvertIndexResourcesInitialized(contextVk));
1517 
1518     vk::CommandBufferAccess access;
1519     access.onBufferComputeShaderRead(src);
1520     access.onBufferComputeShaderWrite(dst);
1521 
1522     vk::CommandBuffer *commandBuffer;
1523     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1524 
1525     VkDescriptorSet descriptorSet;
1526     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
1527     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::ConvertIndexBuffer, &descriptorPoolBinding,
1528                                     &descriptorSet));
1529 
1530     std::array<VkDescriptorBufferInfo, 2> buffers = {{
1531         {dst->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1532         {src->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1533     }};
1534 
1535     VkWriteDescriptorSet writeInfo = {};
1536     writeInfo.sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1537     writeInfo.dstSet               = descriptorSet;
1538     writeInfo.dstBinding           = kConvertIndexDestinationBinding;
1539     writeInfo.descriptorCount      = 2;
1540     writeInfo.descriptorType       = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1541     writeInfo.pBufferInfo          = buffers.data();
1542 
1543     vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr);
1544 
1545     ConvertIndexShaderParams shaderParams = {params.srcOffset, params.dstOffset >> 2,
1546                                              params.maxIndex, 0};
1547 
1548     uint32_t flags = 0;
1549     if (contextVk->getState().isPrimitiveRestartEnabled())
1550     {
1551         flags |= vk::InternalShader::ConvertIndex_comp::kIsPrimitiveRestartEnabled;
1552     }
1553 
1554     vk::RefCounted<vk::ShaderAndSerial> *shader = nullptr;
1555     ANGLE_TRY(contextVk->getShaderLibrary().getConvertIndex_comp(contextVk, flags, &shader));
1556 
1557     ANGLE_TRY(setupProgram(contextVk, Function::ConvertIndexBuffer, shader, nullptr,
1558                            &mConvertIndexPrograms[flags], nullptr, descriptorSet, &shaderParams,
1559                            sizeof(ConvertIndexShaderParams), commandBuffer));
1560 
1561     constexpr uint32_t kInvocationsPerGroup = 64;
1562     constexpr uint32_t kInvocationsPerIndex = 2;
1563     const uint32_t kIndexCount              = params.maxIndex;
1564     const uint32_t kGroupCount =
1565         UnsignedCeilDivide(kIndexCount * kInvocationsPerIndex, kInvocationsPerGroup);
1566     commandBuffer->dispatch(kGroupCount, 1, 1);
1567 
1568     descriptorPoolBinding.reset();
1569 
1570     return angle::Result::Continue;
1571 }
1572 
convertIndexIndirectBuffer(ContextVk * contextVk,vk::BufferHelper * srcIndirectBuf,vk::BufferHelper * srcIndexBuf,vk::BufferHelper * dstIndirectBuf,vk::BufferHelper * dstIndexBuf,const ConvertIndexIndirectParameters & params)1573 angle::Result UtilsVk::convertIndexIndirectBuffer(ContextVk *contextVk,
1574                                                   vk::BufferHelper *srcIndirectBuf,
1575                                                   vk::BufferHelper *srcIndexBuf,
1576                                                   vk::BufferHelper *dstIndirectBuf,
1577                                                   vk::BufferHelper *dstIndexBuf,
1578                                                   const ConvertIndexIndirectParameters &params)
1579 {
1580     ANGLE_TRY(ensureConvertIndexIndirectResourcesInitialized(contextVk));
1581 
1582     vk::CommandBufferAccess access;
1583     access.onBufferComputeShaderRead(srcIndirectBuf);
1584     access.onBufferComputeShaderRead(srcIndexBuf);
1585     access.onBufferComputeShaderWrite(dstIndirectBuf);
1586     access.onBufferComputeShaderWrite(dstIndexBuf);
1587 
1588     vk::CommandBuffer *commandBuffer;
1589     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1590 
1591     VkDescriptorSet descriptorSet;
1592     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
1593     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::ConvertIndexIndirectBuffer,
1594                                     &descriptorPoolBinding, &descriptorSet));
1595 
1596     std::array<VkDescriptorBufferInfo, 4> buffers = {{
1597         {dstIndexBuf->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1598         {srcIndexBuf->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1599         {srcIndirectBuf->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1600         {dstIndirectBuf->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1601     }};
1602 
1603     VkWriteDescriptorSet writeInfo = {};
1604     writeInfo.sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1605     writeInfo.dstSet               = descriptorSet;
1606     writeInfo.dstBinding           = kConvertIndexDestinationBinding;
1607     writeInfo.descriptorCount      = 4;
1608     writeInfo.descriptorType       = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1609     writeInfo.pBufferInfo          = buffers.data();
1610 
1611     vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr);
1612 
1613     ConvertIndexIndirectShaderParams shaderParams = {
1614         params.srcIndirectBufOffset >> 2, params.srcIndexBufOffset, params.dstIndexBufOffset >> 2,
1615         params.maxIndex, params.dstIndirectBufOffset >> 2};
1616 
1617     uint32_t flags = vk::InternalShader::ConvertIndex_comp::kIsIndirect;
1618     if (contextVk->getState().isPrimitiveRestartEnabled())
1619     {
1620         flags |= vk::InternalShader::ConvertIndex_comp::kIsPrimitiveRestartEnabled;
1621     }
1622 
1623     vk::RefCounted<vk::ShaderAndSerial> *shader = nullptr;
1624     ANGLE_TRY(contextVk->getShaderLibrary().getConvertIndex_comp(contextVk, flags, &shader));
1625 
1626     ANGLE_TRY(setupProgram(contextVk, Function::ConvertIndexIndirectBuffer, shader, nullptr,
1627                            &mConvertIndexPrograms[flags], nullptr, descriptorSet, &shaderParams,
1628                            sizeof(ConvertIndexIndirectShaderParams), commandBuffer));
1629 
1630     constexpr uint32_t kInvocationsPerGroup = 64;
1631     constexpr uint32_t kInvocationsPerIndex = 2;
1632     const uint32_t kIndexCount              = params.maxIndex;
1633     const uint32_t kGroupCount =
1634         UnsignedCeilDivide(kIndexCount * kInvocationsPerIndex, kInvocationsPerGroup);
1635     commandBuffer->dispatch(kGroupCount, 1, 1);
1636 
1637     descriptorPoolBinding.reset();
1638 
1639     return angle::Result::Continue;
1640 }
1641 
convertLineLoopIndexIndirectBuffer(ContextVk * contextVk,vk::BufferHelper * srcIndirectBuffer,vk::BufferHelper * dstIndirectBuffer,vk::BufferHelper * dstIndexBuffer,vk::BufferHelper * srcIndexBuffer,const ConvertLineLoopIndexIndirectParameters & params)1642 angle::Result UtilsVk::convertLineLoopIndexIndirectBuffer(
1643     ContextVk *contextVk,
1644     vk::BufferHelper *srcIndirectBuffer,
1645     vk::BufferHelper *dstIndirectBuffer,
1646     vk::BufferHelper *dstIndexBuffer,
1647     vk::BufferHelper *srcIndexBuffer,
1648     const ConvertLineLoopIndexIndirectParameters &params)
1649 {
1650     ANGLE_TRY(ensureConvertIndexIndirectLineLoopResourcesInitialized(contextVk));
1651 
1652     vk::CommandBufferAccess access;
1653     access.onBufferComputeShaderRead(srcIndirectBuffer);
1654     access.onBufferComputeShaderRead(srcIndexBuffer);
1655     access.onBufferComputeShaderWrite(dstIndirectBuffer);
1656     access.onBufferComputeShaderWrite(dstIndexBuffer);
1657 
1658     vk::CommandBuffer *commandBuffer;
1659     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1660 
1661     VkDescriptorSet descriptorSet;
1662     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
1663     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::ConvertIndexIndirectLineLoopBuffer,
1664                                     &descriptorPoolBinding, &descriptorSet));
1665 
1666     std::array<VkDescriptorBufferInfo, 4> buffers = {{
1667         {dstIndexBuffer->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1668         {srcIndexBuffer->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1669         {srcIndirectBuffer->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1670         {dstIndirectBuffer->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1671     }};
1672 
1673     VkWriteDescriptorSet writeInfo = {};
1674     writeInfo.sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1675     writeInfo.dstSet               = descriptorSet;
1676     writeInfo.dstBinding           = kConvertIndexDestinationBinding;
1677     writeInfo.descriptorCount      = 4;
1678     writeInfo.descriptorType       = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1679     writeInfo.pBufferInfo          = buffers.data();
1680 
1681     vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr);
1682 
1683     ConvertIndexIndirectLineLoopShaderParams shaderParams = {
1684         params.indirectBufferOffset >> 2, params.dstIndirectBufferOffset >> 2,
1685         params.srcIndexBufferOffset, params.dstIndexBufferOffset >> 2,
1686         contextVk->getState().isPrimitiveRestartEnabled()};
1687 
1688     uint32_t flags = GetConvertIndexIndirectLineLoopFlag(params.indicesBitsWidth);
1689 
1690     vk::RefCounted<vk::ShaderAndSerial> *shader = nullptr;
1691     ANGLE_TRY(contextVk->getShaderLibrary().getConvertIndexIndirectLineLoop_comp(contextVk, flags,
1692                                                                                  &shader));
1693 
1694     ANGLE_TRY(setupProgram(contextVk, Function::ConvertIndexIndirectLineLoopBuffer, shader, nullptr,
1695                            &mConvertIndexIndirectLineLoopPrograms[flags], nullptr, descriptorSet,
1696                            &shaderParams, sizeof(ConvertIndexIndirectLineLoopShaderParams),
1697                            commandBuffer));
1698 
1699     commandBuffer->dispatch(1, 1, 1);
1700 
1701     descriptorPoolBinding.reset();
1702 
1703     return angle::Result::Continue;
1704 }
1705 
convertLineLoopArrayIndirectBuffer(ContextVk * contextVk,vk::BufferHelper * srcIndirectBuffer,vk::BufferHelper * destIndirectBuffer,vk::BufferHelper * destIndexBuffer,const ConvertLineLoopArrayIndirectParameters & params)1706 angle::Result UtilsVk::convertLineLoopArrayIndirectBuffer(
1707     ContextVk *contextVk,
1708     vk::BufferHelper *srcIndirectBuffer,
1709     vk::BufferHelper *destIndirectBuffer,
1710     vk::BufferHelper *destIndexBuffer,
1711     const ConvertLineLoopArrayIndirectParameters &params)
1712 {
1713     ANGLE_TRY(ensureConvertIndirectLineLoopResourcesInitialized(contextVk));
1714 
1715     vk::CommandBufferAccess access;
1716     access.onBufferComputeShaderRead(srcIndirectBuffer);
1717     access.onBufferComputeShaderWrite(destIndirectBuffer);
1718     access.onBufferComputeShaderWrite(destIndexBuffer);
1719 
1720     vk::CommandBuffer *commandBuffer;
1721     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1722 
1723     VkDescriptorSet descriptorSet;
1724     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
1725     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::ConvertIndirectLineLoopBuffer,
1726                                     &descriptorPoolBinding, &descriptorSet));
1727 
1728     std::array<VkDescriptorBufferInfo, 3> buffers = {{
1729         {srcIndirectBuffer->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1730         {destIndirectBuffer->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1731         {destIndexBuffer->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1732     }};
1733 
1734     VkWriteDescriptorSet writeInfo = {};
1735     writeInfo.sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1736     writeInfo.dstSet               = descriptorSet;
1737     writeInfo.dstBinding           = kConvertIndexDestinationBinding;
1738     writeInfo.descriptorCount      = 3;
1739     writeInfo.descriptorType       = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1740     writeInfo.pBufferInfo          = buffers.data();
1741 
1742     vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr);
1743 
1744     ConvertIndirectLineLoopShaderParams shaderParams = {params.indirectBufferOffset >> 2,
1745                                                         params.dstIndirectBufferOffset >> 2,
1746                                                         params.dstIndexBufferOffset >> 2};
1747 
1748     uint32_t flags = 0;
1749 
1750     vk::RefCounted<vk::ShaderAndSerial> *shader = nullptr;
1751     ANGLE_TRY(
1752         contextVk->getShaderLibrary().getConvertIndirectLineLoop_comp(contextVk, flags, &shader));
1753 
1754     ANGLE_TRY(setupProgram(contextVk, Function::ConvertIndirectLineLoopBuffer, shader, nullptr,
1755                            &mConvertIndirectLineLoopPrograms[flags], nullptr, descriptorSet,
1756                            &shaderParams, sizeof(ConvertIndirectLineLoopShaderParams),
1757                            commandBuffer));
1758 
1759     commandBuffer->dispatch(1, 1, 1);
1760 
1761     descriptorPoolBinding.reset();
1762 
1763     return angle::Result::Continue;
1764 }
1765 
convertVertexBuffer(ContextVk * contextVk,vk::BufferHelper * dst,vk::BufferHelper * src,const ConvertVertexParameters & params)1766 angle::Result UtilsVk::convertVertexBuffer(ContextVk *contextVk,
1767                                            vk::BufferHelper *dst,
1768                                            vk::BufferHelper *src,
1769                                            const ConvertVertexParameters &params)
1770 {
1771     vk::CommandBufferAccess access;
1772     access.onBufferComputeShaderRead(src);
1773     access.onBufferComputeShaderWrite(dst);
1774 
1775     vk::CommandBuffer *commandBuffer;
1776     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1777 
1778     ConvertVertexShaderParams shaderParams;
1779     shaderParams.Ns = params.srcFormat->channelCount;
1780     shaderParams.Bs = params.srcFormat->pixelBytes / params.srcFormat->channelCount;
1781     shaderParams.Ss = static_cast<uint32_t>(params.srcStride);
1782     shaderParams.Nd = params.dstFormat->channelCount;
1783     shaderParams.Bd = params.dstFormat->pixelBytes / params.dstFormat->channelCount;
1784     shaderParams.Sd = shaderParams.Nd * shaderParams.Bd;
1785     // The component size is expected to either be 1, 2 or 4 bytes.
1786     ASSERT(4 % shaderParams.Bs == 0);
1787     ASSERT(4 % shaderParams.Bd == 0);
1788     shaderParams.Es = 4 / shaderParams.Bs;
1789     shaderParams.Ed = 4 / shaderParams.Bd;
1790     // Total number of output components is simply the number of vertices by number of components in
1791     // each.
1792     shaderParams.componentCount = static_cast<uint32_t>(params.vertexCount * shaderParams.Nd);
1793     // Total number of 4-byte outputs is the number of components divided by how many components can
1794     // fit in a 4-byte value.  Note that this value is also the invocation size of the shader.
1795     shaderParams.outputCount = UnsignedCeilDivide(shaderParams.componentCount, shaderParams.Ed);
1796     shaderParams.srcOffset   = static_cast<uint32_t>(params.srcOffset);
1797     shaderParams.dstOffset   = static_cast<uint32_t>(params.dstOffset);
1798 
1799     bool isSrcA2BGR10 =
1800         params.srcFormat->vertexAttribType == gl::VertexAttribType::UnsignedInt2101010 ||
1801         params.srcFormat->vertexAttribType == gl::VertexAttribType::Int2101010;
1802     bool isSrcRGB10A2 =
1803         params.srcFormat->vertexAttribType == gl::VertexAttribType::UnsignedInt1010102 ||
1804         params.srcFormat->vertexAttribType == gl::VertexAttribType::Int1010102;
1805 
1806     shaderParams.isSrcHDR     = isSrcA2BGR10 || isSrcRGB10A2;
1807     shaderParams.isSrcA2BGR10 = isSrcA2BGR10;
1808 
1809     uint32_t flags = GetConvertVertexFlags(params);
1810 
1811     // See GLES3.0 section 2.9.1 Transferring Array Elements
1812     const uint32_t srcValueBits = shaderParams.isSrcHDR ? 2 : shaderParams.Bs * 8;
1813     const uint32_t srcValueMask =
1814         srcValueBits == 32 ? 0xFFFFFFFFu : angle::BitMask<uint32_t>(srcValueBits);
1815     switch (flags)
1816     {
1817         case ConvertVertex_comp::kSintToSint:
1818         case ConvertVertex_comp::kSintToFloat:
1819         case ConvertVertex_comp::kUintToFloat:
1820             // For integers, alpha should take a value of 1.
1821             shaderParams.srcEmulatedAlpha = 1;
1822             break;
1823 
1824         case ConvertVertex_comp::kUintToUint:
1825             // For integers, alpha should take a value of 1.  However, uint->uint is also used to
1826             // add channels to RGB snorm, unorm and half formats.
1827             if (params.dstFormat->isSnorm())
1828             {
1829                 // See case ConvertVertex_comp::kSnormToFloat below.
1830                 shaderParams.srcEmulatedAlpha = srcValueMask >> 1;
1831             }
1832             else if (params.dstFormat->isUnorm())
1833             {
1834                 // See case ConvertVertex_comp::kUnormToFloat below.
1835                 shaderParams.srcEmulatedAlpha = srcValueMask;
1836             }
1837             else if (params.dstFormat->isVertexTypeHalfFloat())
1838             {
1839                 shaderParams.srcEmulatedAlpha = gl::Float16One;
1840             }
1841             else
1842             {
1843                 shaderParams.srcEmulatedAlpha = 1;
1844             }
1845             break;
1846 
1847         case ConvertVertex_comp::kSnormToFloat:
1848             // The largest signed number with as many bits as the alpha channel of the source is
1849             // 0b011...1 which is srcValueMask >> 1
1850             shaderParams.srcEmulatedAlpha = srcValueMask >> 1;
1851             break;
1852 
1853         case ConvertVertex_comp::kUnormToFloat:
1854             // The largest unsigned number with as many bits as the alpha channel of the source is
1855             // 0b11...1 which is srcValueMask
1856             shaderParams.srcEmulatedAlpha = srcValueMask;
1857             break;
1858 
1859         case ConvertVertex_comp::kFixedToFloat:
1860             // 1.0 in fixed point is 0x10000
1861             shaderParams.srcEmulatedAlpha = 0x10000;
1862             break;
1863 
1864         case ConvertVertex_comp::kFloatToFloat:
1865             ASSERT(ValidateFloatOneAsUint());
1866             shaderParams.srcEmulatedAlpha = gl::Float32One;
1867             break;
1868 
1869         default:
1870             UNREACHABLE();
1871     }
1872 
1873     return convertVertexBufferImpl(contextVk, dst, src, flags, commandBuffer, shaderParams);
1874 }
1875 
convertVertexBufferImpl(ContextVk * contextVk,vk::BufferHelper * dst,vk::BufferHelper * src,uint32_t flags,vk::CommandBuffer * commandBuffer,const ConvertVertexShaderParams & shaderParams)1876 angle::Result UtilsVk::convertVertexBufferImpl(ContextVk *contextVk,
1877                                                vk::BufferHelper *dst,
1878                                                vk::BufferHelper *src,
1879                                                uint32_t flags,
1880                                                vk::CommandBuffer *commandBuffer,
1881                                                const ConvertVertexShaderParams &shaderParams)
1882 {
1883     ANGLE_TRY(ensureConvertVertexResourcesInitialized(contextVk));
1884 
1885     VkDescriptorSet descriptorSet;
1886     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
1887     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::ConvertVertexBuffer,
1888                                     &descriptorPoolBinding, &descriptorSet));
1889 
1890     VkWriteDescriptorSet writeInfo    = {};
1891     VkDescriptorBufferInfo buffers[2] = {
1892         {dst->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1893         {src->getBuffer().getHandle(), 0, VK_WHOLE_SIZE},
1894     };
1895     static_assert(kConvertVertexDestinationBinding + 1 == kConvertVertexSourceBinding,
1896                   "Update write info");
1897 
1898     writeInfo.sType           = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1899     writeInfo.dstSet          = descriptorSet;
1900     writeInfo.dstBinding      = kConvertVertexDestinationBinding;
1901     writeInfo.descriptorCount = 2;
1902     writeInfo.descriptorType  = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1903     writeInfo.pBufferInfo     = buffers;
1904 
1905     vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr);
1906 
1907     vk::RefCounted<vk::ShaderAndSerial> *shader = nullptr;
1908     ANGLE_TRY(contextVk->getShaderLibrary().getConvertVertex_comp(contextVk, flags, &shader));
1909 
1910     ANGLE_TRY(setupProgram(contextVk, Function::ConvertVertexBuffer, shader, nullptr,
1911                            &mConvertVertexPrograms[flags], nullptr, descriptorSet, &shaderParams,
1912                            sizeof(shaderParams), commandBuffer));
1913 
1914     commandBuffer->dispatch(UnsignedCeilDivide(shaderParams.outputCount, 64), 1, 1);
1915 
1916     descriptorPoolBinding.reset();
1917 
1918     return angle::Result::Continue;
1919 }
1920 
startRenderPass(ContextVk * contextVk,vk::ImageHelper * image,const vk::ImageView * imageView,const vk::RenderPassDesc & renderPassDesc,const gl::Rectangle & renderArea,vk::CommandBuffer ** commandBufferOut)1921 angle::Result UtilsVk::startRenderPass(ContextVk *contextVk,
1922                                        vk::ImageHelper *image,
1923                                        const vk::ImageView *imageView,
1924                                        const vk::RenderPassDesc &renderPassDesc,
1925                                        const gl::Rectangle &renderArea,
1926                                        vk::CommandBuffer **commandBufferOut)
1927 {
1928     vk::RenderPass *compatibleRenderPass = nullptr;
1929     ANGLE_TRY(contextVk->getCompatibleRenderPass(renderPassDesc, &compatibleRenderPass));
1930 
1931     VkFramebufferCreateInfo framebufferInfo = {};
1932 
1933     // Minimize the framebuffer coverage to only cover up to the render area.
1934     framebufferInfo.sType           = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1935     framebufferInfo.flags           = 0;
1936     framebufferInfo.renderPass      = compatibleRenderPass->getHandle();
1937     framebufferInfo.attachmentCount = 1;
1938     framebufferInfo.pAttachments    = imageView->ptr();
1939     framebufferInfo.width           = renderArea.x + renderArea.width;
1940     framebufferInfo.height          = renderArea.y + renderArea.height;
1941     framebufferInfo.layers          = 1;
1942 
1943     vk::Framebuffer framebuffer;
1944     ANGLE_VK_TRY(contextVk, framebuffer.init(contextVk->getDevice(), framebufferInfo));
1945 
1946     vk::AttachmentOpsArray renderPassAttachmentOps;
1947     vk::PackedClearValuesArray clearValues;
1948     clearValues.store(vk::kAttachmentIndexZero, VK_IMAGE_ASPECT_COLOR_BIT, {});
1949 
1950     renderPassAttachmentOps.initWithLoadStore(vk::kAttachmentIndexZero,
1951                                               vk::ImageLayout::ColorAttachment,
1952                                               vk::ImageLayout::ColorAttachment);
1953 
1954     ANGLE_TRY(contextVk->beginNewRenderPass(
1955         framebuffer, renderArea, renderPassDesc, renderPassAttachmentOps,
1956         vk::PackedAttachmentCount(1), vk::kAttachmentIndexInvalid, clearValues, commandBufferOut));
1957 
1958     contextVk->addGarbage(&framebuffer);
1959 
1960     return angle::Result::Continue;
1961 }
1962 
clearFramebuffer(ContextVk * contextVk,FramebufferVk * framebuffer,const ClearFramebufferParameters & params)1963 angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
1964                                         FramebufferVk *framebuffer,
1965                                         const ClearFramebufferParameters &params)
1966 {
1967     ANGLE_TRY(ensureImageClearResourcesInitialized(contextVk));
1968 
1969     const gl::Rectangle &scissoredRenderArea = params.clearArea;
1970     vk::Framebuffer *currentFramebuffer      = nullptr;
1971     vk::CommandBuffer *commandBuffer;
1972 
1973     // Start a new render pass if not already started
1974     ANGLE_TRY(framebuffer->getFramebuffer(contextVk, &currentFramebuffer, nullptr));
1975     if (contextVk->hasStartedRenderPassWithFramebuffer(currentFramebuffer))
1976     {
1977         commandBuffer = &contextVk->getStartedRenderPassCommands().getCommandBuffer();
1978     }
1979     else
1980     {
1981         ANGLE_TRY(contextVk->startRenderPass(scissoredRenderArea, &commandBuffer, nullptr));
1982     }
1983 
1984     if (params.clearStencil || params.clearDepth)
1985     {
1986         vk::CommandBufferHelper *renderpassCommands;
1987         renderpassCommands = &contextVk->getStartedRenderPassCommands();
1988 
1989         // Because clear is not affected by depth/stencil test, we have to explicitly mark
1990         // depth/stencil write here.
1991         if (params.clearDepth)
1992         {
1993             renderpassCommands->onDepthAccess(vk::ResourceAccess::Write);
1994         }
1995         if (params.clearStencil)
1996         {
1997             renderpassCommands->onStencilAccess(vk::ResourceAccess::Write);
1998         }
1999 
2000         // We may have changed depth stencil access mode, so update read only depth stencil mode
2001         // here.
2002         framebuffer->updateRenderPassReadOnlyDepthMode(contextVk, renderpassCommands);
2003     }
2004 
2005     ImageClearShaderParams shaderParams;
2006     shaderParams.clearValue = params.colorClearValue;
2007     shaderParams.clearDepth = params.depthStencilClearValue.depth;
2008 
2009     vk::GraphicsPipelineDesc pipelineDesc;
2010     pipelineDesc.initDefaults(contextVk);
2011     pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
2012     pipelineDesc.setColorWriteMasks(0, gl::DrawBufferMask(), gl::DrawBufferMask());
2013     pipelineDesc.setSingleColorWriteMask(params.colorAttachmentIndexGL, params.colorMaskFlags);
2014     pipelineDesc.setRasterizationSamples(framebuffer->getSamples());
2015     pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc());
2016     // Note: depth test is disabled by default so this should be unnecessary, but works around an
2017     // Intel bug on windows.  http://anglebug.com/3348
2018     pipelineDesc.setDepthWriteEnabled(false);
2019     // Clears can be done on a currently open render pass, so make sure the correct subpass index is
2020     // used.
2021     pipelineDesc.setSubpass(contextVk->getCurrentSubpassIndex());
2022 
2023     // Clear depth by enabling depth clamping and setting the viewport depth range to the clear
2024     // value if possible.  Otherwise use the shader to export depth.
2025     const bool supportsDepthClamp =
2026         contextVk->getRenderer()->getPhysicalDeviceFeatures().depthClamp == VK_TRUE;
2027     if (params.clearDepth)
2028     {
2029         pipelineDesc.setDepthTestEnabled(true);
2030         pipelineDesc.setDepthWriteEnabled(true);
2031         pipelineDesc.setDepthFunc(VK_COMPARE_OP_ALWAYS);
2032         if (supportsDepthClamp)
2033         {
2034             // Note: this path requires the depthClamp Vulkan feature.
2035             pipelineDesc.setDepthClampEnabled(true);
2036         }
2037     }
2038 
2039     // Clear stencil by enabling stencil write with the right mask.
2040     if (params.clearStencil)
2041     {
2042         const uint8_t compareMask = 0xFF;
2043         const uint8_t clearStencilValue =
2044             static_cast<uint8_t>(params.depthStencilClearValue.stencil);
2045 
2046         pipelineDesc.setStencilTestEnabled(true);
2047         pipelineDesc.setStencilFrontFuncs(clearStencilValue, VK_COMPARE_OP_ALWAYS, compareMask);
2048         pipelineDesc.setStencilBackFuncs(clearStencilValue, VK_COMPARE_OP_ALWAYS, compareMask);
2049         pipelineDesc.setStencilFrontOps(VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE,
2050                                         VK_STENCIL_OP_REPLACE);
2051         pipelineDesc.setStencilBackOps(VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_REPLACE,
2052                                        VK_STENCIL_OP_REPLACE);
2053         pipelineDesc.setStencilFrontWriteMask(params.stencilMask);
2054         pipelineDesc.setStencilBackWriteMask(params.stencilMask);
2055     }
2056 
2057     VkViewport viewport;
2058     gl::Rectangle completeRenderArea = framebuffer->getRotatedCompleteRenderArea(contextVk);
2059     bool invertViewport              = contextVk->isViewportFlipEnabledForDrawFBO();
2060     bool clipSpaceOriginUpperLeft =
2061         contextVk->getState().getClipSpaceOrigin() == gl::ClipSpaceOrigin::UpperLeft;
2062     // Set depth range to clear value.  If clearing depth, the vertex shader depth output is clamped
2063     // to this value, thus clearing the depth buffer to the desired clear value.
2064     const float clearDepthValue = params.depthStencilClearValue.depth;
2065     gl_vk::GetViewport(completeRenderArea, clearDepthValue, clearDepthValue, invertViewport,
2066                        clipSpaceOriginUpperLeft, completeRenderArea.height, &viewport);
2067     commandBuffer->setViewport(0, 1, &viewport);
2068 
2069     const VkRect2D scissor = gl_vk::GetRect(params.clearArea);
2070     commandBuffer->setScissor(0, 1, &scissor);
2071 
2072     contextVk->invalidateViewportAndScissor();
2073 
2074     vk::ShaderLibrary &shaderLibrary                    = contextVk->getShaderLibrary();
2075     vk::RefCounted<vk::ShaderAndSerial> *vertexShader   = nullptr;
2076     vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = nullptr;
2077     vk::ShaderProgramHelper *imageClearProgram          = &mImageClearProgramVSOnly;
2078 
2079     ANGLE_TRY(shaderLibrary.getFullScreenTri_vert(contextVk, 0, &vertexShader));
2080     if (params.clearColor)
2081     {
2082         const uint32_t flags =
2083             GetImageClearFlags(*params.colorFormat, params.colorAttachmentIndexGL,
2084                                params.clearDepth && !supportsDepthClamp);
2085         ANGLE_TRY(shaderLibrary.getImageClear_frag(contextVk, flags, &fragmentShader));
2086         imageClearProgram = &mImageClearPrograms[flags];
2087     }
2088 
2089     // Make sure transform feedback is paused.  Needs to be done before binding the pipeline as
2090     // that's not allowed in Vulkan.
2091     const bool isTransformFeedbackActiveUnpaused =
2092         contextVk->getStartedRenderPassCommands().isTransformFeedbackActiveUnpaused();
2093     contextVk->pauseTransformFeedbackIfActiveUnpaused();
2094 
2095     ANGLE_TRY(setupProgram(contextVk, Function::ImageClear, fragmentShader, vertexShader,
2096                            imageClearProgram, &pipelineDesc, VK_NULL_HANDLE, &shaderParams,
2097                            sizeof(shaderParams), commandBuffer));
2098 
2099     // Make sure this draw call doesn't count towards occlusion query results.
2100     contextVk->pauseRenderPassQueriesIfActive();
2101 
2102     commandBuffer->draw(3, 0);
2103     ANGLE_TRY(contextVk->resumeRenderPassQueriesIfActive());
2104 
2105     // If transform feedback was active, we can't pause and resume it in the same render pass
2106     // because we can't insert a memory barrier for the counter buffers.  In that case, break the
2107     // render pass.
2108     if (isTransformFeedbackActiveUnpaused)
2109     {
2110         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
2111             RenderPassClosureReason::XfbResumeAfterDrawBasedClear));
2112     }
2113 
2114     return angle::Result::Continue;
2115 }
2116 
clearImage(ContextVk * contextVk,vk::ImageHelper * dst,const ClearImageParameters & params)2117 angle::Result UtilsVk::clearImage(ContextVk *contextVk,
2118                                   vk::ImageHelper *dst,
2119                                   const ClearImageParameters &params)
2120 {
2121     ANGLE_TRY(ensureImageClearResourcesInitialized(contextVk));
2122 
2123     const angle::Format &dstActualFormat = dst->getActualFormat();
2124 
2125     // Currently, this function is only used to clear emulated channels of color images.
2126     ASSERT(!dstActualFormat.hasDepthOrStencilBits());
2127 
2128     // TODO: currently this function is only implemented for images that are drawable.  If needed,
2129     // for images that are not drawable, the following algorithm can be used.
2130     //
2131     // - Copy image to temp buffer
2132     // - Use convertVertexBufferImpl to overwrite the alpha channel
2133     // - Copy the result back to the image
2134     //
2135     // Note that the following check is not enough; if the image is AHB-imported, then the draw path
2136     // cannot be taken if AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER hasn't been specified, even if the
2137     // format is renderable.
2138     //
2139     // http://anglebug.com/6151
2140     if (!vk::FormatHasNecessaryFeature(contextVk->getRenderer(), dstActualFormat.id,
2141                                        dst->getTilingMode(),
2142                                        VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
2143     {
2144         UNIMPLEMENTED();
2145         return angle::Result::Continue;
2146     }
2147 
2148     vk::DeviceScoped<vk::ImageView> destView(contextVk->getDevice());
2149     const gl::TextureType destViewType = vk::Get2DTextureType(1, dst->getSamples());
2150 
2151     ANGLE_TRY(dst->initLayerImageView(contextVk, destViewType, VK_IMAGE_ASPECT_COLOR_BIT,
2152                                       gl::SwizzleState(), &destView.get(), params.dstMip, 1,
2153                                       params.dstLayer, 1, gl::SrgbWriteControlMode::Default));
2154 
2155     const gl::Rectangle &renderArea = params.clearArea;
2156 
2157     ImageClearShaderParams shaderParams;
2158     shaderParams.clearValue = params.colorClearValue;
2159     shaderParams.clearDepth = 0;
2160 
2161     vk::RenderPassDesc renderPassDesc;
2162     renderPassDesc.setSamples(dst->getSamples());
2163     renderPassDesc.packColorAttachment(0, dstActualFormat.id);
2164 
2165     vk::GraphicsPipelineDesc pipelineDesc;
2166     pipelineDesc.initDefaults(contextVk);
2167     pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
2168     pipelineDesc.setSingleColorWriteMask(0, params.colorMaskFlags);
2169     pipelineDesc.setRasterizationSamples(dst->getSamples());
2170     pipelineDesc.setRenderPassDesc(renderPassDesc);
2171 
2172     vk::CommandBuffer *commandBuffer;
2173     ANGLE_TRY(startRenderPass(contextVk, dst, &destView.get(), renderPassDesc, renderArea,
2174                               &commandBuffer));
2175 
2176     VkViewport viewport;
2177     gl_vk::GetViewport(renderArea, 0.0f, 1.0f, false, false, dst->getExtents().height, &viewport);
2178     commandBuffer->setViewport(0, 1, &viewport);
2179 
2180     VkRect2D scissor = gl_vk::GetRect(renderArea);
2181     commandBuffer->setScissor(0, 1, &scissor);
2182 
2183     contextVk->invalidateViewportAndScissor();
2184 
2185     contextVk->onImageRenderPassWrite(dst->toGLLevel(params.dstMip), params.dstLayer, 1,
2186                                       VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
2187                                       dst);
2188 
2189     const uint32_t flags = GetImageClearFlags(dstActualFormat, 0, false);
2190 
2191     vk::ShaderLibrary &shaderLibrary                    = contextVk->getShaderLibrary();
2192     vk::RefCounted<vk::ShaderAndSerial> *vertexShader   = nullptr;
2193     vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = nullptr;
2194     ANGLE_TRY(shaderLibrary.getFullScreenTri_vert(contextVk, 0, &vertexShader));
2195     ANGLE_TRY(shaderLibrary.getImageClear_frag(contextVk, flags, &fragmentShader));
2196 
2197     ANGLE_TRY(setupProgram(contextVk, Function::ImageClear, fragmentShader, vertexShader,
2198                            &mImageClearPrograms[flags], &pipelineDesc, VK_NULL_HANDLE,
2199                            &shaderParams, sizeof(shaderParams), commandBuffer));
2200 
2201     // Note: this utility creates its own framebuffer, thus bypassing ContextVk::startRenderPass.
2202     // As such, occlusion queries are not enabled.
2203     commandBuffer->draw(3, 0);
2204 
2205     vk::ImageView destViewObject = destView.release();
2206     contextVk->addGarbage(&destViewObject);
2207 
2208     // Close the render pass for this temporary framebuffer.
2209     return contextVk->flushCommandsAndEndRenderPass(
2210         RenderPassClosureReason::TemporaryForImageClear);
2211 }
2212 
colorBlitResolve(ContextVk * contextVk,FramebufferVk * framebuffer,vk::ImageHelper * src,const vk::ImageView * srcView,const BlitResolveParameters & params)2213 angle::Result UtilsVk::colorBlitResolve(ContextVk *contextVk,
2214                                         FramebufferVk *framebuffer,
2215                                         vk::ImageHelper *src,
2216                                         const vk::ImageView *srcView,
2217                                         const BlitResolveParameters &params)
2218 {
2219     // The views passed to this function are already retained, so a render pass cannot be already
2220     // open.  Otherwise, this function closes the render pass, which may incur a vkQueueSubmit and
2221     // then the views are used in a new command buffer without having been retained for it.
2222     // http://crbug.com/1272266#c22
2223     //
2224     // Note that depth/stencil views for blit are not derived from a ResourceVk object and are
2225     // retained differently.
2226     ASSERT(!contextVk->hasStartedRenderPass());
2227 
2228     return blitResolveImpl(contextVk, framebuffer, src, srcView, nullptr, nullptr, params);
2229 }
2230 
depthStencilBlitResolve(ContextVk * contextVk,FramebufferVk * framebuffer,vk::ImageHelper * src,const vk::ImageView * srcDepthView,const vk::ImageView * srcStencilView,const BlitResolveParameters & params)2231 angle::Result UtilsVk::depthStencilBlitResolve(ContextVk *contextVk,
2232                                                FramebufferVk *framebuffer,
2233                                                vk::ImageHelper *src,
2234                                                const vk::ImageView *srcDepthView,
2235                                                const vk::ImageView *srcStencilView,
2236                                                const BlitResolveParameters &params)
2237 {
2238     return blitResolveImpl(contextVk, framebuffer, src, nullptr, srcDepthView, srcStencilView,
2239                            params);
2240 }
2241 
blitResolveImpl(ContextVk * contextVk,FramebufferVk * framebuffer,vk::ImageHelper * src,const vk::ImageView * srcColorView,const vk::ImageView * srcDepthView,const vk::ImageView * srcStencilView,const BlitResolveParameters & params)2242 angle::Result UtilsVk::blitResolveImpl(ContextVk *contextVk,
2243                                        FramebufferVk *framebuffer,
2244                                        vk::ImageHelper *src,
2245                                        const vk::ImageView *srcColorView,
2246                                        const vk::ImageView *srcDepthView,
2247                                        const vk::ImageView *srcStencilView,
2248                                        const BlitResolveParameters &params)
2249 {
2250     // Possible ways to resolve color are:
2251     //
2252     // - vkCmdResolveImage: This is by far the easiest method, but lacks the ability to flip
2253     //   images during resolve.
2254     // - Manual resolve: A shader can read all samples from input, average them and output.
2255     // - Using subpass resolve attachment: A shader can transform the sample colors from source to
2256     //   destination coordinates and the subpass resolve would finish the job.
2257     //
2258     // The first method is unable to handle flipping, so it's not generally applicable.  The last
2259     // method would have been great were we able to modify the last render pass that rendered into
2260     // source, but still wouldn't be able to handle flipping.  The second method is implemented in
2261     // this function for complete control.
2262 
2263     // Possible ways to resolve depth/stencil are:
2264     //
2265     // - Manual resolve: A shader can read a samples from input and choose that for output.
2266     // - Using subpass resolve attachment through VkSubpassDescriptionDepthStencilResolveKHR: This
2267     //   requires an extension that's not very well supported.
2268     //
2269     // The first method is implemented in this function.
2270 
2271     // Possible ways to blit color, depth or stencil are:
2272     //
2273     // - vkCmdBlitImage: This function works if the source and destination formats have the blit
2274     //   feature.
2275     // - Manual blit: A shader can sample from the source image and write it to the destination.
2276     //
2277     // The first method has a serious shortcoming.  GLES allows blit parameters to exceed the
2278     // source or destination boundaries.  The actual blit is clipped to these limits, but the
2279     // scaling applied is determined solely by the input areas.  Vulkan requires the blit parameters
2280     // to be within the source and destination bounds.  This makes it hard to keep the scaling
2281     // constant.
2282     //
2283     // The second method is implemented in this function, which shares code with the resolve method.
2284 
2285     ANGLE_TRY(ensureBlitResolveResourcesInitialized(contextVk));
2286 
2287     bool isResolve = src->getSamples() > 1;
2288 
2289     BlitResolveShaderParams shaderParams;
2290     // Note: adjustments made for pre-rotatation in FramebufferVk::blit() affect these
2291     // Calculate*Offset() functions.
2292     if (isResolve)
2293     {
2294         CalculateResolveOffset(params, shaderParams.offset.resolve);
2295     }
2296     else
2297     {
2298         CalculateBlitOffset(params, shaderParams.offset.blit);
2299     }
2300     shaderParams.stretch[0]      = params.stretch[0];
2301     shaderParams.stretch[1]      = params.stretch[1];
2302     shaderParams.invSrcExtent[0] = 1.0f / params.srcExtents[0];
2303     shaderParams.invSrcExtent[1] = 1.0f / params.srcExtents[1];
2304     shaderParams.srcLayer        = params.srcLayer;
2305     shaderParams.samples         = src->getSamples();
2306     shaderParams.invSamples      = 1.0f / shaderParams.samples;
2307     shaderParams.outputMask =
2308         static_cast<uint32_t>(framebuffer->getState().getEnabledDrawBuffers().to_ulong());
2309     shaderParams.flipX    = params.flipX;
2310     shaderParams.flipY    = params.flipY;
2311     shaderParams.rotateXY = 0;
2312 
2313     // Potentially make adjustments for pre-rotation.  Depending on the angle some of the
2314     // shaderParams need to be adjusted.
2315     switch (params.rotation)
2316     {
2317         case SurfaceRotation::Identity:
2318             break;
2319         case SurfaceRotation::Rotated90Degrees:
2320             shaderParams.rotateXY = 1;
2321             break;
2322         case SurfaceRotation::Rotated180Degrees:
2323             if (isResolve)
2324             {
2325                 shaderParams.offset.resolve[0] += params.rotatedOffsetFactor[0];
2326                 shaderParams.offset.resolve[1] += params.rotatedOffsetFactor[1];
2327             }
2328             else
2329             {
2330                 shaderParams.offset.blit[0] += params.rotatedOffsetFactor[0];
2331                 shaderParams.offset.blit[1] += params.rotatedOffsetFactor[1];
2332             }
2333             break;
2334         case SurfaceRotation::Rotated270Degrees:
2335             if (isResolve)
2336             {
2337                 shaderParams.offset.resolve[0] += params.rotatedOffsetFactor[0];
2338                 shaderParams.offset.resolve[1] += params.rotatedOffsetFactor[1];
2339             }
2340             else
2341             {
2342                 shaderParams.offset.blit[0] += params.rotatedOffsetFactor[0];
2343                 shaderParams.offset.blit[1] += params.rotatedOffsetFactor[1];
2344             }
2345             shaderParams.rotateXY = 1;
2346             break;
2347         default:
2348             UNREACHABLE();
2349             break;
2350     }
2351 
2352     bool blitColor   = srcColorView != nullptr;
2353     bool blitDepth   = srcDepthView != nullptr;
2354     bool blitStencil = srcStencilView != nullptr;
2355 
2356     // Either color is blitted/resolved or depth/stencil, but not both.
2357     ASSERT(blitColor != (blitDepth || blitStencil));
2358 
2359     // Linear sampling is only valid with color blitting.
2360     ASSERT((blitColor && !isResolve) || !params.linear);
2361 
2362     uint32_t flags =
2363         GetBlitResolveFlags(blitColor, blitDepth, blitStencil, src->getIntendedFormat());
2364     flags |= src->getLayerCount() > 1 ? BlitResolve_frag::kSrcIsArray : 0;
2365     flags |= isResolve ? BlitResolve_frag::kIsResolve : 0;
2366 
2367     VkDescriptorSet descriptorSet;
2368     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
2369     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::BlitResolve, &descriptorPoolBinding,
2370                                     &descriptorSet));
2371 
2372     constexpr VkColorComponentFlags kAllColorComponents =
2373         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
2374         VK_COLOR_COMPONENT_A_BIT;
2375 
2376     vk::GraphicsPipelineDesc pipelineDesc;
2377     pipelineDesc.initDefaults(contextVk);
2378     if (blitColor)
2379     {
2380         pipelineDesc.setColorWriteMasks(
2381             gl::BlendStateExt::ColorMaskStorage::GetReplicatedValue(
2382                 kAllColorComponents, gl::BlendStateExt::ColorMaskStorage::GetMask(
2383                                          framebuffer->getRenderPassDesc().colorAttachmentRange())),
2384             framebuffer->getEmulatedAlphaAttachmentMask(), ~gl::DrawBufferMask());
2385     }
2386     else
2387     {
2388         pipelineDesc.setColorWriteMasks(0, gl::DrawBufferMask(), gl::DrawBufferMask());
2389     }
2390     pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
2391     pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc());
2392     pipelineDesc.setDepthTestEnabled(blitDepth);
2393     pipelineDesc.setDepthWriteEnabled(blitDepth);
2394     pipelineDesc.setDepthFunc(VK_COMPARE_OP_ALWAYS);
2395 
2396     if (blitStencil)
2397     {
2398         SetStencilForShaderExport(contextVk, &pipelineDesc);
2399     }
2400 
2401     vk::CommandBuffer *commandBuffer;
2402     ANGLE_TRY(framebuffer->startNewRenderPass(contextVk, params.blitArea, &commandBuffer, nullptr));
2403 
2404     VkViewport viewport;
2405     gl::Rectangle completeRenderArea = framebuffer->getRotatedCompleteRenderArea(contextVk);
2406     gl_vk::GetViewport(completeRenderArea, 0.0f, 1.0f, false, false, completeRenderArea.height,
2407                        &viewport);
2408     commandBuffer->setViewport(0, 1, &viewport);
2409 
2410     VkRect2D scissor = gl_vk::GetRect(params.blitArea);
2411     commandBuffer->setScissor(0, 1, &scissor);
2412 
2413     contextVk->invalidateViewportAndScissor();
2414 
2415     contextVk->onImageRenderPassRead(src->getAspectFlags(), vk::ImageLayout::FragmentShaderReadOnly,
2416                                      src);
2417 
2418     vk::CommandBufferHelper *renderPassCommands = &contextVk->getStartedRenderPassCommands();
2419     if (blitDepth)
2420     {
2421         // Explicitly mark a depth write because we are modifying the depth buffer.
2422         renderPassCommands->onDepthAccess(vk::ResourceAccess::Write);
2423     }
2424     if (blitStencil)
2425     {
2426         // Explicitly mark a stencil write because we are modifying the stencil buffer.
2427         renderPassCommands->onStencilAccess(vk::ResourceAccess::Write);
2428     }
2429     if (blitDepth || blitStencil)
2430     {
2431         // Because we may have changed the depth stencil access mode, update read only depth mode
2432         // now.
2433         framebuffer->updateRenderPassReadOnlyDepthMode(contextVk, renderPassCommands);
2434     }
2435 
2436     VkDescriptorImageInfo imageInfos[2] = {};
2437 
2438     if (blitColor)
2439     {
2440         imageInfos[0].imageView   = srcColorView->getHandle();
2441         imageInfos[0].imageLayout = src->getCurrentLayout();
2442     }
2443     if (blitDepth)
2444     {
2445         imageInfos[0].imageView   = srcDepthView->getHandle();
2446         imageInfos[0].imageLayout = src->getCurrentLayout();
2447     }
2448     if (blitStencil)
2449     {
2450         imageInfos[1].imageView   = srcStencilView->getHandle();
2451         imageInfos[1].imageLayout = src->getCurrentLayout();
2452     }
2453 
2454     VkDescriptorImageInfo samplerInfo = {};
2455     samplerInfo.sampler = params.linear ? mLinearSampler.getHandle() : mPointSampler.getHandle();
2456 
2457     VkWriteDescriptorSet writeInfos[3] = {};
2458     writeInfos[0].sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
2459     writeInfos[0].dstSet               = descriptorSet;
2460     writeInfos[0].dstBinding           = kBlitResolveColorOrDepthBinding;
2461     writeInfos[0].descriptorCount      = 1;
2462     writeInfos[0].descriptorType       = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
2463     writeInfos[0].pImageInfo           = &imageInfos[0];
2464 
2465     writeInfos[1]            = writeInfos[0];
2466     writeInfos[1].dstBinding = kBlitResolveStencilBinding;
2467     writeInfos[1].pImageInfo = &imageInfos[1];
2468 
2469     writeInfos[2].sType           = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
2470     writeInfos[2].dstSet          = descriptorSet;
2471     writeInfos[2].dstBinding      = kBlitResolveSamplerBinding;
2472     writeInfos[2].descriptorCount = 1;
2473     writeInfos[2].descriptorType  = VK_DESCRIPTOR_TYPE_SAMPLER;
2474     writeInfos[2].pImageInfo      = &samplerInfo;
2475 
2476     // If resolving color, there's one write info; index 0
2477     // If resolving depth, write info index 0 must be written
2478     // If resolving stencil, write info index 1 must also be written
2479     //
2480     // Note again that resolving color and depth/stencil are mutually exclusive here.
2481     uint32_t writeInfoOffset = blitDepth || blitColor ? 0 : 1;
2482     uint32_t writeInfoCount  = blitColor + blitDepth + blitStencil;
2483 
2484     vkUpdateDescriptorSets(contextVk->getDevice(), writeInfoCount, writeInfos + writeInfoOffset, 0,
2485                            nullptr);
2486     vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfos[2], 0, nullptr);
2487 
2488     vk::ShaderLibrary &shaderLibrary                    = contextVk->getShaderLibrary();
2489     vk::RefCounted<vk::ShaderAndSerial> *vertexShader   = nullptr;
2490     vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = nullptr;
2491     ANGLE_TRY(shaderLibrary.getFullScreenTri_vert(contextVk, 0, &vertexShader));
2492     ANGLE_TRY(shaderLibrary.getBlitResolve_frag(contextVk, flags, &fragmentShader));
2493 
2494     ANGLE_TRY(setupProgram(contextVk, Function::BlitResolve, fragmentShader, vertexShader,
2495                            &mBlitResolvePrograms[flags], &pipelineDesc, descriptorSet,
2496                            &shaderParams, sizeof(shaderParams), commandBuffer));
2497 
2498     // Note: this utility starts the render pass directly, thus bypassing
2499     // ContextVk::startRenderPass. As such, occlusion queries are not enabled.
2500     commandBuffer->draw(3, 0);
2501 
2502     descriptorPoolBinding.reset();
2503 
2504     return angle::Result::Continue;
2505 }
2506 
stencilBlitResolveNoShaderExport(ContextVk * contextVk,FramebufferVk * framebuffer,vk::ImageHelper * src,const vk::ImageView * srcStencilView,const BlitResolveParameters & params)2507 angle::Result UtilsVk::stencilBlitResolveNoShaderExport(ContextVk *contextVk,
2508                                                         FramebufferVk *framebuffer,
2509                                                         vk::ImageHelper *src,
2510                                                         const vk::ImageView *srcStencilView,
2511                                                         const BlitResolveParameters &params)
2512 {
2513     // When VK_EXT_shader_stencil_export is not available, stencil is blitted/resolved into a
2514     // temporary buffer which is then copied into the stencil aspect of the image.
2515 
2516     ANGLE_TRY(ensureBlitResolveStencilNoExportResourcesInitialized(contextVk));
2517 
2518     bool isResolve = src->getSamples() > 1;
2519 
2520     VkDescriptorSet descriptorSet;
2521     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
2522     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::BlitResolveStencilNoExport,
2523                                     &descriptorPoolBinding, &descriptorSet));
2524 
2525     // Create a temporary buffer to blit/resolve stencil into.
2526     vk::RendererScoped<vk::BufferHelper> blitBuffer(contextVk->getRenderer());
2527 
2528     uint32_t bufferRowLengthInUints = UnsignedCeilDivide(params.blitArea.width, sizeof(uint32_t));
2529     VkDeviceSize bufferSize = bufferRowLengthInUints * sizeof(uint32_t) * params.blitArea.height;
2530 
2531     VkBufferCreateInfo blitBufferInfo = {};
2532     blitBufferInfo.sType              = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
2533     blitBufferInfo.flags              = 0;
2534     blitBufferInfo.size               = bufferSize;
2535     blitBufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
2536     blitBufferInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
2537     blitBufferInfo.queueFamilyIndexCount = 0;
2538     blitBufferInfo.pQueueFamilyIndices   = nullptr;
2539 
2540     ANGLE_TRY(
2541         blitBuffer.get().init(contextVk, blitBufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
2542     blitBuffer.get().retainReadWrite(&contextVk->getResourceUseList());
2543 
2544     BlitResolveStencilNoExportShaderParams shaderParams;
2545     // Note: adjustments made for pre-rotatation in FramebufferVk::blit() affect these
2546     // Calculate*Offset() functions.
2547     if (isResolve)
2548     {
2549         CalculateResolveOffset(params, shaderParams.offset.resolve);
2550     }
2551     else
2552     {
2553         CalculateBlitOffset(params, shaderParams.offset.blit);
2554     }
2555     shaderParams.stretch[0]      = params.stretch[0];
2556     shaderParams.stretch[1]      = params.stretch[1];
2557     shaderParams.invSrcExtent[0] = 1.0f / params.srcExtents[0];
2558     shaderParams.invSrcExtent[1] = 1.0f / params.srcExtents[1];
2559     shaderParams.srcLayer        = params.srcLayer;
2560     shaderParams.srcWidth        = params.srcExtents[0];
2561     shaderParams.dstPitch        = bufferRowLengthInUints;
2562     shaderParams.blitArea[0]     = params.blitArea.x;
2563     shaderParams.blitArea[1]     = params.blitArea.y;
2564     shaderParams.blitArea[2]     = params.blitArea.width;
2565     shaderParams.blitArea[3]     = params.blitArea.height;
2566     shaderParams.flipX           = params.flipX;
2567     shaderParams.flipY           = params.flipY;
2568     shaderParams.rotateXY        = 0;
2569 
2570     // Potentially make adjustments for pre-rotatation.  Depending on the angle some of the
2571     // shaderParams need to be adjusted.
2572     switch (params.rotation)
2573     {
2574         case SurfaceRotation::Identity:
2575             break;
2576         case SurfaceRotation::Rotated90Degrees:
2577             shaderParams.rotateXY = 1;
2578             break;
2579         case SurfaceRotation::Rotated180Degrees:
2580             if (isResolve)
2581             {
2582                 // Align the offset with minus 1, or the sample position near the edge will be
2583                 // wrong.
2584                 shaderParams.offset.resolve[0] += params.rotatedOffsetFactor[0] - 1;
2585                 shaderParams.offset.resolve[1] += params.rotatedOffsetFactor[1];
2586             }
2587             else
2588             {
2589                 shaderParams.offset.blit[0] += params.rotatedOffsetFactor[0] - 1;
2590                 shaderParams.offset.blit[1] += params.rotatedOffsetFactor[1];
2591             }
2592             break;
2593         case SurfaceRotation::Rotated270Degrees:
2594             if (isResolve)
2595             {
2596                 shaderParams.offset.resolve[0] += params.rotatedOffsetFactor[0] - 1;
2597                 shaderParams.offset.resolve[1] += params.rotatedOffsetFactor[1] - 1;
2598             }
2599             else
2600             {
2601                 shaderParams.offset.blit[0] += params.rotatedOffsetFactor[0] - 1;
2602                 shaderParams.offset.blit[1] += params.rotatedOffsetFactor[1] - 1;
2603             }
2604             shaderParams.rotateXY = 1;
2605             break;
2606         default:
2607             UNREACHABLE();
2608             break;
2609     }
2610 
2611     // Linear sampling is only valid with color blitting.
2612     ASSERT(!params.linear);
2613 
2614     uint32_t flags = src->getLayerCount() > 1 ? BlitResolveStencilNoExport_comp::kSrcIsArray : 0;
2615     flags |= isResolve ? BlitResolve_frag::kIsResolve : 0;
2616 
2617     RenderTargetVk *depthStencilRenderTarget = framebuffer->getDepthStencilRenderTarget();
2618     ASSERT(depthStencilRenderTarget != nullptr);
2619     vk::ImageHelper *depthStencilImage = &depthStencilRenderTarget->getImageForWrite();
2620 
2621     // Change layouts prior to computation.
2622     vk::CommandBufferAccess access;
2623     access.onImageComputeShaderRead(src->getAspectFlags(), src);
2624     access.onImageTransferWrite(depthStencilRenderTarget->getLevelIndex(), 1,
2625                                 depthStencilRenderTarget->getLayerIndex(), 1,
2626                                 depthStencilImage->getAspectFlags(), depthStencilImage);
2627 
2628     vk::CommandBuffer *commandBuffer;
2629     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
2630 
2631     // Blit/resolve stencil into the buffer.
2632     VkDescriptorImageInfo imageInfo = {};
2633     imageInfo.imageView             = srcStencilView->getHandle();
2634     imageInfo.imageLayout           = src->getCurrentLayout();
2635 
2636     VkDescriptorBufferInfo bufferInfo = {};
2637     bufferInfo.buffer                 = blitBuffer.get().getBuffer().getHandle();
2638     bufferInfo.offset                 = 0;
2639     bufferInfo.range                  = VK_WHOLE_SIZE;
2640 
2641     VkDescriptorImageInfo samplerInfo = {};
2642     samplerInfo.sampler = params.linear ? mLinearSampler.getHandle() : mPointSampler.getHandle();
2643 
2644     VkWriteDescriptorSet writeInfos[3] = {};
2645     writeInfos[0].sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
2646     writeInfos[0].dstSet               = descriptorSet;
2647     writeInfos[0].dstBinding           = kBlitResolveStencilNoExportDestBinding;
2648     writeInfos[0].descriptorCount      = 1;
2649     writeInfos[0].descriptorType       = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
2650     writeInfos[0].pBufferInfo          = &bufferInfo;
2651 
2652     writeInfos[1].sType           = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
2653     writeInfos[1].dstSet          = descriptorSet;
2654     writeInfos[1].dstBinding      = kBlitResolveStencilNoExportSrcBinding;
2655     writeInfos[1].descriptorCount = 1;
2656     writeInfos[1].descriptorType  = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
2657     writeInfos[1].pImageInfo      = &imageInfo;
2658 
2659     writeInfos[2].sType           = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
2660     writeInfos[2].dstSet          = descriptorSet;
2661     writeInfos[2].dstBinding      = kBlitResolveStencilNoExportSamplerBinding;
2662     writeInfos[2].descriptorCount = 1;
2663     writeInfos[2].descriptorType  = VK_DESCRIPTOR_TYPE_SAMPLER;
2664     writeInfos[2].pImageInfo      = &samplerInfo;
2665 
2666     vkUpdateDescriptorSets(contextVk->getDevice(), 3, writeInfos, 0, nullptr);
2667 
2668     vk::RefCounted<vk::ShaderAndSerial> *shader = nullptr;
2669     ANGLE_TRY(contextVk->getShaderLibrary().getBlitResolveStencilNoExport_comp(contextVk, flags,
2670                                                                                &shader));
2671 
2672     ANGLE_TRY(setupProgram(contextVk, Function::BlitResolveStencilNoExport, shader, nullptr,
2673                            &mBlitResolveStencilNoExportPrograms[flags], nullptr, descriptorSet,
2674                            &shaderParams, sizeof(shaderParams), commandBuffer));
2675     commandBuffer->dispatch(UnsignedCeilDivide(bufferRowLengthInUints, 8),
2676                             UnsignedCeilDivide(params.blitArea.height, 8), 1);
2677     descriptorPoolBinding.reset();
2678 
2679     // Add a barrier prior to copy.
2680     VkMemoryBarrier memoryBarrier = {};
2681     memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
2682     memoryBarrier.srcAccessMask   = VK_ACCESS_SHADER_WRITE_BIT;
2683     memoryBarrier.dstAccessMask   = VK_ACCESS_TRANSFER_READ_BIT;
2684 
2685     commandBuffer->memoryBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
2686                                  VK_PIPELINE_STAGE_TRANSFER_BIT, &memoryBarrier);
2687 
2688     // Copy the resulting buffer into dst.
2689     VkBufferImageCopy region           = {};
2690     region.bufferOffset                = 0;
2691     region.bufferRowLength             = bufferRowLengthInUints * sizeof(uint32_t);
2692     region.bufferImageHeight           = params.blitArea.height;
2693     region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
2694     region.imageSubresource.mipLevel =
2695         depthStencilImage->toVkLevel(depthStencilRenderTarget->getLevelIndex()).get();
2696     region.imageSubresource.baseArrayLayer = depthStencilRenderTarget->getLayerIndex();
2697     region.imageSubresource.layerCount     = 1;
2698     region.imageOffset.x                   = params.blitArea.x;
2699     region.imageOffset.y                   = params.blitArea.y;
2700     region.imageOffset.z                   = 0;
2701     region.imageExtent.width               = params.blitArea.width;
2702     region.imageExtent.height              = params.blitArea.height;
2703     region.imageExtent.depth               = 1;
2704 
2705     commandBuffer->copyBufferToImage(blitBuffer.get().getBuffer().getHandle(),
2706                                      depthStencilImage->getImage(),
2707                                      depthStencilImage->getCurrentLayout(), 1, &region);
2708 
2709     return angle::Result::Continue;
2710 }
2711 
copyImage(ContextVk * contextVk,vk::ImageHelper * dst,const vk::ImageView * destView,vk::ImageHelper * src,const vk::ImageView * srcView,const CopyImageParameters & params)2712 angle::Result UtilsVk::copyImage(ContextVk *contextVk,
2713                                  vk::ImageHelper *dst,
2714                                  const vk::ImageView *destView,
2715                                  vk::ImageHelper *src,
2716                                  const vk::ImageView *srcView,
2717                                  const CopyImageParameters &params)
2718 {
2719     // The views passed to this function are already retained, so a render pass cannot be already
2720     // open.  Otherwise, this function closes the render pass, which may incur a vkQueueSubmit and
2721     // then the views are used in a new command buffer without having been retained for it.
2722     // http://crbug.com/1272266#c22
2723     ASSERT(!contextVk->hasStartedRenderPass());
2724 
2725     ANGLE_TRY(ensureImageCopyResourcesInitialized(contextVk));
2726 
2727     const angle::Format &srcIntendedFormat = src->getIntendedFormat();
2728     const angle::Format &dstIntendedFormat = dst->getIntendedFormat();
2729 
2730     ImageCopyShaderParams shaderParams;
2731     shaderParams.flipX            = 0;
2732     shaderParams.flipY            = params.srcFlipY || params.dstFlipY;
2733     shaderParams.premultiplyAlpha = params.srcPremultiplyAlpha;
2734     shaderParams.unmultiplyAlpha  = params.srcUnmultiplyAlpha;
2735     shaderParams.dstHasLuminance  = dstIntendedFormat.luminanceBits > 0;
2736     shaderParams.dstIsAlpha       = dstIntendedFormat.isLUMA() && dstIntendedFormat.alphaBits > 0;
2737     shaderParams.dstDefaultChannelsMask =
2738         GetFormatDefaultChannelMask(dst->getIntendedFormat(), dst->getActualFormat());
2739     shaderParams.srcMip       = params.srcMip;
2740     shaderParams.srcLayer     = params.srcLayer;
2741     shaderParams.srcOffset[0] = params.srcOffset[0];
2742     shaderParams.srcOffset[1] = params.srcOffset[1];
2743     shaderParams.dstOffset[0] = params.dstOffset[0];
2744     shaderParams.dstOffset[1] = params.dstOffset[1];
2745     shaderParams.rotateXY     = 0;
2746 
2747     shaderParams.srcIsSRGB = params.srcColorEncoding == GL_SRGB;
2748     shaderParams.dstIsSRGB = params.dstColorEncoding == GL_SRGB;
2749 
2750     // If both src and dst are sRGB, and there is no alpha multiplication/division necessary, then
2751     // the shader can work with sRGB data and pretend they are linear.
2752     if (shaderParams.srcIsSRGB && shaderParams.dstIsSRGB && !shaderParams.premultiplyAlpha &&
2753         !shaderParams.unmultiplyAlpha)
2754     {
2755         shaderParams.srcIsSRGB = false;
2756         shaderParams.dstIsSRGB = false;
2757     }
2758 
2759     ASSERT(!(params.srcFlipY && params.dstFlipY));
2760     if (params.srcFlipY)
2761     {
2762         // If viewport is flipped, the shader expects srcOffset[1] to have the
2763         // last row's index instead of the first's.
2764         shaderParams.srcOffset[1] = params.srcHeight - params.srcOffset[1] - 1;
2765     }
2766     else if (params.dstFlipY)
2767     {
2768         // If image is flipped during copy, the shader uses the same code path as above,
2769         // with srcOffset being set to the last row's index instead of the first's.
2770         shaderParams.srcOffset[1] = params.srcOffset[1] + params.srcExtents[1] - 1;
2771     }
2772 
2773     switch (params.srcRotation)
2774     {
2775         case SurfaceRotation::Identity:
2776             break;
2777         case SurfaceRotation::Rotated90Degrees:
2778             shaderParams.rotateXY = 1;
2779             break;
2780         case SurfaceRotation::Rotated180Degrees:
2781             shaderParams.flipX = true;
2782             ASSERT(shaderParams.flipY);
2783             shaderParams.flipY = false;
2784             shaderParams.srcOffset[0] += params.srcExtents[0];
2785             shaderParams.srcOffset[1] -= params.srcExtents[1];
2786             break;
2787         case SurfaceRotation::Rotated270Degrees:
2788             shaderParams.flipX = true;
2789             ASSERT(!shaderParams.flipY);
2790             shaderParams.flipY = true;
2791             shaderParams.srcOffset[0] += params.srcExtents[0];
2792             shaderParams.srcOffset[1] += params.srcExtents[1];
2793             shaderParams.rotateXY = 1;
2794             break;
2795         default:
2796             UNREACHABLE();
2797             break;
2798     }
2799 
2800     uint32_t flags = GetImageCopyFlags(srcIntendedFormat, dstIntendedFormat);
2801     if (src->getType() == VK_IMAGE_TYPE_3D)
2802     {
2803         flags |= ImageCopy_frag::kSrcIs3D;
2804     }
2805     else if (src->getLayerCount() > 1)
2806     {
2807         flags |= ImageCopy_frag::kSrcIs2DArray;
2808     }
2809     else
2810     {
2811         flags |= ImageCopy_frag::kSrcIs2D;
2812     }
2813 
2814     VkDescriptorSet descriptorSet;
2815     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
2816     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::ImageCopy, &descriptorPoolBinding,
2817                                     &descriptorSet));
2818 
2819     vk::RenderPassDesc renderPassDesc;
2820     renderPassDesc.setSamples(dst->getSamples());
2821     renderPassDesc.packColorAttachment(0, dst->getActualFormatID());
2822 
2823     // Copy from multisampled image is not supported.
2824     ASSERT(src->getSamples() == 1);
2825 
2826     vk::GraphicsPipelineDesc pipelineDesc;
2827     pipelineDesc.initDefaults(contextVk);
2828     pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
2829     pipelineDesc.setRenderPassDesc(renderPassDesc);
2830     pipelineDesc.setRasterizationSamples(dst->getSamples());
2831 
2832     gl::Rectangle renderArea;
2833     renderArea.x      = params.dstOffset[0];
2834     renderArea.y      = params.dstOffset[1];
2835     renderArea.width  = params.srcExtents[0];
2836     renderArea.height = params.srcExtents[1];
2837     if ((params.srcRotation == SurfaceRotation::Rotated90Degrees) ||
2838         (params.srcRotation == SurfaceRotation::Rotated270Degrees))
2839     {
2840         // The surface is rotated 90/270 degrees.  This changes the aspect ratio of the surface.
2841         std::swap(renderArea.x, renderArea.y);
2842         std::swap(renderArea.width, renderArea.height);
2843     }
2844 
2845     vk::CommandBuffer *commandBuffer;
2846     ANGLE_TRY(
2847         startRenderPass(contextVk, dst, destView, renderPassDesc, renderArea, &commandBuffer));
2848 
2849     VkViewport viewport;
2850     gl_vk::GetViewport(renderArea, 0.0f, 1.0f, false, false, dst->getExtents().height, &viewport);
2851     commandBuffer->setViewport(0, 1, &viewport);
2852 
2853     VkRect2D scissor = gl_vk::GetRect(renderArea);
2854     commandBuffer->setScissor(0, 1, &scissor);
2855 
2856     contextVk->invalidateViewportAndScissor();
2857 
2858     // Change source layout inside render pass.
2859     contextVk->onImageRenderPassRead(VK_IMAGE_ASPECT_COLOR_BIT,
2860                                      vk::ImageLayout::FragmentShaderReadOnly, src);
2861     contextVk->onImageRenderPassWrite(params.dstMip, params.dstLayer, 1, VK_IMAGE_ASPECT_COLOR_BIT,
2862                                       vk::ImageLayout::ColorAttachment, dst);
2863 
2864     VkDescriptorImageInfo imageInfo = {};
2865     imageInfo.imageView             = srcView->getHandle();
2866     imageInfo.imageLayout           = src->getCurrentLayout();
2867 
2868     VkWriteDescriptorSet writeInfo = {};
2869     writeInfo.sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
2870     writeInfo.dstSet               = descriptorSet;
2871     writeInfo.dstBinding           = kImageCopySourceBinding;
2872     writeInfo.descriptorCount      = 1;
2873     writeInfo.descriptorType       = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
2874     writeInfo.pImageInfo           = &imageInfo;
2875 
2876     vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr);
2877 
2878     vk::ShaderLibrary &shaderLibrary                    = contextVk->getShaderLibrary();
2879     vk::RefCounted<vk::ShaderAndSerial> *vertexShader   = nullptr;
2880     vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = nullptr;
2881     ANGLE_TRY(shaderLibrary.getFullScreenTri_vert(contextVk, 0, &vertexShader));
2882     ANGLE_TRY(shaderLibrary.getImageCopy_frag(contextVk, flags, &fragmentShader));
2883 
2884     ANGLE_TRY(setupProgram(contextVk, Function::ImageCopy, fragmentShader, vertexShader,
2885                            &mImageCopyPrograms[flags], &pipelineDesc, descriptorSet, &shaderParams,
2886                            sizeof(shaderParams), commandBuffer));
2887 
2888     // Note: this utility creates its own framebuffer, thus bypassing ContextVk::startRenderPass.
2889     // As such, occlusion queries are not enabled.
2890     commandBuffer->draw(3, 0);
2891 
2892     descriptorPoolBinding.reset();
2893 
2894     // Close the render pass for this temporary framebuffer.
2895     return contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::TemporaryForImageCopy);
2896 }
2897 
copyImageBits(ContextVk * contextVk,vk::ImageHelper * dst,vk::ImageHelper * src,const CopyImageBitsParameters & params)2898 angle::Result UtilsVk::copyImageBits(ContextVk *contextVk,
2899                                      vk::ImageHelper *dst,
2900                                      vk::ImageHelper *src,
2901                                      const CopyImageBitsParameters &params)
2902 {
2903     // This function is used to copy the bit representation of an image to another, and is used to
2904     // support EXT_copy_image when a format is emulated.  Currently, only RGB->RGBA emulation is
2905     // possible, and so this function is tailored to this specific kind of emulation.
2906     //
2907     // The copy can be done with various degrees of efficiency:
2908     //
2909     // - If the UINT reinterpretation format for src supports SAMPLED usage, texels can be read
2910     //   directly from that.  Otherwise vkCmdCopyImageToBuffer can be used and data then read from
2911     //   the buffer.
2912     // - If the UINT reinterpretation format for dst supports STORAGE usage, texels can be written
2913     //   directly to that.  Otherwise conversion can be done to a buffer and then
2914     //   vkCmdCopyBufferToImage used.
2915     //
2916     // This requires four different shaders.  For simplicity, this function unconditionally copies
2917     // src to a temp buffer, transforms to another temp buffer and copies to the dst.  No known
2918     // applications use EXT_copy_image on RGB formats, so no further optimization is currently
2919     // necessary.
2920     //
2921     // The conversion between buffers can be done with ConvertVertex.comp in UintToUint mode, so no
2922     // new shader is necessary.  The srcEmulatedAlpha parameter is used to make sure the destination
2923     // alpha value is correct, if dst is RGBA.
2924 
2925     // This path should only be necessary for when RGBA is used as fallback for RGB.  No other
2926     // format which can be used with EXT_copy_image has a fallback.
2927     ASSERT(src->getIntendedFormat().blueBits > 0 && src->getIntendedFormat().alphaBits == 0);
2928     ASSERT(dst->getIntendedFormat().blueBits > 0 && dst->getIntendedFormat().alphaBits == 0);
2929 
2930     const angle::Format &srcImageFormat = src->getActualFormat();
2931     const angle::Format &dstImageFormat = dst->getActualFormat();
2932 
2933     // Create temporary buffers.
2934     vk::RendererScoped<vk::BufferHelper> srcBuffer(contextVk->getRenderer());
2935     vk::RendererScoped<vk::BufferHelper> dstBuffer(contextVk->getRenderer());
2936 
2937     const uint32_t srcPixelBytes = srcImageFormat.pixelBytes;
2938     const uint32_t dstPixelBytes = dstImageFormat.pixelBytes;
2939 
2940     const uint32_t totalPixelCount =
2941         params.copyExtents[0] * params.copyExtents[1] * params.copyExtents[2];
2942     // Note that buffer sizes are rounded up a multiple of uint size, as that the granularity in
2943     // which the compute shader accesses these buffers.
2944     const VkDeviceSize srcBufferSize =
2945         roundUpPow2<uint32_t>(srcPixelBytes * totalPixelCount, sizeof(uint32_t));
2946     const VkDeviceSize dstBufferSize =
2947         roundUpPow2<uint32_t>(dstPixelBytes * totalPixelCount, sizeof(uint32_t));
2948 
2949     VkBufferCreateInfo bufferInfo = {};
2950     bufferInfo.sType              = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
2951     bufferInfo.flags              = 0;
2952     bufferInfo.size               = srcBufferSize;
2953     bufferInfo.usage       = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
2954     bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
2955     bufferInfo.queueFamilyIndexCount = 0;
2956     bufferInfo.pQueueFamilyIndices   = nullptr;
2957 
2958     ANGLE_TRY(srcBuffer.get().init(contextVk, bufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
2959 
2960     bufferInfo.size  = dstBufferSize;
2961     bufferInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
2962 
2963     ANGLE_TRY(dstBuffer.get().init(contextVk, bufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
2964 
2965     srcBuffer.get().retainReadOnly(&contextVk->getResourceUseList());
2966     dstBuffer.get().retainReadWrite(&contextVk->getResourceUseList());
2967 
2968     bool isSrc3D = src->getType() == VK_IMAGE_TYPE_3D;
2969     bool isDst3D = dst->getType() == VK_IMAGE_TYPE_3D;
2970 
2971     // Change layouts prior to computation.
2972     vk::CommandBufferAccess access;
2973     access.onImageTransferRead(src->getAspectFlags(), src);
2974     access.onImageTransferWrite(params.dstLevel, 1, isDst3D ? 0 : params.dstOffset[2],
2975                                 isDst3D ? 1 : params.copyExtents[2], VK_IMAGE_ASPECT_COLOR_BIT,
2976                                 dst);
2977 
2978     vk::CommandBuffer *commandBuffer;
2979     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
2980 
2981     // Copy src into buffer, completely packed.
2982     VkBufferImageCopy srcRegion               = {};
2983     srcRegion.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2984     srcRegion.imageSubresource.mipLevel       = src->toVkLevel(params.srcLevel).get();
2985     srcRegion.imageSubresource.baseArrayLayer = isSrc3D ? 0 : params.srcOffset[2];
2986     srcRegion.imageSubresource.layerCount     = isSrc3D ? 1 : params.copyExtents[2];
2987     srcRegion.imageOffset.x                   = params.srcOffset[0];
2988     srcRegion.imageOffset.y                   = params.srcOffset[1];
2989     srcRegion.imageOffset.z                   = isSrc3D ? params.srcOffset[2] : 0;
2990     srcRegion.imageExtent.width               = params.copyExtents[0];
2991     srcRegion.imageExtent.height              = params.copyExtents[1];
2992     srcRegion.imageExtent.depth               = isSrc3D ? params.copyExtents[2] : 1;
2993 
2994     commandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(),
2995                                      srcBuffer.get().getBuffer().getHandle(), 1, &srcRegion);
2996 
2997     // Add a barrier prior to dispatch call.
2998     VkMemoryBarrier memoryBarrier = {};
2999     memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
3000     memoryBarrier.srcAccessMask   = VK_ACCESS_TRANSFER_WRITE_BIT;
3001     memoryBarrier.dstAccessMask   = VK_ACCESS_SHADER_READ_BIT;
3002 
3003     commandBuffer->memoryBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
3004                                  VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, &memoryBarrier);
3005 
3006     // Set up ConvertVertex shader to convert between the formats.  Only the following three cases
3007     // are possible:
3008     //
3009     // - RGB -> RGBA: Ns = 3, Ss = src.pixelBytes,
3010     //                Nd = 4, Sd = dst.pixelBytes, use srcEmulatedAlpha
3011     //
3012     // - RGBA -> RGBA: Ns = 3, Ss = src.pixelBytes,
3013     //                 Nd = 4, Sd = dst.pixelBytes, use srcEmulatedAlpha
3014     //
3015     // - RGBA -> RGB:  Ns = 3, Ss = src.pixelBytes,
3016     //                 Nd = 3, Sd = dst.pixelBytes
3017     //
3018     // The trick here is with RGBA -> RGBA, where Ns is specified as 3, so that the emulated alpha
3019     // from source is not taken (as uint), but rather one is provided such that the destination
3020     // alpha would contain the correct emulated alpha.
3021     //
3022     ConvertVertexShaderParams shaderParams;
3023     shaderParams.Ns = 3;
3024     shaderParams.Bs = srcImageFormat.pixelBytes / srcImageFormat.channelCount;
3025     shaderParams.Ss = srcImageFormat.pixelBytes;
3026     shaderParams.Nd = dstImageFormat.channelCount;
3027     shaderParams.Bd = dstImageFormat.pixelBytes / dstImageFormat.channelCount;
3028     shaderParams.Sd = shaderParams.Nd * shaderParams.Bd;
3029     // The component size is expected to either be 1, 2 or 4 bytes.
3030     ASSERT(4 % shaderParams.Bs == 0);
3031     ASSERT(4 % shaderParams.Bd == 0);
3032     shaderParams.Es = 4 / shaderParams.Bs;
3033     shaderParams.Ed = 4 / shaderParams.Bd;
3034     // Total number of output components is simply the number of pixels by number of components in
3035     // each.
3036     shaderParams.componentCount = totalPixelCount * shaderParams.Nd;
3037     // Total number of 4-byte outputs is the number of components divided by how many components can
3038     // fit in a 4-byte value.  Note that this value is also the invocation size of the shader.
3039     shaderParams.outputCount  = UnsignedCeilDivide(shaderParams.componentCount, shaderParams.Ed);
3040     shaderParams.srcOffset    = 0;
3041     shaderParams.dstOffset    = 0;
3042     shaderParams.isSrcHDR     = 0;
3043     shaderParams.isSrcA2BGR10 = 0;
3044 
3045     // Due to the requirements of EXT_copy_image, the channel size of src and dst must be
3046     // identical.  Usage of srcEmulatedAlpha relies on this as it's used to output an alpha value in
3047     // dst through the source.
3048     ASSERT(shaderParams.Bs == shaderParams.Bd);
3049 
3050     // The following RGB formats are allowed in EXT_copy_image:
3051     //
3052     // - RGB32F, RGB32UI, RGB32I
3053     // - RGB16F, RGB16UI, RGB16I
3054     // - RGB8, RGB8_SNORM, SRGB8, RGB8UI, RGB8I
3055     //
3056     // The value of emulated alpha is:
3057     //
3058     // - 1 for all RGB*I and RGB*UI formats
3059     // - bit representation of 1.0f for RGB32F
3060     // - bit representation of half-float 1.0f for RGB16F
3061     // - 0xFF for RGB8 and SRGB8
3062     // - 0x7F for RGB8_SNORM
3063     if (dstImageFormat.isInt())
3064     {
3065         shaderParams.srcEmulatedAlpha = 1;
3066     }
3067     else if (dstImageFormat.isUnorm())
3068     {
3069         ASSERT(shaderParams.Bd == 1);
3070         shaderParams.srcEmulatedAlpha = 0xFF;
3071     }
3072     else if (dstImageFormat.isSnorm())
3073     {
3074         ASSERT(shaderParams.Bd == 1);
3075         shaderParams.srcEmulatedAlpha = 0x7F;
3076     }
3077     else if (shaderParams.Bd == 2)
3078     {
3079         ASSERT(dstImageFormat.isFloat());
3080         shaderParams.srcEmulatedAlpha = gl::Float16One;
3081     }
3082     else if (shaderParams.Bd == 4)
3083     {
3084         ASSERT(dstImageFormat.isFloat());
3085         ASSERT(ValidateFloatOneAsUint());
3086         shaderParams.srcEmulatedAlpha = gl::Float32One;
3087     }
3088     else
3089     {
3090         UNREACHABLE();
3091     }
3092 
3093     // Use UintToUint conversion to preserve the bit pattern during transfer.
3094     const uint32_t flags = ConvertVertex_comp::kUintToUint;
3095 
3096     ANGLE_TRY(convertVertexBufferImpl(contextVk, &dstBuffer.get(), &srcBuffer.get(), flags,
3097                                       commandBuffer, shaderParams));
3098 
3099     // Add a barrier prior to copy.
3100     memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
3101     memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
3102 
3103     commandBuffer->memoryBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
3104                                  VK_PIPELINE_STAGE_TRANSFER_BIT, &memoryBarrier);
3105 
3106     // Copy buffer into dst.  It's completely packed.
3107     VkBufferImageCopy dstRegion               = {};
3108     dstRegion.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
3109     dstRegion.imageSubresource.mipLevel       = dst->toVkLevel(params.dstLevel).get();
3110     dstRegion.imageSubresource.baseArrayLayer = isDst3D ? 0 : params.dstOffset[2];
3111     dstRegion.imageSubresource.layerCount     = isDst3D ? 1 : params.copyExtents[2];
3112     dstRegion.imageOffset.x                   = params.dstOffset[0];
3113     dstRegion.imageOffset.y                   = params.dstOffset[1];
3114     dstRegion.imageOffset.z                   = isDst3D ? params.dstOffset[2] : 0;
3115     dstRegion.imageExtent.width               = params.copyExtents[0];
3116     dstRegion.imageExtent.height              = params.copyExtents[1];
3117     dstRegion.imageExtent.depth               = isDst3D ? params.copyExtents[2] : 1;
3118 
3119     commandBuffer->copyBufferToImage(dstBuffer.get().getBuffer().getHandle(), dst->getImage(),
3120                                      dst->getCurrentLayout(), 1, &dstRegion);
3121 
3122     return angle::Result::Continue;
3123 }
3124 
generateMipmap(ContextVk * contextVk,vk::ImageHelper * src,const vk::ImageView * srcLevelZeroView,vk::ImageHelper * dst,const GenerateMipmapDestLevelViews & destLevelViews,const vk::Sampler & sampler,const GenerateMipmapParameters & params)3125 angle::Result UtilsVk::generateMipmap(ContextVk *contextVk,
3126                                       vk::ImageHelper *src,
3127                                       const vk::ImageView *srcLevelZeroView,
3128                                       vk::ImageHelper *dst,
3129                                       const GenerateMipmapDestLevelViews &destLevelViews,
3130                                       const vk::Sampler &sampler,
3131                                       const GenerateMipmapParameters &params)
3132 {
3133     ANGLE_TRY(ensureGenerateMipmapResourcesInitialized(contextVk));
3134 
3135     const gl::Extents &srcExtents = src->getLevelExtents(vk::LevelIndex(params.srcLevel));
3136     ASSERT(srcExtents.depth == 1);
3137 
3138     // Each workgroup processes a 64x64 tile of the image.
3139     constexpr uint32_t kPixelWorkgroupRatio = 64;
3140     const uint32_t workGroupX = UnsignedCeilDivide(srcExtents.width, kPixelWorkgroupRatio);
3141     const uint32_t workGroupY = UnsignedCeilDivide(srcExtents.height, kPixelWorkgroupRatio);
3142 
3143     GenerateMipmapShaderParams shaderParams;
3144     shaderParams.invSrcExtent[0] = 1.0f / srcExtents.width;
3145     shaderParams.invSrcExtent[1] = 1.0f / srcExtents.height;
3146     shaderParams.levelCount      = params.dstLevelCount;
3147 
3148     uint32_t flags = GetGenerateMipmapFlags(contextVk, src->getActualFormat());
3149 
3150     VkDescriptorSet descriptorSet;
3151     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
3152     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::GenerateMipmap, &descriptorPoolBinding,
3153                                     &descriptorSet));
3154 
3155     VkDescriptorImageInfo destImageInfos[kGenerateMipmapMaxLevels] = {};
3156     for (uint32_t level = 0; level < kGenerateMipmapMaxLevels; ++level)
3157     {
3158         destImageInfos[level].imageView   = destLevelViews[level]->getHandle();
3159         destImageInfos[level].imageLayout = dst->getCurrentLayout();
3160     }
3161 
3162     VkDescriptorImageInfo srcImageInfo = {};
3163     srcImageInfo.imageView             = srcLevelZeroView->getHandle();
3164     srcImageInfo.imageLayout           = src->getCurrentLayout();
3165     srcImageInfo.sampler               = sampler.getHandle();
3166 
3167     VkWriteDescriptorSet writeInfos[2] = {};
3168     writeInfos[0].sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3169     writeInfos[0].dstSet               = descriptorSet;
3170     writeInfos[0].dstBinding           = kGenerateMipmapDestinationBinding;
3171     writeInfos[0].descriptorCount      = GetGenerateMipmapMaxLevels(contextVk);
3172     writeInfos[0].descriptorType       = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3173     writeInfos[0].pImageInfo           = destImageInfos;
3174 
3175     writeInfos[1].sType           = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3176     writeInfos[1].dstSet          = descriptorSet;
3177     writeInfos[1].dstBinding      = kGenerateMipmapSourceBinding;
3178     writeInfos[1].descriptorCount = 1;
3179     writeInfos[1].descriptorType  = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
3180     writeInfos[1].pImageInfo      = &srcImageInfo;
3181 
3182     vkUpdateDescriptorSets(contextVk->getDevice(), 2, writeInfos, 0, nullptr);
3183 
3184     vk::RefCounted<vk::ShaderAndSerial> *shader = nullptr;
3185     ANGLE_TRY(contextVk->getShaderLibrary().getGenerateMipmap_comp(contextVk, flags, &shader));
3186 
3187     // Note: onImageRead/onImageWrite is expected to be called by the caller.  This avoids inserting
3188     // barriers between calls for each layer of the image.
3189     vk::CommandBuffer *commandBuffer;
3190     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
3191 
3192     ANGLE_TRY(setupProgram(contextVk, Function::GenerateMipmap, shader, nullptr,
3193                            &mGenerateMipmapPrograms[flags], nullptr, descriptorSet, &shaderParams,
3194                            sizeof(shaderParams), commandBuffer));
3195 
3196     commandBuffer->dispatch(workGroupX, workGroupY, 1);
3197     descriptorPoolBinding.reset();
3198 
3199     return angle::Result::Continue;
3200 }
3201 
unresolve(ContextVk * contextVk,const FramebufferVk * framebuffer,const UnresolveParameters & params)3202 angle::Result UtilsVk::unresolve(ContextVk *contextVk,
3203                                  const FramebufferVk *framebuffer,
3204                                  const UnresolveParameters &params)
3205 {
3206     // Get attachment count and pointers to resolve images and views.
3207     gl::DrawBuffersArray<vk::ImageHelper *> colorSrc         = {};
3208     gl::DrawBuffersArray<const vk::ImageView *> colorSrcView = {};
3209 
3210     vk::DeviceScoped<vk::ImageView> depthView(contextVk->getDevice());
3211     vk::DeviceScoped<vk::ImageView> stencilView(contextVk->getDevice());
3212 
3213     const vk::ImageView *depthSrcView   = nullptr;
3214     const vk::ImageView *stencilSrcView = nullptr;
3215 
3216     // The subpass that initializes the multisampled-render-to-texture attachments packs the
3217     // attachments that need to be unresolved, so the attachment indices of this subpass are not the
3218     // same.  See InitializeUnresolveSubpass for details.
3219     vk::PackedAttachmentIndex colorIndexVk(0);
3220     for (size_t colorIndexGL : params.unresolveColorMask)
3221     {
3222         RenderTargetVk *colorRenderTarget = framebuffer->getColorDrawRenderTarget(colorIndexGL);
3223 
3224         ASSERT(colorRenderTarget->hasResolveAttachment());
3225         ASSERT(colorRenderTarget->isImageTransient());
3226 
3227         colorSrc[colorIndexVk.get()] = &colorRenderTarget->getResolveImageForRenderPass();
3228         ANGLE_TRY(
3229             colorRenderTarget->getResolveImageView(contextVk, &colorSrcView[colorIndexVk.get()]));
3230 
3231         ++colorIndexVk;
3232     }
3233 
3234     if (params.unresolveDepth || params.unresolveStencil)
3235     {
3236         RenderTargetVk *depthStencilRenderTarget = framebuffer->getDepthStencilRenderTarget();
3237 
3238         ASSERT(depthStencilRenderTarget->hasResolveAttachment());
3239         ASSERT(depthStencilRenderTarget->isImageTransient());
3240 
3241         vk::ImageHelper *depthStencilSrc =
3242             &depthStencilRenderTarget->getResolveImageForRenderPass();
3243 
3244         // The resolved depth/stencil image is necessarily single-sampled.
3245         ASSERT(depthStencilSrc->getSamples() == 1);
3246         gl::TextureType textureType = vk::Get2DTextureType(depthStencilSrc->getLayerCount(), 1);
3247 
3248         const vk::LevelIndex levelIndex =
3249             depthStencilSrc->toVkLevel(depthStencilRenderTarget->getLevelIndex());
3250         const uint32_t layerIndex = depthStencilRenderTarget->getLayerIndex();
3251 
3252         if (params.unresolveDepth)
3253         {
3254             ANGLE_TRY(depthStencilSrc->initLayerImageView(
3255                 contextVk, textureType, VK_IMAGE_ASPECT_DEPTH_BIT, gl::SwizzleState(),
3256                 &depthView.get(), levelIndex, 1, layerIndex, 1, gl::SrgbWriteControlMode::Default));
3257             depthSrcView = &depthView.get();
3258         }
3259 
3260         if (params.unresolveStencil)
3261         {
3262             ANGLE_TRY(depthStencilSrc->initLayerImageView(
3263                 contextVk, textureType, VK_IMAGE_ASPECT_STENCIL_BIT, gl::SwizzleState(),
3264                 &stencilView.get(), levelIndex, 1, layerIndex, 1,
3265                 gl::SrgbWriteControlMode::Default));
3266             stencilSrcView = &stencilView.get();
3267         }
3268     }
3269 
3270     const uint32_t colorAttachmentCount = colorIndexVk.get();
3271     const uint32_t depthStencilBindingCount =
3272         (params.unresolveDepth ? 1 : 0) + (params.unresolveStencil ? 1 : 0);
3273     const uint32_t totalBindingCount = colorAttachmentCount + depthStencilBindingCount;
3274 
3275     ASSERT(totalBindingCount > 0);
3276     const Function function = static_cast<Function>(
3277         static_cast<uint32_t>(Function::Unresolve1Attachment) + totalBindingCount - 1);
3278 
3279     ANGLE_TRY(ensureUnresolveResourcesInitialized(contextVk, function, totalBindingCount));
3280 
3281     vk::GraphicsPipelineDesc pipelineDesc;
3282     pipelineDesc.initDefaults(contextVk);
3283     pipelineDesc.setCullMode(VK_CULL_MODE_NONE);
3284     pipelineDesc.setRasterizationSamples(framebuffer->getSamples());
3285     pipelineDesc.setRenderPassDesc(framebuffer->getRenderPassDesc());
3286     pipelineDesc.setDepthTestEnabled(params.unresolveDepth);
3287     pipelineDesc.setDepthWriteEnabled(params.unresolveDepth);
3288     pipelineDesc.setDepthFunc(VK_COMPARE_OP_ALWAYS);
3289 
3290     if (params.unresolveStencil)
3291     {
3292         SetStencilForShaderExport(contextVk, &pipelineDesc);
3293     }
3294 
3295     vk::CommandBuffer *commandBuffer =
3296         &contextVk->getStartedRenderPassCommands().getCommandBuffer();
3297 
3298     VkViewport viewport;
3299     gl::Rectangle completeRenderArea = framebuffer->getRotatedCompleteRenderArea(contextVk);
3300     bool invertViewport              = contextVk->isViewportFlipEnabledForDrawFBO();
3301     bool clipSpaceOriginUpperLeft =
3302         contextVk->getState().getClipSpaceOrigin() == gl::ClipSpaceOrigin::UpperLeft;
3303     gl_vk::GetViewport(completeRenderArea, 0.0f, 1.0f, invertViewport, clipSpaceOriginUpperLeft,
3304                        completeRenderArea.height, &viewport);
3305     commandBuffer->setViewport(0, 1, &viewport);
3306 
3307     VkRect2D scissor = gl_vk::GetRect(completeRenderArea);
3308     commandBuffer->setScissor(0, 1, &scissor);
3309 
3310     contextVk->invalidateViewportAndScissor();
3311 
3312     VkDescriptorSet descriptorSet;
3313     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
3314     ANGLE_TRY(allocateDescriptorSet(contextVk, function, &descriptorPoolBinding, &descriptorSet));
3315 
3316     vk::FramebufferAttachmentArray<VkDescriptorImageInfo> inputImageInfo = {};
3317     for (uint32_t attachmentIndex = 0; attachmentIndex < colorAttachmentCount; ++attachmentIndex)
3318     {
3319         inputImageInfo[attachmentIndex].imageView   = colorSrcView[attachmentIndex]->getHandle();
3320         inputImageInfo[attachmentIndex].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3321     }
3322 
3323     uint32_t depthStencilBindingIndex = colorAttachmentCount;
3324     if (params.unresolveDepth)
3325     {
3326         inputImageInfo[depthStencilBindingIndex].imageView = depthSrcView->getHandle();
3327         inputImageInfo[depthStencilBindingIndex].imageLayout =
3328             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3329         ++depthStencilBindingIndex;
3330     }
3331     if (params.unresolveStencil)
3332     {
3333         inputImageInfo[depthStencilBindingIndex].imageView = stencilSrcView->getHandle();
3334         inputImageInfo[depthStencilBindingIndex].imageLayout =
3335             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3336     }
3337 
3338     VkWriteDescriptorSet writeInfo = {};
3339     writeInfo.sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3340     writeInfo.dstSet               = descriptorSet;
3341     writeInfo.dstBinding           = 0;
3342     writeInfo.descriptorCount      = totalBindingCount;
3343     writeInfo.descriptorType       = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
3344     writeInfo.pImageInfo           = inputImageInfo.data();
3345 
3346     vkUpdateDescriptorSets(contextVk->getDevice(), 1, &writeInfo, 0, nullptr);
3347 
3348     gl::DrawBuffersArray<UnresolveColorAttachmentType> colorAttachmentTypes;
3349     uint32_t flags = GetUnresolveFlags(colorAttachmentCount, colorSrc, params.unresolveDepth,
3350                                        params.unresolveStencil, &colorAttachmentTypes);
3351 
3352     vk::ShaderLibrary &shaderLibrary                    = contextVk->getShaderLibrary();
3353     vk::RefCounted<vk::ShaderAndSerial> *vertexShader   = nullptr;
3354     vk::RefCounted<vk::ShaderAndSerial> *fragmentShader = &mUnresolveFragShaders[flags];
3355     ANGLE_TRY(shaderLibrary.getFullScreenTri_vert(contextVk, 0, &vertexShader));
3356     ANGLE_TRY(GetUnresolveFrag(contextVk, colorAttachmentCount, colorAttachmentTypes,
3357                                params.unresolveDepth, params.unresolveStencil, fragmentShader));
3358 
3359     ANGLE_TRY(setupProgram(contextVk, function, fragmentShader, vertexShader,
3360                            &mUnresolvePrograms[flags], &pipelineDesc, descriptorSet, nullptr, 0,
3361                            commandBuffer));
3362     // This draw call is made before ContextVk gets a chance to start the occlusion query.  As such,
3363     // occlusion queries are not enabled.
3364     commandBuffer->draw(3, 0);
3365 
3366     // Release temporary views
3367     vk::ImageView depthViewObject   = depthView.release();
3368     vk::ImageView stencilViewObject = stencilView.release();
3369 
3370     contextVk->addGarbage(&depthViewObject);
3371     contextVk->addGarbage(&stencilViewObject);
3372 
3373     return angle::Result::Continue;
3374 }
3375 
cullOverlayWidgets(ContextVk * contextVk,vk::BufferHelper * enabledWidgetsBuffer,vk::ImageHelper * dst,const vk::ImageView * destView,const OverlayCullParameters & params)3376 angle::Result UtilsVk::cullOverlayWidgets(ContextVk *contextVk,
3377                                           vk::BufferHelper *enabledWidgetsBuffer,
3378                                           vk::ImageHelper *dst,
3379                                           const vk::ImageView *destView,
3380                                           const OverlayCullParameters &params)
3381 {
3382     ANGLE_TRY(ensureOverlayCullResourcesInitialized(contextVk));
3383 
3384     ASSERT(params.subgroupSize[0] == 8 &&
3385            (params.subgroupSize[1] == 8 || params.subgroupSize[1] == 4));
3386     uint32_t flags =
3387         params.subgroupSize[1] == 8 ? OverlayCull_comp::kIs8x8 : OverlayCull_comp::kIs8x4;
3388     if (params.supportsSubgroupBallot)
3389     {
3390         flags |= OverlayCull_comp::kSupportsBallot;
3391     }
3392     else if (params.supportsSubgroupBallot)
3393     {
3394         flags |= OverlayCull_comp::kSupportsArithmetic;
3395     }
3396     else
3397     {
3398         flags |= OverlayCull_comp::kSupportsNone;
3399     }
3400 
3401     VkDescriptorSet descriptorSet;
3402     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
3403     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayCull, &descriptorPoolBinding,
3404                                     &descriptorSet));
3405 
3406     ASSERT(dst->getLevelCount() == 1 && dst->getLayerCount() == 1 &&
3407            dst->getFirstAllocatedLevel() == gl::LevelIndex(0));
3408 
3409     vk::CommandBufferAccess access;
3410     access.onBufferComputeShaderRead(enabledWidgetsBuffer);
3411     access.onImageComputeShaderWrite(gl::LevelIndex(0), 1, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, dst);
3412 
3413     vk::CommandBuffer *commandBuffer;
3414     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
3415 
3416     VkDescriptorImageInfo imageInfo = {};
3417     imageInfo.imageView             = destView->getHandle();
3418     imageInfo.imageLayout           = dst->getCurrentLayout();
3419 
3420     VkDescriptorBufferInfo bufferInfo = {};
3421     bufferInfo.buffer                 = enabledWidgetsBuffer->getBuffer().getHandle();
3422     bufferInfo.offset                 = 0;
3423     bufferInfo.range                  = VK_WHOLE_SIZE;
3424 
3425     VkWriteDescriptorSet writeInfos[2] = {};
3426     writeInfos[0].sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3427     writeInfos[0].dstSet               = descriptorSet;
3428     writeInfos[0].dstBinding           = kOverlayCullCulledWidgetsBinding;
3429     writeInfos[0].descriptorCount      = 1;
3430     writeInfos[0].descriptorType       = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3431     writeInfos[0].pImageInfo           = &imageInfo;
3432 
3433     writeInfos[1].sType           = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3434     writeInfos[1].dstSet          = descriptorSet;
3435     writeInfos[1].dstBinding      = kOverlayCullWidgetCoordsBinding;
3436     writeInfos[1].descriptorCount = 1;
3437     writeInfos[1].descriptorType  = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3438     writeInfos[1].pBufferInfo     = &bufferInfo;
3439 
3440     vkUpdateDescriptorSets(contextVk->getDevice(), 2, writeInfos, 0, nullptr);
3441 
3442     vk::RefCounted<vk::ShaderAndSerial> *shader = nullptr;
3443     ANGLE_TRY(contextVk->getShaderLibrary().getOverlayCull_comp(contextVk, flags, &shader));
3444 
3445     ANGLE_TRY(setupProgram(contextVk, Function::OverlayCull, shader, nullptr,
3446                            &mOverlayCullPrograms[flags], nullptr, descriptorSet, nullptr, 0,
3447                            commandBuffer));
3448 
3449     commandBuffer->dispatch(dst->getExtents().width, dst->getExtents().height, 1);
3450     descriptorPoolBinding.reset();
3451 
3452     return angle::Result::Continue;
3453 }
3454 
drawOverlay(ContextVk * contextVk,vk::BufferHelper * textWidgetsBuffer,vk::BufferHelper * graphWidgetsBuffer,vk::ImageHelper * font,const vk::ImageView * fontView,vk::ImageHelper * culledWidgets,const vk::ImageView * culledWidgetsView,vk::ImageHelper * dst,const vk::ImageView * destView,const OverlayDrawParameters & params)3455 angle::Result UtilsVk::drawOverlay(ContextVk *contextVk,
3456                                    vk::BufferHelper *textWidgetsBuffer,
3457                                    vk::BufferHelper *graphWidgetsBuffer,
3458                                    vk::ImageHelper *font,
3459                                    const vk::ImageView *fontView,
3460                                    vk::ImageHelper *culledWidgets,
3461                                    const vk::ImageView *culledWidgetsView,
3462                                    vk::ImageHelper *dst,
3463                                    const vk::ImageView *destView,
3464                                    const OverlayDrawParameters &params)
3465 {
3466     ANGLE_TRY(ensureOverlayDrawResourcesInitialized(contextVk));
3467 
3468     OverlayDrawShaderParams shaderParams;
3469     shaderParams.outputSize[0] = dst->getExtents().width;
3470     shaderParams.outputSize[1] = dst->getExtents().height;
3471     shaderParams.rotateXY      = params.rotateXY;
3472 
3473     ASSERT(params.subgroupSize[0] == 8 &&
3474            (params.subgroupSize[1] == 8 || params.subgroupSize[1] == 4));
3475     uint32_t flags =
3476         params.subgroupSize[1] == 8 ? OverlayDraw_comp::kIs8x8 : OverlayDraw_comp::kIs8x4;
3477 
3478     VkDescriptorSet descriptorSet;
3479     vk::RefCountedDescriptorPoolBinding descriptorPoolBinding;
3480     ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayDraw, &descriptorPoolBinding,
3481                                     &descriptorSet));
3482 
3483     ASSERT(dst->getLevelCount() == 1 && dst->getLayerCount() == 1 &&
3484            dst->getFirstAllocatedLevel() == gl::LevelIndex(0));
3485 
3486     vk::CommandBufferAccess access;
3487     access.onImageComputeShaderWrite(gl::LevelIndex(0), 1, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, dst);
3488     access.onImageComputeShaderRead(VK_IMAGE_ASPECT_COLOR_BIT, culledWidgets);
3489     access.onImageComputeShaderRead(VK_IMAGE_ASPECT_COLOR_BIT, font);
3490     access.onBufferComputeShaderRead(textWidgetsBuffer);
3491     access.onBufferComputeShaderRead(graphWidgetsBuffer);
3492 
3493     vk::CommandBuffer *commandBuffer;
3494     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
3495 
3496     VkDescriptorImageInfo imageInfos[3] = {};
3497     imageInfos[0].imageView             = destView->getHandle();
3498     imageInfos[0].imageLayout           = dst->getCurrentLayout();
3499 
3500     imageInfos[1].imageView   = culledWidgetsView->getHandle();
3501     imageInfos[1].imageLayout = culledWidgets->getCurrentLayout();
3502 
3503     imageInfos[2].imageView   = fontView->getHandle();
3504     imageInfos[2].imageLayout = font->getCurrentLayout();
3505 
3506     VkDescriptorBufferInfo bufferInfos[2] = {};
3507     bufferInfos[0].buffer                 = textWidgetsBuffer->getBuffer().getHandle();
3508     bufferInfos[0].offset                 = 0;
3509     bufferInfos[0].range                  = VK_WHOLE_SIZE;
3510 
3511     bufferInfos[1].buffer = graphWidgetsBuffer->getBuffer().getHandle();
3512     bufferInfos[1].offset = 0;
3513     bufferInfos[1].range  = VK_WHOLE_SIZE;
3514 
3515     VkWriteDescriptorSet writeInfos[5] = {};
3516     writeInfos[0].sType                = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3517     writeInfos[0].dstSet               = descriptorSet;
3518     writeInfos[0].dstBinding           = kOverlayDrawOutputBinding;
3519     writeInfos[0].descriptorCount      = 1;
3520     writeInfos[0].descriptorType       = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
3521     writeInfos[0].pImageInfo           = &imageInfos[0];
3522 
3523     writeInfos[1].sType           = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3524     writeInfos[1].dstSet          = descriptorSet;
3525     writeInfos[1].dstBinding      = kOverlayDrawCulledWidgetsBinding;
3526     writeInfos[1].descriptorCount = 1;
3527     writeInfos[1].descriptorType  = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3528     writeInfos[1].pImageInfo      = &imageInfos[1];
3529 
3530     writeInfos[2].sType           = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3531     writeInfos[2].dstSet          = descriptorSet;
3532     writeInfos[2].dstBinding      = kOverlayDrawFontBinding;
3533     writeInfos[2].descriptorCount = 1;
3534     writeInfos[2].descriptorType  = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
3535     writeInfos[2].pImageInfo      = &imageInfos[2];
3536 
3537     writeInfos[3].sType           = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
3538     writeInfos[3].dstSet          = descriptorSet;
3539     writeInfos[3].dstBinding      = kOverlayDrawTextWidgetsBinding;
3540     writeInfos[3].descriptorCount = 1;
3541     writeInfos[3].descriptorType  = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3542     writeInfos[3].pBufferInfo     = &bufferInfos[0];
3543 
3544     writeInfos[4]             = writeInfos[3];
3545     writeInfos[4].dstBinding  = kOverlayDrawGraphWidgetsBinding;
3546     writeInfos[4].pBufferInfo = &bufferInfos[1];
3547 
3548     vkUpdateDescriptorSets(contextVk->getDevice(), 5, writeInfos, 0, nullptr);
3549 
3550     vk::RefCounted<vk::ShaderAndSerial> *shader = nullptr;
3551     ANGLE_TRY(contextVk->getShaderLibrary().getOverlayDraw_comp(contextVk, flags, &shader));
3552 
3553     ANGLE_TRY(setupProgram(contextVk, Function::OverlayDraw, shader, nullptr,
3554                            &mOverlayDrawPrograms[flags], nullptr, descriptorSet, &shaderParams,
3555                            sizeof(shaderParams), commandBuffer));
3556 
3557     // Every pixel of culledWidgets corresponds to one workgroup, so we can use that as dispatch
3558     // size.
3559     const VkExtent3D &extents = culledWidgets->getExtents();
3560     commandBuffer->dispatch(extents.width, extents.height, 1);
3561     descriptorPoolBinding.reset();
3562 
3563     return angle::Result::Continue;
3564 }
3565 
allocateDescriptorSet(ContextVk * contextVk,Function function,vk::RefCountedDescriptorPoolBinding * bindingOut,VkDescriptorSet * descriptorSetOut)3566 angle::Result UtilsVk::allocateDescriptorSet(ContextVk *contextVk,
3567                                              Function function,
3568                                              vk::RefCountedDescriptorPoolBinding *bindingOut,
3569                                              VkDescriptorSet *descriptorSetOut)
3570 {
3571     ANGLE_TRY(mDescriptorPools[function].allocateSets(
3572         contextVk, mDescriptorSetLayouts[function][DescriptorSetIndex::Internal].get().ptr(), 1,
3573         bindingOut, descriptorSetOut));
3574 
3575     mPerfCounters.descriptorSetsAllocated++;
3576 
3577     return angle::Result::Continue;
3578 }
3579 
ClearFramebufferParameters()3580 UtilsVk::ClearFramebufferParameters::ClearFramebufferParameters()
3581     : clearColor(false),
3582       clearDepth(false),
3583       clearStencil(false),
3584       stencilMask(0),
3585       colorMaskFlags(0),
3586       colorAttachmentIndexGL(0),
3587       colorFormat(nullptr),
3588       colorClearValue{},
3589       depthStencilClearValue{}
3590 {}
3591 
3592 // Requires that trace is enabled to see the output, which is supported with is_debug=true
outputCumulativePerfCounters()3593 void UtilsVk::outputCumulativePerfCounters()
3594 {
3595     if (!vk::kOutputCumulativePerfCounters)
3596     {
3597         return;
3598     }
3599 
3600     INFO() << "Utils Descriptor Set Allocations: "
3601            << mCumulativePerfCounters.descriptorSetsAllocated;
3602 }
3603 
getAndResetObjectPerfCounters()3604 InternalShaderPerfCounters UtilsVk::getAndResetObjectPerfCounters()
3605 {
3606     mCumulativePerfCounters.descriptorSetsAllocated += mPerfCounters.descriptorSetsAllocated;
3607 
3608     InternalShaderPerfCounters counters   = mPerfCounters;
3609     mPerfCounters.descriptorSetsAllocated = 0;
3610     return counters;
3611 }
3612 }  // namespace rx
3613