Coverage Report

Created: 2024-09-14 07:19

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