From d841d557eec57575adc856a8b081042861dab9e8 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 22 Mar 2022 09:53:09 +0200 Subject: [PATCH] Refactor render pass operations into a helper struct --- source/backends/vulkan/commands_backend.cpp | 54 ++----- source/backends/vulkan/pipelinecache.cpp | 87 ++-------- source/backends/vulkan/pipelinecache.h | 4 +- .../backends/vulkan/pipelinestate_backend.cpp | 7 +- source/backends/vulkan/renderpass.cpp | 151 ++++++++++++++++++ source/backends/vulkan/renderpass.h | 35 ++++ 6 files changed, 215 insertions(+), 123 deletions(-) create mode 100644 source/backends/vulkan/renderpass.cpp create mode 100644 source/backends/vulkan/renderpass.h diff --git a/source/backends/vulkan/commands_backend.cpp b/source/backends/vulkan/commands_backend.cpp index 777d1a6b..ff9e6cf6 100644 --- a/source/backends/vulkan/commands_backend.cpp +++ b/source/backends/vulkan/commands_backend.cpp @@ -8,8 +8,8 @@ #include "frameformat.h" #include "pipelinestate.h" #include "rect.h" +#include "renderpass.h" #include "semaphore.h" -#include "structurebuilder.h" #include "swapchaintexture.h" #include "vulkan.h" @@ -98,52 +98,20 @@ void VulkanCommands::begin_render_pass(bool clear, const ClearValue *clear_value if(dynamic_cast(framebuffer->get_attachment(i))) fb_is_swapchain = true; - Rect fb_rect = framebuffer->get_rect(); - Rect render_area = fb_rect.intersect(viewport); - bool full_viewport = render_area==fb_rect; - discard_fb_contents = (clear && full_viewport); - framebuffer->refresh(); - VkRenderPass render_pass = device.get_pipeline_cache().get_render_pass(framebuffer->get_format(), - clear, (!clear_values && full_viewport), fb_is_swapchain); - begin_buffer(render_pass); - - StructureBuilder sb(pass_begin_info, 2); - VkRenderPassBeginInfo *const &begin_info = sb.add(1); - VkClearValue *const &vk_clear_values = sb.add(FrameFormat::MAX_ATTACHMENTS); - - begin_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - begin_info->renderPass = handle_cast<::VkRenderPass>(render_pass); - begin_info->framebuffer = handle_cast<::VkFramebuffer>(framebuffer->handle); + RenderPass render_pass; + render_pass.framebuffer = framebuffer; + render_pass.render_area = viewport; + render_pass.clear = clear; + render_pass.clear_values = clear_values; + render_pass.to_present = fb_is_swapchain; + render_pass.update(device); - begin_info->renderArea.offset.x = render_area.left; - begin_info->renderArea.offset.y = render_area.bottom; - begin_info->renderArea.extent.width = render_area.width; - begin_info->renderArea.extent.height = render_area.height; + discard_fb_contents = render_pass.discard_fb_contents; - if(clear_values) - { - unsigned i = 0; - for(FrameAttachment a: framebuffer->get_format()) - { - if(get_attach_point(a)==get_attach_point(DEPTH_ATTACHMENT)) - vk_clear_values[i].depthStencil.depth = clear_values[i].depth_stencil.depth; - else if(get_attach_point(a)==get_attach_point(STENCIL_ATTACHMENT)) - vk_clear_values[i].depthStencil.stencil = clear_values[i].depth_stencil.stencil; - else - { - vk_clear_values[i].color.float32[0] = clear_values[i].color.r; - vk_clear_values[i].color.float32[1] = clear_values[i].color.g; - vk_clear_values[i].color.float32[2] = clear_values[i].color.b; - vk_clear_values[i].color.float32[3] = clear_values[i].color.a; - } - ++i; - } - - begin_info->clearValueCount = framebuffer->get_format().size(); - begin_info->pClearValues = vk_clear_values; - } + begin_buffer(render_pass.handle); + render_pass.fill_begin_info(pass_begin_info); } void VulkanCommands::end_render_pass() diff --git a/source/backends/vulkan/pipelinecache.cpp b/source/backends/vulkan/pipelinecache.cpp index 646d7932..951d33f3 100644 --- a/source/backends/vulkan/pipelinecache.cpp +++ b/source/backends/vulkan/pipelinecache.cpp @@ -1,8 +1,7 @@ -#include #include "device.h" -#include "framebuffer.h" #include "pipelinecache.h" #include "pipelinestate.h" +#include "renderpass.h" #include "vulkan.h" using namespace std; @@ -24,85 +23,21 @@ PipelineCache::~PipelineCache() vk.DestroyPipeline(kvp.second); } -VkRenderPass PipelineCache::get_render_pass(const FrameFormat &format, bool clear, bool discard, bool to_present) +VkRenderPass PipelineCache::get_render_pass(const RenderPass &rp) { + uint64_t key = rp.compute_hash(); + auto i = render_passes.find(key); + if(i!=render_passes.end()) + return i->second; + const VulkanFunctions &vk = device.get_functions(); - uint64_t key = hash<64>(static_cast(clear | (discard*2) | (to_present*4))); - for(FrameAttachment a: format) - key = hash_update<64>(key, a); - - auto j = render_passes.find(key); - if(j!=render_passes.end()) - return j->second; - - VkAttachmentDescription attachments[FrameFormat::MAX_ATTACHMENTS] = { }; - VkAttachmentReference color_refs[FrameFormat::MAX_ATTACHMENTS] = { }; - VkAttachmentReference depth_stencil_ref = { }; - depth_stencil_ref.attachment = VK_ATTACHMENT_UNUSED; - - VkSampleCountFlagBits vk_samples = static_cast(get_vulkan_samples(format.get_samples())); - - unsigned i = 0; - unsigned color_count = 0; - for(FrameAttachment a: format) - { - VkImageLayout subpass_layout = static_cast(get_vulkan_attachment_layout(get_components(get_attachment_pixelformat(a)))); - VkImageLayout external_layout = (to_present ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : subpass_layout); - - attachments[i].format = static_cast(get_vulkan_pixelformat(get_attachment_pixelformat(a))); - attachments[i].samples = vk_samples; - attachments[i].loadOp = (clear ? discard ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD); - attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[i].initialLayout = ((clear && discard) ? VK_IMAGE_LAYOUT_UNDEFINED : external_layout); - attachments[i].finalLayout = external_layout; - - if(subpass_layout==VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) - { - color_refs[color_count].attachment = i; - color_refs[color_count].layout = subpass_layout; - ++color_count; - } - else - { - depth_stencil_ref.attachment = i; - depth_stencil_ref.layout = subpass_layout; - } - - ++i; - } - - VkSubpassDescription subpass = { }; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = color_count; - subpass.pColorAttachments = color_refs; - subpass.pDepthStencilAttachment = &depth_stencil_ref; - - VkSubpassDependency dependency = { }; - VkRenderPassCreateInfo render_pass_info = { }; - render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - render_pass_info.attachmentCount = format.size(); - render_pass_info.pAttachments = attachments; - render_pass_info.subpassCount = 1; - render_pass_info.pSubpasses = &subpass; - - if(to_present) - { - dependency.srcSubpass = 0; - dependency.dstSubpass = VK_SUBPASS_EXTERNAL; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; - dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependency.dstAccessMask = 0; - - render_pass_info.dependencyCount = 1; - render_pass_info.pDependencies = &dependency; - } + vector buffer; + rp.fill_creation_info(buffer); + const VkRenderPassCreateInfo *creation_info = reinterpret_cast(buffer.data()); VkRenderPass render_pass; - vk.CreateRenderPass(render_pass_info, render_pass); + vk.CreateRenderPass(*creation_info, render_pass); render_passes.insert(make_pair(key, render_pass)); diff --git a/source/backends/vulkan/pipelinecache.h b/source/backends/vulkan/pipelinecache.h index 5023b40c..2f325119 100644 --- a/source/backends/vulkan/pipelinecache.h +++ b/source/backends/vulkan/pipelinecache.h @@ -3,7 +3,6 @@ #include #include -#include "frameformat.h" #include "handles.h" namespace Msp { @@ -11,6 +10,7 @@ namespace GL { class Device; class PipelineState; +struct RenderPass; class PipelineCache { @@ -24,7 +24,7 @@ public: PipelineCache(PipelineCache &&); ~PipelineCache(); - VkRenderPass get_render_pass(const FrameFormat &, bool, bool, bool); + VkRenderPass get_render_pass(const RenderPass &); VkPipeline get_pipeline(const PipelineState &); }; diff --git a/source/backends/vulkan/pipelinestate_backend.cpp b/source/backends/vulkan/pipelinestate_backend.cpp index 87e03242..b7e50873 100644 --- a/source/backends/vulkan/pipelinestate_backend.cpp +++ b/source/backends/vulkan/pipelinestate_backend.cpp @@ -10,6 +10,7 @@ #include "pipelinestate_backend.h" #include "program.h" #include "rect.h" +#include "renderpass.h" #include "sampler.h" #include "stenciltest.h" #include "structurebuilder.h" @@ -149,7 +150,9 @@ void VulkanPipelineState::fill_creation_info(vector &buffer) const const PipelineState &self = *static_cast(this); const FrameFormat &format = self.framebuffer->get_format(); - VkRenderPass render_pass = device.get_pipeline_cache().get_render_pass(format, false, false, false); + RenderPass render_pass; + render_pass.framebuffer = self.framebuffer; + render_pass.update(device); unsigned n_color_attachments = 0; for(FrameAttachment a: format) @@ -253,7 +256,7 @@ void VulkanPipelineState::fill_creation_info(vector &buffer) const pipeline_info->pDepthStencilState = depth_stencil_info; pipeline_info->pColorBlendState = blend_info; pipeline_info->pDynamicState = dynamic_info; - pipeline_info->renderPass = handle_cast<::VkRenderPass>(render_pass); + pipeline_info->renderPass = handle_cast<::VkRenderPass>(render_pass.handle); pipeline_info->subpass = 0; if(self.shprog) diff --git a/source/backends/vulkan/renderpass.cpp b/source/backends/vulkan/renderpass.cpp new file mode 100644 index 00000000..fb2389e5 --- /dev/null +++ b/source/backends/vulkan/renderpass.cpp @@ -0,0 +1,151 @@ +#include +#include "device.h" +#include "framebuffer.h" +#include "renderpass.h" +#include "structurebuilder.h" +#include "vulkan.h" + +using namespace std; + +namespace Msp { +namespace GL { + +void RenderPass::update(Device &device) +{ + Rect fb_rect = framebuffer->get_rect(); + render_area = fb_rect.intersect(render_area); + discard_fb_contents = (clear && render_area==fb_rect); + handle = device.get_pipeline_cache().get_render_pass(*this); +} + +uint64_t RenderPass::compute_hash() const +{ + bool discard = (!clear_values && discard_fb_contents); + uint64_t result = hash<64>(static_cast(clear | (discard*2) | (to_present*4))); + for(FrameAttachment a: framebuffer->get_format()) + result = hash_update<64>(result, a); + + return result; +} + +void RenderPass::fill_creation_info(vector &buffer) const +{ + const FrameFormat &format = framebuffer->get_format(); + + bool discard = (!clear_values && discard_fb_contents); + bool has_depth = any_of(format.begin(), format.end(), [](FrameAttachment a){ + return get_components(get_attachment_pixelformat(a))==DEPTH_COMPONENT; + }); + unsigned color_count = format.size()-has_depth; + + StructureBuilder sb(buffer, 6); + VkRenderPassCreateInfo *const &render_pass_info = sb.add(); + VkSubpassDescription *const &subpass = sb.add(); + VkAttachmentDescription *const &attachments = sb.add(format.size()); + VkAttachmentReference *const &color_refs = sb.add(color_count); + VkAttachmentReference *const &depth_stencil_ref = sb.add(has_depth); + VkSubpassDependency *const &dependency = sb.add(to_present); + + VkSampleCountFlagBits vk_samples = static_cast(get_vulkan_samples(format.get_samples())); + + VkAttachmentReference *color_ptr = color_refs; + unsigned i = 0; + for(FrameAttachment a: format) + { + VkImageLayout subpass_layout = static_cast(get_vulkan_attachment_layout(get_components(get_attachment_pixelformat(a)))); + VkImageLayout external_layout = (to_present ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : subpass_layout); + + attachments[i].format = static_cast(get_vulkan_pixelformat(get_attachment_pixelformat(a))); + attachments[i].samples = vk_samples; + attachments[i].loadOp = (clear ? discard ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD); + attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[i].initialLayout = ((clear && discard) ? VK_IMAGE_LAYOUT_UNDEFINED : external_layout); + attachments[i].finalLayout = external_layout; + + if(subpass_layout==VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + { + color_ptr->attachment = i; + color_ptr->layout = subpass_layout; + ++color_ptr; + } + else + { + depth_stencil_ref->attachment = i; + depth_stencil_ref->layout = subpass_layout; + } + + ++i; + } + + subpass->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass->colorAttachmentCount = color_count; + if(color_count) + subpass->pColorAttachments = color_refs; + if(has_depth) + subpass->pDepthStencilAttachment = depth_stencil_ref; + + render_pass_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_info->attachmentCount = format.size(); + render_pass_info->pAttachments = attachments; + render_pass_info->subpassCount = 1; + render_pass_info->pSubpasses = subpass; + + if(to_present) + { + dependency->srcSubpass = 0; + dependency->dstSubpass = VK_SUBPASS_EXTERNAL; + dependency->srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency->srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; + dependency->dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependency->dstAccessMask = 0; + + render_pass_info->dependencyCount = 1; + render_pass_info->pDependencies = dependency; + } +} + +void RenderPass::fill_begin_info(vector &buffer) const +{ + const FrameFormat &format = framebuffer->get_format(); + + StructureBuilder sb(buffer, 2); + VkRenderPassBeginInfo *const &begin_info = sb.add(1); + VkClearValue *const &vk_clear_values = sb.add(format.size()); + + begin_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + begin_info->renderPass = handle_cast<::VkRenderPass>(handle); + begin_info->framebuffer = handle_cast<::VkFramebuffer>(framebuffer->handle); + + begin_info->renderArea.offset.x = render_area.left; + begin_info->renderArea.offset.y = render_area.bottom; + begin_info->renderArea.extent.width = render_area.width; + begin_info->renderArea.extent.height = render_area.height; + + if(clear_values) + { + unsigned i = 0; + for(FrameAttachment a: format) + { + if(get_attach_point(a)==get_attach_point(DEPTH_ATTACHMENT)) + vk_clear_values[i].depthStencil.depth = clear_values[i].depth_stencil.depth; + else if(get_attach_point(a)==get_attach_point(STENCIL_ATTACHMENT)) + vk_clear_values[i].depthStencil.stencil = clear_values[i].depth_stencil.stencil; + else + { + vk_clear_values[i].color.float32[0] = clear_values[i].color.r; + vk_clear_values[i].color.float32[1] = clear_values[i].color.g; + vk_clear_values[i].color.float32[2] = clear_values[i].color.b; + vk_clear_values[i].color.float32[3] = clear_values[i].color.a; + } + ++i; + } + + begin_info->clearValueCount = format.size(); + begin_info->pClearValues = vk_clear_values; + } +} + +} // namespace GL +} // namespace Msp diff --git a/source/backends/vulkan/renderpass.h b/source/backends/vulkan/renderpass.h new file mode 100644 index 00000000..e59dc164 --- /dev/null +++ b/source/backends/vulkan/renderpass.h @@ -0,0 +1,35 @@ +#ifndef MSP_GL_RENDERPASS_H_ +#define MSP_GL_RENDERPASS_H_ + +#include +#include "handles.h" + +namespace Msp { +namespace GL { + +class Device; +class Framebuffer; +union ClearValue; + +struct RenderPass +{ + const Framebuffer *framebuffer = 0; + Rect render_area; + bool clear = false; + const ClearValue *clear_values = 0; + bool to_present = false; + bool discard_fb_contents = false; + VkRenderPass handle = 0; + + void update(Device &); + + std::uint64_t compute_hash() const; + bool discards_framebuffer_contents() const; + void fill_creation_info(std::vector &) const; + void fill_begin_info(std::vector &) const; +}; + +} // namespace GL +} // namespace Msp + +#endif -- 2.45.2