Coverage Report

Created: 2024-05-20 07:14

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