/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrVkResourceProvider_DEFINED #define GrVkResourceProvider_DEFINED #include "GrGpu.h" #include "GrResourceHandle.h" #include "GrVkDescriptorPool.h" #include "GrVkDescriptorSetManager.h" #include "GrVkPipelineState.h" #include "GrVkRenderPass.h" #include "GrVkResource.h" #include "GrVkUtil.h" #include "SkLRUCache.h" #include "SkTArray.h" #include "SkTDynamicHash.h" #include "SkTInternalLList.h" #include "vk/GrVkDefines.h" class GrPipeline; class GrPrimitiveProcessor; class GrSamplerParams; class GrVkCopyPipeline; class GrVkGpu; class GrVkPipeline; class GrVkPrimaryCommandBuffer; class GrVkRenderTarget; class GrVkSampler; class GrVkSecondaryCommandBuffer; class GrVkUniformHandler; class GrVkResourceProvider { public: GrVkResourceProvider(GrVkGpu* gpu); ~GrVkResourceProvider(); // Set up any initial vk objects void init(); GrVkPipeline* createPipeline(const GrPipeline& pipeline, const GrStencilSettings& stencil, const GrPrimitiveProcessor& primProc, VkPipelineShaderStageCreateInfo* shaderStageInfo, int shaderStageCount, GrPrimitiveType primitiveType, const GrVkRenderPass& renderPass, VkPipelineLayout layout); GrVkCopyPipeline* findOrCreateCopyPipeline(const GrVkRenderTarget* dst, VkPipelineShaderStageCreateInfo*, VkPipelineLayout); GR_DEFINE_RESOURCE_HANDLE_CLASS(CompatibleRPHandle); // Finds or creates a simple render pass that matches the target, increments the refcount, // and returns. The caller can optionally pass in a pointer to a CompatibleRPHandle. If this is // non null it will be set to a handle that can be used in the furutre to quickly return a // compatible GrVkRenderPasses without the need inspecting a GrVkRenderTarget. const GrVkRenderPass* findCompatibleRenderPass(const GrVkRenderTarget& target, CompatibleRPHandle* compatibleHandle = nullptr); // The CompatibleRPHandle must be a valid handle previously set by a call to // findCompatibleRenderPass(GrVkRenderTarget&, CompatibleRPHandle*). const GrVkRenderPass* findCompatibleRenderPass(const CompatibleRPHandle& compatibleHandle); // Finds or creates a render pass that matches the target and LoadStoreOps, increments the // refcount, and returns. The caller can optionally pass in a pointer to a CompatibleRPHandle. // If this is non null it will be set to a handle that can be used in the furutre to quickly // return a GrVkRenderPasses without the need inspecting a GrVkRenderTarget. const GrVkRenderPass* findRenderPass(const GrVkRenderTarget& target, const GrVkRenderPass::LoadStoreOps& colorOps, const GrVkRenderPass::LoadStoreOps& stencilOps, CompatibleRPHandle* compatibleHandle = nullptr); // The CompatibleRPHandle must be a valid handle previously set by a call to findRenderPass or // findCompatibleRenderPass. const GrVkRenderPass* findRenderPass(const CompatibleRPHandle& compatibleHandle, const GrVkRenderPass::LoadStoreOps& colorOps, const GrVkRenderPass::LoadStoreOps& stencilOps); GrVkPrimaryCommandBuffer* findOrCreatePrimaryCommandBuffer(); void checkCommandBuffers(); GrVkSecondaryCommandBuffer* findOrCreateSecondaryCommandBuffer(); void recycleSecondaryCommandBuffer(GrVkSecondaryCommandBuffer* cb); // Finds or creates a compatible GrVkDescriptorPool for the requested type and count. // The refcount is incremented and a pointer returned. // TODO: Currently this will just create a descriptor pool without holding onto a ref itself // so we currently do not reuse them. Rquires knowing if another draw is currently using // the GrVkDescriptorPool, the ability to reset pools, and the ability to purge pools out // of our cache of GrVkDescriptorPools. GrVkDescriptorPool* findOrCreateCompatibleDescriptorPool(VkDescriptorType type, uint32_t count); // Finds or creates a compatible GrVkSampler based on the GrSamplerParams. // The refcount is incremented and a pointer returned. GrVkSampler* findOrCreateCompatibleSampler(const GrSamplerParams&, uint32_t mipLevels); sk_sp<GrVkPipelineState> findOrCreateCompatiblePipelineState(const GrPipeline&, const GrPrimitiveProcessor&, GrPrimitiveType, const GrVkRenderPass& renderPass); void getSamplerDescriptorSetHandle(const GrVkUniformHandler&, GrVkDescriptorSetManager::Handle* handle); void getSamplerDescriptorSetHandle(const SkTArray<uint32_t>& visibilities, GrVkDescriptorSetManager::Handle* handle); // Returns the compatible VkDescriptorSetLayout to use for uniform buffers. The caller does not // own the VkDescriptorSetLayout and thus should not delete it. This function should be used // when the caller needs the layout to create a VkPipelineLayout. VkDescriptorSetLayout getUniformDSLayout() const; // Returns the compatible VkDescriptorSetLayout to use for a specific sampler handle. The caller // does not own the VkDescriptorSetLayout and thus should not delete it. This function should be // used when the caller needs the layout to create a VkPipelineLayout. VkDescriptorSetLayout getSamplerDSLayout(const GrVkDescriptorSetManager::Handle&) const; // Returns a GrVkDescriptorSet that can be used for uniform buffers. The GrVkDescriptorSet // is already reffed for the caller. const GrVkDescriptorSet* getUniformDescriptorSet(); // Returns a GrVkDescriptorSet that can be used for sampler descriptors that are compatible with // the GrVkDescriptorSetManager::Handle passed in. The GrVkDescriptorSet is already reffed for // the caller. const GrVkDescriptorSet* getSamplerDescriptorSet(const GrVkDescriptorSetManager::Handle&); // Signals that the descriptor set passed it, which is compatible with the passed in handle, // can be reused by the next allocation request. void recycleDescriptorSet(const GrVkDescriptorSet* descSet, const GrVkDescriptorSetManager::Handle&); // Creates or finds free uniform buffer resources of size GrVkUniformBuffer::kStandardSize. // Anything larger will need to be created and released by the client. const GrVkResource* findOrCreateStandardUniformBufferResource(); // Signals that the resource passed to it (which should be a uniform buffer resource) // can be reused by the next uniform buffer resource request. void recycleStandardUniformBufferResource(const GrVkResource*); // Destroy any cached resources. To be called before destroying the VkDevice. // The assumption is that all queues are idle and all command buffers are finished. // For resource tracing to work properly, this should be called after unrefing all other // resource usages. // If deviceLost is true, then resources will not be checked to see if they've finished // before deleting (see section 4.2.4 of the Vulkan spec). void destroyResources(bool deviceLost); // Abandon any cached resources. To be used when the context/VkDevice is lost. // For resource tracing to work properly, this should be called after unrefing all other // resource usages. void abandonResources(); private: #ifdef SK_DEBUG #define GR_PIPELINE_STATE_CACHE_STATS #endif class PipelineStateCache : public ::SkNoncopyable { public: PipelineStateCache(GrVkGpu* gpu); ~PipelineStateCache(); void abandon(); void release(); sk_sp<GrVkPipelineState> refPipelineState(const GrPipeline&, const GrPrimitiveProcessor&, GrPrimitiveType, const GrVkRenderPass& renderPass); private: enum { // We may actually have kMaxEntries+1 PipelineStates in context because we create a new // PipelineState before evicting from the cache. kMaxEntries = 128, }; struct Entry; struct DescHash { uint32_t operator()(const GrProgramDesc& desc) const { return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0); } }; SkLRUCache<const GrVkPipelineState::Desc, std::unique_ptr<Entry>, DescHash> fMap; GrVkGpu* fGpu; #ifdef GR_PIPELINE_STATE_CACHE_STATS int fTotalRequests; int fCacheMisses; #endif }; class CompatibleRenderPassSet { public: // This will always construct the basic load store render pass (all attachments load and // store their data) so that there is at least one compatible VkRenderPass that can be used // with this set. CompatibleRenderPassSet(const GrVkGpu* gpu, const GrVkRenderTarget& target); bool isCompatible(const GrVkRenderTarget& target) const; GrVkRenderPass* getCompatibleRenderPass() const { // The first GrVkRenderpass should always exist since we create the basic load store // render pass on create SkASSERT(fRenderPasses[0]); return fRenderPasses[0]; } GrVkRenderPass* getRenderPass(const GrVkGpu* gpu, const GrVkRenderPass::LoadStoreOps& colorOps, const GrVkRenderPass::LoadStoreOps& stencilOps); void releaseResources(const GrVkGpu* gpu); void abandonResources(); private: SkSTArray<4, GrVkRenderPass*> fRenderPasses; int fLastReturnedIndex; }; GrVkGpu* fGpu; // Central cache for creating pipelines VkPipelineCache fPipelineCache; // Cache of previously created copy pipelines SkTArray<GrVkCopyPipeline*> fCopyPipelines; SkSTArray<4, CompatibleRenderPassSet> fRenderPassArray; // Array of PrimaryCommandBuffers that are currently in flight SkSTArray<4, GrVkPrimaryCommandBuffer*, true> fActiveCommandBuffers; // Array of available primary command buffers that are not in flight SkSTArray<4, GrVkPrimaryCommandBuffer*, true> fAvailableCommandBuffers; // Array of available secondary command buffers SkSTArray<16, GrVkSecondaryCommandBuffer*, true> fAvailableSecondaryCommandBuffers; // Array of available uniform buffer resources SkSTArray<16, const GrVkResource*, true> fAvailableUniformBufferResources; // Stores GrVkSampler objects that we've already created so we can reuse them across multiple // GrVkPipelineStates SkTDynamicHash<GrVkSampler, uint16_t> fSamplers; // Cache of GrVkPipelineStates PipelineStateCache* fPipelineStateCache; SkSTArray<4, GrVkDescriptorSetManager, true> fDescriptorSetManagers; GrVkDescriptorSetManager::Handle fUniformDSHandle; }; #endif