]> git.tdb.fi Git - libs/gl.git/commitdiff
Implement multisample resolve for Vulkan
authorMikko Rasa <tdb@tdb.fi>
Tue, 19 Apr 2022 08:46:11 +0000 (11:46 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 19 Apr 2022 08:46:11 +0000 (11:46 +0300)
source/backends/vulkan/commands_backend.cpp
source/backends/vulkan/framebuffer_backend.cpp
source/backends/vulkan/pipelinecache.cpp
source/backends/vulkan/renderpass.cpp
source/backends/vulkan/vulkan.cpp
source/backends/vulkan/vulkan.h

index 2273d91920e555741f86991c1694e761bc83a877..9f53f1ce56f172a060e91bd3cfb102e5c4613c1e 100644 (file)
@@ -252,7 +252,10 @@ void VulkanCommands::dispatch(unsigned count_x, unsigned count_y, unsigned count
 
 void VulkanCommands::resolve_multisample()
 {
-       throw logic_error("VulkanCommands::resolve_multisample is unimplemented");
+       if(!framebuffer || !framebuffer->has_resolve_attachments())
+               throw invalid_operation("VulkanCommands::resolve_multisample");
+
+       end_render_pass();
 }
 
 void VulkanCommands::begin_query(const QueryPool &, unsigned)
index 5db8c356faff5072d5d612aa94c01a64461070f1..9af8a2f7b1a7a9e52464d6d0027da801bee96700 100644 (file)
@@ -64,8 +64,9 @@ void VulkanFramebuffer::update(unsigned mask) const
        if(handle)
                device.get_destroy_queue().destroy(handle);
 
-       VkImageView vk_attachments[FrameFormat::MAX_ATTACHMENTS] = { };
+       VkImageView vk_attachments[FrameFormat::MAX_ATTACHMENTS*2] = { };
        unsigned i = 0;
+       bool any_resolve = false;
        for(const Framebuffer::Attachment &a: self.attachments)
        {
                bool use_tex_view = (a.tex->view_type==VK_IMAGE_VIEW_TYPE_2D || (a.tex->view_type==VK_IMAGE_VIEW_TYPE_2D_ARRAY && a.layer<0));
@@ -109,6 +110,13 @@ void VulkanFramebuffer::update(unsigned mask) const
                else
                        throw logic_error("unexpected framebuffer configuration");
 
+               if(a.resolve)
+               {
+                       a.resolve->refresh_mip_views();
+                       vk_attachments[self.format.size()+i] = a.resolve->mip_view_handles[0];
+                       any_resolve = true;
+               }
+
                ++i;
        }
 
@@ -119,7 +127,7 @@ void VulkanFramebuffer::update(unsigned mask) const
        VkFramebufferCreateInfo framebuffer_info = { };
        framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
        framebuffer_info.renderPass = handle_cast<::VkRenderPass>(render_pass.handle);
-       framebuffer_info.attachmentCount = self.format.size();
+       framebuffer_info.attachmentCount = self.format.size()*(1+any_resolve);
        framebuffer_info.pAttachments = handle_cast<::VkImageView *>(vk_attachments);
        framebuffer_info.width = self.width;
        framebuffer_info.height = self.height;
@@ -134,7 +142,11 @@ void VulkanFramebuffer::update(unsigned mask) const
 void VulkanFramebuffer::prepare_image_layouts(bool discard) const
 {
        for(const Framebuffer::Attachment &a: static_cast<const Framebuffer *>(this)->attachments)
+       {
                a.tex->change_layout(a.level, get_vulkan_attachment_layout(get_components(a.tex->get_format())), (discard && a.layer<0));
+               if(a.resolve)
+                       a.resolve->change_layout(a.level, get_vulkan_attachment_layout(get_components(a.resolve->get_format())), discard);
+       }
 }
 
 void VulkanFramebuffer::set_debug_name(const string &name)
index 0ec5fcc78fbd12f7e8a2a693ae07fd6bbadf64b5..618ddc9323b68d24678b372648a42ce3ec6530e6 100644 (file)
@@ -34,10 +34,10 @@ VkRenderPass PipelineCache::get_render_pass(const RenderPass &rp)
 
        vector<char> buffer;
        rp.fill_creation_info(buffer);
-       const VkRenderPassCreateInfo *creation_info = reinterpret_cast<const VkRenderPassCreateInfo *>(buffer.data());
+       const VkRenderPassCreateInfo2 *creation_info = reinterpret_cast<const VkRenderPassCreateInfo2 *>(buffer.data());
 
        VkRenderPass render_pass;
-       vk.CreateRenderPass(*creation_info, render_pass);
+       vk.CreateRenderPass2(*creation_info, render_pass);
 
        render_passes.insert(make_pair(key, render_pass));
 
index fb2389e5c8736d9078bba13a18748fb996e65a2d..8459b3a99c37a01b93fe6869b2ee6e116ed22e39 100644 (file)
@@ -20,8 +20,11 @@ void RenderPass::update(Device &device)
 
 uint64_t RenderPass::compute_hash() const
 {
-       bool discard = (!clear_values && discard_fb_contents);
-       uint64_t result = hash<64>(static_cast<uint8_t>(clear | (discard*2) | (to_present*4)));
+       const FrameFormat &format = framebuffer->get_format();
+       bool discard = (clear && !clear_values && discard_fb_contents);
+       bool resolve = framebuffer->has_resolve_attachments();
+       uint64_t result = hash<64>(static_cast<uint8_t>(clear | (discard<<1) | (resolve<<2) | (to_present<<3)));
+       result = hash_round<64>(result, format.get_samples());
        for(FrameAttachment a: framebuffer->get_format())
                result = hash_update<64>(result, a);
 
@@ -32,68 +35,96 @@ void RenderPass::fill_creation_info(vector<char> &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<VkRenderPassCreateInfo>();
-       VkSubpassDescription *const &subpass = sb.add<VkSubpassDescription>();
-       VkAttachmentDescription *const &attachments = sb.add<VkAttachmentDescription>(format.size());
-       VkAttachmentReference *const &color_refs = sb.add<VkAttachmentReference>(color_count);
-       VkAttachmentReference *const &depth_stencil_ref = sb.add<VkAttachmentReference>(has_depth);
-       VkSubpassDependency *const &dependency = sb.add<VkSubpassDependency>(to_present);
-
-       VkSampleCountFlagBits vk_samples = static_cast<VkSampleCountFlagBits>(get_vulkan_samples(format.get_samples()));
-
-       VkAttachmentReference *color_ptr = color_refs;
+       bool resolve = framebuffer->has_resolve_attachments();
+
+       StructureBuilder sb(buffer, 7);
+       VkRenderPassCreateInfo2 *const &render_pass_info = sb.add<VkRenderPassCreateInfo2>();
+       VkSubpassDescription2 *const &subpass = sb.add<VkSubpassDescription2>();
+       VkAttachmentDescription2 *const &attachments = sb.add<VkAttachmentDescription2>(format.size()*(1+resolve));
+       VkAttachmentReference2 *const &color_refs = sb.add<VkAttachmentReference2>(color_count*(1+resolve));
+       VkAttachmentReference2 *const &depth_stencil_ref = sb.add<VkAttachmentReference2>(has_depth*(1+resolve));
+       VkSubpassDescriptionDepthStencilResolve *const &depth_stencil_resolve = sb.add<VkSubpassDescriptionDepthStencilResolve>(has_depth && resolve);
+       VkSubpassDependency2 *const &dependency = sb.add<VkSubpassDependency2>(to_present);
+
+       VkAttachmentReference2 *color_ptr = color_refs;
+       VkAttachmentReference2 *ds_ptr = depth_stencil_ref;
        unsigned i = 0;
-       for(FrameAttachment a: format)
-       {
+       auto fill_attachment = [=, &color_ptr, &ds_ptr, &i](FrameAttachment a, VkSampleCountFlagBits samples, bool discard){
                VkImageLayout subpass_layout = static_cast<VkImageLayout>(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].sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
                attachments[i].format = static_cast<VkFormat>(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].samples = samples;
+               attachments[i].loadOp = (discard ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : clear ? 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].initialLayout = (discard ? VK_IMAGE_LAYOUT_UNDEFINED : external_layout);
                attachments[i].finalLayout = external_layout;
 
                if(subpass_layout==VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
                {
+                       color_ptr->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
                        color_ptr->attachment = i;
                        color_ptr->layout = subpass_layout;
                        ++color_ptr;
                }
                else
                {
-                       depth_stencil_ref->attachment = i;
-                       depth_stencil_ref->layout = subpass_layout;
+                       ds_ptr->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
+                       ds_ptr->attachment = i;
+                       ds_ptr->layout = subpass_layout;
                }
 
                ++i;
+       };
+
+       bool discard = (clear && !clear_values && discard_fb_contents);
+       VkSampleCountFlagBits vk_samples = static_cast<VkSampleCountFlagBits>(get_vulkan_samples(format.get_samples()));
+       for(FrameAttachment a: format)
+               fill_attachment(a, vk_samples, discard);
+
+       if(resolve)
+       {
+               ++ds_ptr;
+               for(FrameAttachment a: format)
+                       fill_attachment(a, VK_SAMPLE_COUNT_1_BIT, true);
        }
 
+       subpass->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
        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;
+       if(resolve)
+       {
+               subpass->pResolveAttachments = color_refs+color_count;
+
+               if(has_depth)
+               {
+                       depth_stencil_resolve->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
+                       depth_stencil_resolve->depthResolveMode = VK_RESOLVE_MODE_MIN_BIT;
+                       depth_stencil_resolve->pDepthStencilResolveAttachment = depth_stencil_ref+1;
+                       subpass->pNext = depth_stencil_resolve;
+               }
+       }
 
-       render_pass_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
-       render_pass_info->attachmentCount = format.size();
+       render_pass_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2;
+       render_pass_info->attachmentCount = format.size()*(1+resolve);
        render_pass_info->pAttachments = attachments;
        render_pass_info->subpassCount = 1;
        render_pass_info->pSubpasses = subpass;
 
        if(to_present)
        {
+               dependency->sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2;
                dependency->srcSubpass = 0;
                dependency->dstSubpass = VK_SUBPASS_EXTERNAL;
                dependency->srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
index 31349e8fad7a76e60af472e14835bb1bcd526f56..c7823ae544cbf5782dcfe5d5a3157c60784a4b97 100644 (file)
@@ -32,6 +32,7 @@ VulkanFunctions::VulkanFunctions(const Graphics::VulkanContext &c):
        vkQueueWaitIdle(context.get_function<PFN_vkQueueWaitIdle>("vkQueueWaitIdle")),
        // 8
        vkCreateRenderPass(context.get_function<PFN_vkCreateRenderPass>("vkCreateRenderPass")),
+       vkCreateRenderPass2(context.get_function<PFN_vkCreateRenderPass2>("vkCreateRenderPass2")),
        vkDestroyRenderPass(context.get_function<PFN_vkDestroyRenderPass>("vkDestroyRenderPass")),
        vkCreateFramebuffer(context.get_function<PFN_vkCreateFramebuffer>("vkCreateFramebuffer")),
        vkDestroyFramebuffer(context.get_function<PFN_vkDestroyFramebuffer>("vkDestroyFramebuffer")),
index 2b42550c24657ad2b493c8497f99ee22f6d83d76..6c3726f6024c32c289c991d0686105b657d469c7 100644 (file)
@@ -117,6 +117,7 @@ private:
        PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier = 0;  // 7.6
        PFN_vkQueueWaitIdle vkQueueWaitIdle = 0;  // 7.8
        PFN_vkCreateRenderPass vkCreateRenderPass = 0;  // 8.1
+       PFN_vkCreateRenderPass2 vkCreateRenderPass2 = 0;  // 8.1
        PFN_vkDestroyRenderPass vkDestroyRenderPass = 0;  // 8.1
        PFN_vkCreateFramebuffer vkCreateFramebuffer = 0;  // 8.3
        PFN_vkDestroyFramebuffer vkDestroyFramebuffer = 0;  // 8.3
@@ -239,6 +240,9 @@ public:
        Result CreateRenderPass(const VkRenderPassCreateInfo &rCreateInfo, VkRenderPass &rRenderPass) const
        { return { vkCreateRenderPass(device, &rCreateInfo, 0, handle_cast<::VkRenderPass *>(&rRenderPass)), "vkCreateRenderPass" }; }
 
+       Result CreateRenderPass2(const VkRenderPassCreateInfo2 &rCreateInfo, VkRenderPass &rRenderPass) const
+       { return { vkCreateRenderPass2(device, &rCreateInfo, 0, handle_cast<::VkRenderPass *>(&rRenderPass)), "vkCreateRenderPass2" }; }
+
        void DestroyRenderPass(VkRenderPass renderPass) const
        { vkDestroyRenderPass(device, handle_cast<::VkRenderPass>(renderPass), 0); }