From 1cd31ea144384a45d5d2ebfd20565d82b9b2a7d6 Mon Sep 17 00:00:00 2001 From: Alexis Hetu Date: Thu, 17 Jan 2019 17:14:57 -0500 Subject: [PATCH] Support for clearing Framebuffer attachments MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This is the implementation for vkCmdClearAttachments. It includes the new command along with the plumbing to get the information to the Image clear function. The only non trivial behavior here is that the provided baseArrayLayer for the clear command is to be offset by the ImageView's subresourceRange's baseArrayLayer so that it clears the correct layers. Bug b/119621736 Passes all tests in: api.image_clearing.dedicated_allocation.clear_color_attachment.* Change-Id: I19f86b63239ca2fb4d53f2c6c9cb75185794f061 Reviewed-on: https://swiftshader-review.googlesource.com/c/23748 Tested-by: Alexis Hétu Reviewed-by: Chris Forbes --- src/Vulkan/VkCommandBuffer.cpp | 73 ++++++++++++++++++++++++++++++++++-------- src/Vulkan/VkCommandBuffer.hpp | 9 ++++-- src/Vulkan/VkFramebuffer.cpp | 27 ++++++++++++++++ src/Vulkan/VkFramebuffer.hpp | 3 ++ src/Vulkan/VkImageView.cpp | 24 ++++++++++++++ src/Vulkan/VkImageView.hpp | 1 + 6 files changed, 122 insertions(+), 15 deletions(-) diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp index b4ece0114..59f77fc35 100644 --- a/src/Vulkan/VkCommandBuffer.cpp +++ b/src/Vulkan/VkCommandBuffer.cpp @@ -36,10 +36,10 @@ public: class BeginRenderPass : public CommandBuffer::Command { public: - BeginRenderPass(VkRenderPass pRenderPass, VkFramebuffer pFramebuffer, VkRect2D pRenderArea, - uint32_t pClearValueCount, const VkClearValue* pClearValues) : - renderPass(pRenderPass), framebuffer(pFramebuffer), renderArea(pRenderArea), - clearValueCount(pClearValueCount) + BeginRenderPass(VkRenderPass renderPass, VkFramebuffer framebuffer, VkRect2D renderArea, + uint32_t clearValueCount, const VkClearValue* pClearValues) : + renderPass(Cast(renderPass)), framebuffer(Cast(framebuffer)), renderArea(renderArea), + clearValueCount(clearValueCount) { // FIXME (b/119409619): use an allocator here so we can control all memory allocations clearValues = new VkClearValue[clearValueCount]; @@ -54,18 +54,36 @@ public: protected: void play(CommandBuffer::ExecutionState& executionState) { - Cast(renderPass)->begin(); - Cast(framebuffer)->clear(clearValueCount, clearValues, renderArea); + executionState.renderPass = renderPass; + executionState.renderPassFramebuffer = framebuffer; + renderPass->begin(); + framebuffer->clear(clearValueCount, clearValues, renderArea); } private: - VkRenderPass renderPass; - VkFramebuffer framebuffer; + RenderPass* renderPass; + Framebuffer* framebuffer; VkRect2D renderArea; uint32_t clearValueCount; VkClearValue* clearValues; }; +class NextSubpass : public CommandBuffer::Command +{ +public: + NextSubpass() + { + } + +protected: + void play(CommandBuffer::ExecutionState& executionState) + { + executionState.renderPass->nextSubpass(); + } + +private: +}; + class EndRenderPass : public CommandBuffer::Command { public: @@ -76,7 +94,9 @@ public: protected: void play(CommandBuffer::ExecutionState& executionState) { - Cast(executionState.renderpass)->end(); + executionState.renderPass->end(); + executionState.renderPass = nullptr; + executionState.renderPassFramebuffer = nullptr; } private: @@ -93,7 +113,7 @@ public: protected: void play(CommandBuffer::ExecutionState& executionState) { - executionState.pipelines[pipelineBindPoint] = pipeline; + executionState.pipelines[pipelineBindPoint] = Cast(pipeline); } private: @@ -127,7 +147,7 @@ struct Draw : public CommandBuffer::Command void play(CommandBuffer::ExecutionState& executionState) { GraphicsPipeline* pipeline = static_cast( - Cast(executionState.pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS])); + executionState.pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS]); sw::Context context = pipeline->getContext(); for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++) @@ -256,6 +276,23 @@ private: const VkImageSubresourceRange range; }; +struct ClearAttachment : public CommandBuffer::Command +{ + ClearAttachment(const VkClearAttachment& attachment, const VkClearRect& rect) : + attachment(attachment), rect(rect) + { + } + + void play(CommandBuffer::ExecutionState& executionState) + { + executionState.renderPassFramebuffer->clear(attachment, rect); + } + +private: + const VkClearAttachment attachment; + const VkClearRect rect; +}; + struct BlitImage : public CommandBuffer::Command { BlitImage(VkImage srcImage, VkImage dstImage, const VkImageBlit& region, VkFilter filter) : @@ -374,7 +411,9 @@ void CommandBuffer::beginRenderPass(VkRenderPass renderPass, VkFramebuffer frame void CommandBuffer::nextSubpass(VkSubpassContents contents) { - UNIMPLEMENTED(); + ASSERT(state == RECORDING); + + addCommand(); } void CommandBuffer::endRenderPass() @@ -661,7 +700,15 @@ void CommandBuffer::clearDepthStencilImage(VkImage image, VkImageLayout imageLay void CommandBuffer::clearAttachments(uint32_t attachmentCount, const VkClearAttachment* pAttachments, uint32_t rectCount, const VkClearRect* pRects) { - UNIMPLEMENTED(); + ASSERT(state == RECORDING); + + for(uint32_t i = 0; i < attachmentCount; i++) + { + for(uint32_t j = 0; j < rectCount; j++) + { + addCommand(pAttachments[i], pRects[j]); + } + } } void CommandBuffer::resolveImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, diff --git a/src/Vulkan/VkCommandBuffer.hpp b/src/Vulkan/VkCommandBuffer.hpp index 7e31b6153..9b08bab2a 100644 --- a/src/Vulkan/VkCommandBuffer.hpp +++ b/src/Vulkan/VkCommandBuffer.hpp @@ -28,6 +28,10 @@ namespace sw namespace vk { +class Framebuffer; +class Pipeline; +class RenderPass; + class CommandBuffer { public: @@ -118,8 +122,9 @@ public: struct ExecutionState { sw::Renderer* renderer = nullptr; - VkRenderPass renderpass = VK_NULL_HANDLE; - VkPipeline pipelines[VK_PIPELINE_BIND_POINT_RANGE_SIZE] = {}; + RenderPass* renderPass = nullptr; + Framebuffer* renderPassFramebuffer = nullptr; + Pipeline* pipelines[VK_PIPELINE_BIND_POINT_RANGE_SIZE] = {}; struct VertexInputBinding { diff --git a/src/Vulkan/VkFramebuffer.cpp b/src/Vulkan/VkFramebuffer.cpp index 379ef09ca..c7fd0781e 100644 --- a/src/Vulkan/VkFramebuffer.cpp +++ b/src/Vulkan/VkFramebuffer.cpp @@ -14,12 +14,14 @@ #include "VkFramebuffer.hpp" #include "VkImageView.hpp" +#include "VkRenderPass.hpp" #include namespace vk { Framebuffer::Framebuffer(const VkFramebufferCreateInfo* pCreateInfo, void* mem) : + renderPass(Cast(pCreateInfo->renderPass)), attachmentCount(pCreateInfo->attachmentCount), attachments(reinterpret_cast(mem)) { @@ -44,6 +46,31 @@ void Framebuffer::clear(uint32_t clearValueCount, const VkClearValue* pClearValu } } +void Framebuffer::clear(const VkClearAttachment& attachment, const VkClearRect& rect) +{ + if(attachment.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) + { + if(attachment.colorAttachment != VK_ATTACHMENT_UNUSED) + { + VkSubpassDescription subpass = renderPass->getCurrentSubpass(); + + ASSERT(attachment.colorAttachment < subpass.colorAttachmentCount); + ASSERT(subpass.pColorAttachments[attachment.colorAttachment].attachment < attachmentCount); + + attachments[subpass.pColorAttachments[attachment.colorAttachment].attachment]->clear( + attachment.clearValue, attachment.aspectMask, rect); + } + } + else if(attachment.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) + { + VkSubpassDescription subpass = renderPass->getCurrentSubpass(); + + ASSERT(subpass.pDepthStencilAttachment->attachment < attachmentCount); + + attachments[subpass.pDepthStencilAttachment->attachment]->clear(attachment.clearValue, attachment.aspectMask, rect); + } +} + size_t Framebuffer::ComputeRequiredAllocationSize(const VkFramebufferCreateInfo* pCreateInfo) { return pCreateInfo->attachmentCount * sizeof(void*); diff --git a/src/Vulkan/VkFramebuffer.hpp b/src/Vulkan/VkFramebuffer.hpp index 9049c1730..2e16e994d 100644 --- a/src/Vulkan/VkFramebuffer.hpp +++ b/src/Vulkan/VkFramebuffer.hpp @@ -21,6 +21,7 @@ namespace vk { class ImageView; +class RenderPass; class Framebuffer : public Object { @@ -30,10 +31,12 @@ public: void destroy(const VkAllocationCallbacks* pAllocator); void clear(uint32_t clearValueCount, const VkClearValue* pClearValues, const VkRect2D& renderArea); + void clear(const VkClearAttachment& attachment, const VkClearRect& rect); static size_t ComputeRequiredAllocationSize(const VkFramebufferCreateInfo* pCreateInfo); private: + RenderPass* renderPass; uint32_t attachmentCount = 0; ImageView** attachments = nullptr; }; diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp index e2c211366..293c8d72b 100644 --- a/src/Vulkan/VkImageView.cpp +++ b/src/Vulkan/VkImageView.cpp @@ -89,4 +89,28 @@ void ImageView::clear(const VkClearValue& clearValue, const VkRect2D& renderArea image->clear(clearValue, renderArea, subresourceRange); } +void ImageView::clear(const VkClearValue& clearValue, const VkImageAspectFlags aspectMask, const VkClearRect& renderArea) +{ + // Note: clearing ignores swizzling, so components is ignored. + + if(!imageTypesMatch(image->getImageType())) + { + UNIMPLEMENTED(); + } + + if(image->getFormat() != format) + { + UNIMPLEMENTED(); + } + + VkImageSubresourceRange sr; + sr.aspectMask = aspectMask; + sr.baseMipLevel = subresourceRange.baseMipLevel; + sr.levelCount = subresourceRange.levelCount; + sr.baseArrayLayer = renderArea.baseArrayLayer + subresourceRange.baseArrayLayer; + sr.layerCount = renderArea.layerCount; + + image->clear(clearValue, renderArea.rect, sr); +} + } \ No newline at end of file diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp index cdc3896f9..d2a0124f4 100644 --- a/src/Vulkan/VkImageView.hpp +++ b/src/Vulkan/VkImageView.hpp @@ -32,6 +32,7 @@ public: static size_t ComputeRequiredAllocationSize(const VkImageViewCreateInfo* pCreateInfo); void clear(const VkClearValue& clearValues, const VkRect2D& renderArea); + void clear(const VkClearValue& clearValue, const VkImageAspectFlags aspectMask, const VkClearRect& renderArea); private: bool imageTypesMatch(VkImageType imageType) const; -- 2.11.0