diff options
author | egdaniel <egdaniel@google.com> | 2016-06-07 08:43:30 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-06-07 08:43:30 -0700 |
commit | d62e28b19a23b913c549b7891ecf79e779577181 (patch) | |
tree | 7216b9b6ce31898d4d892eac7fd414ceb9857acb /src | |
parent | af18fb49fbefb96a6670171a07442b1ccb9f746f (diff) |
Refactor creation of GrVkRenderPasses to make them move general
This change is a refactorization to open up more flexable use for render passes
in the future. Once we start bundling draw calls into a single render pass we
will need to start using specific load and store ops instead of the default
currently of load and store everything.
We still will need to simply get a compatible render pass for creation of framebuffers
and pipeline objects. These render passes don't need to know load and store ops. Thus
in this change, I'm defaulting the "compatible" render pass to always be the one
which both loads and stores. All other load/store combinations will be created lazily
when requested for a specific draw (future change).
The CompatibleRPHandle is a way for us to avoid analysing the RenderTarget every time
we want to get a new GrVkRenderPass.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1977403002
Review-Url: https://codereview.chromium.org/1977403002
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/vk/GrVkRenderPass.cpp | 61 | ||||
-rw-r--r-- | src/gpu/vk/GrVkRenderPass.h | 18 | ||||
-rw-r--r-- | src/gpu/vk/GrVkRenderTarget.cpp | 3 | ||||
-rw-r--r-- | src/gpu/vk/GrVkRenderTarget.h | 3 | ||||
-rw-r--r-- | src/gpu/vk/GrVkResourceProvider.cpp | 83 | ||||
-rw-r--r-- | src/gpu/vk/GrVkResourceProvider.h | 59 |
6 files changed, 177 insertions, 50 deletions
diff --git a/src/gpu/vk/GrVkRenderPass.cpp b/src/gpu/vk/GrVkRenderPass.cpp index 1aedab4cfa..c56bafa92d 100644 --- a/src/gpu/vk/GrVkRenderPass.cpp +++ b/src/gpu/vk/GrVkRenderPass.cpp @@ -13,17 +13,31 @@ #include "GrVkRenderTarget.h" #include "GrVkUtil.h" -void setup_simple_vk_attachment_description(VkAttachmentDescription* attachment, - VkFormat format, - uint32_t samples, - VkImageLayout layout) { +typedef GrVkRenderPass::AttachmentsDescriptor::AttachmentDesc AttachmentDesc; + +void setup_vk_attachment_description(VkAttachmentDescription* attachment, + const AttachmentDesc& desc, + VkImageLayout layout) { attachment->flags = 0; - attachment->format = format; - SkAssertResult(GrSampleCountToVkSampleCount(samples, &attachment->samples)); - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment->format = desc.fFormat; + SkAssertResult(GrSampleCountToVkSampleCount(desc.fSamples, &attachment->samples)); + switch (layout) { + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + attachment->loadOp = desc.fLoadOp; + attachment->storeOp = desc.fStoreOp; + attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + break; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment->stencilLoadOp = desc.fLoadOp; + attachment->stencilStoreOp = desc.fStoreOp; + break; + default: + SkFAIL("Unexpected attachment layout"); + } + attachment->initialLayout = layout; attachment->finalLayout = layout; } @@ -56,10 +70,9 @@ void GrVkRenderPass::initSimple(const GrVkGpu* gpu, const GrVkRenderTarget& targ subpassDesc.pInputAttachments = nullptr; if (fAttachmentFlags & kColor_AttachmentFlag) { // set up color attachment - setup_simple_vk_attachment_description(&attachments[currentAttachment], - fAttachmentsDescriptor.fColor.fFormat, - fAttachmentsDescriptor.fColor.fSamples, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + setup_vk_attachment_description(&attachments[currentAttachment], + fAttachmentsDescriptor.fColor, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // setup subpass use of attachment colorRef.attachment = currentAttachment++; colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -75,10 +88,9 @@ void GrVkRenderPass::initSimple(const GrVkGpu* gpu, const GrVkRenderTarget& targ if (fAttachmentFlags & kResolve_AttachmentFlag) { // set up resolve attachment - setup_simple_vk_attachment_description(&attachments[currentAttachment], - fAttachmentsDescriptor.fResolve.fFormat, - fAttachmentsDescriptor.fResolve.fSamples, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + setup_vk_attachment_description(&attachments[currentAttachment], + fAttachmentsDescriptor.fResolve, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // setup subpass use of attachment resolveRef.attachment = currentAttachment++; // I'm really not sure what the layout should be for the resolve textures. @@ -90,10 +102,9 @@ void GrVkRenderPass::initSimple(const GrVkGpu* gpu, const GrVkRenderTarget& targ if (fAttachmentFlags & kStencil_AttachmentFlag) { // set up stencil attachment - setup_simple_vk_attachment_description(&attachments[currentAttachment], - fAttachmentsDescriptor.fStencil.fFormat, - fAttachmentsDescriptor.fStencil.fSamples, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + setup_vk_attachment_description(&attachments[currentAttachment], + fAttachmentsDescriptor.fStencil, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); // setup subpass use of attachment stencilRef.attachment = currentAttachment++; stencilRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; @@ -202,17 +213,17 @@ bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const { } if (fAttachmentFlags & kColor_AttachmentFlag) { - if (fAttachmentsDescriptor.fColor != desc.fColor) { + if (!fAttachmentsDescriptor.fColor.isCompatible(desc.fColor)) { return false; } } if (fAttachmentFlags & kResolve_AttachmentFlag) { - if (fAttachmentsDescriptor.fResolve != desc.fResolve) { + if (!fAttachmentsDescriptor.fResolve.isCompatible(desc.fResolve)) { return false; } } if (fAttachmentFlags & kStencil_AttachmentFlag) { - if (fAttachmentsDescriptor.fStencil != desc.fStencil) { + if (!fAttachmentsDescriptor.fStencil.isCompatible(desc.fStencil)) { return false; } } diff --git a/src/gpu/vk/GrVkRenderPass.h b/src/gpu/vk/GrVkRenderPass.h index d38848fe1e..082cccda77 100644 --- a/src/gpu/vk/GrVkRenderPass.h +++ b/src/gpu/vk/GrVkRenderPass.h @@ -27,13 +27,26 @@ public: struct AttachmentDesc { VkFormat fFormat; int fSamples; - AttachmentDesc() : fFormat(VK_FORMAT_UNDEFINED), fSamples(0) {} + VkAttachmentLoadOp fLoadOp; + VkAttachmentStoreOp fStoreOp; + + AttachmentDesc() + : fFormat(VK_FORMAT_UNDEFINED) + , fSamples(0) + , fLoadOp(VK_ATTACHMENT_LOAD_OP_LOAD) + , fStoreOp(VK_ATTACHMENT_STORE_OP_STORE) {} bool operator==(const AttachmentDesc& right) const { - return (fFormat == right.fFormat && fSamples == right.fSamples); + return (fFormat == right.fFormat && + fSamples == right.fSamples && + fLoadOp == right.fLoadOp && + fStoreOp == right.fStoreOp); } bool operator!=(const AttachmentDesc& right) const { return !(*this == right); } + bool isCompatible(const AttachmentDesc& desc) const { + return (fFormat == desc.fFormat && fSamples == desc.fSamples); + } }; AttachmentDesc fColor; AttachmentDesc fResolve; @@ -77,7 +90,6 @@ public: private: GrVkRenderPass(const GrVkRenderPass&); - GrVkRenderPass& operator=(const GrVkRenderPass&); void freeGPUData(const GrVkGpu* gpu) const override; diff --git a/src/gpu/vk/GrVkRenderTarget.cpp b/src/gpu/vk/GrVkRenderTarget.cpp index dd3bca57db..708af7970e 100644 --- a/src/gpu/vk/GrVkRenderTarget.cpp +++ b/src/gpu/vk/GrVkRenderTarget.cpp @@ -231,7 +231,8 @@ void GrVkRenderTarget::createFramebuffer(GrVkGpu* gpu) { // Vulkan requires us to create a compatible renderpass before we can create our framebuffer, // so we use this to get a (cached) basic renderpass, only for creation. - fCachedSimpleRenderPass = gpu->resourceProvider().findOrCreateCompatibleRenderPass(*this); + fCachedSimpleRenderPass = + gpu->resourceProvider().findCompatibleRenderPass(*this, &fCompatibleRPHandle); // Stencil attachment view is stored in the base RT stencil attachment const GrVkImageView* stencilView = this->stencilAttachmentView(); diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h index accc677806..0467371ecb 100644 --- a/src/gpu/vk/GrVkRenderTarget.h +++ b/src/gpu/vk/GrVkRenderTarget.h @@ -13,6 +13,7 @@ #include "GrRenderTarget.h" #include "GrVkRenderPass.h" +#include "GrVkResourceProvider.h" class GrVkCommandBuffer; class GrVkFramebuffer; @@ -135,6 +136,8 @@ private: // This is a cached pointer to a simple render pass. The render target should unref it // once it is done with it. const GrVkRenderPass* fCachedSimpleRenderPass; + // This is a handle to be used to quickly get compatible GrVkRenderPasses for this render target + GrVkResourceProvider::CompatibleRPHandle fCompatibleRPHandle; }; #endif diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp index bf283fc512..fdc9e90686 100644 --- a/src/gpu/vk/GrVkResourceProvider.cpp +++ b/src/gpu/vk/GrVkResourceProvider.cpp @@ -28,7 +28,7 @@ GrVkResourceProvider::GrVkResourceProvider(GrVkGpu* gpu) } GrVkResourceProvider::~GrVkResourceProvider() { - SkASSERT(0 == fSimpleRenderPasses.count()); + SkASSERT(0 == fRenderPassArray.count()); SkASSERT(VK_NULL_HANDLE == fPipelineCache); delete fPipelineStateCache; } @@ -102,18 +102,34 @@ GrVkPipeline* GrVkResourceProvider::createPipeline(const GrPipeline& pipeline, // only used for framebuffer creation. When we actually render we will create // RenderPasses as needed that are compatible with the framebuffer. const GrVkRenderPass* -GrVkResourceProvider::findOrCreateCompatibleRenderPass(const GrVkRenderTarget& target) { - for (int i = 0; i < fSimpleRenderPasses.count(); ++i) { - GrVkRenderPass* renderPass = fSimpleRenderPasses[i]; - if (renderPass->isCompatible(target)) { +GrVkResourceProvider::findCompatibleRenderPass(const GrVkRenderTarget& target, + CompatibleRPHandle* compatibleHandle) { + for (int i = 0; i < fRenderPassArray.count(); ++i) { + if (fRenderPassArray[i].isCompatible(target)) { + const GrVkRenderPass* renderPass = fRenderPassArray[i].getCompatibleRenderPass(); renderPass->ref(); + if (compatibleHandle) { + *compatibleHandle = CompatibleRPHandle(i); + } return renderPass; } } - GrVkRenderPass* renderPass = new GrVkRenderPass(); - renderPass->initSimple(fGpu, target); - fSimpleRenderPasses.push_back(renderPass); + const GrVkRenderPass* renderPass = + fRenderPassArray.emplace_back(fGpu, target).getCompatibleRenderPass(); + renderPass->ref(); + + if (compatibleHandle) { + *compatibleHandle = CompatibleRPHandle(fRenderPassArray.count() - 1); + } + return renderPass; +} + +const GrVkRenderPass* +GrVkResourceProvider::findCompatibleRenderPass(const CompatibleRPHandle& compatibleHandle) { + SkASSERT(compatibleHandle.isValid() && compatibleHandle.toIndex() < fRenderPassArray.count()); + int index = compatibleHandle.toIndex(); + const GrVkRenderPass* renderPass = fRenderPassArray[index].getCompatibleRenderPass(); renderPass->ref(); return renderPass; } @@ -198,11 +214,11 @@ void GrVkResourceProvider::destroyResources() { } fActiveCommandBuffers.reset(); - // loop over all render passes to make sure we destroy all the internal VkRenderPasses - for (int i = 0; i < fSimpleRenderPasses.count(); ++i) { - fSimpleRenderPasses[i]->unref(fGpu); + // loop over all render pass sets to make sure we destroy all the internal VkRenderPasses + for (int i = 0; i < fRenderPassArray.count(); ++i) { + fRenderPassArray[i].releaseResources(fGpu); } - fSimpleRenderPasses.reset(); + fRenderPassArray.reset(); // Iterate through all store GrVkSamplers and unref them before resetting the hash. SkTDynamicHash<GrVkSampler, uint16_t>::Iter iter(&fSamplers); @@ -237,10 +253,11 @@ void GrVkResourceProvider::abandonResources() { } fActiveCommandBuffers.reset(); - for (int i = 0; i < fSimpleRenderPasses.count(); ++i) { - fSimpleRenderPasses[i]->unrefAndAbandon(); + // loop over all render pass sets to make sure we destroy all the internal VkRenderPasses + for (int i = 0; i < fRenderPassArray.count(); ++i) { + fRenderPassArray[i].abandonResources(); } - fSimpleRenderPasses.reset(); + fRenderPassArray.reset(); // Iterate through all store GrVkSamplers and unrefAndAbandon them before resetting the hash. SkTDynamicHash<GrVkSampler, uint16_t>::Iter iter(&fSamplers); @@ -259,3 +276,39 @@ void GrVkResourceProvider::abandonResources() { fUniformDescLayout = VK_NULL_HANDLE; fUniformDescPool->unrefAndAbandon(); } + +//////////////////////////////////////////////////////////////////////////////// + +GrVkResourceProvider::CompatibleRenderPassSet::CompatibleRenderPassSet( + const GrVkGpu* gpu, + const GrVkRenderTarget& target) + : fLastReturnedIndex(0) { + fRenderPasses.emplace_back(new GrVkRenderPass()); + fRenderPasses[0]->initSimple(gpu, target); +} + +bool GrVkResourceProvider::CompatibleRenderPassSet::isCompatible( + const GrVkRenderTarget& target) const { + // The first GrVkRenderpass should always exists since we create the basic load store + // render pass on create + SkASSERT(fRenderPasses[0]); + return fRenderPasses[0]->isCompatible(target); +} + +void GrVkResourceProvider::CompatibleRenderPassSet::releaseResources(const GrVkGpu* gpu) { + for (int i = 0; i < fRenderPasses.count(); ++i) { + if (fRenderPasses[i]) { + fRenderPasses[i]->unref(gpu); + fRenderPasses[i] = nullptr; + } + } +} + +void GrVkResourceProvider::CompatibleRenderPassSet::abandonResources() { + for (int i = 0; i < fRenderPasses.count(); ++i) { + if (fRenderPasses[i]) { + fRenderPasses[i]->unrefAndAbandon(); + fRenderPasses[i] = nullptr; + } + } +} diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h index 37ec6fdee5..5368a212b4 100644 --- a/src/gpu/vk/GrVkResourceProvider.h +++ b/src/gpu/vk/GrVkResourceProvider.h @@ -9,6 +9,7 @@ #define GrVkResourceProvider_DEFINED #include "GrGpu.h" +#include "GrResourceHandle.h" #include "GrVkDescriptorPool.h" #include "GrVkPipelineState.h" #include "GrVkResource.h" @@ -46,9 +47,33 @@ public: const GrVkRenderPass& renderPass, VkPipelineLayout layout); + GR_DEFINE_RESOURCE_HANDLE_CLASS(CompatibleRPHandle); + // Finds or creates a simple render pass that matches the target, increments the refcount, - // and returns. - const GrVkRenderPass* findOrCreateCompatibleRenderPass(const GrVkRenderTarget& target); + // 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); + +#if 0 + // TODO: + const GrVkRenderPass* findRenderPass(const GrVkRenderTarget& target, + VkAttachmentLoadOp colorLoad, + VkAttachmentStoreOp colorStore, + VkAttachmentLoadOp stencilLoad, + VkAttachmentStoreOp stencilStore, + CompatibleRPHandle* compatibleHandle = nullptr); + + const GrVkRenderPass* findRenderPass(const CompatibleRPHandle& compatibleHandle, + VkAttachmentLoadOp colorLoad, + VkAttachmentStoreOp colorStore, + VkAttachmentLoadOp stencilLoad, + VkAttachmentStoreOp stencilStore); +#endif GrVkCommandBuffer* createCommandBuffer(); void checkCommandBuffers(); @@ -94,7 +119,6 @@ public: void abandonResources(); private: - #ifdef SK_DEBUG #define GR_PIPELINE_STATE_CACHE_STATS #endif @@ -134,6 +158,31 @@ private: #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]; + } + + void releaseResources(const GrVkGpu* gpu); + void abandonResources(); + + private: + SkSTArray<4, GrVkRenderPass*> fRenderPasses; + int fLastReturnedIndex; + }; + // Initialiaze the vkDescriptorSetLayout used for allocating new uniform buffer descritpor sets. void initUniformDescObjects(); @@ -142,9 +191,7 @@ private: // Central cache for creating pipelines VkPipelineCache fPipelineCache; - // Array of RenderPasses that only have a single color attachment, optional stencil attachment, - // optional resolve attachment, and only one subpass - SkSTArray<4, GrVkRenderPass*> fSimpleRenderPasses; + SkSTArray<4, CompatibleRenderPassSet> fRenderPassArray; // Array of CommandBuffers that are currently in flight SkSTArray<4, GrVkCommandBuffer*> fActiveCommandBuffers; |