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