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