1/* 2 * Copyright 2022 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/MtlComputePipeline.h" 9 10#include "include/gpu/GpuTypes.h" 11#include "include/gpu/ShaderErrorHandler.h" 12#include "src/gpu/graphite/ComputePipelineDesc.h" 13#include "src/gpu/graphite/ContextUtils.h" 14#include "src/gpu/graphite/Log.h" 15#include "src/gpu/graphite/ResourceProvider.h" 16#include "src/gpu/graphite/mtl/MtlGraphiteUtils.h" 17#include "src/gpu/graphite/mtl/MtlSharedContext.h" 18#include "src/gpu/mtl/MtlUtilsPriv.h" 19#include "src/sksl/SkSLCompiler.h" 20#include "src/sksl/SkSLProgramKind.h" 21#include "src/sksl/SkSLProgramSettings.h" 22#include "src/sksl/ir/SkSLProgram.h" 23 24namespace skgpu::graphite { 25 26// static 27sk_sp<MtlComputePipeline> MtlComputePipeline::Make(const MtlSharedContext* sharedContext, 28 const ComputePipelineDesc& pipelineDesc) { 29 sk_cfp<id<MTLLibrary>> library; 30 std::string entryPointName; 31 ShaderErrorHandler* errorHandler = sharedContext->caps()->shaderErrorHandler(); 32 if (pipelineDesc.computeStep()->supportsNativeShader()) { 33 auto nativeShader = pipelineDesc.computeStep()->nativeShaderSource( 34 ComputeStep::NativeShaderFormat::kMSL); 35 library = MtlCompileShaderLibrary(sharedContext, 36 pipelineDesc.computeStep()->name(), 37 nativeShader.fSource, 38 errorHandler); 39 if (library == nil) { 40 return nullptr; 41 } 42 entryPointName = std::move(nativeShader.fEntryPoint); 43 } else { 44 std::string msl; 45 SkSL::Program::Interface interface; 46 SkSL::ProgramSettings settings; 47 48 SkSL::Compiler skslCompiler; 49 std::string sksl = BuildComputeSkSL(sharedContext->caps(), 50 pipelineDesc.computeStep(), 51 BackendApi::kMetal); 52 if (!SkSLToMSL(sharedContext->caps()->shaderCaps(), 53 sksl, 54 SkSL::ProgramKind::kCompute, 55 settings, 56 &msl, 57 &interface, 58 errorHandler)) { 59 return nullptr; 60 } 61 library = MtlCompileShaderLibrary(sharedContext, 62 pipelineDesc.computeStep()->name(), 63 msl, 64 errorHandler); 65 if (library == nil) { 66 return nullptr; 67 } 68 entryPointName = "computeMain"; 69 } 70 71 sk_cfp<MTLComputePipelineDescriptor*> psoDescriptor([MTLComputePipelineDescriptor new]); 72 73 (*psoDescriptor).label = @(pipelineDesc.computeStep()->name()); 74 75 NSString* entryPoint = [NSString stringWithUTF8String:entryPointName.c_str()]; 76 (*psoDescriptor).computeFunction = [library.get() newFunctionWithName:entryPoint]; 77 78 // TODO(b/240604614): Populate input data attribute and buffer layout descriptors using the 79 // `stageInputDescriptor` property based on the contents of `pipelineDesc` (on iOS 10+ or 80 // macOS 10.12+). 81 82 // TODO(b/240604614): Define input buffer mutability using the `buffers` property based on 83 // the contents of `pipelineDesc` (on iOS 11+ or macOS 10.13+). 84 85 // TODO(b/240615224): Metal docs claim that setting the 86 // `threadGroupSizeIsMultipleOfThreadExecutionWidth` to YES may improve performance, IF we can 87 // guarantee that the thread group size used in a dispatch command is a multiple of 88 // `threadExecutionWidth` property of the pipeline state object (otherwise this will cause UB). 89 90 NSError* error; 91 sk_cfp<id<MTLComputePipelineState>> pso([sharedContext->device() 92 newComputePipelineStateWithDescriptor:psoDescriptor.get() 93 options:MTLPipelineOptionNone 94 reflection:nil 95 error:&error]); 96 if (!pso) { 97 SKGPU_LOG_E("Compute pipeline creation failure:\n%s", error.debugDescription.UTF8String); 98 return nullptr; 99 } 100 101 return sk_sp<MtlComputePipeline>(new MtlComputePipeline(sharedContext, std::move(pso))); 102} 103 104void MtlComputePipeline::freeGpuData() { fPipelineState.reset(); } 105 106} // namespace skgpu::graphite 107