1 /* 2 * Copyright 2018 Google Inc. 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 "GrMtlResourceProvider.h" 9 10 #include "GrMtlCopyManager.h" 11 #include "GrMtlGpu.h" 12 #include "GrMtlPipelineState.h" 13 #include "GrMtlUtil.h" 14 15 #include "SkSLCompiler.h" 16 17 18 GrMtlResourceProvider::GrMtlResourceProvider(GrMtlGpu* gpu) 19 : fGpu(gpu) { 20 fPipelineStateCache.reset(new PipelineStateCache(gpu)); 21 } 22 23 GrMtlCopyPipelineState* GrMtlResourceProvider::findOrCreateCopyPipelineState( 24 MTLPixelFormat dstPixelFormat, 25 id<MTLFunction> vertexFunction, 26 id<MTLFunction> fragmentFunction, 27 MTLVertexDescriptor* vertexDescriptor) { 28 29 for (const auto& copyPipelineState: fCopyPipelineStateCache) { 30 if (GrMtlCopyManager::IsCompatible(copyPipelineState.get(), dstPixelFormat)) { 31 return copyPipelineState.get(); 32 } 33 } 34 35 fCopyPipelineStateCache.emplace_back(GrMtlCopyPipelineState::CreateCopyPipelineState( 36 fGpu, dstPixelFormat, vertexFunction, fragmentFunction, vertexDescriptor)); 37 return fCopyPipelineStateCache.back().get(); 38 } 39 40 GrMtlPipelineState* GrMtlResourceProvider::findOrCreateCompatiblePipelineState( 41 GrRenderTarget* renderTarget, GrSurfaceOrigin origin, 42 const GrPipeline& pipeline, const GrPrimitiveProcessor& proc, 43 const GrTextureProxy* const primProcProxies[], GrPrimitiveType primType) { 44 return fPipelineStateCache->refPipelineState(renderTarget, origin, proc, primProcProxies, 45 pipeline, primType); 46 } 47 48 //////////////////////////////////////////////////////////////////////////////////////////////// 49 50 #ifdef GR_PIPELINE_STATE_CACHE_STATS 51 // Display pipeline state cache usage 52 static const bool c_DisplayMtlPipelineCache{false}; 53 #endif 54 55 struct GrMtlResourceProvider::PipelineStateCache::Entry { 56 Entry(GrMtlGpu* gpu, GrMtlPipelineState* pipelineState) 57 : fGpu(gpu) 58 , fPipelineState(pipelineState) {} 59 60 GrMtlGpu* fGpu; 61 std::unique_ptr<GrMtlPipelineState> fPipelineState; 62 }; 63 64 GrMtlResourceProvider::PipelineStateCache::PipelineStateCache(GrMtlGpu* gpu) 65 : fMap(kMaxEntries) 66 , fGpu(gpu) 67 #ifdef GR_PIPELINE_STATE_CACHE_STATS 68 , fTotalRequests(0) 69 , fCacheMisses(0) 70 #endif 71 {} 72 73 GrMtlResourceProvider::PipelineStateCache::~PipelineStateCache() { 74 // TODO: determine if we need abandon/release methods 75 fMap.reset(); 76 // dump stats 77 #ifdef GR_PIPELINE_STATE_CACHE_STATS 78 if (c_DisplayMtlPipelineCache) { 79 SkDebugf("--- Pipeline State Cache ---\n"); 80 SkDebugf("Total requests: %d\n", fTotalRequests); 81 SkDebugf("Cache misses: %d\n", fCacheMisses); 82 SkDebugf("Cache miss %%: %f\n", (fTotalRequests > 0) ? 83 100.f * fCacheMisses / fTotalRequests : 84 0.f); 85 SkDebugf("---------------------\n"); 86 } 87 #endif 88 } 89 90 GrMtlPipelineState* GrMtlResourceProvider::PipelineStateCache::refPipelineState( 91 GrRenderTarget* renderTarget, 92 GrSurfaceOrigin origin, 93 const GrPrimitiveProcessor& primProc, 94 const GrTextureProxy* const primProcProxies[], 95 const GrPipeline& pipeline, 96 GrPrimitiveType primType) { 97 #ifdef GR_PIPELINE_STATE_CACHE_STATS 98 ++fTotalRequests; 99 #endif 100 // Get GrMtlProgramDesc 101 GrMtlPipelineStateBuilder::Desc desc; 102 if (!GrMtlPipelineStateBuilder::Desc::Build(&desc, renderTarget, primProc, pipeline, primType, 103 fGpu)) { 104 GrCapsDebugf(fGpu->caps(), "Failed to build mtl program descriptor!\n"); 105 return nullptr; 106 } 107 108 std::unique_ptr<Entry>* entry = fMap.find(desc); 109 if (!entry) { 110 // Didn't find an origin-independent version, check with the specific origin 111 desc.setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(origin)); 112 entry = fMap.find(desc); 113 } 114 if (!entry) { 115 #ifdef GR_PIPELINE_STATE_CACHE_STATS 116 ++fCacheMisses; 117 #endif 118 GrMtlPipelineState* pipelineState(GrMtlPipelineStateBuilder::CreatePipelineState( 119 fGpu, renderTarget, origin, primProc, primProcProxies, pipeline, &desc)); 120 if (nullptr == pipelineState) { 121 return nullptr; 122 } 123 entry = fMap.insert(desc, std::unique_ptr<Entry>(new Entry(fGpu, pipelineState))); 124 return (*entry)->fPipelineState.get(); 125 } 126 return (*entry)->fPipelineState.get(); 127 } 128