1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlResourceProvider.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/gpu/GrContextOptions.h" 11cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 12cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrProgramDesc.h" 15cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlCommandBuffer.h" 16cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlGpu.h" 17cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlPipelineState.h" 18cb93a386Sopenharmony_ci#include "src/gpu/mtl/GrMtlUtil.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci#include "src/sksl/SkSLCompiler.h" 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ci#if !__has_feature(objc_arc) 23cb93a386Sopenharmony_ci#error This file must be compiled with Arc. Use -fobjc-arc flag 24cb93a386Sopenharmony_ci#endif 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ciGR_NORETAIN_BEGIN 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ciGrMtlResourceProvider::GrMtlResourceProvider(GrMtlGpu* gpu) 29cb93a386Sopenharmony_ci : fGpu(gpu) { 30cb93a386Sopenharmony_ci fPipelineStateCache.reset(new PipelineStateCache(gpu)); 31cb93a386Sopenharmony_ci} 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ciGrMtlPipelineState* GrMtlResourceProvider::findOrCreateCompatiblePipelineState( 34cb93a386Sopenharmony_ci const GrProgramDesc& programDesc, 35cb93a386Sopenharmony_ci const GrProgramInfo& programInfo, 36cb93a386Sopenharmony_ci GrThreadSafePipelineBuilder::Stats::ProgramCacheResult* stat) { 37cb93a386Sopenharmony_ci return fPipelineStateCache->refPipelineState(programDesc, programInfo, stat); 38cb93a386Sopenharmony_ci} 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_cibool GrMtlResourceProvider::precompileShader(const SkData& key, const SkData& data) { 41cb93a386Sopenharmony_ci return fPipelineStateCache->precompileShader(key, data); 42cb93a386Sopenharmony_ci} 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////// 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ciGrMtlDepthStencil* GrMtlResourceProvider::findOrCreateCompatibleDepthStencilState( 47cb93a386Sopenharmony_ci const GrStencilSettings& stencil, GrSurfaceOrigin origin) { 48cb93a386Sopenharmony_ci GrMtlDepthStencil* depthStencilState; 49cb93a386Sopenharmony_ci GrMtlDepthStencil::Key key = GrMtlDepthStencil::GenerateKey(stencil, origin); 50cb93a386Sopenharmony_ci depthStencilState = fDepthStencilStates.find(key); 51cb93a386Sopenharmony_ci if (!depthStencilState) { 52cb93a386Sopenharmony_ci depthStencilState = GrMtlDepthStencil::Create(fGpu, stencil, origin); 53cb93a386Sopenharmony_ci fDepthStencilStates.add(depthStencilState); 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci SkASSERT(depthStencilState); 56cb93a386Sopenharmony_ci return depthStencilState; 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ciGrMtlSampler* GrMtlResourceProvider::findOrCreateCompatibleSampler(GrSamplerState params) { 60cb93a386Sopenharmony_ci GrMtlSampler* sampler; 61cb93a386Sopenharmony_ci sampler = fSamplers.find(GrMtlSampler::GenerateKey(params)); 62cb93a386Sopenharmony_ci if (!sampler) { 63cb93a386Sopenharmony_ci sampler = GrMtlSampler::Create(fGpu, params); 64cb93a386Sopenharmony_ci fSamplers.add(sampler); 65cb93a386Sopenharmony_ci } 66cb93a386Sopenharmony_ci SkASSERT(sampler); 67cb93a386Sopenharmony_ci return sampler; 68cb93a386Sopenharmony_ci} 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ciconst GrMtlRenderPipeline* GrMtlResourceProvider::findOrCreateMSAALoadPipeline( 71cb93a386Sopenharmony_ci MTLPixelFormat colorFormat, int sampleCount, MTLPixelFormat stencilFormat) { 72cb93a386Sopenharmony_ci if (!fMSAALoadLibrary) { 73cb93a386Sopenharmony_ci TRACE_EVENT0("skia", TRACE_FUNC); 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci SkSL::String shaderText; 76cb93a386Sopenharmony_ci shaderText.append( 77cb93a386Sopenharmony_ci "#include <metal_stdlib>\n" 78cb93a386Sopenharmony_ci "#include <simd/simd.h>\n" 79cb93a386Sopenharmony_ci "using namespace metal;\n" 80cb93a386Sopenharmony_ci "\n" 81cb93a386Sopenharmony_ci "typedef struct {\n" 82cb93a386Sopenharmony_ci " float4 position [[position]];\n" 83cb93a386Sopenharmony_ci "} VertexOutput;\n" 84cb93a386Sopenharmony_ci "\n" 85cb93a386Sopenharmony_ci "typedef struct {\n" 86cb93a386Sopenharmony_ci " float4 uPosXform;\n" 87cb93a386Sopenharmony_ci " uint2 uTextureSize;\n" 88cb93a386Sopenharmony_ci "} VertexUniforms;\n" 89cb93a386Sopenharmony_ci "\n" 90cb93a386Sopenharmony_ci "vertex VertexOutput vertexMain(constant VertexUniforms& uniforms [[buffer(0)]],\n" 91cb93a386Sopenharmony_ci " uint vertexID [[vertex_id]]) {\n" 92cb93a386Sopenharmony_ci " VertexOutput out;\n" 93cb93a386Sopenharmony_ci " float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n" 94cb93a386Sopenharmony_ci " out.position.xy = position * uniforms.uPosXform.xy + uniforms.uPosXform.zw;\n" 95cb93a386Sopenharmony_ci " out.position.zw = float2(0.0, 1.0);\n" 96cb93a386Sopenharmony_ci " return out;\n" 97cb93a386Sopenharmony_ci "}\n" 98cb93a386Sopenharmony_ci "\n" 99cb93a386Sopenharmony_ci "fragment float4 fragmentMain(VertexOutput in [[stage_in]],\n" 100cb93a386Sopenharmony_ci " texture2d<half> colorMap [[texture(0)]]) {\n" 101cb93a386Sopenharmony_ci " uint2 coords = uint2(in.position.x, in.position.y);" 102cb93a386Sopenharmony_ci " half4 colorSample = colorMap.read(coords);\n" 103cb93a386Sopenharmony_ci " return float4(colorSample);\n" 104cb93a386Sopenharmony_ci "}" 105cb93a386Sopenharmony_ci ); 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci auto errorHandler = fGpu->getContext()->priv().getShaderErrorHandler(); 108cb93a386Sopenharmony_ci fMSAALoadLibrary = GrCompileMtlShaderLibrary(fGpu, shaderText, errorHandler); 109cb93a386Sopenharmony_ci if (!fMSAALoadLibrary) { 110cb93a386Sopenharmony_ci return nullptr; 111cb93a386Sopenharmony_ci } 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci for (int i = 0; i < fMSAALoadPipelines.count(); ++i) { 115cb93a386Sopenharmony_ci if (fMSAALoadPipelines[i].fColorFormat == colorFormat && 116cb93a386Sopenharmony_ci fMSAALoadPipelines[i].fSampleCount == sampleCount && 117cb93a386Sopenharmony_ci fMSAALoadPipelines[i].fStencilFormat == stencilFormat) { 118cb93a386Sopenharmony_ci return fMSAALoadPipelines[i].fPipeline.get(); 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci auto pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci pipelineDescriptor.label = @"loadMSAAFromResolve"; 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci pipelineDescriptor.vertexFunction = 127cb93a386Sopenharmony_ci [fMSAALoadLibrary newFunctionWithName: @"vertexMain"]; 128cb93a386Sopenharmony_ci pipelineDescriptor.fragmentFunction = 129cb93a386Sopenharmony_ci [fMSAALoadLibrary newFunctionWithName: @"fragmentMain"]; 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init]; 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci mtlColorAttachment.pixelFormat = colorFormat; 134cb93a386Sopenharmony_ci mtlColorAttachment.blendingEnabled = FALSE; 135cb93a386Sopenharmony_ci mtlColorAttachment.writeMask = MTLColorWriteMaskAll; 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci pipelineDescriptor.colorAttachments[0] = mtlColorAttachment; 138cb93a386Sopenharmony_ci pipelineDescriptor.sampleCount = sampleCount; 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci pipelineDescriptor.stencilAttachmentPixelFormat = stencilFormat; 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci NSError* error; 143cb93a386Sopenharmony_ci auto pso = 144cb93a386Sopenharmony_ci [fGpu->device() newRenderPipelineStateWithDescriptor: pipelineDescriptor 145cb93a386Sopenharmony_ci error: &error]; 146cb93a386Sopenharmony_ci if (!pso) { 147cb93a386Sopenharmony_ci SkDebugf("Error creating pipeline: %s\n", 148cb93a386Sopenharmony_ci [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]); 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci auto renderPipeline = GrMtlRenderPipeline::Make(pso); 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci fMSAALoadPipelines.push_back({renderPipeline, colorFormat, sampleCount, stencilFormat}); 154cb93a386Sopenharmony_ci return fMSAALoadPipelines[fMSAALoadPipelines.count()-1].fPipeline.get(); 155cb93a386Sopenharmony_ci} 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_civoid GrMtlResourceProvider::destroyResources() { 158cb93a386Sopenharmony_ci fMSAALoadLibrary = nil; 159cb93a386Sopenharmony_ci fMSAALoadPipelines.reset(); 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci fSamplers.foreach([&](GrMtlSampler* sampler) { sampler->unref(); }); 162cb93a386Sopenharmony_ci fSamplers.reset(); 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci fDepthStencilStates.foreach([&](GrMtlDepthStencil* stencil) { stencil->unref(); }); 165cb93a386Sopenharmony_ci fDepthStencilStates.reset(); 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci fPipelineStateCache->release(); 168cb93a386Sopenharmony_ci} 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////// 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_cistruct GrMtlResourceProvider::PipelineStateCache::Entry { 173cb93a386Sopenharmony_ci Entry(GrMtlPipelineState* pipelineState) 174cb93a386Sopenharmony_ci : fPipelineState(pipelineState) {} 175cb93a386Sopenharmony_ci Entry(const GrMtlPrecompiledLibraries& precompiledLibraries) 176cb93a386Sopenharmony_ci : fPipelineState(nullptr) 177cb93a386Sopenharmony_ci , fPrecompiledLibraries(precompiledLibraries) {} 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci std::unique_ptr<GrMtlPipelineState> fPipelineState; 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci // TODO: change to one library once we can build that 182cb93a386Sopenharmony_ci GrMtlPrecompiledLibraries fPrecompiledLibraries; 183cb93a386Sopenharmony_ci}; 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ciGrMtlResourceProvider::PipelineStateCache::PipelineStateCache(GrMtlGpu* gpu) 186cb93a386Sopenharmony_ci : fMap(gpu->getContext()->priv().options().fRuntimeProgramCacheSize) 187cb93a386Sopenharmony_ci , fGpu(gpu) {} 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ciGrMtlResourceProvider::PipelineStateCache::~PipelineStateCache() { 190cb93a386Sopenharmony_ci SkASSERT(0 == fMap.count()); 191cb93a386Sopenharmony_ci} 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_civoid GrMtlResourceProvider::PipelineStateCache::release() { 194cb93a386Sopenharmony_ci fMap.reset(); 195cb93a386Sopenharmony_ci} 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ciGrMtlPipelineState* GrMtlResourceProvider::PipelineStateCache::refPipelineState( 198cb93a386Sopenharmony_ci const GrProgramDesc& desc, 199cb93a386Sopenharmony_ci const GrProgramInfo& programInfo, 200cb93a386Sopenharmony_ci Stats::ProgramCacheResult* statPtr) { 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci if (!statPtr) { 203cb93a386Sopenharmony_ci // If stat is NULL we are using inline compilation rather than through DDL, 204cb93a386Sopenharmony_ci // so we need to track those stats as well. 205cb93a386Sopenharmony_ci GrThreadSafePipelineBuilder::Stats::ProgramCacheResult stat; 206cb93a386Sopenharmony_ci auto tmp = this->onRefPipelineState(desc, programInfo, &stat); 207cb93a386Sopenharmony_ci if (!tmp) { 208cb93a386Sopenharmony_ci fStats.incNumInlineCompilationFailures(); 209cb93a386Sopenharmony_ci } else { 210cb93a386Sopenharmony_ci fStats.incNumInlineProgramCacheResult(stat); 211cb93a386Sopenharmony_ci } 212cb93a386Sopenharmony_ci return tmp; 213cb93a386Sopenharmony_ci } else { 214cb93a386Sopenharmony_ci return this->onRefPipelineState(desc, programInfo, statPtr); 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci} 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ciGrMtlPipelineState* GrMtlResourceProvider::PipelineStateCache::onRefPipelineState( 219cb93a386Sopenharmony_ci const GrProgramDesc& desc, 220cb93a386Sopenharmony_ci const GrProgramInfo& programInfo, 221cb93a386Sopenharmony_ci Stats::ProgramCacheResult* stat) { 222cb93a386Sopenharmony_ci *stat = Stats::ProgramCacheResult::kHit; 223cb93a386Sopenharmony_ci std::unique_ptr<Entry>* entry = fMap.find(desc); 224cb93a386Sopenharmony_ci if (entry && !(*entry)->fPipelineState) { 225cb93a386Sopenharmony_ci // We've pre-compiled the MSL shaders but don't yet have the pipelineState 226cb93a386Sopenharmony_ci const GrMtlPrecompiledLibraries* precompiledLibs = &((*entry)->fPrecompiledLibraries); 227cb93a386Sopenharmony_ci SkASSERT(precompiledLibs->fVertexLibrary); 228cb93a386Sopenharmony_ci SkASSERT(precompiledLibs->fFragmentLibrary); 229cb93a386Sopenharmony_ci (*entry)->fPipelineState.reset( 230cb93a386Sopenharmony_ci GrMtlPipelineStateBuilder::CreatePipelineState(fGpu, desc, programInfo, 231cb93a386Sopenharmony_ci precompiledLibs)); 232cb93a386Sopenharmony_ci if (!(*entry)->fPipelineState) { 233cb93a386Sopenharmony_ci // Should we purge the precompiled shaders from the cache at this point? 234cb93a386Sopenharmony_ci SkDEBUGFAIL("Couldn't create pipelineState from precompiled shaders"); 235cb93a386Sopenharmony_ci fStats.incNumCompilationFailures(); 236cb93a386Sopenharmony_ci return nullptr; 237cb93a386Sopenharmony_ci } 238cb93a386Sopenharmony_ci // release the libraries 239cb93a386Sopenharmony_ci (*entry)->fPrecompiledLibraries.fVertexLibrary = nil; 240cb93a386Sopenharmony_ci (*entry)->fPrecompiledLibraries.fFragmentLibrary = nil; 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_ci fStats.incNumPartialCompilationSuccesses(); 243cb93a386Sopenharmony_ci *stat = Stats::ProgramCacheResult::kPartial; 244cb93a386Sopenharmony_ci } else if (!entry) { 245cb93a386Sopenharmony_ci GrMtlPipelineState* pipelineState( 246cb93a386Sopenharmony_ci GrMtlPipelineStateBuilder::CreatePipelineState(fGpu, desc, programInfo)); 247cb93a386Sopenharmony_ci if (!pipelineState) { 248cb93a386Sopenharmony_ci fStats.incNumCompilationFailures(); 249cb93a386Sopenharmony_ci return nullptr; 250cb93a386Sopenharmony_ci } 251cb93a386Sopenharmony_ci fStats.incNumCompilationSuccesses(); 252cb93a386Sopenharmony_ci entry = fMap.insert(desc, std::unique_ptr<Entry>(new Entry(pipelineState))); 253cb93a386Sopenharmony_ci *stat = Stats::ProgramCacheResult::kMiss; 254cb93a386Sopenharmony_ci return (*entry)->fPipelineState.get(); 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci return (*entry)->fPipelineState.get(); 257cb93a386Sopenharmony_ci} 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_cibool GrMtlResourceProvider::PipelineStateCache::precompileShader(const SkData& key, 260cb93a386Sopenharmony_ci const SkData& data) { 261cb93a386Sopenharmony_ci GrProgramDesc desc; 262cb93a386Sopenharmony_ci if (!GrProgramDesc::BuildFromData(&desc, key.data(), key.size())) { 263cb93a386Sopenharmony_ci return false; 264cb93a386Sopenharmony_ci } 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci std::unique_ptr<Entry>* entry = fMap.find(desc); 267cb93a386Sopenharmony_ci if (entry) { 268cb93a386Sopenharmony_ci // We've already seen/compiled this shader 269cb93a386Sopenharmony_ci return true; 270cb93a386Sopenharmony_ci } 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ci GrMtlPrecompiledLibraries precompiledLibraries; 273cb93a386Sopenharmony_ci if (!GrMtlPipelineStateBuilder::PrecompileShaders(fGpu, data, &precompiledLibraries)) { 274cb93a386Sopenharmony_ci return false; 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci fMap.insert(desc, std::make_unique<Entry>(precompiledLibraries)); 278cb93a386Sopenharmony_ci return true; 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci} 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ciGR_NORETAIN_END 283