• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/gpu/graphite/vk/VulkanGraphicsPipeline.h"
9 
10 #include "include/gpu/ShaderErrorHandler.h"
11 #include "include/gpu/graphite/TextureInfo.h"
12 #include "include/private/base/SkTArray.h"
13 #include "src/core/SkSLTypeShared.h"
14 #include "src/core/SkTraceEvent.h"
15 #include "src/gpu/PipelineUtils.h"
16 #include "src/gpu/graphite/Attribute.h"
17 #include "src/gpu/graphite/ContextUtils.h"
18 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
19 #include "src/gpu/graphite/Log.h"
20 #include "src/gpu/graphite/RenderPassDesc.h"
21 #include "src/gpu/graphite/RendererProvider.h"
22 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
23 #include "src/gpu/graphite/vk/VulkanCaps.h"
24 #include "src/gpu/graphite/vk/VulkanGraphicsPipeline.h"
25 #include "src/gpu/graphite/vk/VulkanRenderPass.h"
26 #include "src/gpu/graphite/vk/VulkanSharedContext.h"
27 #include "src/gpu/vk/VulkanUtilsPriv.h"
28 #include "src/sksl/SkSLProgramKind.h"
29 #include "src/sksl/SkSLProgramSettings.h"
30 #include "src/sksl/ir/SkSLProgram.h"
31 
32 namespace skgpu::graphite {
33 
attrib_type_to_vkformat(VertexAttribType type)34 static inline VkFormat attrib_type_to_vkformat(VertexAttribType type) {
35     switch (type) {
36         case VertexAttribType::kFloat:
37             return VK_FORMAT_R32_SFLOAT;
38         case VertexAttribType::kFloat2:
39             return VK_FORMAT_R32G32_SFLOAT;
40         case VertexAttribType::kFloat3:
41             return VK_FORMAT_R32G32B32_SFLOAT;
42         case VertexAttribType::kFloat4:
43             return VK_FORMAT_R32G32B32A32_SFLOAT;
44         case VertexAttribType::kHalf:
45             return VK_FORMAT_R16_SFLOAT;
46         case VertexAttribType::kHalf2:
47             return VK_FORMAT_R16G16_SFLOAT;
48         case VertexAttribType::kHalf4:
49             return VK_FORMAT_R16G16B16A16_SFLOAT;
50         case VertexAttribType::kInt2:
51             return VK_FORMAT_R32G32_SINT;
52         case VertexAttribType::kInt3:
53             return VK_FORMAT_R32G32B32_SINT;
54         case VertexAttribType::kInt4:
55             return VK_FORMAT_R32G32B32A32_SINT;
56         case VertexAttribType::kByte:
57             return VK_FORMAT_R8_SINT;
58         case VertexAttribType::kByte2:
59             return VK_FORMAT_R8G8_SINT;
60         case VertexAttribType::kByte4:
61             return VK_FORMAT_R8G8B8A8_SINT;
62         case VertexAttribType::kUByte:
63             return VK_FORMAT_R8_UINT;
64         case VertexAttribType::kUByte2:
65             return VK_FORMAT_R8G8_UINT;
66         case VertexAttribType::kUByte4:
67             return VK_FORMAT_R8G8B8A8_UINT;
68         case VertexAttribType::kUByte_norm:
69             return VK_FORMAT_R8_UNORM;
70         case VertexAttribType::kUByte4_norm:
71             return VK_FORMAT_R8G8B8A8_UNORM;
72         case VertexAttribType::kShort2:
73             return VK_FORMAT_R16G16_SINT;
74         case VertexAttribType::kShort4:
75             return VK_FORMAT_R16G16B16A16_SINT;
76         case VertexAttribType::kUShort2:
77             return VK_FORMAT_R16G16_UINT;
78         case VertexAttribType::kUShort2_norm:
79             return VK_FORMAT_R16G16_UNORM;
80         case VertexAttribType::kInt:
81             return VK_FORMAT_R32_SINT;
82         case VertexAttribType::kUInt:
83             return VK_FORMAT_R32_UINT;
84         case VertexAttribType::kUShort_norm:
85             return VK_FORMAT_R16_UNORM;
86         case VertexAttribType::kUShort4_norm:
87             return VK_FORMAT_R16G16B16A16_UNORM;
88     }
89     SK_ABORT("Unknown vertex attrib type");
90 }
91 
setup_vertex_input_state(const SkSpan<const Attribute> & vertexAttrs,const SkSpan<const Attribute> & instanceAttrs,VkPipelineVertexInputStateCreateInfo * vertexInputInfo,skia_private::STArray<2,VkVertexInputBindingDescription,true> * bindingDescs,skia_private::STArray<16,VkVertexInputAttributeDescription> * attributeDescs)92 static void setup_vertex_input_state(
93         const SkSpan<const Attribute>& vertexAttrs,
94         const SkSpan<const Attribute>& instanceAttrs,
95         VkPipelineVertexInputStateCreateInfo* vertexInputInfo,
96         skia_private::STArray<2, VkVertexInputBindingDescription, true>* bindingDescs,
97         skia_private::STArray<16, VkVertexInputAttributeDescription>* attributeDescs) {
98     // Setup attribute & binding descriptions
99     int attribIndex = 0;
100     size_t vertexAttributeOffset = 0;
101     for (auto attrib : vertexAttrs) {
102         VkVertexInputAttributeDescription vkAttrib;
103         vkAttrib.location = attribIndex++;
104         vkAttrib.binding = VulkanGraphicsPipeline::kVertexBufferIndex;
105         vkAttrib.format = attrib_type_to_vkformat(attrib.cpuType());
106         vkAttrib.offset = vertexAttributeOffset;
107         vertexAttributeOffset += attrib.sizeAlign4();
108         attributeDescs->push_back(vkAttrib);
109     }
110 
111     size_t instanceAttributeOffset = 0;
112     for (auto attrib : instanceAttrs) {
113         VkVertexInputAttributeDescription vkAttrib;
114         vkAttrib.location = attribIndex++;
115         vkAttrib.binding = VulkanGraphicsPipeline::kInstanceBufferIndex;
116         vkAttrib.format = attrib_type_to_vkformat(attrib.cpuType());
117         vkAttrib.offset = instanceAttributeOffset;
118         instanceAttributeOffset += attrib.sizeAlign4();
119         attributeDescs->push_back(vkAttrib);
120     }
121 
122     if (bindingDescs && !vertexAttrs.empty()) {
123         bindingDescs->push_back() = {
124                 VulkanGraphicsPipeline::kVertexBufferIndex,
125                 (uint32_t) vertexAttributeOffset,
126                 VK_VERTEX_INPUT_RATE_VERTEX
127         };
128     }
129     if (bindingDescs && !instanceAttrs.empty()) {
130         bindingDescs->push_back() = {
131                 VulkanGraphicsPipeline::kInstanceBufferIndex,
132                 (uint32_t) instanceAttributeOffset,
133                 VK_VERTEX_INPUT_RATE_INSTANCE
134         };
135     }
136 
137     memset(vertexInputInfo, 0, sizeof(VkPipelineVertexInputStateCreateInfo));
138     vertexInputInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
139     vertexInputInfo->pNext = nullptr;
140     vertexInputInfo->flags = 0;
141     vertexInputInfo->vertexBindingDescriptionCount = bindingDescs ? bindingDescs->size() : 0;
142     vertexInputInfo->pVertexBindingDescriptions =
143             bindingDescs && !bindingDescs->empty() ? bindingDescs->begin() : VK_NULL_HANDLE;
144     vertexInputInfo->vertexAttributeDescriptionCount = attributeDescs ? attributeDescs->size() : 0;
145     vertexInputInfo->pVertexAttributeDescriptions =
146             attributeDescs && !attributeDescs->empty() ? attributeDescs->begin() : VK_NULL_HANDLE;
147 }
148 
primitive_type_to_vk_topology(PrimitiveType primitiveType)149 static VkPrimitiveTopology primitive_type_to_vk_topology(PrimitiveType primitiveType) {
150     switch (primitiveType) {
151         case PrimitiveType::kTriangles:
152             return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
153         case PrimitiveType::kTriangleStrip:
154             return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
155         case PrimitiveType::kPoints:
156             return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
157     }
158     SkUNREACHABLE;
159 }
160 
setup_input_assembly_state(PrimitiveType primitiveType,VkPipelineInputAssemblyStateCreateInfo * inputAssemblyInfo)161 static void setup_input_assembly_state(PrimitiveType primitiveType,
162                                        VkPipelineInputAssemblyStateCreateInfo* inputAssemblyInfo) {
163     memset(inputAssemblyInfo, 0, sizeof(VkPipelineInputAssemblyStateCreateInfo));
164     inputAssemblyInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
165     inputAssemblyInfo->pNext = nullptr;
166     inputAssemblyInfo->flags = 0;
167     inputAssemblyInfo->primitiveRestartEnable = false;
168     inputAssemblyInfo->topology = primitive_type_to_vk_topology(primitiveType);
169 }
170 
stencil_op_to_vk_stencil_op(StencilOp op)171 static VkStencilOp stencil_op_to_vk_stencil_op(StencilOp op) {
172     static const VkStencilOp gTable[] = {
173         VK_STENCIL_OP_KEEP,                 // kKeep
174         VK_STENCIL_OP_ZERO,                 // kZero
175         VK_STENCIL_OP_REPLACE,              // kReplace
176         VK_STENCIL_OP_INVERT,               // kInvert
177         VK_STENCIL_OP_INCREMENT_AND_WRAP,   // kIncWrap
178         VK_STENCIL_OP_DECREMENT_AND_WRAP,   // kDecWrap
179         VK_STENCIL_OP_INCREMENT_AND_CLAMP,  // kIncClamp
180         VK_STENCIL_OP_DECREMENT_AND_CLAMP,  // kDecClamp
181     };
182     static_assert(std::size(gTable) == kStencilOpCount);
183     static_assert(0 == (int)StencilOp::kKeep);
184     static_assert(1 == (int)StencilOp::kZero);
185     static_assert(2 == (int)StencilOp::kReplace);
186     static_assert(3 == (int)StencilOp::kInvert);
187     static_assert(4 == (int)StencilOp::kIncWrap);
188     static_assert(5 == (int)StencilOp::kDecWrap);
189     static_assert(6 == (int)StencilOp::kIncClamp);
190     static_assert(7 == (int)StencilOp::kDecClamp);
191     SkASSERT(op < (StencilOp)kStencilOpCount);
192     return gTable[(int)op];
193 }
194 
compare_op_to_vk_compare_op(CompareOp op)195 static VkCompareOp compare_op_to_vk_compare_op(CompareOp op) {
196     static const VkCompareOp gTable[] = {
197         VK_COMPARE_OP_ALWAYS,              // kAlways
198         VK_COMPARE_OP_NEVER,               // kNever
199         VK_COMPARE_OP_GREATER,             // kGreater
200         VK_COMPARE_OP_GREATER_OR_EQUAL,    // kGEqual
201         VK_COMPARE_OP_LESS,                // kLess
202         VK_COMPARE_OP_LESS_OR_EQUAL,       // kLEqual
203         VK_COMPARE_OP_EQUAL,               // kEqual
204         VK_COMPARE_OP_NOT_EQUAL,           // kNotEqual
205     };
206     static_assert(std::size(gTable) == kCompareOpCount);
207     static_assert(0 == (int)CompareOp::kAlways);
208     static_assert(1 == (int)CompareOp::kNever);
209     static_assert(2 == (int)CompareOp::kGreater);
210     static_assert(3 == (int)CompareOp::kGEqual);
211     static_assert(4 == (int)CompareOp::kLess);
212     static_assert(5 == (int)CompareOp::kLEqual);
213     static_assert(6 == (int)CompareOp::kEqual);
214     static_assert(7 == (int)CompareOp::kNotEqual);
215     SkASSERT(op < (CompareOp)kCompareOpCount);
216 
217     return gTable[(int)op];
218 }
219 
setup_stencil_op_state(VkStencilOpState * opState,const DepthStencilSettings::Face & face,uint32_t referenceValue)220 static void setup_stencil_op_state(VkStencilOpState* opState,
221                                    const DepthStencilSettings::Face& face,
222                                    uint32_t referenceValue) {
223     opState->failOp = stencil_op_to_vk_stencil_op(face.fStencilFailOp);
224     opState->passOp = stencil_op_to_vk_stencil_op(face.fDepthStencilPassOp);
225     opState->depthFailOp = stencil_op_to_vk_stencil_op(face.fDepthFailOp);
226     opState->compareOp = compare_op_to_vk_compare_op(face.fCompareOp);
227     opState->compareMask = face.fReadMask; // TODO - check this.
228     opState->writeMask = face.fWriteMask;
229     opState->reference = referenceValue;
230 }
231 
setup_depth_stencil_state(const DepthStencilSettings & stencilSettings,VkPipelineDepthStencilStateCreateInfo * stencilInfo)232 static void setup_depth_stencil_state(const DepthStencilSettings& stencilSettings,
233                                       VkPipelineDepthStencilStateCreateInfo* stencilInfo) {
234     SkASSERT(stencilSettings.fDepthTestEnabled ||
235              stencilSettings.fDepthCompareOp == CompareOp::kAlways);
236 
237     memset(stencilInfo, 0, sizeof(VkPipelineDepthStencilStateCreateInfo));
238     stencilInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
239     stencilInfo->pNext = nullptr;
240     stencilInfo->flags = 0;
241     stencilInfo->depthTestEnable = stencilSettings.fDepthTestEnabled;
242     stencilInfo->depthWriteEnable = stencilSettings.fDepthWriteEnabled;
243     stencilInfo->depthCompareOp = compare_op_to_vk_compare_op(stencilSettings.fDepthCompareOp);
244     stencilInfo->depthBoundsTestEnable = VK_FALSE; // Default value TODO - Confirm
245     stencilInfo->stencilTestEnable = stencilSettings.fStencilTestEnabled;
246     if (stencilSettings.fStencilTestEnabled) {
247         setup_stencil_op_state(&stencilInfo->front,
248                                stencilSettings.fFrontStencil,
249                                stencilSettings.fStencilReferenceValue);
250         setup_stencil_op_state(&stencilInfo->back,
251                                stencilSettings.fBackStencil,
252                                stencilSettings.fStencilReferenceValue);
253     }
254     stencilInfo->minDepthBounds = 0.0f;
255     stencilInfo->maxDepthBounds = 1.0f;
256 }
257 
setup_viewport_scissor_state(VkPipelineViewportStateCreateInfo * viewportInfo)258 static void setup_viewport_scissor_state(VkPipelineViewportStateCreateInfo* viewportInfo) {
259     memset(viewportInfo, 0, sizeof(VkPipelineViewportStateCreateInfo));
260     viewportInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
261     viewportInfo->pNext = nullptr;
262     viewportInfo->flags = 0;
263 
264     viewportInfo->viewportCount = 1;
265     viewportInfo->pViewports = nullptr; // This is set dynamically with a draw pass command
266 
267     viewportInfo->scissorCount = 1;
268     viewportInfo->pScissors = nullptr; // This is set dynamically with a draw pass command
269 
270     SkASSERT(viewportInfo->viewportCount == viewportInfo->scissorCount);
271 }
272 
setup_multisample_state(int numSamples,VkPipelineMultisampleStateCreateInfo * multisampleInfo)273 static void setup_multisample_state(int numSamples,
274                                     VkPipelineMultisampleStateCreateInfo* multisampleInfo) {
275     memset(multisampleInfo, 0, sizeof(VkPipelineMultisampleStateCreateInfo));
276     multisampleInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
277     multisampleInfo->pNext = nullptr;
278     multisampleInfo->flags = 0;
279     SkAssertResult(skgpu::SampleCountToVkSampleCount(numSamples,
280                                                      &multisampleInfo->rasterizationSamples));
281     multisampleInfo->sampleShadingEnable = VK_FALSE;
282     multisampleInfo->minSampleShading = 0.0f;
283     multisampleInfo->pSampleMask = nullptr;
284     multisampleInfo->alphaToCoverageEnable = VK_FALSE;
285     multisampleInfo->alphaToOneEnable = VK_FALSE;
286 }
287 
blend_coeff_to_vk_blend(skgpu::BlendCoeff coeff)288 static VkBlendFactor blend_coeff_to_vk_blend(skgpu::BlendCoeff coeff) {
289     switch (coeff) {
290         case skgpu::BlendCoeff::kZero:
291             return VK_BLEND_FACTOR_ZERO;
292         case skgpu::BlendCoeff::kOne:
293             return VK_BLEND_FACTOR_ONE;
294         case skgpu::BlendCoeff::kSC:
295             return VK_BLEND_FACTOR_SRC_COLOR;
296         case skgpu::BlendCoeff::kISC:
297             return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
298         case skgpu::BlendCoeff::kDC:
299             return VK_BLEND_FACTOR_DST_COLOR;
300         case skgpu::BlendCoeff::kIDC:
301             return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
302         case skgpu::BlendCoeff::kSA:
303             return VK_BLEND_FACTOR_SRC_ALPHA;
304         case skgpu::BlendCoeff::kISA:
305             return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
306         case skgpu::BlendCoeff::kDA:
307             return VK_BLEND_FACTOR_DST_ALPHA;
308         case skgpu::BlendCoeff::kIDA:
309             return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
310         case skgpu::BlendCoeff::kConstC:
311             return VK_BLEND_FACTOR_CONSTANT_COLOR;
312         case skgpu::BlendCoeff::kIConstC:
313             return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
314         case skgpu::BlendCoeff::kS2C:
315             return VK_BLEND_FACTOR_SRC1_COLOR;
316         case skgpu::BlendCoeff::kIS2C:
317             return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
318         case skgpu::BlendCoeff::kS2A:
319             return VK_BLEND_FACTOR_SRC1_ALPHA;
320         case skgpu::BlendCoeff::kIS2A:
321             return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
322         case skgpu::BlendCoeff::kIllegal:
323             return VK_BLEND_FACTOR_ZERO;
324     }
325     SkUNREACHABLE;
326 }
327 
blend_equation_to_vk_blend_op(skgpu::BlendEquation equation)328 static VkBlendOp blend_equation_to_vk_blend_op(skgpu::BlendEquation equation) {
329     static const VkBlendOp gTable[] = {
330         // Basic blend ops
331         VK_BLEND_OP_ADD,
332         VK_BLEND_OP_SUBTRACT,
333         VK_BLEND_OP_REVERSE_SUBTRACT,
334 
335         // Advanced blend ops
336         VK_BLEND_OP_SCREEN_EXT,
337         VK_BLEND_OP_OVERLAY_EXT,
338         VK_BLEND_OP_DARKEN_EXT,
339         VK_BLEND_OP_LIGHTEN_EXT,
340         VK_BLEND_OP_COLORDODGE_EXT,
341         VK_BLEND_OP_COLORBURN_EXT,
342         VK_BLEND_OP_HARDLIGHT_EXT,
343         VK_BLEND_OP_SOFTLIGHT_EXT,
344         VK_BLEND_OP_DIFFERENCE_EXT,
345         VK_BLEND_OP_EXCLUSION_EXT,
346         VK_BLEND_OP_MULTIPLY_EXT,
347         VK_BLEND_OP_HSL_HUE_EXT,
348         VK_BLEND_OP_HSL_SATURATION_EXT,
349         VK_BLEND_OP_HSL_COLOR_EXT,
350         VK_BLEND_OP_HSL_LUMINOSITY_EXT,
351 
352         // Illegal.
353         VK_BLEND_OP_ADD,
354     };
355     static_assert(0 == (int)skgpu::BlendEquation::kAdd);
356     static_assert(1 == (int)skgpu::BlendEquation::kSubtract);
357     static_assert(2 == (int)skgpu::BlendEquation::kReverseSubtract);
358     static_assert(3 == (int)skgpu::BlendEquation::kScreen);
359     static_assert(4 == (int)skgpu::BlendEquation::kOverlay);
360     static_assert(5 == (int)skgpu::BlendEquation::kDarken);
361     static_assert(6 == (int)skgpu::BlendEquation::kLighten);
362     static_assert(7 == (int)skgpu::BlendEquation::kColorDodge);
363     static_assert(8 == (int)skgpu::BlendEquation::kColorBurn);
364     static_assert(9 == (int)skgpu::BlendEquation::kHardLight);
365     static_assert(10 == (int)skgpu::BlendEquation::kSoftLight);
366     static_assert(11 == (int)skgpu::BlendEquation::kDifference);
367     static_assert(12 == (int)skgpu::BlendEquation::kExclusion);
368     static_assert(13 == (int)skgpu::BlendEquation::kMultiply);
369     static_assert(14 == (int)skgpu::BlendEquation::kHSLHue);
370     static_assert(15 == (int)skgpu::BlendEquation::kHSLSaturation);
371     static_assert(16 == (int)skgpu::BlendEquation::kHSLColor);
372     static_assert(17 == (int)skgpu::BlendEquation::kHSLLuminosity);
373     static_assert(std::size(gTable) == skgpu::kBlendEquationCnt);
374 
375     SkASSERT((unsigned)equation < skgpu::kBlendEquationCnt);
376     return gTable[(int)equation];
377 }
378 
setup_color_blend_state(const skgpu::BlendInfo & blendInfo,VkPipelineColorBlendStateCreateInfo * colorBlendInfo,VkPipelineColorBlendAttachmentState * attachmentState)379 static void setup_color_blend_state(const skgpu::BlendInfo& blendInfo,
380                                     VkPipelineColorBlendStateCreateInfo* colorBlendInfo,
381                                     VkPipelineColorBlendAttachmentState* attachmentState) {
382     skgpu::BlendEquation equation = blendInfo.fEquation;
383     skgpu::BlendCoeff srcCoeff = blendInfo.fSrcBlend;
384     skgpu::BlendCoeff dstCoeff = blendInfo.fDstBlend;
385     bool blendOff = skgpu::BlendShouldDisable(equation, srcCoeff, dstCoeff);
386 
387     memset(attachmentState, 0, sizeof(VkPipelineColorBlendAttachmentState));
388     attachmentState->blendEnable = !blendOff;
389     if (!blendOff) {
390         attachmentState->srcColorBlendFactor = blend_coeff_to_vk_blend(srcCoeff);
391         attachmentState->dstColorBlendFactor = blend_coeff_to_vk_blend(dstCoeff);
392         attachmentState->colorBlendOp = blend_equation_to_vk_blend_op(equation);
393         attachmentState->srcAlphaBlendFactor = blend_coeff_to_vk_blend(srcCoeff);
394         attachmentState->dstAlphaBlendFactor = blend_coeff_to_vk_blend(dstCoeff);
395         attachmentState->alphaBlendOp = blend_equation_to_vk_blend_op(equation);
396     }
397 
398     if (!blendInfo.fWritesColor) {
399         attachmentState->colorWriteMask = 0;
400     } else {
401         attachmentState->colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
402                                           VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
403     }
404 
405     memset(colorBlendInfo, 0, sizeof(VkPipelineColorBlendStateCreateInfo));
406     colorBlendInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
407     colorBlendInfo->pNext = nullptr;
408     colorBlendInfo->flags = 0;
409     colorBlendInfo->logicOpEnable = VK_FALSE;
410     colorBlendInfo->attachmentCount = 1;
411     colorBlendInfo->pAttachments = attachmentState;
412     // colorBlendInfo->blendConstants is set dynamically
413 }
414 
setup_raster_state(bool isWireframe,VkPipelineRasterizationStateCreateInfo * rasterInfo)415 static void setup_raster_state(bool isWireframe,
416                                VkPipelineRasterizationStateCreateInfo* rasterInfo) {
417     memset(rasterInfo, 0, sizeof(VkPipelineRasterizationStateCreateInfo));
418     rasterInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
419     rasterInfo->pNext = nullptr;
420     rasterInfo->flags = 0;
421     rasterInfo->depthClampEnable = VK_FALSE;
422     rasterInfo->rasterizerDiscardEnable = VK_FALSE;
423     rasterInfo->polygonMode = isWireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
424     rasterInfo->cullMode = VK_CULL_MODE_NONE;
425     rasterInfo->frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
426     rasterInfo->depthBiasEnable = VK_FALSE;
427     rasterInfo->depthBiasConstantFactor = 0.0f;
428     rasterInfo->depthBiasClamp = 0.0f;
429     rasterInfo->depthBiasSlopeFactor = 0.0f;
430     rasterInfo->lineWidth = 1.0f;
431 }
432 
setup_shader_stage_info(VkShaderStageFlagBits stage,VkShaderModule shaderModule,VkPipelineShaderStageCreateInfo * shaderStageInfo)433 static void setup_shader_stage_info(VkShaderStageFlagBits stage,
434                                     VkShaderModule shaderModule,
435                                     VkPipelineShaderStageCreateInfo* shaderStageInfo) {
436     memset(shaderStageInfo, 0, sizeof(VkPipelineShaderStageCreateInfo));
437     shaderStageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
438     shaderStageInfo->pNext = nullptr;
439     shaderStageInfo->flags = 0;
440     shaderStageInfo->stage = stage;
441     shaderStageInfo->module = shaderModule;
442     shaderStageInfo->pName = "main";
443     shaderStageInfo->pSpecializationInfo = nullptr;
444 }
445 
446 
descriptor_data_to_layout(const VulkanSharedContext * sharedContext,const SkSpan<DescriptorData> & descriptorData)447 static VkDescriptorSetLayout descriptor_data_to_layout(const VulkanSharedContext* sharedContext,
448         const SkSpan<DescriptorData>& descriptorData) {
449     if (descriptorData.size() == 0) { return VK_NULL_HANDLE; }
450 
451     VkDescriptorSetLayout setLayout;
452     DescriptorDataToVkDescSetLayout(sharedContext, descriptorData, &setLayout);
453     if (setLayout == VK_NULL_HANDLE) {
454         SKGPU_LOG_E("Failed to create descriptor set layout; pipeline creation will fail.\n");
455         return VK_NULL_HANDLE;
456     }
457     return setLayout;
458 }
459 
destroy_desc_set_layouts(const VulkanSharedContext * sharedContext,skia_private::TArray<VkDescriptorSetLayout> & setLayouts)460 static void destroy_desc_set_layouts(const VulkanSharedContext* sharedContext,
461                                      skia_private::TArray<VkDescriptorSetLayout>& setLayouts) {
462     for (int i = 0; i < setLayouts.size(); i++) {
463         if (setLayouts[i] != VK_NULL_HANDLE) {
464             VULKAN_CALL(sharedContext->interface(),
465             DestroyDescriptorSetLayout(sharedContext->device(),
466                                        setLayouts[i],
467                                        nullptr));
468         }
469     }
470 }
471 
setup_pipeline_layout(const VulkanSharedContext * sharedContext,bool usesIntrinsicConstantUbo,bool hasStepUniforms,int numPaintUniforms,int numTextureSamplers,int numInputAttachments)472 static VkPipelineLayout setup_pipeline_layout(const VulkanSharedContext* sharedContext,
473                                               bool usesIntrinsicConstantUbo,
474                                               bool hasStepUniforms,
475                                               int numPaintUniforms,
476                                               int numTextureSamplers,
477                                               int numInputAttachments) {
478     // Determine descriptor set layouts for this pipeline based upon render pass information.
479     skia_private::STArray<3, VkDescriptorSetLayout> setLayouts;
480 
481     // Determine uniform descriptor set layout
482     skia_private::STArray<VulkanGraphicsPipeline::kNumUniformBuffers, DescriptorData>
483             uniformDescriptors;
484     if (usesIntrinsicConstantUbo) {
485         uniformDescriptors.push_back(VulkanGraphicsPipeline::kIntrinsicUniformBufferDescriptor);
486     }
487     if (hasStepUniforms) {
488         uniformDescriptors.push_back(VulkanGraphicsPipeline::kRenderStepUniformDescriptor);
489     }
490     if (numPaintUniforms > 0) {
491         uniformDescriptors.push_back(VulkanGraphicsPipeline::kPaintUniformDescriptor);
492     }
493 
494     if (!uniformDescriptors.empty()) {
495         VkDescriptorSetLayout uniformSetLayout =
496                 descriptor_data_to_layout(sharedContext, {uniformDescriptors});
497         if (uniformSetLayout == VK_NULL_HANDLE) { return VK_NULL_HANDLE; }
498         setLayouts.push_back(uniformSetLayout);
499     }
500 
501     // Determine input attachment descriptor set layout
502     if (numInputAttachments > 0) {
503         // For now, we only expect to have up to 1 input attachment. We also share that descriptor
504         // set number with uniform descriptors for normal graphics pipeline usages, so verify that
505         // we are not using any uniform descriptors to avoid conflicts.
506         SkASSERT(numInputAttachments == 1 && uniformDescriptors.empty());
507         skia_private::TArray<DescriptorData> inputAttachmentDescriptors(numInputAttachments);
508         inputAttachmentDescriptors.push_back(VulkanGraphicsPipeline::kInputAttachmentDescriptor);
509 
510         VkDescriptorSetLayout inputAttachmentDescSetLayout =
511                 descriptor_data_to_layout(sharedContext, {inputAttachmentDescriptors});
512 
513         if (inputAttachmentDescSetLayout == VK_NULL_HANDLE) {
514             destroy_desc_set_layouts(sharedContext, setLayouts);
515             return VK_NULL_HANDLE;
516         }
517         setLayouts.push_back(inputAttachmentDescSetLayout);
518     }
519 
520     // Determine texture/sampler descriptor set layout
521     if (numTextureSamplers > 0) {
522         skia_private::TArray<DescriptorData> textureSamplerDescs(numTextureSamplers);
523         for (int i = 0; i < numTextureSamplers; i++) {
524             textureSamplerDescs.push_back({DescriptorType::kCombinedTextureSampler,
525                                             /*count=*/1,
526                                             /*bindingIdx=*/i,
527                                             PipelineStageFlags::kFragmentShader});
528         }
529         VkDescriptorSetLayout textureSamplerDescSetLayout =
530                 descriptor_data_to_layout(sharedContext, {textureSamplerDescs});
531 
532         if (textureSamplerDescSetLayout == VK_NULL_HANDLE) {
533             destroy_desc_set_layouts(sharedContext, setLayouts);
534             return VK_NULL_HANDLE;
535         }
536         setLayouts.push_back(textureSamplerDescSetLayout);
537     }
538 
539     // Generate a pipeline layout using the now-populated descriptor set layout array
540     VkPipelineLayoutCreateInfo layoutCreateInfo;
541     memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
542     layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
543     layoutCreateInfo.pNext = nullptr;
544     layoutCreateInfo.flags = 0;
545     layoutCreateInfo.setLayoutCount = setLayouts.size();
546     layoutCreateInfo.pSetLayouts = setLayouts.begin();
547     // TODO: Add support for push constants.
548     layoutCreateInfo.pushConstantRangeCount = 0;
549     layoutCreateInfo.pPushConstantRanges = nullptr;
550 
551     VkResult result;
552     VkPipelineLayout layout;
553     VULKAN_CALL_RESULT(sharedContext,
554                        result,
555                        CreatePipelineLayout(sharedContext->device(),
556                                             &layoutCreateInfo,
557                                             /*const VkAllocationCallbacks*=*/nullptr,
558                                             &layout));
559 
560     // DescriptorSetLayouts can be deleted after the pipeline layout is created.
561     destroy_desc_set_layouts(sharedContext, setLayouts);
562 
563     return result == VK_SUCCESS ? layout : VK_NULL_HANDLE;
564 }
565 
destroy_shader_modules(const VulkanSharedContext * sharedContext,VkShaderModule vsModule,VkShaderModule fsModule)566 static void destroy_shader_modules(const VulkanSharedContext* sharedContext,
567                                    VkShaderModule vsModule,
568                                    VkShaderModule fsModule) {
569     if (vsModule != VK_NULL_HANDLE) {
570         VULKAN_CALL(sharedContext->interface(),
571                     DestroyShaderModule(sharedContext->device(), vsModule, nullptr));
572     }
573     if (fsModule != VK_NULL_HANDLE) {
574         VULKAN_CALL(sharedContext->interface(),
575                     DestroyShaderModule(sharedContext->device(), fsModule, nullptr));
576     }
577 }
578 
setup_dynamic_state(VkPipelineDynamicStateCreateInfo * dynamicInfo,VkDynamicState * dynamicStates)579 static void setup_dynamic_state(VkPipelineDynamicStateCreateInfo* dynamicInfo,
580                                 VkDynamicState* dynamicStates) {
581     memset(dynamicInfo, 0, sizeof(VkPipelineDynamicStateCreateInfo));
582     dynamicInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
583     dynamicInfo->pNext = VK_NULL_HANDLE;
584     dynamicInfo->flags = 0;
585     dynamicStates[0] = VK_DYNAMIC_STATE_VIEWPORT;
586     dynamicStates[1] = VK_DYNAMIC_STATE_SCISSOR;
587     dynamicStates[2] = VK_DYNAMIC_STATE_BLEND_CONSTANTS;
588     dynamicInfo->dynamicStateCount = 3;
589     dynamicInfo->pDynamicStates = dynamicStates;
590 }
591 
Make(const VulkanSharedContext * sharedContext,const RuntimeEffectDictionary * runtimeDict,const GraphicsPipelineDesc & pipelineDesc,const RenderPassDesc & renderPassDesc,const sk_sp<VulkanRenderPass> & compatibleRenderPass,VkPipelineCache pipelineCache)592 sk_sp<VulkanGraphicsPipeline> VulkanGraphicsPipeline::Make(
593         const VulkanSharedContext* sharedContext,
594         const RuntimeEffectDictionary* runtimeDict,
595         const GraphicsPipelineDesc& pipelineDesc,
596         const RenderPassDesc& renderPassDesc,
597         const sk_sp<VulkanRenderPass>& compatibleRenderPass,
598         VkPipelineCache pipelineCache) {
599 
600     SkSL::Program::Interface vsInterface, fsInterface;
601     SkSL::ProgramSettings settings;
602     settings.fForceNoRTFlip = true; // TODO: Confirm
603     ShaderErrorHandler* errorHandler = sharedContext->caps()->shaderErrorHandler();
604 
605     const RenderStep* step = sharedContext->rendererProvider()->lookup(pipelineDesc.renderStepID());
606     const bool useStorageBuffers = sharedContext->caps()->storageBufferPreferred();
607 
608     if (step->vertexAttributes().size() + step->instanceAttributes().size() >
609         sharedContext->vulkanCaps().maxVertexAttributes()) {
610         SKGPU_LOG_W("Requested more than the supported number of vertex attributes");
611         return nullptr;
612     }
613 
614     FragSkSLInfo fsSkSLInfo = BuildFragmentSkSL(sharedContext->caps(),
615                                                 sharedContext->shaderCodeDictionary(),
616                                                 runtimeDict,
617                                                 step,
618                                                 pipelineDesc.paintParamsID(),
619                                                 useStorageBuffers,
620                                                 renderPassDesc.fWriteSwizzle);
621     std::string& fsSkSL = fsSkSLInfo.fSkSL;
622     const bool localCoordsNeeded = fsSkSLInfo.fRequiresLocalCoords;
623 
624     bool hasFragmentSkSL = !fsSkSL.empty();
625     std::string vsSPIRV, fsSPIRV;
626     VkShaderModule fsModule = VK_NULL_HANDLE, vsModule = VK_NULL_HANDLE;
627 
628     if (hasFragmentSkSL) {
629         if (!skgpu::SkSLToSPIRV(sharedContext->caps()->shaderCaps(),
630                                 fsSkSL,
631                                 SkSL::ProgramKind::kGraphiteFragment,
632                                 settings,
633                                 &fsSPIRV,
634                                 &fsInterface,
635                                 errorHandler)) {
636             return nullptr;
637         }
638 
639         fsModule = createVulkanShaderModule(sharedContext, fsSPIRV, VK_SHADER_STAGE_FRAGMENT_BIT);
640         if (!fsModule) {
641             return nullptr;
642         }
643     }
644 
645     VertSkSLInfo vsSkSLInfo = BuildVertexSkSL(sharedContext->caps()->resourceBindingRequirements(),
646                                               step,
647                                               useStorageBuffers,
648                                               localCoordsNeeded);
649     const std::string& vsSkSL = vsSkSLInfo.fSkSL;
650     if (!skgpu::SkSLToSPIRV(sharedContext->caps()->shaderCaps(),
651                             vsSkSL,
652                             SkSL::ProgramKind::kGraphiteVertex,
653                             settings,
654                             &vsSPIRV,
655                             &vsInterface,
656                             errorHandler)) {
657         return nullptr;
658     }
659 
660     vsModule = createVulkanShaderModule(sharedContext, vsSPIRV, VK_SHADER_STAGE_VERTEX_BIT);
661     if (!vsModule) {
662         // Clean up the other shader module before returning.
663         destroy_shader_modules(sharedContext, VK_NULL_HANDLE, fsModule);
664         return nullptr;
665     }
666 
667     VkPipelineVertexInputStateCreateInfo vertexInputInfo;
668     skia_private::STArray<2, VkVertexInputBindingDescription, true> bindingDescs;
669     skia_private::STArray<16, VkVertexInputAttributeDescription> attributeDescs;
670     setup_vertex_input_state(step->vertexAttributes(),
671                              step->instanceAttributes(),
672                              &vertexInputInfo,
673                              &bindingDescs,
674                              &attributeDescs);
675 
676     VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo;
677     setup_input_assembly_state(step->primitiveType(), &inputAssemblyInfo);
678 
679     VkPipelineDepthStencilStateCreateInfo depthStencilInfo;
680     setup_depth_stencil_state(step->depthStencilSettings(), &depthStencilInfo);
681 
682     VkPipelineViewportStateCreateInfo viewportInfo;
683     setup_viewport_scissor_state(&viewportInfo);
684 
685     VkPipelineMultisampleStateCreateInfo multisampleInfo;
686     setup_multisample_state(renderPassDesc.fColorAttachment.fTextureInfo.numSamples(),
687                             &multisampleInfo);
688 
689     // We will only have one color blend attachment per pipeline.
690     VkPipelineColorBlendAttachmentState attachmentStates[1];
691     VkPipelineColorBlendStateCreateInfo colorBlendInfo;
692     setup_color_blend_state(fsSkSLInfo.fBlendInfo, &colorBlendInfo, attachmentStates);
693 
694     VkPipelineRasterizationStateCreateInfo rasterInfo;
695     // TODO: Check for wire frame mode once that is an available context option within graphite.
696     setup_raster_state(/*isWireframe=*/false, &rasterInfo);
697 
698     VkPipelineShaderStageCreateInfo pipelineShaderStages[2];
699     setup_shader_stage_info(VK_SHADER_STAGE_VERTEX_BIT,
700                             vsModule,
701                             &pipelineShaderStages[0]);
702     if (hasFragmentSkSL) {
703         setup_shader_stage_info(VK_SHADER_STAGE_FRAGMENT_BIT,
704                                 fsModule,
705                                 &pipelineShaderStages[1]);
706     }
707 
708     // TODO: Query RenderPassDesc for input attachment information. For now, we only use one for
709     // loading MSAA from resolve so we can simply pass in 0 when not doing that.
710     VkPipelineLayout pipelineLayout = setup_pipeline_layout(sharedContext,
711                                                             /*usesIntrinsicConstantUbo=*/true,
712                                                             !step->uniforms().empty(),
713                                                             fsSkSLInfo.fNumPaintUniforms,
714                                                             fsSkSLInfo.fNumTexturesAndSamplers,
715                                                             /*numInputAttachments=*/0);
716     if (pipelineLayout == VK_NULL_HANDLE) {
717         destroy_shader_modules(sharedContext, vsModule, fsModule);
718         return nullptr;
719     }
720 
721     VkDynamicState dynamicStates[3];
722     VkPipelineDynamicStateCreateInfo dynamicInfo;
723     setup_dynamic_state(&dynamicInfo, dynamicStates);
724 
725     bool loadMsaaFromResolve = renderPassDesc.fColorResolveAttachment.fTextureInfo.isValid() &&
726                                renderPassDesc.fColorResolveAttachment.fLoadOp == LoadOp::kLoad;
727 
728     VkGraphicsPipelineCreateInfo pipelineCreateInfo;
729     memset(&pipelineCreateInfo, 0, sizeof(VkGraphicsPipelineCreateInfo));
730     pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
731     pipelineCreateInfo.pNext = nullptr;
732     pipelineCreateInfo.flags = 0;
733     pipelineCreateInfo.stageCount = hasFragmentSkSL ? 2 : 1;
734     pipelineCreateInfo.pStages = &pipelineShaderStages[0];
735     pipelineCreateInfo.pVertexInputState = &vertexInputInfo;
736     pipelineCreateInfo.pInputAssemblyState = &inputAssemblyInfo;
737     pipelineCreateInfo.pTessellationState = nullptr;
738     pipelineCreateInfo.pViewportState = &viewportInfo;
739     pipelineCreateInfo.pRasterizationState = &rasterInfo;
740     pipelineCreateInfo.pMultisampleState = &multisampleInfo;
741     pipelineCreateInfo.pDepthStencilState = &depthStencilInfo;
742     pipelineCreateInfo.pColorBlendState = &colorBlendInfo;
743     pipelineCreateInfo.pDynamicState = &dynamicInfo;
744     pipelineCreateInfo.layout = pipelineLayout;
745     pipelineCreateInfo.renderPass = compatibleRenderPass->renderPass();
746     pipelineCreateInfo.subpass = loadMsaaFromResolve ? 1 : 0;
747     pipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
748     pipelineCreateInfo.basePipelineIndex = -1;
749 
750     VkPipeline vkPipeline;
751     VkResult result;
752     {
753         TRACE_EVENT0_ALWAYS("skia.shaders", "VkCreateGraphicsPipeline");
754         VULKAN_CALL_RESULT(sharedContext,
755                            result,
756                            CreateGraphicsPipelines(sharedContext->device(),
757                                                    pipelineCache,
758                                                    /*createInfoCount=*/1,
759                                                    &pipelineCreateInfo,
760                                                    /*pAllocator=*/nullptr,
761                                                    &vkPipeline));
762     }
763     if (result != VK_SUCCESS) {
764         SkDebugf("Failed to create pipeline. Error: %d\n", result);
765         return nullptr;
766     }
767 
768     // After creating the pipeline object, we can clean up the VkShaderModule(s).
769     destroy_shader_modules(sharedContext, vsModule, fsModule);
770 
771 #if defined(GRAPHITE_TEST_UTILS)
772     GraphicsPipeline::PipelineInfo pipelineInfo = {pipelineDesc.renderStepID(),
773                                                    pipelineDesc.paintParamsID(),
774                                                    std::move(vsSkSL),
775                                                    std::move(fsSkSL),
776                                                    "SPIR-V disassembly not available",
777                                                    "SPIR-V disassembly not available"};
778     GraphicsPipeline::PipelineInfo* pipelineInfoPtr = &pipelineInfo;
779 #else
780     GraphicsPipeline::PipelineInfo* pipelineInfoPtr = nullptr;
781 #endif
782 
783     return sk_sp<VulkanGraphicsPipeline>(
784             new VulkanGraphicsPipeline(sharedContext,
785                                        pipelineInfoPtr,
786                                        pipelineLayout,
787                                        vkPipeline,
788                                        fsSkSLInfo.fNumPaintUniforms > 0,
789                                        !step->uniforms().empty(),
790                                        fsSkSLInfo.fNumTexturesAndSamplers,
791                                        /*ownsPipelineLayout=*/true));
792 }
793 
InitializeMSAALoadPipelineStructs(const VulkanSharedContext * sharedContext,VkShaderModule * outVertexShaderModule,VkShaderModule * outFragShaderModule,VkPipelineShaderStageCreateInfo * outShaderStageInfo,VkPipelineLayout * outPipelineLayout)794 bool VulkanGraphicsPipeline::InitializeMSAALoadPipelineStructs(
795         const VulkanSharedContext* sharedContext,
796         VkShaderModule* outVertexShaderModule,
797         VkShaderModule* outFragShaderModule,
798         VkPipelineShaderStageCreateInfo* outShaderStageInfo,
799         VkPipelineLayout* outPipelineLayout) {
800     SkSL::Program::Interface vsInterface, fsInterface;
801     SkSL::ProgramSettings settings;
802     settings.fForceNoRTFlip = true;
803     std::string vsSPIRV, fsSPIRV;
804     ShaderErrorHandler* errorHandler = sharedContext->caps()->shaderErrorHandler();
805 
806     std::string vertShaderText;
807     vertShaderText.append(
808             "// MSAA Load Program VS\n"
809             "layout(vulkan, location=0) in float2 ndc_position;"
810 
811             "void main() {"
812             "sk_Position.xy = ndc_position;"
813             "sk_Position.zw = half2(0, 1);"
814             "}");
815 
816     std::string fragShaderText;
817     fragShaderText.append(
818             "layout(vulkan, input_attachment_index=0, set=0, binding=0) subpassInput uInput;"
819 
820             "// MSAA Load Program FS\n"
821             "void main() {"
822             "sk_FragColor = subpassLoad(uInput);"
823             "}");
824 
825     if (!skgpu::SkSLToSPIRV(sharedContext->caps()->shaderCaps(),
826                             vertShaderText,
827                             SkSL::ProgramKind::kGraphiteVertex,
828                             settings,
829                             &vsSPIRV,
830                             &vsInterface,
831                             errorHandler)) {
832         return false;
833     }
834     if (!skgpu::SkSLToSPIRV(sharedContext->caps()->shaderCaps(),
835                             fragShaderText,
836                             SkSL::ProgramKind::kGraphiteFragment,
837                             settings,
838                             &fsSPIRV,
839                             &fsInterface,
840                             errorHandler)) {
841         return false;
842     }
843     *outFragShaderModule =
844             createVulkanShaderModule(sharedContext, fsSPIRV, VK_SHADER_STAGE_FRAGMENT_BIT);
845     if (*outFragShaderModule == VK_NULL_HANDLE) {
846         return false;
847     }
848 
849     *outVertexShaderModule =
850             createVulkanShaderModule(sharedContext, vsSPIRV, VK_SHADER_STAGE_VERTEX_BIT);
851     if (*outVertexShaderModule == VK_NULL_HANDLE) {
852         destroy_shader_modules(sharedContext, VK_NULL_HANDLE, *outFragShaderModule);
853         return false;
854     }
855 
856     setup_shader_stage_info(VK_SHADER_STAGE_VERTEX_BIT,
857                             *outVertexShaderModule,
858                             &outShaderStageInfo[0]);
859 
860     setup_shader_stage_info(VK_SHADER_STAGE_FRAGMENT_BIT,
861                             *outFragShaderModule,
862                             &outShaderStageInfo[1]);
863 
864     // The load msaa pipeline takes no step or paint uniforms and no instance attributes. It only
865     // references one input attachment texture (which does not require a sampler) and one vertex
866     // attribute (NDC position)
867     skia_private::TArray<DescriptorData> inputAttachmentDescriptors(1);
868     inputAttachmentDescriptors.push_back(VulkanGraphicsPipeline::kInputAttachmentDescriptor);
869     *outPipelineLayout = setup_pipeline_layout(sharedContext,
870                                                /*usesIntrinsicConstantUbo=*/false,
871                                                /*hasStepUniforms=*/false,
872                                                /*numPaintUniforms=*/0,
873                                                /*numTextureSamplers=*/0,
874                                                /*numInputAttachments=*/1);
875 
876     if (*outPipelineLayout == VK_NULL_HANDLE) {
877         destroy_shader_modules(sharedContext, *outVertexShaderModule, *outFragShaderModule);
878         return false;
879     }
880     return true;
881 }
882 
MakeLoadMSAAPipeline(const VulkanSharedContext * sharedContext,VkShaderModule vsModule,VkShaderModule fsModule,VkPipelineShaderStageCreateInfo * pipelineShaderStages,VkPipelineLayout pipelineLayout,sk_sp<VulkanRenderPass> compatibleRenderPass,VkPipelineCache pipelineCache,const TextureInfo & dstColorAttachmentTexInfo)883 sk_sp<VulkanGraphicsPipeline> VulkanGraphicsPipeline::MakeLoadMSAAPipeline(
884         const VulkanSharedContext* sharedContext,
885         VkShaderModule vsModule,
886         VkShaderModule fsModule,
887         VkPipelineShaderStageCreateInfo* pipelineShaderStages,
888         VkPipelineLayout pipelineLayout,
889         sk_sp<VulkanRenderPass> compatibleRenderPass,
890         VkPipelineCache pipelineCache,
891         const TextureInfo& dstColorAttachmentTexInfo) {
892 
893     int numSamples = dstColorAttachmentTexInfo.numSamples();
894 
895     // Create vertex attribute list
896     Attribute vertexAttrib[1] = {{"ndc_position", VertexAttribType::kFloat2, SkSLType::kFloat2}};
897     SkSpan<const Attribute> loadMSAAVertexAttribs = {vertexAttrib};
898 
899     VkPipelineVertexInputStateCreateInfo vertexInputInfo;
900     skia_private::STArray<2, VkVertexInputBindingDescription, true> bindingDescs;
901     skia_private::STArray<16, VkVertexInputAttributeDescription> attributeDescs;
902     setup_vertex_input_state(loadMSAAVertexAttribs,
903                              /*instanceAttrs=*/{}, // Load msaa pipeline takes no instance attribs
904                              &vertexInputInfo,
905                              &bindingDescs,
906                              &attributeDescs);
907 
908     VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo;
909     setup_input_assembly_state(PrimitiveType::kTriangleStrip, &inputAssemblyInfo);
910 
911     VkPipelineDepthStencilStateCreateInfo depthStencilInfo;
912     setup_depth_stencil_state(/*stencilSettings=*/{}, &depthStencilInfo);
913 
914     VkPipelineViewportStateCreateInfo viewportInfo;
915     setup_viewport_scissor_state(&viewportInfo);
916 
917     VkPipelineMultisampleStateCreateInfo multisampleInfo;
918     setup_multisample_state(numSamples, &multisampleInfo);
919 
920     // We will only have one color blend attachment per pipeline.
921     VkPipelineColorBlendAttachmentState attachmentStates[1];
922     VkPipelineColorBlendStateCreateInfo colorBlendInfo;
923     setup_color_blend_state({}, &colorBlendInfo, attachmentStates);
924 
925     VkPipelineRasterizationStateCreateInfo rasterInfo;
926     // TODO: Check for wire frame mode once that is an available context option within graphite.
927     setup_raster_state(/*isWireframe=*/false, &rasterInfo);
928 
929     VkDynamicState dynamicStates[3];
930     VkPipelineDynamicStateCreateInfo dynamicInfo;
931     setup_dynamic_state(&dynamicInfo, dynamicStates);
932 
933     VkGraphicsPipelineCreateInfo pipelineCreateInfo;
934     memset(&pipelineCreateInfo, 0, sizeof(VkGraphicsPipelineCreateInfo));
935     pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
936     pipelineCreateInfo.pNext = nullptr;
937     pipelineCreateInfo.flags = 0;
938     pipelineCreateInfo.stageCount = 2;
939     pipelineCreateInfo.pStages = pipelineShaderStages;
940     pipelineCreateInfo.pVertexInputState = &vertexInputInfo;
941     pipelineCreateInfo.pInputAssemblyState = &inputAssemblyInfo;
942     pipelineCreateInfo.pTessellationState = nullptr;
943     pipelineCreateInfo.pViewportState = &viewportInfo;
944     pipelineCreateInfo.pRasterizationState = &rasterInfo;
945     pipelineCreateInfo.pMultisampleState = &multisampleInfo;
946     pipelineCreateInfo.pDepthStencilState = &depthStencilInfo;
947     pipelineCreateInfo.pColorBlendState = &colorBlendInfo;
948     pipelineCreateInfo.pDynamicState = &dynamicInfo;
949     pipelineCreateInfo.layout = pipelineLayout;
950     pipelineCreateInfo.renderPass = compatibleRenderPass->renderPass();
951 
952     VkPipeline vkPipeline;
953     VkResult result;
954     {
955         TRACE_EVENT0_ALWAYS("skia.shaders", "CreateGraphicsPipeline");
956         SkASSERT(pipelineCache != VK_NULL_HANDLE);
957         VULKAN_CALL_RESULT(sharedContext,
958                            result,
959                            CreateGraphicsPipelines(sharedContext->device(),
960                                                    pipelineCache,
961                                                    /*createInfoCount=*/1,
962                                                    &pipelineCreateInfo,
963                                                    /*pAllocator=*/nullptr,
964                                                    &vkPipeline));
965     }
966     if (result != VK_SUCCESS) {
967         SkDebugf("Failed to create pipeline. Error: %d\n", result);
968         return nullptr;
969     }
970 
971     // TODO: If we want to track GraphicsPipeline::PipelineInfo in debug, we'll need to add
972     // PipelineDesc as an argument for this method. For now, just pass in nullptr.
973     return sk_sp<VulkanGraphicsPipeline>(
974             new VulkanGraphicsPipeline(sharedContext,
975                                        /*pipelineInfo=*/nullptr,
976                                        pipelineLayout,
977                                        vkPipeline,
978                                        /*hasFragmentUniforms=*/false,
979                                        /*hasStepUniforms=*/false,
980                                        /*numTextureSamplers*/0,
981                                        /*ownsPipelineLayout=*/false));
982 }
983 
VulkanGraphicsPipeline(const skgpu::graphite::SharedContext * sharedContext,PipelineInfo * pipelineInfo,VkPipelineLayout pipelineLayout,VkPipeline pipeline,bool hasFragmentUniforms,bool hasStepUniforms,int numTextureSamplers,bool ownsPipelineLayout)984 VulkanGraphicsPipeline::VulkanGraphicsPipeline(const skgpu::graphite::SharedContext* sharedContext,
985                                                PipelineInfo* pipelineInfo,
986                                                VkPipelineLayout pipelineLayout,
987                                                VkPipeline pipeline,
988                                                bool hasFragmentUniforms,
989                                                bool hasStepUniforms,
990                                                int numTextureSamplers,
991                                                bool ownsPipelineLayout)
992         : GraphicsPipeline(sharedContext, pipelineInfo)
993         , fPipelineLayout(pipelineLayout)
994         , fPipeline(pipeline)
995         , fHasFragmentUniforms(hasFragmentUniforms)
996         , fHasStepUniforms(hasStepUniforms)
997         , fNumTextureSamplers(numTextureSamplers)
998         , fOwnsPipelineLayout(ownsPipelineLayout) {}
999 
freeGpuData()1000 void VulkanGraphicsPipeline::freeGpuData() {
1001     auto sharedCtxt = static_cast<const VulkanSharedContext*>(this->sharedContext());
1002     if (fPipeline != VK_NULL_HANDLE) {
1003         VULKAN_CALL(sharedCtxt->interface(),
1004             DestroyPipeline(sharedCtxt->device(), fPipeline, nullptr));
1005     }
1006     if (fOwnsPipelineLayout && fPipelineLayout != VK_NULL_HANDLE) {
1007         VULKAN_CALL(sharedCtxt->interface(),
1008                     DestroyPipelineLayout(sharedCtxt->device(), fPipelineLayout, nullptr));
1009     }
1010 }
1011 
1012 } // namespace skgpu::graphite
1013