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/MtlGraphiteTypes.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 return MtlTexture::Make(this->mtlSharedContext(), dimensions, info); 80} 81 82sk_sp<Texture> MtlResourceProvider::onCreateWrappedTexture(const BackendTexture& texture) { 83 CFTypeRef mtlHandleTexture = BackendTextures::GetMtlTexture(texture); 84 if (!mtlHandleTexture) { 85 return nullptr; 86 } 87 sk_cfp<id<MTLTexture>> mtlTexture = sk_ret_cfp((id<MTLTexture>)mtlHandleTexture); 88 return MtlTexture::MakeWrapped(this->mtlSharedContext(), texture.dimensions(), texture.info(), 89 std::move(mtlTexture)); 90} 91 92sk_sp<Buffer> MtlResourceProvider::createBuffer(size_t size, 93 BufferType type, 94 AccessPattern accessPattern) { 95 return MtlBuffer::Make(this->mtlSharedContext(), size, type, accessPattern); 96} 97 98sk_sp<Sampler> MtlResourceProvider::createSampler(const SamplerDesc& samplerDesc) { 99 return MtlSampler::Make(this->mtlSharedContext(), 100 samplerDesc.samplingOptions(), 101 samplerDesc.tileModeX(), 102 samplerDesc.tileModeY()); 103} 104 105namespace { 106MTLCompareFunction compare_op_to_mtl(CompareOp op) { 107 switch (op) { 108 case CompareOp::kAlways: 109 return MTLCompareFunctionAlways; 110 case CompareOp::kNever: 111 return MTLCompareFunctionNever; 112 case CompareOp::kGreater: 113 return MTLCompareFunctionGreater; 114 case CompareOp::kGEqual: 115 return MTLCompareFunctionGreaterEqual; 116 case CompareOp::kLess: 117 return MTLCompareFunctionLess; 118 case CompareOp::kLEqual: 119 return MTLCompareFunctionLessEqual; 120 case CompareOp::kEqual: 121 return MTLCompareFunctionEqual; 122 case CompareOp::kNotEqual: 123 return MTLCompareFunctionNotEqual; 124 } 125} 126 127MTLStencilOperation stencil_op_to_mtl(StencilOp op) { 128 switch (op) { 129 case StencilOp::kKeep: 130 return MTLStencilOperationKeep; 131 case StencilOp::kZero: 132 return MTLStencilOperationZero; 133 case StencilOp::kReplace: 134 return MTLStencilOperationReplace; 135 case StencilOp::kInvert: 136 return MTLStencilOperationInvert; 137 case StencilOp::kIncWrap: 138 return MTLStencilOperationIncrementWrap; 139 case StencilOp::kDecWrap: 140 return MTLStencilOperationDecrementWrap; 141 case StencilOp::kIncClamp: 142 return MTLStencilOperationIncrementClamp; 143 case StencilOp::kDecClamp: 144 return MTLStencilOperationDecrementClamp; 145 } 146} 147 148MTLStencilDescriptor* stencil_face_to_mtl(DepthStencilSettings::Face face) { 149 MTLStencilDescriptor* result = [[MTLStencilDescriptor alloc] init]; 150 result.stencilCompareFunction = compare_op_to_mtl(face.fCompareOp); 151 result.readMask = face.fReadMask; 152 result.writeMask = face.fWriteMask; 153 result.depthStencilPassOperation = stencil_op_to_mtl(face.fDepthStencilPassOp); 154 result.stencilFailureOperation = stencil_op_to_mtl(face.fStencilFailOp); 155 return result; 156} 157} // anonymous namespace 158 159sk_cfp<id<MTLDepthStencilState>> MtlResourceProvider::findOrCreateCompatibleDepthStencilState( 160 const DepthStencilSettings& depthStencilSettings) { 161 sk_cfp<id<MTLDepthStencilState>>* depthStencilState; 162 depthStencilState = fDepthStencilStates.find(depthStencilSettings); 163 if (!depthStencilState) { 164 MTLDepthStencilDescriptor* desc = [[MTLDepthStencilDescriptor alloc] init]; 165 SkASSERT(depthStencilSettings.fDepthTestEnabled || 166 depthStencilSettings.fDepthCompareOp == CompareOp::kAlways); 167 desc.depthCompareFunction = compare_op_to_mtl(depthStencilSettings.fDepthCompareOp); 168 if (depthStencilSettings.fDepthTestEnabled) { 169 desc.depthWriteEnabled = depthStencilSettings.fDepthWriteEnabled; 170 } 171 if (depthStencilSettings.fStencilTestEnabled) { 172 desc.frontFaceStencil = stencil_face_to_mtl(depthStencilSettings.fFrontStencil); 173 desc.backFaceStencil = stencil_face_to_mtl(depthStencilSettings.fBackStencil); 174 } 175 176 sk_cfp<id<MTLDepthStencilState>> dss( 177 [this->mtlSharedContext()->device() newDepthStencilStateWithDescriptor: desc]); 178 depthStencilState = fDepthStencilStates.set(depthStencilSettings, std::move(dss)); 179 } 180 181 SkASSERT(depthStencilState); 182 return *depthStencilState; 183} 184 185BackendTexture MtlResourceProvider::onCreateBackendTexture(SkISize dimensions, 186 const TextureInfo& info) { 187 sk_cfp<id<MTLTexture>> texture = MtlTexture::MakeMtlTexture(this->mtlSharedContext(), 188 dimensions, 189 info); 190 if (!texture) { 191 return {}; 192 } 193 return BackendTextures::MakeMetal(dimensions, (CFTypeRef)texture.release()); 194} 195 196void MtlResourceProvider::onDeleteBackendTexture(const BackendTexture& texture) { 197 SkASSERT(texture.backend() == BackendApi::kMetal); 198 CFTypeRef texHandle = BackendTextures::GetMtlTexture(texture); 199 SkCFSafeRelease(texHandle); 200} 201 202} // namespace skgpu::graphite 203