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