• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2018 Google Inc.
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/mtl/GrMtlPipelineStateBuilder.h"
9
10#include "include/gpu/GrContext.h"
11#include "src/gpu/GrContextPriv.h"
12
13#include "src/gpu/mtl/GrMtlGpu.h"
14#include "src/gpu/mtl/GrMtlPipelineState.h"
15#include "src/gpu/mtl/GrMtlUtil.h"
16
17#include "src/gpu/GrRenderTargetPriv.h"
18
19#import <simd/simd.h>
20
21#if !__has_feature(objc_arc)
22#error This file must be compiled with Arc. Use -fobjc-arc flag
23#endif
24
25GrMtlPipelineState* GrMtlPipelineStateBuilder::CreatePipelineState(
26        GrMtlGpu* gpu,
27        GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
28        const GrPrimitiveProcessor& primProc,
29        const GrTextureProxy* const primProcProxies[],
30        const GrPipeline& pipeline,
31        Desc* desc) {
32    GrMtlPipelineStateBuilder builder(gpu, renderTarget, origin, pipeline, primProc,
33                                      primProcProxies, desc);
34
35    if (!builder.emitAndInstallProcs()) {
36        return nullptr;
37    }
38    return builder.finalize(renderTarget, primProc, pipeline, desc);
39}
40
41GrMtlPipelineStateBuilder::GrMtlPipelineStateBuilder(GrMtlGpu* gpu,
42                                                     GrRenderTarget* renderTarget,
43                                                     GrSurfaceOrigin origin,
44                                                     const GrPipeline& pipeline,
45                                                     const GrPrimitiveProcessor& primProc,
46                                                     const GrTextureProxy* const primProcProxies[],
47                                                     GrProgramDesc* desc)
48        : INHERITED(renderTarget, origin, primProc, primProcProxies, pipeline, desc)
49        , fGpu(gpu)
50        , fUniformHandler(this)
51        , fVaryingHandler(this) {
52}
53
54const GrCaps* GrMtlPipelineStateBuilder::caps() const {
55    return fGpu->caps();
56}
57
58void GrMtlPipelineStateBuilder::finalizeFragmentOutputColor(GrShaderVar& outputColor) {
59    outputColor.addLayoutQualifier("location = 0, index = 0");
60}
61
62void GrMtlPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {
63    outputColor.addLayoutQualifier("location = 0, index = 1");
64}
65
66id<MTLLibrary> GrMtlPipelineStateBuilder::createMtlShaderLibrary(
67        const GrGLSLShaderBuilder& builder,
68        SkSL::Program::Kind kind,
69        const SkSL::Program::Settings& settings,
70        GrProgramDesc* desc) {
71    SkSL::Program::Inputs inputs;
72    id<MTLLibrary> shaderLibrary = GrCompileMtlShaderLibrary(fGpu, builder.fCompilerString.c_str(),
73                                                             kind, settings, &inputs);
74    if (shaderLibrary == nil) {
75        return nil;
76    }
77    if (inputs.fRTHeight) {
78        this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
79    }
80    return shaderLibrary;
81}
82
83static inline MTLVertexFormat attribute_type_to_mtlformat(GrVertexAttribType type) {
84    // All half types will actually be float types. We are currently not using half types with
85    // metal to avoid an issue with narrow type coercions (float->half) http://skbug.com/8221
86    switch (type) {
87        case kFloat_GrVertexAttribType:
88            return MTLVertexFormatFloat;
89        case kFloat2_GrVertexAttribType:
90            return MTLVertexFormatFloat2;
91        case kFloat3_GrVertexAttribType:
92            return MTLVertexFormatFloat3;
93        case kFloat4_GrVertexAttribType:
94            return MTLVertexFormatFloat4;
95        case kHalf_GrVertexAttribType:
96            return MTLVertexFormatHalf;
97        case kHalf2_GrVertexAttribType:
98            return MTLVertexFormatHalf2;
99        case kHalf3_GrVertexAttribType:
100            return MTLVertexFormatHalf3;
101        case kHalf4_GrVertexAttribType:
102            return MTLVertexFormatHalf4;
103        case kInt2_GrVertexAttribType:
104            return MTLVertexFormatInt2;
105        case kInt3_GrVertexAttribType:
106            return MTLVertexFormatInt3;
107        case kInt4_GrVertexAttribType:
108            return MTLVertexFormatInt4;
109        case kByte_GrVertexAttribType:
110            return MTLVertexFormatChar;
111        case kByte2_GrVertexAttribType:
112            return MTLVertexFormatChar2;
113        case kByte3_GrVertexAttribType:
114            return MTLVertexFormatChar3;
115        case kByte4_GrVertexAttribType:
116            return MTLVertexFormatChar4;
117        case kUByte_GrVertexAttribType:
118            return MTLVertexFormatUChar;
119        case kUByte2_GrVertexAttribType:
120            return MTLVertexFormatUChar2;
121        case kUByte3_GrVertexAttribType:
122            return MTLVertexFormatUChar3;
123        case kUByte4_GrVertexAttribType:
124            return MTLVertexFormatUChar4;
125        case kUByte_norm_GrVertexAttribType:
126            return MTLVertexFormatUCharNormalized;
127        case kUByte4_norm_GrVertexAttribType:
128            return MTLVertexFormatUChar4Normalized;
129        case kShort2_GrVertexAttribType:
130            return MTLVertexFormatShort2;
131        case kShort4_GrVertexAttribType:
132            return MTLVertexFormatShort4;
133        case kUShort2_GrVertexAttribType:
134            return MTLVertexFormatUShort2;
135        case kUShort2_norm_GrVertexAttribType:
136            return MTLVertexFormatUShort2Normalized;
137        case kInt_GrVertexAttribType:
138            return MTLVertexFormatInt;
139        case kUint_GrVertexAttribType:
140            return MTLVertexFormatUInt;
141        case kUShort_norm_GrVertexAttribType:
142            return MTLVertexFormatUShortNormalized;
143        // Experimental (for Y416)
144        case kUShort4_norm_GrVertexAttribType:
145            return MTLVertexFormatUShort4Normalized;
146    }
147    SK_ABORT("Unknown vertex attribute type");
148}
149
150static MTLVertexDescriptor* create_vertex_descriptor(const GrPrimitiveProcessor& primProc) {
151    uint32_t vertexBinding = 0, instanceBinding = 0;
152
153    int nextBinding = GrMtlUniformHandler::kLastUniformBinding + 1;
154    if (primProc.hasVertexAttributes()) {
155        vertexBinding = nextBinding++;
156    }
157
158    if (primProc.hasInstanceAttributes()) {
159        instanceBinding = nextBinding;
160    }
161
162    auto vertexDescriptor = [[MTLVertexDescriptor alloc] init];
163    int attributeIndex = 0;
164
165    int vertexAttributeCount = primProc.numVertexAttributes();
166    size_t vertexAttributeOffset = 0;
167    for (const auto& attribute : primProc.vertexAttributes()) {
168        MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
169        mtlAttribute.format = attribute_type_to_mtlformat(attribute.cpuType());
170        mtlAttribute.offset = vertexAttributeOffset;
171        mtlAttribute.bufferIndex = vertexBinding;
172
173        vertexAttributeOffset += attribute.sizeAlign4();
174        attributeIndex++;
175    }
176    SkASSERT(vertexAttributeOffset == primProc.vertexStride());
177
178    if (vertexAttributeCount) {
179        MTLVertexBufferLayoutDescriptor* vertexBufferLayout =
180                vertexDescriptor.layouts[vertexBinding];
181        vertexBufferLayout.stepFunction = MTLVertexStepFunctionPerVertex;
182        vertexBufferLayout.stepRate = 1;
183        vertexBufferLayout.stride = vertexAttributeOffset;
184    }
185
186    int instanceAttributeCount = primProc.numInstanceAttributes();
187    size_t instanceAttributeOffset = 0;
188    for (const auto& attribute : primProc.instanceAttributes()) {
189        MTLVertexAttributeDescriptor* mtlAttribute = vertexDescriptor.attributes[attributeIndex];
190        mtlAttribute.format = attribute_type_to_mtlformat(attribute.cpuType());
191        mtlAttribute.offset = instanceAttributeOffset;
192        mtlAttribute.bufferIndex = instanceBinding;
193
194        instanceAttributeOffset += attribute.sizeAlign4();
195        attributeIndex++;
196    }
197    SkASSERT(instanceAttributeOffset == primProc.instanceStride());
198
199    if (instanceAttributeCount) {
200        MTLVertexBufferLayoutDescriptor* instanceBufferLayout =
201                vertexDescriptor.layouts[instanceBinding];
202        instanceBufferLayout.stepFunction = MTLVertexStepFunctionPerInstance;
203        instanceBufferLayout.stepRate = 1;
204        instanceBufferLayout.stride = instanceAttributeOffset;
205    }
206    return vertexDescriptor;
207}
208
209static MTLBlendFactor blend_coeff_to_mtl_blend(GrBlendCoeff coeff) {
210    static const MTLBlendFactor gTable[] = {
211        MTLBlendFactorZero,                      // kZero_GrBlendCoeff
212        MTLBlendFactorOne,                       // kOne_GrBlendCoeff
213        MTLBlendFactorSourceColor,               // kSC_GrBlendCoeff
214        MTLBlendFactorOneMinusSourceColor,       // kISC_GrBlendCoeff
215        MTLBlendFactorDestinationColor,          // kDC_GrBlendCoeff
216        MTLBlendFactorOneMinusDestinationColor,  // kIDC_GrBlendCoeff
217        MTLBlendFactorSourceAlpha,               // kSA_GrBlendCoeff
218        MTLBlendFactorOneMinusSourceAlpha,       // kISA_GrBlendCoeff
219        MTLBlendFactorDestinationAlpha,          // kDA_GrBlendCoeff
220        MTLBlendFactorOneMinusDestinationAlpha,  // kIDA_GrBlendCoeff
221        MTLBlendFactorBlendColor,                // kConstC_GrBlendCoeff
222        MTLBlendFactorOneMinusBlendColor,        // kIConstC_GrBlendCoeff
223        MTLBlendFactorBlendAlpha,                // kConstA_GrBlendCoeff
224        MTLBlendFactorOneMinusBlendAlpha,        // kIConstA_GrBlendCoeff
225        MTLBlendFactorSource1Color,              // kS2C_GrBlendCoeff
226        MTLBlendFactorOneMinusSource1Color,      // kIS2C_GrBlendCoeff
227        MTLBlendFactorSource1Alpha,              // kS2A_GrBlendCoeff
228        MTLBlendFactorOneMinusSource1Alpha,      // kIS2A_GrBlendCoeff
229        MTLBlendFactorZero,                      // kIllegal_GrBlendCoeff
230    };
231    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kGrBlendCoeffCnt);
232    GR_STATIC_ASSERT(0 == kZero_GrBlendCoeff);
233    GR_STATIC_ASSERT(1 == kOne_GrBlendCoeff);
234    GR_STATIC_ASSERT(2 == kSC_GrBlendCoeff);
235    GR_STATIC_ASSERT(3 == kISC_GrBlendCoeff);
236    GR_STATIC_ASSERT(4 == kDC_GrBlendCoeff);
237    GR_STATIC_ASSERT(5 == kIDC_GrBlendCoeff);
238    GR_STATIC_ASSERT(6 == kSA_GrBlendCoeff);
239    GR_STATIC_ASSERT(7 == kISA_GrBlendCoeff);
240    GR_STATIC_ASSERT(8 == kDA_GrBlendCoeff);
241    GR_STATIC_ASSERT(9 == kIDA_GrBlendCoeff);
242    GR_STATIC_ASSERT(10 == kConstC_GrBlendCoeff);
243    GR_STATIC_ASSERT(11 == kIConstC_GrBlendCoeff);
244    GR_STATIC_ASSERT(12 == kConstA_GrBlendCoeff);
245    GR_STATIC_ASSERT(13 == kIConstA_GrBlendCoeff);
246    GR_STATIC_ASSERT(14 == kS2C_GrBlendCoeff);
247    GR_STATIC_ASSERT(15 == kIS2C_GrBlendCoeff);
248    GR_STATIC_ASSERT(16 == kS2A_GrBlendCoeff);
249    GR_STATIC_ASSERT(17 == kIS2A_GrBlendCoeff);
250
251    SkASSERT((unsigned)coeff < kGrBlendCoeffCnt);
252    return gTable[coeff];
253}
254
255static MTLBlendOperation blend_equation_to_mtl_blend_op(GrBlendEquation equation) {
256    static const MTLBlendOperation gTable[] = {
257        MTLBlendOperationAdd,              // kAdd_GrBlendEquation
258        MTLBlendOperationSubtract,         // kSubtract_GrBlendEquation
259        MTLBlendOperationReverseSubtract,  // kReverseSubtract_GrBlendEquation
260    };
261    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kFirstAdvancedGrBlendEquation);
262    GR_STATIC_ASSERT(0 == kAdd_GrBlendEquation);
263    GR_STATIC_ASSERT(1 == kSubtract_GrBlendEquation);
264    GR_STATIC_ASSERT(2 == kReverseSubtract_GrBlendEquation);
265
266    SkASSERT((unsigned)equation < kGrBlendEquationCnt);
267    return gTable[equation];
268}
269
270static MTLRenderPipelineColorAttachmentDescriptor* create_color_attachment(
271        GrPixelConfig config, const GrPipeline& pipeline) {
272    auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
273
274    // pixel format
275    MTLPixelFormat format;
276    SkAssertResult(GrPixelConfigToMTLFormat(config, &format));
277    mtlColorAttachment.pixelFormat = format;
278
279    // blending
280    const GrXferProcessor::BlendInfo& blendInfo = pipeline.getXferProcessor().getBlendInfo();
281
282    GrBlendEquation equation = blendInfo.fEquation;
283    GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
284    GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
285    bool blendOff = (kAdd_GrBlendEquation == equation || kSubtract_GrBlendEquation == equation) &&
286                    kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff;
287
288    mtlColorAttachment.blendingEnabled = !blendOff;
289    if (!blendOff) {
290        mtlColorAttachment.sourceRGBBlendFactor = blend_coeff_to_mtl_blend(srcCoeff);
291        mtlColorAttachment.destinationRGBBlendFactor = blend_coeff_to_mtl_blend(dstCoeff);
292        mtlColorAttachment.rgbBlendOperation = blend_equation_to_mtl_blend_op(equation);
293        mtlColorAttachment.sourceAlphaBlendFactor = blend_coeff_to_mtl_blend(srcCoeff);
294        mtlColorAttachment.destinationAlphaBlendFactor = blend_coeff_to_mtl_blend(dstCoeff);
295        mtlColorAttachment.alphaBlendOperation = blend_equation_to_mtl_blend_op(equation);
296    }
297
298    if (!blendInfo.fWriteColor) {
299        mtlColorAttachment.writeMask = MTLColorWriteMaskNone;
300    } else {
301        mtlColorAttachment.writeMask = MTLColorWriteMaskAll;
302    }
303    return mtlColorAttachment;
304}
305
306uint32_t buffer_size(uint32_t offset, uint32_t maxAlignment) {
307    // Metal expects the buffer to be padded at the end according to the alignment
308    // of the largest element in the buffer.
309    uint32_t offsetDiff = offset & maxAlignment;
310    if (offsetDiff != 0) {
311        offsetDiff = maxAlignment - offsetDiff + 1;
312    }
313    return offset + offsetDiff;
314}
315
316GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTarget,
317                                                        const GrPrimitiveProcessor& primProc,
318                                                        const GrPipeline& pipeline,
319                                                        Desc* desc) {
320    auto pipelineDescriptor = [MTLRenderPipelineDescriptor new];
321
322    fVS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
323    fFS.extensions().appendf("#extension GL_ARB_separate_shader_objects : enable\n");
324    fVS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
325    fFS.extensions().appendf("#extension GL_ARB_shading_language_420pack : enable\n");
326
327    this->finalizeShaders();
328
329    SkSL::Program::Settings settings;
330    settings.fCaps = this->caps()->shaderCaps();
331    settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin;
332    settings.fSharpenTextures = fGpu->getContext()->priv().options().fSharpenMipmappedTextures;
333    SkASSERT(!this->fragColorIsInOut());
334
335    // TODO: Store shaders in cache
336    id<MTLLibrary> vertexLibrary = nil;
337    id<MTLLibrary> fragmentLibrary = nil;
338    vertexLibrary = this->createMtlShaderLibrary(fVS,
339                                                 SkSL::Program::kVertex_Kind,
340                                                 settings,
341                                                 desc);
342    fragmentLibrary = this->createMtlShaderLibrary(fFS,
343                                                   SkSL::Program::kFragment_Kind,
344                                                   settings,
345                                                   desc);
346    SkASSERT(!this->primitiveProcessor().willUseGeoShader());
347
348    if (!vertexLibrary || !fragmentLibrary) {
349        return nullptr;
350    }
351
352    id<MTLFunction> vertexFunction = [vertexLibrary newFunctionWithName: @"vertexMain"];
353    id<MTLFunction> fragmentFunction = [fragmentLibrary newFunctionWithName: @"fragmentMain"];
354
355    if (vertexFunction == nil) {
356        SkDebugf("Couldn't find vertexMain() in library\n");
357        return nullptr;
358    }
359    if (fragmentFunction == nil) {
360        SkDebugf("Couldn't find fragmentMain() in library\n");
361        return nullptr;
362    }
363
364    pipelineDescriptor.vertexFunction = vertexFunction;
365    pipelineDescriptor.fragmentFunction = fragmentFunction;
366    pipelineDescriptor.vertexDescriptor = create_vertex_descriptor(primProc);
367    pipelineDescriptor.colorAttachments[0] = create_color_attachment(this->config(), pipeline);
368    pipelineDescriptor.sampleCount = renderTarget->numSamples();
369    bool hasStencilAttachment = SkToBool(renderTarget->renderTargetPriv().getStencilAttachment());
370    GrMtlCaps* mtlCaps = (GrMtlCaps*)this->caps();
371    pipelineDescriptor.stencilAttachmentPixelFormat =
372        hasStencilAttachment ? mtlCaps->preferredStencilFormat().fInternalFormat
373                             : MTLPixelFormatInvalid;
374
375    SkASSERT(pipelineDescriptor.vertexFunction);
376    SkASSERT(pipelineDescriptor.fragmentFunction);
377    SkASSERT(pipelineDescriptor.vertexDescriptor);
378    SkASSERT(pipelineDescriptor.colorAttachments[0]);
379
380#if defined(SK_BUILD_FOR_MAC) && defined(GR_USE_COMPLETION_HANDLER)
381    bool timedout;
382    id<MTLRenderPipelineState> pipelineState = GrMtlNewRenderPipelineStateWithDescriptor(
383                                                     fGpu->device(), pipelineDescriptor, &timedout);
384    if (timedout) {
385        // try a second time
386        pipelineState = GrMtlNewRenderPipelineStateWithDescriptor(
387                                fGpu->device(), pipelineDescriptor, &timedout);
388    }
389    if (!pipelineState) {
390        return nullptr;
391    }
392#else
393    NSError* error = nil;
394    id<MTLRenderPipelineState> pipelineState =
395            [fGpu->device() newRenderPipelineStateWithDescriptor: pipelineDescriptor
396                                                           error: &error];
397    if (error) {
398        SkDebugf("Error creating pipeline: %s\n",
399                 [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
400        return nullptr;
401    }
402#endif
403
404    uint32_t bufferSize = buffer_size(fUniformHandler.fCurrentUBOOffset,
405                                      fUniformHandler.fCurrentUBOMaxAlignment);
406    return new GrMtlPipelineState(fGpu,
407                                  pipelineState,
408                                  pipelineDescriptor.colorAttachments[0].pixelFormat,
409                                  fUniformHandles,
410                                  fUniformHandler.fUniforms,
411                                  bufferSize,
412                                  (uint32_t)fUniformHandler.numSamplers(),
413                                  std::move(fGeometryProcessor),
414                                  std::move(fXferProcessor),
415                                  std::move(fFragmentProcessors),
416                                  fFragmentProcessorCnt);
417}
418
419//////////////////////////////////////////////////////////////////////////////
420
421bool GrMtlPipelineStateBuilder::Desc::Build(Desc* desc,
422                                            GrRenderTarget* renderTarget,
423                                            const GrPrimitiveProcessor& primProc,
424                                            const GrPipeline& pipeline,
425                                            GrPrimitiveType primitiveType,
426                                            GrMtlGpu* gpu) {
427    if (!INHERITED::Build(desc, renderTarget, primProc,
428                          GrPrimitiveType::kLines == primitiveType, pipeline, gpu)) {
429        return false;
430    }
431
432    GrProcessorKeyBuilder b(&desc->key());
433
434    int keyLength = desc->key().count();
435    SkASSERT(0 == (keyLength % 4));
436    desc->fShaderKeyLength = SkToU32(keyLength);
437
438    b.add32(renderTarget->config());
439    b.add32(renderTarget->numSamples());
440    bool hasStencilAttachment = SkToBool(renderTarget->renderTargetPriv().getStencilAttachment());
441    b.add32(hasStencilAttachment ? gpu->mtlCaps().preferredStencilFormat().fInternalFormat
442                                 : MTLPixelFormatInvalid);
443    b.add32((uint32_t)pipeline.isStencilEnabled());
444    // Stencil samples don't seem to be tracked in the MTLRenderPipeline
445
446    b.add32(pipeline.getBlendInfoKey());
447
448    b.add32((uint32_t)primitiveType);
449
450    return true;
451}
452