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