xref: /aosp_15_r20/external/skia/src/gpu/ganesh/vk/GrVkResourceProvider.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2 * Copyright 2016 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 GrVkResourceProvider_DEFINED
9 #define GrVkResourceProvider_DEFINED
10 
11 #include "include/core/SkRefCnt.h"
12 #include "include/private/base/SkAssert.h"
13 #include "include/private/base/SkTArray.h"
14 #include "include/private/gpu/vk/SkiaVulkan.h"
15 #include "src/core/SkChecksum.h"
16 #include "src/core/SkLRUCache.h"
17 #include "src/core/SkTDynamicHash.h"
18 #include "src/gpu/ganesh/GrProgramDesc.h"
19 #include "src/gpu/ganesh/GrResourceHandle.h"
20 #include "src/gpu/ganesh/GrSamplerState.h"
21 #include "src/gpu/ganesh/GrThreadSafePipelineBuilder.h"
22 #include "src/gpu/ganesh/vk/GrVkDescriptorSetManager.h"
23 #include "src/gpu/ganesh/vk/GrVkPipeline.h"
24 #include "src/gpu/ganesh/vk/GrVkRenderPass.h"
25 #include "src/gpu/ganesh/vk/GrVkSampler.h"
26 #include "src/gpu/ganesh/vk/GrVkSamplerYcbcrConversion.h"
27 
28 #include <cstdint>
29 #include <memory>
30 
31 class GrProgramInfo;
32 class GrRenderTarget;
33 class GrVkCommandPool;
34 class GrVkDescriptorPool;
35 class GrVkDescriptorSet;
36 class GrVkGpu;
37 class GrVkPipelineState;
38 class GrVkRenderTarget;
39 class GrVkUniformHandler;
40 namespace skgpu {
41 class RefCntedCallback;
42 struct VulkanYcbcrConversionInfo;
43 }  // namespace skgpu
44 
45 class GrVkResourceProvider {
46 public:
47     GrVkResourceProvider(GrVkGpu* gpu);
48     ~GrVkResourceProvider();
49 
pipelineStateCache()50     GrThreadSafePipelineBuilder* pipelineStateCache() {
51         return fPipelineStateCache.get();
52     }
53 
refPipelineStateCache()54     sk_sp<GrThreadSafePipelineBuilder> refPipelineStateCache() {
55         return fPipelineStateCache;
56     }
57 
58     // Set up any initial vk objects
59     void init();
60 
61     sk_sp<const GrVkPipeline> makePipeline(const GrProgramInfo&,
62                                            VkPipelineShaderStageCreateInfo* shaderStageInfo,
63                                            int shaderStageCount,
64                                            VkRenderPass compatibleRenderPass,
65                                            VkPipelineLayout layout,
66                                            uint32_t subpass);
67 
68     GR_DEFINE_RESOURCE_HANDLE_CLASS(CompatibleRPHandle)
69 
70     using SelfDependencyFlags = GrVkRenderPass::SelfDependencyFlags;
71     using LoadFromResolve = GrVkRenderPass::LoadFromResolve;
72 
73     // Finds or creates a simple render pass that matches the target, increments the refcount,
74     // and returns. The caller can optionally pass in a pointer to a CompatibleRPHandle. If this is
75     // non null it will be set to a handle that can be used in the furutre to quickly return a
76     // compatible GrVkRenderPasses without the need inspecting a GrVkRenderTarget.
77     const GrVkRenderPass* findCompatibleRenderPass(GrVkRenderTarget* target,
78                                                    CompatibleRPHandle* compatibleHandle,
79                                                    bool withResolve,
80                                                    bool withStencil,
81                                                    SelfDependencyFlags selfDepFlags,
82                                                    LoadFromResolve);
83     const GrVkRenderPass* findCompatibleRenderPass(GrVkRenderPass::AttachmentsDescriptor*,
84                                                    GrVkRenderPass::AttachmentFlags,
85                                                    SelfDependencyFlags selfDepFlags,
86                                                    LoadFromResolve,
87                                                    CompatibleRPHandle* compatibleHandle = nullptr);
88 
89     const GrVkRenderPass* findCompatibleExternalRenderPass(VkRenderPass,
90                                                            uint32_t colorAttachmentIndex);
91 
92 
93     // Finds or creates a render pass that matches the target and LoadStoreOps, increments the
94     // refcount, and returns. The caller can optionally pass in a pointer to a CompatibleRPHandle.
95     // If this is non null it will be set to a handle that can be used in the future to quickly
96     // return a GrVkRenderPass without the need to inspect a GrVkRenderTarget.
97     // TODO: sk_sp?
98     const GrVkRenderPass* findRenderPass(GrVkRenderTarget* target,
99                                          const GrVkRenderPass::LoadStoreOps& colorOps,
100                                          const GrVkRenderPass::LoadStoreOps& resolveOps,
101                                          const GrVkRenderPass::LoadStoreOps& stencilOps,
102                                          CompatibleRPHandle* compatibleHandle,
103                                          bool withResolve,
104                                          bool withStencil,
105                                          SelfDependencyFlags selfDepFlags,
106                                          LoadFromResolve);
107 
108     // The CompatibleRPHandle must be a valid handle previously set by a call to findRenderPass or
109     // findCompatibleRenderPass.
110     const GrVkRenderPass* findRenderPass(const CompatibleRPHandle& compatibleHandle,
111                                          const GrVkRenderPass::LoadStoreOps& colorOps,
112                                          const GrVkRenderPass::LoadStoreOps& resolveOps,
113                                          const GrVkRenderPass::LoadStoreOps& stencilOps);
114 
115     GrVkCommandPool* findOrCreateCommandPool();
116 
117     void checkCommandBuffers();
118 
119     void forceSyncAllCommandBuffers();
120 
121     // We must add the finishedProc to all active command buffers since we may have flushed work
122     // that the client cares about before they explicitly called flush and the GPU may reorder
123     // command execution. So we make sure all previously submitted work finishes before we call the
124     // finishedProc.
125     void addFinishedProcToActiveCommandBuffers(sk_sp<skgpu::RefCntedCallback> finishedCallback);
126 
127     // Finds or creates a compatible GrVkDescriptorPool for the requested type and count.
128     // The refcount is incremented and a pointer returned.
129     // TODO: Currently this will just create a descriptor pool without holding onto a ref itself
130     //       so we currently do not reuse them. Rquires knowing if another draw is currently using
131     //       the GrVkDescriptorPool, the ability to reset pools, and the ability to purge pools out
132     //       of our cache of GrVkDescriptorPools.
133     GrVkDescriptorPool* findOrCreateCompatibleDescriptorPool(VkDescriptorType type, uint32_t count);
134 
135     // Finds or creates a compatible GrVkSampler based on the GrSamplerState and
136     // skgpu::VulkanYcbcrConversionInfo. The refcount is incremented and a pointer returned.
137     GrVkSampler* findOrCreateCompatibleSampler(GrSamplerState,
138                                                const skgpu::VulkanYcbcrConversionInfo& ycbcrInfo);
139 
140     // Finds or creates a compatible GrVkSamplerYcbcrConversion based on the GrSamplerState and
141     // skgpu::VulkanYcbcrConversionInfo. The refcount is incremented and a pointer returned.
142     GrVkSamplerYcbcrConversion* findOrCreateCompatibleSamplerYcbcrConversion(
143             const skgpu::VulkanYcbcrConversionInfo& ycbcrInfo);
144 
145     GrVkPipelineState* findOrCreateCompatiblePipelineState(
146             GrRenderTarget*,
147             const GrProgramInfo&,
148             VkRenderPass compatibleRenderPass,
149             bool overrideSubpassForResolveLoad);
150 
151     GrVkPipelineState* findOrCreateCompatiblePipelineState(
152             const GrProgramDesc&,
153             const GrProgramInfo&,
154             VkRenderPass compatibleRenderPass,
155             GrThreadSafePipelineBuilder::Stats::ProgramCacheResult* stat);
156 
157     sk_sp<const GrVkPipeline> findOrCreateMSAALoadPipeline(
158             const GrVkRenderPass& renderPass,
159             int numSamples,
160             VkPipelineShaderStageCreateInfo*,
161             VkPipelineLayout);
162 
163     void getSamplerDescriptorSetHandle(VkDescriptorType type,
164                                        const GrVkUniformHandler&,
165                                        GrVkDescriptorSetManager::Handle* handle);
166 
167     // This is a convenience function to return a descriptor set for zero sammples. When making a
168     // VkPipelineLayout we must pass in an array of valid descriptor set handles. However, we have
169     // set up our system to have the descriptor sets be in the order uniform, sampler, input. So
170     // if we have a uniform and input we will need to have a valid handle for the sampler as well.
171     // When using the GrVkMSAALoadManager this is the case, but we also don't have a
172     // GrVkUniformHandler to pass into the more general function. Thus we use this call instead.
173     void getZeroSamplerDescriptorSetHandle(GrVkDescriptorSetManager::Handle* handle);
174 
175     // Returns the compatible VkDescriptorSetLayout to use for uniform buffers. The caller does not
176     // own the VkDescriptorSetLayout and thus should not delete it. This function should be used
177     // when the caller needs the layout to create a VkPipelineLayout.
178     VkDescriptorSetLayout getUniformDSLayout() const;
179 
180     // Returns the compatible VkDescriptorSetLayout to use for input attachments. The caller does
181     // not own the VkDescriptorSetLayout and thus should not delete it. This function should be used
182     // when the caller needs the layout to create a VkPipelineLayout.
183     VkDescriptorSetLayout getInputDSLayout() const;
184 
185     // Returns the compatible VkDescriptorSetLayout to use for a specific sampler handle. The caller
186     // does not own the VkDescriptorSetLayout and thus should not delete it. This function should be
187     // used when the caller needs the layout to create a VkPipelineLayout.
188     VkDescriptorSetLayout getSamplerDSLayout(const GrVkDescriptorSetManager::Handle&) const;
189 
190     // Returns a GrVkDescriptorSet that can be used for uniform buffers. The GrVkDescriptorSet
191     // is already reffed for the caller.
192     const GrVkDescriptorSet* getUniformDescriptorSet();
193 
194     // Returns a GrVkDescriptorSet that can be used for sampler descriptors that are compatible with
195     // the GrVkDescriptorSetManager::Handle passed in. The GrVkDescriptorSet is already reffed for
196     // the caller.
197     const GrVkDescriptorSet* getSamplerDescriptorSet(const GrVkDescriptorSetManager::Handle&);
198 
199     // Returns a GrVkDescriptorSet that can be used for input attachments. The GrVkDescriptorSet
200     // is already reffed for the caller.
201     const GrVkDescriptorSet* getInputDescriptorSet();
202 
203     // Signals that the descriptor set passed it, which is compatible with the passed in handle,
204     // can be reused by the next allocation request.
205     void recycleDescriptorSet(const GrVkDescriptorSet* descSet,
206                               const GrVkDescriptorSetManager::Handle&);
207 
208     void storePipelineCacheData();
209 
210     // Destroy any cached resources. To be called before destroying the VkDevice.
211     // The assumption is that all queues are idle and all command buffers are finished.
212     // For resource tracing to work properly, this should be called after unrefing all other
213     // resource usages.
214     void destroyResources();
215 
216     // Currently we just release available command pools (which also releases their buffers). The
217     // command buffers and pools take up the most memory. Other objects (e.g. samples,
218     // ycbcr conversions, etc.) tend to be fairly light weight and not worth the effort to remove
219     // them and then possibly remake them. Additionally many of those objects have refs/handles that
220     // are held by other objects that aren't deleted here. Thus the memory wins for removing these
221     // objects from the cache are probably not worth the complexity of safely releasing them.
222     void releaseUnlockedBackendObjects();
223 
224 #if defined(GPU_TEST_UTILS)
resetShaderCacheForTesting()225     void resetShaderCacheForTesting() const { fPipelineStateCache->release(); }
226 #endif
227 
228 private:
229     class PipelineStateCache : public GrThreadSafePipelineBuilder {
230     public:
231         PipelineStateCache(GrVkGpu* gpu);
232         ~PipelineStateCache() override;
233 
234         void release();
235         GrVkPipelineState* findOrCreatePipelineState(GrRenderTarget*,
236                                                      const GrProgramInfo&,
237                                                      VkRenderPass compatibleRenderPass,
238                                                      bool overrideSubpassForResolveLoad);
findOrCreatePipelineState(const GrProgramDesc & desc,const GrProgramInfo & programInfo,VkRenderPass compatibleRenderPass,Stats::ProgramCacheResult * stat)239         GrVkPipelineState* findOrCreatePipelineState(const GrProgramDesc& desc,
240                                                      const GrProgramInfo& programInfo,
241                                                      VkRenderPass compatibleRenderPass,
242                                                      Stats::ProgramCacheResult* stat) {
243             return this->findOrCreatePipelineStateImpl(desc, programInfo, compatibleRenderPass,
244                                                        false, stat);
245         }
246 
247     private:
248         struct Entry;
249 
250         GrVkPipelineState* findOrCreatePipelineStateImpl(const GrProgramDesc&,
251                                                          const GrProgramInfo&,
252                                                          VkRenderPass compatibleRenderPass,
253                                                          bool overrideSubpassForResolveLoad,
254                                                          Stats::ProgramCacheResult*);
255 
256         struct DescHash {
operatorDescHash257             uint32_t operator()(const GrProgramDesc& desc) const {
258                 return SkChecksum::Hash32(desc.asKey(), desc.keyLength());
259             }
260         };
261 
262         SkLRUCache<const GrProgramDesc, std::unique_ptr<Entry>, DescHash> fMap;
263 
264         GrVkGpu*                    fGpu;
265     };
266 
267     class CompatibleRenderPassSet {
268     public:
269         // This will always construct the basic load store render pass (all attachments load and
270         // store their data) so that there is at least one compatible VkRenderPass that can be used
271         // with this set.
272         CompatibleRenderPassSet(GrVkRenderPass* renderPass);
273 
274         bool isCompatible(const GrVkRenderPass::AttachmentsDescriptor&,
275                           GrVkRenderPass::AttachmentFlags,
276                           SelfDependencyFlags selfDepFlags,
277                           LoadFromResolve) const;
278 
getCompatibleRenderPass()279         const GrVkRenderPass* getCompatibleRenderPass() const {
280             // The first GrVkRenderpass should always exist since we create the basic load store
281             // render pass on create
282             SkASSERT(fRenderPasses[0]);
283             return fRenderPasses[0];
284         }
285 
286         GrVkRenderPass* getRenderPass(GrVkGpu* gpu,
287                                       const GrVkRenderPass::LoadStoreOps& colorOps,
288                                       const GrVkRenderPass::LoadStoreOps& resolveOps,
289                                       const GrVkRenderPass::LoadStoreOps& stencilOps);
290 
291         void releaseResources();
292 
293     private:
294         skia_private::STArray<4, GrVkRenderPass*> fRenderPasses;
295         int                           fLastReturnedIndex;
296     };
297 
298     VkPipelineCache pipelineCache();
299 
300     GrVkGpu* fGpu;
301 
302     // Central cache for creating pipelines
303     VkPipelineCache fPipelineCache;
304 
305     struct MSAALoadPipeline {
306         sk_sp<const GrVkPipeline> fPipeline;
307         const GrVkRenderPass* fRenderPass;
308     };
309 
310     // Cache of previously created msaa load pipelines
311     skia_private::TArray<MSAALoadPipeline> fMSAALoadPipelines;
312 
313     skia_private::STArray<4, CompatibleRenderPassSet> fRenderPassArray;
314 
315     skia_private::TArray<const GrVkRenderPass*> fExternalRenderPasses;
316 
317     // Array of command pools that we are waiting on
318     skia_private::STArray<4, GrVkCommandPool*, true> fActiveCommandPools;
319 
320     // Array of available command pools that are not in flight
321     skia_private::STArray<4, GrVkCommandPool*, true> fAvailableCommandPools;
322 
323     // Stores GrVkSampler objects that we've already created so we can reuse them across multiple
324     // GrVkPipelineStates
325     SkTDynamicHash<GrVkSampler, GrVkSampler::Key> fSamplers;
326 
327     // Stores GrVkSamplerYcbcrConversion objects that we've already created so we can reuse them.
328     SkTDynamicHash<GrVkSamplerYcbcrConversion, GrVkSamplerYcbcrConversion::Key> fYcbcrConversions;
329 
330     // Cache of GrVkPipelineStates
331     sk_sp<PipelineStateCache> fPipelineStateCache;
332 
333     skia_private::STArray<4, std::unique_ptr<GrVkDescriptorSetManager>> fDescriptorSetManagers;
334 
335     GrVkDescriptorSetManager::Handle fUniformDSHandle;
336     GrVkDescriptorSetManager::Handle fInputDSHandle;
337 };
338 
339 #endif
340