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