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