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/MtlResourceProvider.h" 9 10#include "include/gpu/ShaderErrorHandler.h" 11#include "include/gpu/graphite/BackendTexture.h" 12#include "include/gpu/graphite/mtl/MtlGraphiteTypesUtils.h" 13#include "src/sksl/SkSLProgramKind.h" 14 15#include "src/core/SkSLTypeShared.h" 16#include "src/gpu/Blend.h" 17#include "src/gpu/Swizzle.h" 18#include "src/gpu/graphite/GlobalCache.h" 19#include "src/gpu/graphite/RenderPassDesc.h" 20#include "src/gpu/graphite/Renderer.h" 21#include "src/gpu/graphite/mtl/MtlBuffer.h" 22#include "src/gpu/graphite/mtl/MtlCommandBuffer.h" 23#include "src/gpu/graphite/mtl/MtlComputePipeline.h" 24#include "src/gpu/graphite/mtl/MtlGraphicsPipeline.h" 25#include "src/gpu/graphite/mtl/MtlSampler.h" 26#include "src/gpu/graphite/mtl/MtlSharedContext.h" 27#include "src/gpu/graphite/mtl/MtlTexture.h" 28#include "src/gpu/mtl/MtlUtilsPriv.h" 29 30#import <Metal/Metal.h> 31 32namespace skgpu::graphite { 33 34MtlResourceProvider::MtlResourceProvider(SharedContext* sharedContext, 35 SingleOwner* singleOwner, 36 uint32_t recorderID, 37 size_t resourceBudget) 38 : ResourceProvider(sharedContext, singleOwner, recorderID, resourceBudget) {} 39 40const MtlSharedContext* MtlResourceProvider::mtlSharedContext() { 41 return static_cast<const MtlSharedContext*>(fSharedContext); 42} 43 44sk_sp<MtlGraphicsPipeline> MtlResourceProvider::findOrCreateLoadMSAAPipeline( 45 const RenderPassDesc& renderPassDesc) { 46 uint64_t renderPassKey = 47 this->mtlSharedContext()->mtlCaps().getRenderPassDescKey(renderPassDesc); 48 sk_sp<MtlGraphicsPipeline> pipeline = fLoadMSAAPipelines[renderPassKey]; 49 if (!pipeline) { 50 pipeline = MtlGraphicsPipeline::MakeLoadMSAAPipeline(this->mtlSharedContext(), this, 51 renderPassDesc); 52 if (pipeline) { 53 fLoadMSAAPipelines.set(renderPassKey, pipeline); 54 } 55 } 56 57 return pipeline; 58} 59 60sk_sp<GraphicsPipeline> MtlResourceProvider::createGraphicsPipeline( 61 const RuntimeEffectDictionary* runtimeDict, 62 const UniqueKey& pipelineKey, 63 const GraphicsPipelineDesc& pipelineDesc, 64 const RenderPassDesc& renderPassDesc, 65 SkEnumBitMask<PipelineCreationFlags> pipelineCreationFlags, 66 uint32_t compilationID) { 67 return MtlGraphicsPipeline::Make(this->mtlSharedContext(), this, 68 runtimeDict, pipelineKey, pipelineDesc, renderPassDesc, 69 pipelineCreationFlags, compilationID); 70} 71 72sk_sp<ComputePipeline> MtlResourceProvider::createComputePipeline( 73 const ComputePipelineDesc& pipelineDesc) { 74 return MtlComputePipeline::Make(this->mtlSharedContext(), pipelineDesc); 75} 76 77sk_sp<Texture> MtlResourceProvider::createTexture(SkISize dimensions, 78 const TextureInfo& info, 79 skgpu::Budgeted budgeted) { 80 return MtlTexture::Make(this->mtlSharedContext(), dimensions, info, budgeted); 81} 82 83sk_sp<Texture> MtlResourceProvider::onCreateWrappedTexture(const BackendTexture& texture) { 84 CFTypeRef mtlHandleTexture = BackendTextures::GetMtlTexture(texture); 85 if (!mtlHandleTexture) { 86 return nullptr; 87 } 88 sk_cfp<id<MTLTexture>> mtlTexture = sk_ret_cfp((id<MTLTexture>)mtlHandleTexture); 89 return MtlTexture::MakeWrapped(this->mtlSharedContext(), texture.dimensions(), texture.info(), 90 std::move(mtlTexture)); 91} 92 93sk_sp<Buffer> MtlResourceProvider::createBuffer(size_t size, 94 BufferType type, 95 AccessPattern accessPattern) { 96 return MtlBuffer::Make(this->mtlSharedContext(), size, type, accessPattern); 97} 98 99sk_sp<Sampler> MtlResourceProvider::createSampler(const SamplerDesc& samplerDesc) { 100 return MtlSampler::Make(this->mtlSharedContext(), 101 samplerDesc.samplingOptions(), 102 samplerDesc.tileModeX(), 103 samplerDesc.tileModeY()); 104} 105 106namespace { 107MTLCompareFunction compare_op_to_mtl(CompareOp op) { 108 switch (op) { 109 case CompareOp::kAlways: 110 return MTLCompareFunctionAlways; 111 case CompareOp::kNever: 112 return MTLCompareFunctionNever; 113 case CompareOp::kGreater: 114 return MTLCompareFunctionGreater; 115 case CompareOp::kGEqual: 116 return MTLCompareFunctionGreaterEqual; 117 case CompareOp::kLess: 118 return MTLCompareFunctionLess; 119 case CompareOp::kLEqual: 120 return MTLCompareFunctionLessEqual; 121 case CompareOp::kEqual: 122 return MTLCompareFunctionEqual; 123 case CompareOp::kNotEqual: 124 return MTLCompareFunctionNotEqual; 125 } 126} 127 128MTLStencilOperation stencil_op_to_mtl(StencilOp op) { 129 switch (op) { 130 case StencilOp::kKeep: 131 return MTLStencilOperationKeep; 132 case StencilOp::kZero: 133 return MTLStencilOperationZero; 134 case StencilOp::kReplace: 135 return MTLStencilOperationReplace; 136 case StencilOp::kInvert: 137 return MTLStencilOperationInvert; 138 case StencilOp::kIncWrap: 139 return MTLStencilOperationIncrementWrap; 140 case StencilOp::kDecWrap: 141 return MTLStencilOperationDecrementWrap; 142 case StencilOp::kIncClamp: 143 return MTLStencilOperationIncrementClamp; 144 case StencilOp::kDecClamp: 145 return MTLStencilOperationDecrementClamp; 146 } 147} 148 149MTLStencilDescriptor* stencil_face_to_mtl(DepthStencilSettings::Face face) { 150 MTLStencilDescriptor* result = [[MTLStencilDescriptor alloc] init]; 151 result.stencilCompareFunction = compare_op_to_mtl(face.fCompareOp); 152 result.readMask = face.fReadMask; 153 result.writeMask = face.fWriteMask; 154 result.depthStencilPassOperation = stencil_op_to_mtl(face.fDepthStencilPassOp); 155 result.stencilFailureOperation = stencil_op_to_mtl(face.fStencilFailOp); 156 return result; 157} 158} // anonymous namespace 159 160sk_cfp<id<MTLDepthStencilState>> MtlResourceProvider::findOrCreateCompatibleDepthStencilState( 161 const DepthStencilSettings& depthStencilSettings) { 162 sk_cfp<id<MTLDepthStencilState>>* depthStencilState; 163 depthStencilState = fDepthStencilStates.find(depthStencilSettings); 164 if (!depthStencilState) { 165 MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init]; 166 SkASSERT(depthStencilSettings.fDepthTestEnabled || 167 depthStencilSettings.fDepthCompareOp == CompareOp::kAlways); 168 desc.depthCompareFunction = compare_op_to_mtl(depthStencilSettings.fDepthCompareOp); 169 if (depthStencilSettings.fDepthTestEnabled) { 170 desc.depthWriteEnabled = depthStencilSettings.fDepthWriteEnabled; 171 } 172 if (depthStencilSettings.fStencilTestEnabled) { 173 desc.frontFaceStencil = stencil_face_to_mtl(depthStencilSettings.fFrontStencil); 174 desc.backFaceStencil = stencil_face_to_mtl(depthStencilSettings.fBackStencil); 175 } 176 177 sk_cfp<id<MTLDepthStencilState>> dss( 178 [this->mtlSharedContext()->device() newDepthStencilStateWithDescriptor: desc]); 179 depthStencilState = fDepthStencilStates.set(depthStencilSettings, std::move(dss)); 180 } 181 182 SkASSERT(depthStencilState); 183 return *depthStencilState; 184} 185 186BackendTexture MtlResourceProvider::onCreateBackendTexture(SkISize dimensions, 187 const TextureInfo& info) { 188 sk_cfp<id<MTLTexture>> texture = MtlTexture::MakeMtlTexture(this->mtlSharedContext(), 189 dimensions, 190 info); 191 if (!texture) { 192 return {}; 193 } 194 return BackendTextures::MakeMetal(dimensions, (CFTypeRef)texture.release()); 195} 196 197void MtlResourceProvider::onDeleteBackendTexture(const BackendTexture& texture) { 198 SkASSERT(texture.backend() == BackendApi::kMetal); 199 CFTypeRef texHandle = BackendTextures::GetMtlTexture(texture); 200 SkCFSafeRelease(texHandle); 201} 202 203} // namespace skgpu::graphite 204