1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlGraphicsPipeline.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "experimental/graphite/src/GraphicsPipelineDesc.h"
11cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlGpu.h"
12cb93a386Sopenharmony_ci#include "experimental/graphite/src/mtl/MtlUtils.h"
13cb93a386Sopenharmony_ci#include "include/private/SkSLString.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_cinamespace skgpu::mtl {
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_cistatic const char* kTestingOnlyShaders[] = {
18cb93a386Sopenharmony_ci    // clear viewport to blue
19cb93a386Sopenharmony_ci    "#include <metal_stdlib>\n"
20cb93a386Sopenharmony_ci    "#include <simd/simd.h>\n"
21cb93a386Sopenharmony_ci    "using namespace metal;\n"
22cb93a386Sopenharmony_ci    "\n"
23cb93a386Sopenharmony_ci    "typedef struct {\n"
24cb93a386Sopenharmony_ci    "    float4 position [[position]];\n"
25cb93a386Sopenharmony_ci    "} VertexOutput;\n"
26cb93a386Sopenharmony_ci    "\n"
27cb93a386Sopenharmony_ci    "vertex VertexOutput vertexMain(uint vertexID [[vertex_id]]) {\n"
28cb93a386Sopenharmony_ci    "    VertexOutput out;\n"
29cb93a386Sopenharmony_ci    "    float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n"
30cb93a386Sopenharmony_ci    "    out.position.xy = position * 2 - 1;\n"
31cb93a386Sopenharmony_ci    "    out.position.zw = float2(0.0, 1.0);\n"
32cb93a386Sopenharmony_ci    "    return out;\n"
33cb93a386Sopenharmony_ci    "}\n"
34cb93a386Sopenharmony_ci    "\n"
35cb93a386Sopenharmony_ci    "fragment float4 fragmentMain(VertexOutput in [[stage_in]]) {\n"
36cb93a386Sopenharmony_ci    "    return float4(0.0, 0.0, 1.0, 1.0);\n"
37cb93a386Sopenharmony_ci    "}",
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    // clear subarea to given color, using uniform buffer
40cb93a386Sopenharmony_ci    "#include <metal_stdlib>\n"
41cb93a386Sopenharmony_ci    "#include <simd/simd.h>\n"
42cb93a386Sopenharmony_ci    "using namespace metal;\n"
43cb93a386Sopenharmony_ci    "\n"
44cb93a386Sopenharmony_ci    "typedef struct {\n"
45cb93a386Sopenharmony_ci    "    float4 position [[position]];\n"
46cb93a386Sopenharmony_ci    "} VertexOutput;\n"
47cb93a386Sopenharmony_ci    "\n"
48cb93a386Sopenharmony_ci    "typedef struct {\n"
49cb93a386Sopenharmony_ci    "    float4 uPosXform;\n"
50cb93a386Sopenharmony_ci    "    float4 uColor;\n"
51cb93a386Sopenharmony_ci    "} UniformData;\n"
52cb93a386Sopenharmony_ci    "\n"
53cb93a386Sopenharmony_ci    "vertex VertexOutput vertexMain(constant UniformData& uniforms [[buffer(0)]],\n"
54cb93a386Sopenharmony_ci    "                               uint vertexID [[vertex_id]]) {\n"
55cb93a386Sopenharmony_ci    "    VertexOutput out;\n"
56cb93a386Sopenharmony_ci    "    float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n"
57cb93a386Sopenharmony_ci    "    out.position.xy = position * uniforms.uPosXform.xy + uniforms.uPosXform.zw;\n"
58cb93a386Sopenharmony_ci    "    out.position.zw = float2(0.0, 1.0);\n"
59cb93a386Sopenharmony_ci    "    return out;\n"
60cb93a386Sopenharmony_ci    "}\n"
61cb93a386Sopenharmony_ci    "\n"
62cb93a386Sopenharmony_ci    "fragment float4 fragmentMain(constant UniformData& uniforms [[buffer(0)]],\n"
63cb93a386Sopenharmony_ci    "                             VertexOutput in [[stage_in]]) {\n"
64cb93a386Sopenharmony_ci    "    return uniforms.uColor;\n"
65cb93a386Sopenharmony_ci    "}",
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci    // draw triangles with given color, using uniform buffer and vertex data
68cb93a386Sopenharmony_ci    "#include <metal_stdlib>\n"
69cb93a386Sopenharmony_ci    "#include <simd/simd.h>\n"
70cb93a386Sopenharmony_ci    "using namespace metal;\n"
71cb93a386Sopenharmony_ci    "\n"
72cb93a386Sopenharmony_ci    "typedef struct {\n"
73cb93a386Sopenharmony_ci    "    float2 position [[attribute(0)]];\n"
74cb93a386Sopenharmony_ci    "} VertexInput;\n"
75cb93a386Sopenharmony_ci    "\n"
76cb93a386Sopenharmony_ci    "typedef struct {\n"
77cb93a386Sopenharmony_ci    "    float4 position [[position]];\n"
78cb93a386Sopenharmony_ci    "} VertexOutput;\n"
79cb93a386Sopenharmony_ci    "\n"
80cb93a386Sopenharmony_ci    "typedef struct {\n"
81cb93a386Sopenharmony_ci    "    float4 uPosXform;\n"
82cb93a386Sopenharmony_ci    "    float4 uColor;\n"
83cb93a386Sopenharmony_ci    "} UniformData;\n"
84cb93a386Sopenharmony_ci    "\n"
85cb93a386Sopenharmony_ci    "vertex VertexOutput vertexMain(VertexInput in [[stage_in]],\n"
86cb93a386Sopenharmony_ci    "                               constant UniformData& uniforms [[buffer(0)]],\n"
87cb93a386Sopenharmony_ci    "                               uint vertexID [[vertex_id]]) {\n"
88cb93a386Sopenharmony_ci    "    VertexOutput out;\n"
89cb93a386Sopenharmony_ci    "    float2 position = in.position;\n"
90cb93a386Sopenharmony_ci    "    out.position.xy = position * uniforms.uPosXform.xy + uniforms.uPosXform.zw;\n"
91cb93a386Sopenharmony_ci    "    out.position.zw = float2(0.0, 1.0);\n"
92cb93a386Sopenharmony_ci    "    return out;\n"
93cb93a386Sopenharmony_ci    "}\n"
94cb93a386Sopenharmony_ci    "\n"
95cb93a386Sopenharmony_ci    "fragment float4 fragmentMain(constant UniformData& uniforms [[buffer(0)]],\n"
96cb93a386Sopenharmony_ci    "                             VertexOutput in [[stage_in]]) {\n"
97cb93a386Sopenharmony_ci    "    return uniforms.uColor;\n"
98cb93a386Sopenharmony_ci    "}",
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ci    // draw triangles with vertex ID and instance buffer
101cb93a386Sopenharmony_ci    "#include <metal_stdlib>\n"
102cb93a386Sopenharmony_ci    "#include <simd/simd.h>\n"
103cb93a386Sopenharmony_ci    "using namespace metal;\n"
104cb93a386Sopenharmony_ci    "\n"
105cb93a386Sopenharmony_ci    "typedef struct {\n"
106cb93a386Sopenharmony_ci    "    float2 position [[attribute(0)]];\n"
107cb93a386Sopenharmony_ci    "    float2 dims [[attribute(1)]];\n"
108cb93a386Sopenharmony_ci    "    float4 color [[attribute(2)]];\n"
109cb93a386Sopenharmony_ci    "} InstanceInput;\n"
110cb93a386Sopenharmony_ci    "\n"
111cb93a386Sopenharmony_ci    "typedef struct {\n"
112cb93a386Sopenharmony_ci    "    float4 position [[position]];\n"
113cb93a386Sopenharmony_ci    "    float4 color;\n"
114cb93a386Sopenharmony_ci    "} VertexOutput;\n"
115cb93a386Sopenharmony_ci    "\n"
116cb93a386Sopenharmony_ci    "vertex VertexOutput vertexMain(InstanceInput in [[stage_in]],\n"
117cb93a386Sopenharmony_ci    "                               uint vertexID [[vertex_id]]) {\n"
118cb93a386Sopenharmony_ci    "    VertexOutput out;\n"
119cb93a386Sopenharmony_ci    "    float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n"
120cb93a386Sopenharmony_ci    "    out.position.xy = position * in.dims + in.position;\n"
121cb93a386Sopenharmony_ci    "    out.position.zw = float2(0.0, 1.0);\n"
122cb93a386Sopenharmony_ci    "    out.color = in.color;"
123cb93a386Sopenharmony_ci    "    return out;\n"
124cb93a386Sopenharmony_ci    "}\n"
125cb93a386Sopenharmony_ci    "\n"
126cb93a386Sopenharmony_ci    "fragment float4 fragmentMain(VertexOutput in [[stage_in]]) {\n"
127cb93a386Sopenharmony_ci    "    return in.color;\n"
128cb93a386Sopenharmony_ci    "}",
129cb93a386Sopenharmony_ci};
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_cistatic constexpr NSString* kTestingOnlyShaderLabels[]  = {
132cb93a386Sopenharmony_ci    @"Clear viewport to blue",
133cb93a386Sopenharmony_ci    @"Clear rect with uniforms",
134cb93a386Sopenharmony_ci    @"Draw triangles with uniform color",
135cb93a386Sopenharmony_ci    @"Draw triangles with instance buffer"
136cb93a386Sopenharmony_ci};
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_cistatic inline MTLVertexFormat attribute_type_to_mtlformat(VertexAttribType type) {
139cb93a386Sopenharmony_ci    switch (type) {
140cb93a386Sopenharmony_ci        case VertexAttribType::kFloat:
141cb93a386Sopenharmony_ci            return MTLVertexFormatFloat;
142cb93a386Sopenharmony_ci        case VertexAttribType::kFloat2:
143cb93a386Sopenharmony_ci            return MTLVertexFormatFloat2;
144cb93a386Sopenharmony_ci        case VertexAttribType::kFloat3:
145cb93a386Sopenharmony_ci            return MTLVertexFormatFloat3;
146cb93a386Sopenharmony_ci        case VertexAttribType::kFloat4:
147cb93a386Sopenharmony_ci            return MTLVertexFormatFloat4;
148cb93a386Sopenharmony_ci        case VertexAttribType::kHalf:
149cb93a386Sopenharmony_ci            if (@available(macOS 10.13, iOS 11.0, *)) {
150cb93a386Sopenharmony_ci                return MTLVertexFormatHalf;
151cb93a386Sopenharmony_ci            } else {
152cb93a386Sopenharmony_ci                return MTLVertexFormatInvalid;
153cb93a386Sopenharmony_ci            }
154cb93a386Sopenharmony_ci        case VertexAttribType::kHalf2:
155cb93a386Sopenharmony_ci            return MTLVertexFormatHalf2;
156cb93a386Sopenharmony_ci        case VertexAttribType::kHalf4:
157cb93a386Sopenharmony_ci            return MTLVertexFormatHalf4;
158cb93a386Sopenharmony_ci        case VertexAttribType::kInt2:
159cb93a386Sopenharmony_ci            return MTLVertexFormatInt2;
160cb93a386Sopenharmony_ci        case VertexAttribType::kInt3:
161cb93a386Sopenharmony_ci            return MTLVertexFormatInt3;
162cb93a386Sopenharmony_ci        case VertexAttribType::kInt4:
163cb93a386Sopenharmony_ci            return MTLVertexFormatInt4;
164cb93a386Sopenharmony_ci        case VertexAttribType::kByte:
165cb93a386Sopenharmony_ci            if (@available(macOS 10.13, iOS 11.0, *)) {
166cb93a386Sopenharmony_ci                return MTLVertexFormatChar;
167cb93a386Sopenharmony_ci            } else {
168cb93a386Sopenharmony_ci                return MTLVertexFormatInvalid;
169cb93a386Sopenharmony_ci            }
170cb93a386Sopenharmony_ci        case VertexAttribType::kByte2:
171cb93a386Sopenharmony_ci            return MTLVertexFormatChar2;
172cb93a386Sopenharmony_ci        case VertexAttribType::kByte4:
173cb93a386Sopenharmony_ci            return MTLVertexFormatChar4;
174cb93a386Sopenharmony_ci        case VertexAttribType::kUByte:
175cb93a386Sopenharmony_ci            if (@available(macOS 10.13, iOS 11.0, *)) {
176cb93a386Sopenharmony_ci                return MTLVertexFormatUChar;
177cb93a386Sopenharmony_ci            } else {
178cb93a386Sopenharmony_ci                return MTLVertexFormatInvalid;
179cb93a386Sopenharmony_ci            }
180cb93a386Sopenharmony_ci        case VertexAttribType::kUByte2:
181cb93a386Sopenharmony_ci            return MTLVertexFormatUChar2;
182cb93a386Sopenharmony_ci        case VertexAttribType::kUByte4:
183cb93a386Sopenharmony_ci            return MTLVertexFormatUChar4;
184cb93a386Sopenharmony_ci        case VertexAttribType::kUByte_norm:
185cb93a386Sopenharmony_ci            if (@available(macOS 10.13, iOS 11.0, *)) {
186cb93a386Sopenharmony_ci                return MTLVertexFormatUCharNormalized;
187cb93a386Sopenharmony_ci            } else {
188cb93a386Sopenharmony_ci                return MTLVertexFormatInvalid;
189cb93a386Sopenharmony_ci            }
190cb93a386Sopenharmony_ci        case VertexAttribType::kUByte4_norm:
191cb93a386Sopenharmony_ci            return MTLVertexFormatUChar4Normalized;
192cb93a386Sopenharmony_ci        case VertexAttribType::kShort2:
193cb93a386Sopenharmony_ci            return MTLVertexFormatShort2;
194cb93a386Sopenharmony_ci        case VertexAttribType::kShort4:
195cb93a386Sopenharmony_ci            return MTLVertexFormatShort4;
196cb93a386Sopenharmony_ci        case VertexAttribType::kUShort2:
197cb93a386Sopenharmony_ci            return MTLVertexFormatUShort2;
198cb93a386Sopenharmony_ci        case VertexAttribType::kUShort2_norm:
199cb93a386Sopenharmony_ci            return MTLVertexFormatUShort2Normalized;
200cb93a386Sopenharmony_ci        case VertexAttribType::kInt:
201cb93a386Sopenharmony_ci            return MTLVertexFormatInt;
202cb93a386Sopenharmony_ci        case VertexAttribType::kUInt:
203cb93a386Sopenharmony_ci            return MTLVertexFormatUInt;
204cb93a386Sopenharmony_ci        case VertexAttribType::kUShort_norm:
205cb93a386Sopenharmony_ci            if (@available(macOS 10.13, iOS 11.0, *)) {
206cb93a386Sopenharmony_ci                return MTLVertexFormatUShortNormalized;
207cb93a386Sopenharmony_ci            } else {
208cb93a386Sopenharmony_ci                return MTLVertexFormatInvalid;
209cb93a386Sopenharmony_ci            }
210cb93a386Sopenharmony_ci        case VertexAttribType::kUShort4_norm:
211cb93a386Sopenharmony_ci            return MTLVertexFormatUShort4Normalized;
212cb93a386Sopenharmony_ci    }
213cb93a386Sopenharmony_ci    SK_ABORT("Unknown vertex attribute type");
214cb93a386Sopenharmony_ci}
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_cistatic MTLVertexDescriptor* create_vertex_descriptor(const GraphicsPipelineDesc& desc) {
217cb93a386Sopenharmony_ci    auto vertexDescriptor = [[MTLVertexDescriptor alloc] init];
218cb93a386Sopenharmony_ci    int attributeIndex = 0;
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    int vertexAttributeCount = desc.numVertexAttributes();
221cb93a386Sopenharmony_ci    size_t vertexAttributeOffset = 0;
222cb93a386Sopenharmony_ci    for (const auto& attribute : desc.vertexAttributes()) {
223cb93a386Sopenharmony_ci        MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
224cb93a386Sopenharmony_ci        MTLVertexFormat format = attribute_type_to_mtlformat(attribute.cpuType());
225cb93a386Sopenharmony_ci        SkASSERT(MTLVertexFormatInvalid != format);
226cb93a386Sopenharmony_ci        mtlAttribute.format = format;
227cb93a386Sopenharmony_ci        mtlAttribute.offset = vertexAttributeOffset;
228cb93a386Sopenharmony_ci        mtlAttribute.bufferIndex = GraphicsPipeline::kVertexBufferIndex;
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci        vertexAttributeOffset += attribute.sizeAlign4();
231cb93a386Sopenharmony_ci        attributeIndex++;
232cb93a386Sopenharmony_ci    }
233cb93a386Sopenharmony_ci    SkASSERT(vertexAttributeOffset == desc.vertexStride());
234cb93a386Sopenharmony_ci
235cb93a386Sopenharmony_ci    if (vertexAttributeCount) {
236cb93a386Sopenharmony_ci        MTLVertexBufferLayoutDescriptor* vertexBufferLayout =
237cb93a386Sopenharmony_ci                vertexDescriptor.layouts[GraphicsPipeline::kVertexBufferIndex];
238cb93a386Sopenharmony_ci        vertexBufferLayout.stepFunction = MTLVertexStepFunctionPerVertex;
239cb93a386Sopenharmony_ci        vertexBufferLayout.stepRate = 1;
240cb93a386Sopenharmony_ci        vertexBufferLayout.stride = vertexAttributeOffset;
241cb93a386Sopenharmony_ci    }
242cb93a386Sopenharmony_ci
243cb93a386Sopenharmony_ci    int instanceAttributeCount = desc.numInstanceAttributes();
244cb93a386Sopenharmony_ci    size_t instanceAttributeOffset = 0;
245cb93a386Sopenharmony_ci    for (const auto& attribute : desc.instanceAttributes()) {
246cb93a386Sopenharmony_ci        MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
247cb93a386Sopenharmony_ci        MTLVertexFormat format = attribute_type_to_mtlformat(attribute.cpuType());
248cb93a386Sopenharmony_ci        SkASSERT(MTLVertexFormatInvalid != format);
249cb93a386Sopenharmony_ci        mtlAttribute.format = format;
250cb93a386Sopenharmony_ci        mtlAttribute.offset = instanceAttributeOffset;
251cb93a386Sopenharmony_ci        mtlAttribute.bufferIndex = GraphicsPipeline::kInstanceBufferIndex;
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_ci        instanceAttributeOffset += attribute.sizeAlign4();
254cb93a386Sopenharmony_ci        attributeIndex++;
255cb93a386Sopenharmony_ci    }
256cb93a386Sopenharmony_ci    SkASSERT(instanceAttributeOffset == desc.instanceStride());
257cb93a386Sopenharmony_ci
258cb93a386Sopenharmony_ci    if (instanceAttributeCount) {
259cb93a386Sopenharmony_ci        MTLVertexBufferLayoutDescriptor* instanceBufferLayout =
260cb93a386Sopenharmony_ci                vertexDescriptor.layouts[GraphicsPipeline::kInstanceBufferIndex];
261cb93a386Sopenharmony_ci        instanceBufferLayout.stepFunction = MTLVertexStepFunctionPerInstance;
262cb93a386Sopenharmony_ci        instanceBufferLayout.stepRate = 1;
263cb93a386Sopenharmony_ci        instanceBufferLayout.stride = instanceAttributeOffset;
264cb93a386Sopenharmony_ci    }
265cb93a386Sopenharmony_ci    return vertexDescriptor;
266cb93a386Sopenharmony_ci}
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_cisk_sp<GraphicsPipeline> GraphicsPipeline::Make(const Gpu* gpu,
269cb93a386Sopenharmony_ci                                               const skgpu::GraphicsPipelineDesc& desc) {
270cb93a386Sopenharmony_ci    sk_cfp<MTLRenderPipelineDescriptor*> psoDescriptor([[MTLRenderPipelineDescriptor alloc] init]);
271cb93a386Sopenharmony_ci
272cb93a386Sopenharmony_ci    // Temp pipeline for now that just fills the viewport with blue
273cb93a386Sopenharmony_ci    int shaderIndex = desc.testingOnlyShaderIndex();
274cb93a386Sopenharmony_ci    SkSL::String shaderText;
275cb93a386Sopenharmony_ci    shaderText.append(kTestingOnlyShaders[shaderIndex]);
276cb93a386Sopenharmony_ci
277cb93a386Sopenharmony_ci    auto metallib = CompileShaderLibrary(gpu, shaderText);
278cb93a386Sopenharmony_ci    if (!metallib) {
279cb93a386Sopenharmony_ci        return nullptr;
280cb93a386Sopenharmony_ci    }
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_ci    (*psoDescriptor).label = kTestingOnlyShaderLabels[shaderIndex];
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ci    (*psoDescriptor).vertexFunction =
285cb93a386Sopenharmony_ci            [*metallib newFunctionWithName: @"vertexMain"];
286cb93a386Sopenharmony_ci    (*psoDescriptor).fragmentFunction =
287cb93a386Sopenharmony_ci            [*metallib newFunctionWithName: @"fragmentMain"];
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci    // TODO: I *think* this gets cleaned up by the pipelineDescriptor?
290cb93a386Sopenharmony_ci    (*psoDescriptor).vertexDescriptor = create_vertex_descriptor(desc);
291cb93a386Sopenharmony_ci
292cb93a386Sopenharmony_ci    // TODO: I *think* this gets cleaned up by the pipelineDescriptor as well?
293cb93a386Sopenharmony_ci    auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci    mtlColorAttachment.pixelFormat = MTLPixelFormatRGBA8Unorm;
296cb93a386Sopenharmony_ci    mtlColorAttachment.blendingEnabled = FALSE;
297cb93a386Sopenharmony_ci    mtlColorAttachment.writeMask = MTLColorWriteMaskAll;
298cb93a386Sopenharmony_ci
299cb93a386Sopenharmony_ci    (*psoDescriptor).colorAttachments[0] = mtlColorAttachment;
300cb93a386Sopenharmony_ci    (*psoDescriptor).sampleCount = 1;
301cb93a386Sopenharmony_ci
302cb93a386Sopenharmony_ci    NSError* error;
303cb93a386Sopenharmony_ci    sk_cfp<id<MTLRenderPipelineState>> pso(
304cb93a386Sopenharmony_ci            [gpu->device() newRenderPipelineStateWithDescriptor:psoDescriptor.get()
305cb93a386Sopenharmony_ci                                                          error:&error]);
306cb93a386Sopenharmony_ci    if (!pso) {
307cb93a386Sopenharmony_ci        SkDebugf("Pipeline creation failure\n");
308cb93a386Sopenharmony_ci        SkDebugf("Errors:\n%s", error.debugDescription.UTF8String);
309cb93a386Sopenharmony_ci        return nullptr;
310cb93a386Sopenharmony_ci    }
311cb93a386Sopenharmony_ci    return sk_sp<GraphicsPipeline>(new GraphicsPipeline(std::move(pso), desc.vertexStride(),
312cb93a386Sopenharmony_ci                                                        desc.instanceStride()));
313cb93a386Sopenharmony_ci}
314cb93a386Sopenharmony_ci
315cb93a386Sopenharmony_ci} // namespace skgpu::mtl
316