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 #ifndef GrMtlResourceProvider_DEFINED 9 #define GrMtlResourceProvider_DEFINED 10 11 #include "include/private/SkSpinlock.h" 12 #include "include/private/SkTArray.h" 13 #include "src/core/SkLRUCache.h" 14 #include "src/gpu/mtl/GrMtlDepthStencil.h" 15 #include "src/gpu/mtl/GrMtlPipelineStateBuilder.h" 16 #include "src/gpu/mtl/GrMtlSampler.h" 17 18 #import <Metal/Metal.h> 19 20 class GrMtlGpu; 21 class GrMtlCommandBuffer; 22 23 class GrMtlResourceProvider { 24 public: 25 GrMtlResourceProvider(GrMtlGpu* gpu); 26 27 GrMtlPipelineState* findOrCreateCompatiblePipelineState(GrRenderTarget*, 28 const GrProgramInfo&, 29 GrPrimitiveType); 30 31 // Finds or creates a compatible MTLDepthStencilState based on the GrStencilSettings. 32 GrMtlDepthStencil* findOrCreateCompatibleDepthStencilState(const GrStencilSettings&, 33 GrSurfaceOrigin); 34 35 // Finds or creates a compatible MTLSamplerState based on the GrSamplerState. 36 GrMtlSampler* findOrCreateCompatibleSampler(const GrSamplerState&); 37 38 id<MTLBuffer> getDynamicBuffer(size_t size, size_t* offset); 39 void addBufferCompletionHandler(GrMtlCommandBuffer* cmdBuffer); 40 41 // Destroy any cached resources. To be called before releasing the MtlDevice. 42 void destroyResources(); 43 44 private: 45 #ifdef SK_DEBUG 46 #define GR_PIPELINE_STATE_CACHE_STATS 47 #endif 48 49 class PipelineStateCache : public ::SkNoncopyable { 50 public: 51 PipelineStateCache(GrMtlGpu* gpu); 52 ~PipelineStateCache(); 53 54 void release(); 55 GrMtlPipelineState* refPipelineState(GrRenderTarget*, const GrProgramInfo&, 56 GrPrimitiveType); 57 58 private: 59 struct Entry; 60 61 struct DescHash { operatorDescHash62 uint32_t operator()(const GrProgramDesc& desc) const { 63 return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0); 64 } 65 }; 66 67 SkLRUCache<const GrMtlPipelineStateBuilder::Desc, std::unique_ptr<Entry>, DescHash> fMap; 68 69 GrMtlGpu* fGpu; 70 71 #ifdef GR_PIPELINE_STATE_CACHE_STATS 72 int fTotalRequests; 73 int fCacheMisses; 74 #endif 75 }; 76 77 // Buffer allocator 78 class BufferSuballocator : public SkRefCnt { 79 public: 80 BufferSuballocator(id<MTLDevice> device, size_t size); ~BufferSuballocator()81 ~BufferSuballocator() { 82 fBuffer = nil; 83 fTotalSize = 0; 84 } 85 86 id<MTLBuffer> getAllocation(size_t size, size_t* offset); 87 void addCompletionHandler(GrMtlCommandBuffer* cmdBuffer); size()88 size_t size() { return fTotalSize; } 89 90 private: 91 id<MTLBuffer> fBuffer; 92 size_t fTotalSize; 93 size_t fHead SK_GUARDED_BY(fMutex); // where we start allocating 94 size_t fTail SK_GUARDED_BY(fMutex); // where we start deallocating 95 SkSpinlock fMutex; 96 }; 97 static constexpr size_t kBufferSuballocatorStartSize = 1024*1024; 98 99 GrMtlGpu* fGpu; 100 101 // Cache of GrMtlPipelineStates 102 std::unique_ptr<PipelineStateCache> fPipelineStateCache; 103 104 SkTDynamicHash<GrMtlSampler, GrMtlSampler::Key> fSamplers; 105 SkTDynamicHash<GrMtlDepthStencil, GrMtlDepthStencil::Key> fDepthStencilStates; 106 107 // This is ref-counted because we might delete the GrContext before the command buffer 108 // finishes. The completion handler will retain a reference to this so it won't get 109 // deleted along with the GrContext. 110 sk_sp<BufferSuballocator> fBufferSuballocator; 111 size_t fBufferSuballocatorMaxSize; 112 }; 113 114 #endif 115