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