xref: /aosp_15_r20/external/skia/src/gpu/graphite/mtl/MtlGraphicsPipeline.mm (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1/*
2 * Copyright 2021 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/mtl/MtlGraphicsPipeline.h"
9
10#include "include/gpu/graphite/TextureInfo.h"
11#include "src/gpu/graphite/Attribute.h"
12#include "src/gpu/graphite/ContextUtils.h"
13#include "src/gpu/graphite/GraphicsPipelineDesc.h"
14#include "src/gpu/graphite/Log.h"
15#include "src/gpu/graphite/RenderPassDesc.h"
16#include "src/gpu/graphite/RendererProvider.h"
17#include "src/gpu/graphite/ShaderInfo.h"
18#include "src/gpu/graphite/mtl/MtlGraphiteTypesPriv.h"
19#include "src/gpu/graphite/mtl/MtlGraphiteUtilsPriv.h"
20#include "src/gpu/graphite/mtl/MtlResourceProvider.h"
21#include "src/gpu/graphite/mtl/MtlSharedContext.h"
22#include "src/gpu/mtl/MtlUtilsPriv.h"
23#include "src/sksl/SkSLCompiler.h"
24#include "src/sksl/SkSLProgramSettings.h"
25#include "src/sksl/ir/SkSLProgram.h"
26
27namespace skgpu::graphite {
28
29namespace {
30
31inline MTLVertexFormat attribute_type_to_mtlformat(VertexAttribType type) {
32    switch (type) {
33        case VertexAttribType::kFloat:
34            return MTLVertexFormatFloat;
35        case VertexAttribType::kFloat2:
36            return MTLVertexFormatFloat2;
37        case VertexAttribType::kFloat3:
38            return MTLVertexFormatFloat3;
39        case VertexAttribType::kFloat4:
40            return MTLVertexFormatFloat4;
41        case VertexAttribType::kHalf:
42            if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
43                return MTLVertexFormatHalf;
44            } else {
45                return MTLVertexFormatInvalid;
46            }
47        case VertexAttribType::kHalf2:
48            return MTLVertexFormatHalf2;
49        case VertexAttribType::kHalf4:
50            return MTLVertexFormatHalf4;
51        case VertexAttribType::kInt2:
52            return MTLVertexFormatInt2;
53        case VertexAttribType::kInt3:
54            return MTLVertexFormatInt3;
55        case VertexAttribType::kInt4:
56            return MTLVertexFormatInt4;
57        case VertexAttribType::kUInt2:
58            return MTLVertexFormatUInt2;
59        case VertexAttribType::kByte:
60            if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
61                return MTLVertexFormatChar;
62            } else {
63                return MTLVertexFormatInvalid;
64            }
65        case VertexAttribType::kByte2:
66            return MTLVertexFormatChar2;
67        case VertexAttribType::kByte4:
68            return MTLVertexFormatChar4;
69        case VertexAttribType::kUByte:
70            if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
71                return MTLVertexFormatUChar;
72            } else {
73                return MTLVertexFormatInvalid;
74            }
75        case VertexAttribType::kUByte2:
76            return MTLVertexFormatUChar2;
77        case VertexAttribType::kUByte4:
78            return MTLVertexFormatUChar4;
79        case VertexAttribType::kUByte_norm:
80            if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
81                return MTLVertexFormatUCharNormalized;
82            } else {
83                return MTLVertexFormatInvalid;
84            }
85        case VertexAttribType::kUByte4_norm:
86            return MTLVertexFormatUChar4Normalized;
87        case VertexAttribType::kShort2:
88            return MTLVertexFormatShort2;
89        case VertexAttribType::kShort4:
90            return MTLVertexFormatShort4;
91        case VertexAttribType::kUShort2:
92            return MTLVertexFormatUShort2;
93        case VertexAttribType::kUShort2_norm:
94            return MTLVertexFormatUShort2Normalized;
95        case VertexAttribType::kInt:
96            return MTLVertexFormatInt;
97        case VertexAttribType::kUInt:
98            return MTLVertexFormatUInt;
99        case VertexAttribType::kUShort_norm:
100            if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
101                return MTLVertexFormatUShortNormalized;
102            } else {
103                return MTLVertexFormatInvalid;
104            }
105        case VertexAttribType::kUShort4_norm:
106            return MTLVertexFormatUShort4Normalized;
107    }
108    SK_ABORT("Unknown vertex attribute type");
109}
110
111MTLVertexDescriptor* create_vertex_descriptor(SkSpan<const Attribute> vertexAttrs,
112                                              SkSpan<const Attribute> instanceAttrs) {
113    auto vertexDescriptor = [[MTLVertexDescriptor alloc] init];
114    int attributeIndex = 0;
115
116    size_t vertexAttributeOffset = 0;
117    for (const auto& attribute : vertexAttrs) {
118        MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
119        MTLVertexFormat format = attribute_type_to_mtlformat(attribute.cpuType());
120        SkASSERT(MTLVertexFormatInvalid != format);
121        mtlAttribute.format = format;
122        mtlAttribute.offset = vertexAttributeOffset;
123        mtlAttribute.bufferIndex = MtlGraphicsPipeline::kVertexBufferIndex;
124
125        vertexAttributeOffset += attribute.sizeAlign4();
126        attributeIndex++;
127    }
128
129    if (vertexAttributeOffset) {
130        MTLVertexBufferLayoutDescriptor* vertexBufferLayout =
131                vertexDescriptor.layouts[MtlGraphicsPipeline::kVertexBufferIndex];
132        vertexBufferLayout.stepFunction = MTLVertexStepFunctionPerVertex;
133        vertexBufferLayout.stepRate = 1;
134        vertexBufferLayout.stride = vertexAttributeOffset;
135    }
136
137    size_t instanceAttributeOffset = 0;
138    for (const auto& attribute : instanceAttrs) {
139        MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
140        MTLVertexFormat format = attribute_type_to_mtlformat(attribute.cpuType());
141        SkASSERT(MTLVertexFormatInvalid != format);
142        mtlAttribute.format = format;
143        mtlAttribute.offset = instanceAttributeOffset;
144        mtlAttribute.bufferIndex = MtlGraphicsPipeline::kInstanceBufferIndex;
145
146        instanceAttributeOffset += attribute.sizeAlign4();
147        attributeIndex++;
148    }
149
150    if (instanceAttributeOffset) {
151        MTLVertexBufferLayoutDescriptor* instanceBufferLayout =
152                vertexDescriptor.layouts[MtlGraphicsPipeline::kInstanceBufferIndex];
153        instanceBufferLayout.stepFunction = MTLVertexStepFunctionPerInstance;
154        instanceBufferLayout.stepRate = 1;
155        instanceBufferLayout.stride = instanceAttributeOffset;
156    }
157    return vertexDescriptor;
158}
159
160// TODO: share this w/ Ganesh Metal backend?
161static MTLBlendFactor blend_coeff_to_mtl_blend(skgpu::BlendCoeff coeff) {
162    switch (coeff) {
163        case skgpu::BlendCoeff::kZero:
164            return MTLBlendFactorZero;
165        case skgpu::BlendCoeff::kOne:
166            return MTLBlendFactorOne;
167        case skgpu::BlendCoeff::kSC:
168            return MTLBlendFactorSourceColor;
169        case skgpu::BlendCoeff::kISC:
170            return MTLBlendFactorOneMinusSourceColor;
171        case skgpu::BlendCoeff::kDC:
172            return MTLBlendFactorDestinationColor;
173        case skgpu::BlendCoeff::kIDC:
174            return MTLBlendFactorOneMinusDestinationColor;
175        case skgpu::BlendCoeff::kSA:
176            return MTLBlendFactorSourceAlpha;
177        case skgpu::BlendCoeff::kISA:
178            return MTLBlendFactorOneMinusSourceAlpha;
179        case skgpu::BlendCoeff::kDA:
180            return MTLBlendFactorDestinationAlpha;
181        case skgpu::BlendCoeff::kIDA:
182            return MTLBlendFactorOneMinusDestinationAlpha;
183        case skgpu::BlendCoeff::kConstC:
184            return MTLBlendFactorBlendColor;
185        case skgpu::BlendCoeff::kIConstC:
186            return MTLBlendFactorOneMinusBlendColor;
187        case skgpu::BlendCoeff::kS2C:
188            if (@available(macOS 10.12, iOS 11.0, tvOS 11.0, *)) {
189                return MTLBlendFactorSource1Color;
190            } else {
191                return MTLBlendFactorZero;
192            }
193        case skgpu::BlendCoeff::kIS2C:
194            if (@available(macOS 10.12, iOS 11.0, tvOS 11.0, *)) {
195                return MTLBlendFactorOneMinusSource1Color;
196            } else {
197                return MTLBlendFactorZero;
198            }
199        case skgpu::BlendCoeff::kS2A:
200            if (@available(macOS 10.12, iOS 11.0, tvOS 11.0, *)) {
201                return MTLBlendFactorSource1Alpha;
202            } else {
203                return MTLBlendFactorZero;
204            }
205        case skgpu::BlendCoeff::kIS2A:
206            if (@available(macOS 10.12, iOS 11.0, tvOS 11.0, *)) {
207                return MTLBlendFactorOneMinusSource1Alpha;
208            } else {
209                return MTLBlendFactorZero;
210            }
211        case skgpu::BlendCoeff::kIllegal:
212            return MTLBlendFactorZero;
213    }
214
215    SK_ABORT("Unknown blend coefficient");
216}
217
218// TODO: share this w/ Ganesh Metal backend?
219static MTLBlendOperation blend_equation_to_mtl_blend_op(skgpu::BlendEquation equation) {
220    static const MTLBlendOperation gTable[] = {
221            MTLBlendOperationAdd,              // skgpu::BlendEquation::kAdd
222            MTLBlendOperationSubtract,         // skgpu::BlendEquation::kSubtract
223            MTLBlendOperationReverseSubtract,  // skgpu::BlendEquation::kReverseSubtract
224    };
225    static_assert(std::size(gTable) == (int)skgpu::BlendEquation::kFirstAdvanced);
226    static_assert(0 == (int)skgpu::BlendEquation::kAdd);
227    static_assert(1 == (int)skgpu::BlendEquation::kSubtract);
228    static_assert(2 == (int)skgpu::BlendEquation::kReverseSubtract);
229
230    SkASSERT((unsigned)equation < skgpu::kBlendEquationCnt);
231    return gTable[(int)equation];
232}
233
234static MTLRenderPipelineColorAttachmentDescriptor* create_color_attachment(
235        MTLPixelFormat format,
236        const BlendInfo& blendInfo) {
237
238    skgpu::BlendEquation equation = blendInfo.fEquation;
239    skgpu::BlendCoeff srcCoeff = blendInfo.fSrcBlend;
240    skgpu::BlendCoeff dstCoeff = blendInfo.fDstBlend;
241    bool blendOn = !skgpu::BlendShouldDisable(equation, srcCoeff, dstCoeff);
242
243    // TODO: I *think* this gets cleaned up by the pipelineDescriptor?
244    auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
245
246    mtlColorAttachment.pixelFormat = format;
247
248    mtlColorAttachment.blendingEnabled = blendOn;
249
250    if (blendOn) {
251        mtlColorAttachment.sourceRGBBlendFactor = blend_coeff_to_mtl_blend(srcCoeff);
252        mtlColorAttachment.destinationRGBBlendFactor = blend_coeff_to_mtl_blend(dstCoeff);
253        mtlColorAttachment.rgbBlendOperation = blend_equation_to_mtl_blend_op(equation);
254        mtlColorAttachment.sourceAlphaBlendFactor = blend_coeff_to_mtl_blend(srcCoeff);
255        mtlColorAttachment.destinationAlphaBlendFactor = blend_coeff_to_mtl_blend(dstCoeff);
256        mtlColorAttachment.alphaBlendOperation = blend_equation_to_mtl_blend_op(equation);
257    }
258
259    mtlColorAttachment.writeMask = blendInfo.fWritesColor ? MTLColorWriteMaskAll
260                                                          : MTLColorWriteMaskNone;
261
262    return mtlColorAttachment;
263}
264
265} // anonymous namespace
266
267sk_sp<MtlGraphicsPipeline> MtlGraphicsPipeline::Make(
268        const MtlSharedContext* sharedContext,
269        MtlResourceProvider* resourceProvider,
270        const RuntimeEffectDictionary* runtimeDict,
271        const GraphicsPipelineDesc& pipelineDesc,
272        const RenderPassDesc& renderPassDesc,
273        SkEnumBitMask<PipelineCreationFlags> pipelineCreationFlags) {
274    std::string vsMSL, fsMSL;
275    SkSL::Program::Interface vsInterface, fsInterface;
276
277    SkSL::ProgramSettings settings;
278    settings.fSharpenTextures = true;
279    settings.fForceNoRTFlip = true;
280
281    SkSL::Compiler skslCompiler;
282    ShaderErrorHandler* errorHandler = sharedContext->caps()->shaderErrorHandler();
283
284    const RenderStep* step =
285            sharedContext->rendererProvider()->lookup(pipelineDesc.renderStepID());
286    const bool useStorageBuffers = sharedContext->caps()->storageBufferSupport();
287
288    UniquePaintParamsID paintID = pipelineDesc.paintParamsID();
289
290    std::unique_ptr<ShaderInfo> shaderInfo = ShaderInfo::Make(sharedContext->caps(),
291                                                              sharedContext->shaderCodeDictionary(),
292                                                              runtimeDict,
293                                                              step,
294                                                              paintID,
295                                                              useStorageBuffers,
296                                                              renderPassDesc.fWriteSwizzle);
297
298    const std::string& fsSkSL = shaderInfo->fragmentSkSL();
299    const BlendInfo& blendInfo = shaderInfo->blendInfo();
300    if (!SkSLToMSL(sharedContext->caps()->shaderCaps(),
301                   fsSkSL,
302                   SkSL::ProgramKind::kGraphiteFragment,
303                   settings,
304                   &fsMSL,
305                   &fsInterface,
306                   errorHandler)) {
307        return nullptr;
308    }
309
310    const std::string& vsSkSL = shaderInfo->vertexSkSL();
311    if (!SkSLToMSL(sharedContext->caps()->shaderCaps(),
312                   vsSkSL,
313                   SkSL::ProgramKind::kGraphiteVertex,
314                   settings,
315                   &vsMSL,
316                   &vsInterface,
317                   errorHandler)) {
318        return nullptr;
319    }
320
321    auto vsLibrary =
322            MtlCompileShaderLibrary(sharedContext, shaderInfo->vsLabel(), vsMSL, errorHandler);
323    auto fsLibrary =
324            MtlCompileShaderLibrary(sharedContext, shaderInfo->fsLabel(), fsMSL, errorHandler);
325
326    sk_cfp<id<MTLDepthStencilState>> dss =
327            resourceProvider->findOrCreateCompatibleDepthStencilState(step->depthStencilSettings());
328
329    PipelineInfo pipelineInfo{*shaderInfo, pipelineCreationFlags};
330#if defined(GPU_TEST_UTILS)
331    pipelineInfo.fNativeVertexShader = std::move(vsMSL);
332    pipelineInfo.fNativeFragmentShader = std::move(fsMSL);
333#endif
334
335    std::string pipelineLabel =
336            GetPipelineLabel(sharedContext->shaderCodeDictionary(), renderPassDesc, step, paintID);
337    return Make(sharedContext,
338                pipelineLabel,
339                pipelineInfo,
340                {vsLibrary.get(), "vertexMain"},
341                step->vertexAttributes(),
342                step->instanceAttributes(),
343                {fsLibrary.get(), "fragmentMain"},
344                std::move(dss),
345                step->depthStencilSettings().fStencilReferenceValue,
346                blendInfo,
347                renderPassDesc);
348}
349
350sk_sp<MtlGraphicsPipeline> MtlGraphicsPipeline::MakeLoadMSAAPipeline(
351        const MtlSharedContext* sharedContext,
352        MtlResourceProvider* resourceProvider,
353        const RenderPassDesc& renderPassDesc) {
354    static const char* kLoadMSAAShaderText = R"(
355            #include <metal_stdlib>
356            #include <simd/simd.h>
357            using namespace metal;
358
359            typedef struct {
360                float4 position [[position]];
361            } VertexOutput;
362
363            vertex VertexOutput vertexMain(uint vertexID [[vertex_id]]) {
364                VertexOutput out;
365                float2 position = float2(float(vertexID >> 1), float(vertexID & 1));
366                out.position = float4(2.0 * position - 1.0, 0.0, 1.0);
367                return out;
368            }
369
370            fragment float4 fragmentMain(VertexOutput in [[stage_in]],
371                                            texture2d<half> colorMap [[texture(0)]]) {
372                uint2 coords = uint2(in.position.x, in.position.y);
373                half4 colorSample   = colorMap.read(coords);
374                return float4(colorSample);
375            }
376    )";
377
378    auto mtlLibrary = MtlCompileShaderLibrary(sharedContext,
379                                              "LoadMSAAFromResolve",
380                                              kLoadMSAAShaderText,
381                                              sharedContext->caps()->shaderErrorHandler());
382    BlendInfo noBlend{}; // default is equivalent to kSrc blending
383    sk_cfp<id<MTLDepthStencilState>> ignoreDS =
384            resourceProvider->findOrCreateCompatibleDepthStencilState({});
385
386    std::string pipelineLabel = "LoadMSAAFromResolve + ";
387    pipelineLabel += renderPassDesc.toString().c_str();
388
389    PipelineInfo pipelineInfo;
390    pipelineInfo.fNumFragTexturesAndSamplers = 1;
391    // This is an internal shader, leave off filling out the test-utils shader code
392    return Make(sharedContext,
393                pipelineLabel,
394                pipelineInfo,
395                {mtlLibrary.get(), "vertexMain"},
396                /*vertexAttrs=*/{},
397                /*instanceAttrs=*/{},
398                {mtlLibrary.get(), "fragmentMain"},
399                std::move(ignoreDS),
400                /*stencilRefValue=*/0,
401                noBlend,
402                renderPassDesc);
403}
404
405sk_sp<MtlGraphicsPipeline> MtlGraphicsPipeline::Make(const MtlSharedContext* sharedContext,
406                                                     const std::string& label,
407                                                     const PipelineInfo& pipelineInfo,
408                                                     MSLFunction vertexMain,
409                                                     SkSpan<const Attribute> vertexAttrs,
410                                                     SkSpan<const Attribute> instanceAttrs,
411                                                     MSLFunction fragmentMain,
412                                                     sk_cfp<id<MTLDepthStencilState>> dss,
413                                                     uint32_t stencilRefValue,
414                                                     const BlendInfo& blendInfo,
415                                                     const RenderPassDesc& renderPassDesc) {
416    id<MTLLibrary> vsLibrary = std::get<0>(vertexMain);
417    id<MTLLibrary> fsLibrary = std::get<0>(fragmentMain);
418    if (!vsLibrary || !fsLibrary) {
419        return nullptr;
420    }
421
422    sk_cfp<MTLRenderPipelineDescriptor*> psoDescriptor([[MTLRenderPipelineDescriptor alloc] init]);
423
424    NSString* labelName =  [NSString stringWithUTF8String: label.c_str()];
425    NSString* vsFuncName = [NSString stringWithUTF8String: std::get<1>(vertexMain).c_str()];
426    NSString* fsFuncName = [NSString stringWithUTF8String: std::get<1>(fragmentMain).c_str()];
427
428    (*psoDescriptor).label = labelName;
429    (*psoDescriptor).vertexFunction = [vsLibrary newFunctionWithName: vsFuncName];
430    (*psoDescriptor).fragmentFunction = [fsLibrary newFunctionWithName: fsFuncName];
431
432    // TODO: I *think* this gets cleaned up by the pipelineDescriptor?
433    (*psoDescriptor).vertexDescriptor = create_vertex_descriptor(vertexAttrs, instanceAttrs);
434
435    MTLPixelFormat pixelFormat =
436            TextureInfos::GetMTLPixelFormat(renderPassDesc.fColorAttachment.fTextureInfo);
437    auto mtlColorAttachment = create_color_attachment(pixelFormat, blendInfo);
438    (*psoDescriptor).colorAttachments[0] = mtlColorAttachment;
439
440    (*psoDescriptor).rasterSampleCount =
441            renderPassDesc.fColorAttachment.fTextureInfo.numSamples();
442
443    MTLPixelFormat depthStencilFormat =
444            TextureInfos::GetMTLPixelFormat(renderPassDesc.fDepthStencilAttachment.fTextureInfo);
445    if (MtlFormatIsStencil(depthStencilFormat)) {
446        (*psoDescriptor).stencilAttachmentPixelFormat = depthStencilFormat;
447    } else {
448        (*psoDescriptor).stencilAttachmentPixelFormat = MTLPixelFormatInvalid;
449    }
450    if (MtlFormatIsDepth(depthStencilFormat)) {
451        (*psoDescriptor).depthAttachmentPixelFormat = depthStencilFormat;
452    } else {
453        (*psoDescriptor).depthAttachmentPixelFormat = MTLPixelFormatInvalid;
454    }
455
456    NSError* error;
457    sk_cfp<id<MTLRenderPipelineState>> pso(
458            [sharedContext->device() newRenderPipelineStateWithDescriptor:psoDescriptor.get()
459                                                                    error:&error]);
460    if (!pso) {
461        SKGPU_LOG_E("Render pipeline creation failure:\n%s", error.debugDescription.UTF8String);
462        return nullptr;
463    }
464
465    return sk_sp<MtlGraphicsPipeline>(new MtlGraphicsPipeline(sharedContext,
466                                                              pipelineInfo,
467                                                              std::move(pso),
468                                                              std::move(dss),
469                                                              stencilRefValue));
470}
471
472MtlGraphicsPipeline::MtlGraphicsPipeline(const skgpu::graphite::SharedContext* sharedContext,
473                                         const PipelineInfo& pipelineInfo,
474                                         sk_cfp<id<MTLRenderPipelineState>> pso,
475                                         sk_cfp<id<MTLDepthStencilState>> dss,
476                                         uint32_t refValue)
477        : GraphicsPipeline(sharedContext, pipelineInfo)
478        , fPipelineState(std::move(pso))
479        , fDepthStencilState(std::move(dss))
480        , fStencilReferenceValue(refValue) {}
481
482void MtlGraphicsPipeline::freeGpuData() {
483    fPipelineState.reset();
484}
485
486} // namespace skgpu::graphite
487