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 UniqueKey& pipelineKey, 272 const GraphicsPipelineDesc& pipelineDesc, 273 const RenderPassDesc& renderPassDesc, 274 SkEnumBitMask<PipelineCreationFlags> pipelineCreationFlags, 275 uint32_t compilationID) { 276 std::string vsMSL, fsMSL; 277 SkSL::Program::Interface vsInterface, fsInterface; 278 279 SkSL::ProgramSettings settings; 280 settings.fSharpenTextures = true; 281 settings.fForceNoRTFlip = true; 282 283 SkSL::Compiler skslCompiler; 284 ShaderErrorHandler* errorHandler = sharedContext->caps()->shaderErrorHandler(); 285 286 const RenderStep* step = 287 sharedContext->rendererProvider()->lookup(pipelineDesc.renderStepID()); 288 const bool useStorageBuffers = sharedContext->caps()->storageBufferSupport(); 289 290 UniquePaintParamsID paintID = pipelineDesc.paintParamsID(); 291 292 std::unique_ptr<ShaderInfo> shaderInfo = ShaderInfo::Make(sharedContext->caps(), 293 sharedContext->shaderCodeDictionary(), 294 runtimeDict, 295 step, 296 paintID, 297 useStorageBuffers, 298 renderPassDesc.fWriteSwizzle); 299 300 const std::string& fsSkSL = shaderInfo->fragmentSkSL(); 301 const BlendInfo& blendInfo = shaderInfo->blendInfo(); 302 if (!SkSLToMSL(sharedContext->caps()->shaderCaps(), 303 fsSkSL, 304 SkSL::ProgramKind::kGraphiteFragment, 305 settings, 306 &fsMSL, 307 &fsInterface, 308 errorHandler)) { 309 return nullptr; 310 } 311 312 const std::string& vsSkSL = shaderInfo->vertexSkSL(); 313 if (!SkSLToMSL(sharedContext->caps()->shaderCaps(), 314 vsSkSL, 315 SkSL::ProgramKind::kGraphiteVertex, 316 settings, 317 &vsMSL, 318 &vsInterface, 319 errorHandler)) { 320 return nullptr; 321 } 322 323 auto vsLibrary = 324 MtlCompileShaderLibrary(sharedContext, shaderInfo->vsLabel(), vsMSL, errorHandler); 325 auto fsLibrary = 326 MtlCompileShaderLibrary(sharedContext, shaderInfo->fsLabel(), fsMSL, errorHandler); 327 328 sk_cfp<id<MTLDepthStencilState>> dss = 329 resourceProvider->findOrCreateCompatibleDepthStencilState(step->depthStencilSettings()); 330 331 PipelineInfo pipelineInfo{ *shaderInfo, pipelineCreationFlags, 332 pipelineKey.hash(), compilationID }; 333#if defined(GPU_TEST_UTILS) 334 pipelineInfo.fNativeVertexShader = std::move(vsMSL); 335 pipelineInfo.fNativeFragmentShader = std::move(fsMSL); 336#endif 337 338 std::string pipelineLabel = 339 GetPipelineLabel(sharedContext->shaderCodeDictionary(), renderPassDesc, step, paintID); 340 return Make(sharedContext, 341 pipelineLabel, 342 pipelineInfo, 343 {vsLibrary.get(), "vertexMain"}, 344 step->vertexAttributes(), 345 step->instanceAttributes(), 346 {fsLibrary.get(), "fragmentMain"}, 347 std::move(dss), 348 step->depthStencilSettings().fStencilReferenceValue, 349 blendInfo, 350 renderPassDesc); 351} 352 353sk_sp<MtlGraphicsPipeline> MtlGraphicsPipeline::MakeLoadMSAAPipeline( 354 const MtlSharedContext* sharedContext, 355 MtlResourceProvider* resourceProvider, 356 const RenderPassDesc& renderPassDesc) { 357 static const char* kLoadMSAAShaderText = R"( 358 #include <metal_stdlib> 359 #include <simd/simd.h> 360 using namespace metal; 361 362 typedef struct { 363 float4 position [[position]]; 364 } VertexOutput; 365 366 vertex VertexOutput vertexMain(uint vertexID [[vertex_id]]) { 367 VertexOutput out; 368 float2 position = float2(float(vertexID >> 1), float(vertexID & 1)); 369 out.position = float4(2.0 * position - 1.0, 0.0, 1.0); 370 return out; 371 } 372 373 fragment float4 fragmentMain(VertexOutput in [[stage_in]], 374 texture2d<half> colorMap [[texture(0)]]) { 375 uint2 coords = uint2(in.position.x, in.position.y); 376 half4 colorSample = colorMap.read(coords); 377 return float4(colorSample); 378 } 379 )"; 380 381 auto mtlLibrary = MtlCompileShaderLibrary(sharedContext, 382 "LoadMSAAFromResolve", 383 kLoadMSAAShaderText, 384 sharedContext->caps()->shaderErrorHandler()); 385 BlendInfo noBlend{}; // default is equivalent to kSrc blending 386 sk_cfp<id<MTLDepthStencilState>> ignoreDS = 387 resourceProvider->findOrCreateCompatibleDepthStencilState({}); 388 389 std::string pipelineLabel = "LoadMSAAFromResolve + "; 390 pipelineLabel += renderPassDesc.toString().c_str(); 391 392 PipelineInfo pipelineInfo; 393 pipelineInfo.fNumFragTexturesAndSamplers = 1; 394 // This is an internal shader, leave off filling out the test-utils shader code 395 return Make(sharedContext, 396 pipelineLabel, 397 pipelineInfo, 398 {mtlLibrary.get(), "vertexMain"}, 399 /*vertexAttrs=*/{}, 400 /*instanceAttrs=*/{}, 401 {mtlLibrary.get(), "fragmentMain"}, 402 std::move(ignoreDS), 403 /*stencilRefValue=*/0, 404 noBlend, 405 renderPassDesc); 406} 407 408sk_sp<MtlGraphicsPipeline> MtlGraphicsPipeline::Make(const MtlSharedContext* sharedContext, 409 const std::string& label, 410 const PipelineInfo& pipelineInfo, 411 MSLFunction vertexMain, 412 SkSpan<const Attribute> vertexAttrs, 413 SkSpan<const Attribute> instanceAttrs, 414 MSLFunction fragmentMain, 415 sk_cfp<id<MTLDepthStencilState>> dss, 416 uint32_t stencilRefValue, 417 const BlendInfo& blendInfo, 418 const RenderPassDesc& renderPassDesc) { 419 id<MTLLibrary> vsLibrary = std::get<0>(vertexMain); 420 id<MTLLibrary> fsLibrary = std::get<0>(fragmentMain); 421 if (!vsLibrary || !fsLibrary) { 422 return nullptr; 423 } 424 425 sk_cfp<MTLRenderPipelineDescriptor*> psoDescriptor([[MTLRenderPipelineDescriptor alloc] init]); 426 427 NSString* labelName = [NSString stringWithUTF8String: label.c_str()]; 428 NSString* vsFuncName = [NSString stringWithUTF8String: std::get<1>(vertexMain).c_str()]; 429 NSString* fsFuncName = [NSString stringWithUTF8String: std::get<1>(fragmentMain).c_str()]; 430 431 (*psoDescriptor).label = labelName; 432 (*psoDescriptor).vertexFunction = [vsLibrary newFunctionWithName: vsFuncName]; 433 (*psoDescriptor).fragmentFunction = [fsLibrary newFunctionWithName: fsFuncName]; 434 435 // TODO: I *think* this gets cleaned up by the pipelineDescriptor? 436 (*psoDescriptor).vertexDescriptor = create_vertex_descriptor(vertexAttrs, instanceAttrs); 437 438 MTLPixelFormat pixelFormat = 439 TextureInfos::GetMTLPixelFormat(renderPassDesc.fColorAttachment.fTextureInfo); 440 auto mtlColorAttachment = create_color_attachment(pixelFormat, blendInfo); 441 (*psoDescriptor).colorAttachments[0] = mtlColorAttachment; 442 443 (*psoDescriptor).rasterSampleCount = 444 renderPassDesc.fColorAttachment.fTextureInfo.numSamples(); 445 446 MTLPixelFormat depthStencilFormat = 447 TextureInfos::GetMTLPixelFormat(renderPassDesc.fDepthStencilAttachment.fTextureInfo); 448 if (MtlFormatIsStencil(depthStencilFormat)) { 449 (*psoDescriptor).stencilAttachmentPixelFormat = depthStencilFormat; 450 } else { 451 (*psoDescriptor).stencilAttachmentPixelFormat = MTLPixelFormatInvalid; 452 } 453 if (MtlFormatIsDepth(depthStencilFormat)) { 454 (*psoDescriptor).depthAttachmentPixelFormat = depthStencilFormat; 455 } else { 456 (*psoDescriptor).depthAttachmentPixelFormat = MTLPixelFormatInvalid; 457 } 458 459 NSError* error; 460 sk_cfp<id<MTLRenderPipelineState>> pso( 461 [sharedContext->device() newRenderPipelineStateWithDescriptor:psoDescriptor.get() 462 error:&error]); 463 if (!pso) { 464 SKGPU_LOG_E("Render pipeline creation failure:\n%s", error.debugDescription.UTF8String); 465 return nullptr; 466 } 467 468 return sk_sp<MtlGraphicsPipeline>(new MtlGraphicsPipeline(sharedContext, 469 pipelineInfo, 470 std::move(pso), 471 std::move(dss), 472 stencilRefValue)); 473} 474 475MtlGraphicsPipeline::MtlGraphicsPipeline(const skgpu::graphite::SharedContext* sharedContext, 476 const PipelineInfo& pipelineInfo, 477 sk_cfp<id<MTLRenderPipelineState>> pso, 478 sk_cfp<id<MTLDepthStencilState>> dss, 479 uint32_t refValue) 480 : GraphicsPipeline(sharedContext, pipelineInfo) 481 , fPipelineState(std::move(pso)) 482 , fDepthStencilState(std::move(dss)) 483 , fStencilReferenceValue(refValue) {} 484 485void MtlGraphicsPipeline::freeGpuData() { 486 fPipelineState.reset(); 487} 488 489} // namespace skgpu::graphite 490