From 3e2ff91654ce06bfe3c68273a18917d543b89ce3 Mon Sep 17 00:00:00 2001 From: Benau Date: Mon, 21 Mar 2022 11:54:28 +0800 Subject: [PATCH] Add dynamic scissor support --- .../include/ge_vulkan_driver.hpp | 10 +- .../src/ge_vulkan_2d_renderer.cpp | 118 ++++++++++++------ lib/graphics_engine/src/ge_vulkan_driver.cpp | 13 ++ 3 files changed, 101 insertions(+), 40 deletions(-) diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index b8d3665dc..64f35a846 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -267,8 +267,12 @@ namespace GE //! Returns the maximum texture size supported. virtual core::dimension2du getMaxTextureSize() const { return core::dimension2du(16384, 16384); } - virtual void enableScissorTest(const core::rect& r) {} - virtual void disableScissorTest() {} + virtual void enableScissorTest(const core::rect& r) { m_clip = r; } + core::rect getFullscreenClip() const + { + return core::rect(0, 0, ScreenSize.Width, ScreenSize.Height); + } + virtual void disableScissorTest() { m_clip = getFullscreenClip(); } virtual const core::dimension2d& getCurrentRenderTargetSize() const { return ScreenSize; } VkSampler getSampler(GEVulkanSampler s) const { @@ -306,6 +310,7 @@ namespace GE unsigned int getCurrentImageIndex() const { return m_image_index; } constexpr static unsigned getMaxFrameInFlight() { return 2; } video::SColor getClearColor() const { return m_clear_color; } + const core::rect& getCurrentClip() const { return m_clip; } private: struct SwapChainSupportDetails { @@ -419,6 +424,7 @@ namespace GE unsigned int m_current_frame; uint32_t m_image_index; video::SColor m_clear_color; + core::rect m_clip; void createInstance(SDL_Window* window); void findPhysicalDevice(); diff --git a/lib/graphics_engine/src/ge_vulkan_2d_renderer.cpp b/lib/graphics_engine/src/ge_vulkan_2d_renderer.cpp index 213d54b0c..7c8fe8953 100644 --- a/lib/graphics_engine/src/ge_vulkan_2d_renderer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_2d_renderer.cpp @@ -13,6 +13,7 @@ #include #include +#include "rect.h" #include "vector2d.h" #include "SColor.h" @@ -46,6 +47,7 @@ struct Tri }; std::map g_tex_map; +std::vector g_tris_clip; std::vector g_tris_queue; std::vector g_tris_index_queue; } // GEVulkan2dRenderer @@ -242,6 +244,12 @@ void GEVulkan2dRenderer::createGraphicsPipeline() color_blending.blendConstants[2] = 0.0f; color_blending.blendConstants[3] = 0.0f; + VkDynamicState dynamic_state = VK_DYNAMIC_STATE_SCISSOR; + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + dynamic_state_info.dynamicStateCount = 1, + dynamic_state_info.pDynamicStates = &dynamic_state; + VkGraphicsPipelineCreateInfo pipeline_info = {}; pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_info.stageCount = 2; @@ -253,6 +261,7 @@ void GEVulkan2dRenderer::createGraphicsPipeline() pipeline_info.pMultisampleState = &multisampling; pipeline_info.pDepthStencilState = &depth_stencil; pipeline_info.pColorBlendState = &color_blending; + pipeline_info.pDynamicState = &dynamic_state_info; pipeline_info.layout = g_pipeline_layout; pipeline_info.renderPass = g_vk->getRenderPass(); pipeline_info.subpass = 0; @@ -420,6 +429,10 @@ void GEVulkan2dRenderer::render() VkDeviceSize offsets[] = {0}; VkBuffer vertex_buffer = VK_NULL_HANDLE; VkBuffer indices_buffer = VK_NULL_HANDLE; + unsigned idx = 0; + unsigned idx_count = 0; + int sampler_idx = 0; + core::recti clip; VkResult result = vkBeginCommandBuffer(g_vk->getCurrentCommandBuffer(), &begin_info); @@ -456,49 +469,61 @@ void GEVulkan2dRenderer::render() &g_descriptor_sets[g_vk->getCurrentFrame()], 0, NULL); } - if (GEVulkanFeatures::supportsDifferentTexturePerDraw()) + sampler_idx = g_tris_queue[0].sampler_idx; + clip = g_tris_clip[0]; + for (; idx < g_tris_index_queue.size(); idx += 3) { - vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(), - (uint32_t)(g_tris_index_queue.size()), 1, 0, 0, 0); + Tri& cur_tri = g_tris_queue[g_tris_index_queue[idx]]; + int cur_sampler_idx = cur_tri.sampler_idx; + if (GEVulkanFeatures::supportsDifferentTexturePerDraw()) + cur_sampler_idx = g_tris_queue[0].sampler_idx; + const core::recti& cur_clip = g_tris_clip[g_tris_index_queue[idx]]; + if (cur_sampler_idx != sampler_idx || cur_clip != clip) + { + if (!GEVulkanFeatures::supportsBindTexturesAtOnce()) + { + const unsigned set_idx = g_vk->getCurrentFrame() * GEVulkanShaderManager::getSamplerSize() + sampler_idx; + vkCmdBindDescriptorSets(g_vk->getCurrentCommandBuffer(), + VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline_layout, 0, 1, + &g_descriptor_sets[set_idx], 0, NULL); + } + + VkRect2D scissor; + scissor.offset.x = clip.UpperLeftCorner.X; + scissor.offset.y = clip.UpperLeftCorner.Y; + scissor.extent.width = clip.getWidth(); + scissor.extent.height = clip.getHeight(); + vkCmdSetScissor(g_vk->getCurrentCommandBuffer(), 0, 1, &scissor); + + vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(), idx_count, 1, + idx - idx_count, 0, 0); + sampler_idx = cur_sampler_idx; + clip = cur_clip; + idx_count = 3; + } + else + { + idx_count += 3; + } } - else + if (!GEVulkanFeatures::supportsBindTexturesAtOnce()) { - unsigned idx = 0; - unsigned idx_count = 0; - int sampler_idx = g_tris_queue[0].sampler_idx; - for (; idx < g_tris_index_queue.size(); idx += 3) - { - Tri& cur_tri = g_tris_queue[g_tris_index_queue[idx]]; - if (cur_tri.sampler_idx != sampler_idx) - { - if (!GEVulkanFeatures::supportsBindTexturesAtOnce()) - { - const unsigned set_idx = g_vk->getCurrentFrame() * GEVulkanShaderManager::getSamplerSize() + sampler_idx; - vkCmdBindDescriptorSets(g_vk->getCurrentCommandBuffer(), - VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline_layout, 0, 1, - &g_descriptor_sets[set_idx], 0, NULL); - } - vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(), idx_count, 1, - idx - idx_count, 0, 0); - sampler_idx = cur_tri.sampler_idx; - idx_count = 3; - } - else - { - idx_count += 3; - } - } - if (!GEVulkanFeatures::supportsBindTexturesAtOnce()) - { - const unsigned set_idx = g_vk->getCurrentFrame() * GEVulkanShaderManager::getSamplerSize() + sampler_idx; - vkCmdBindDescriptorSets(g_vk->getCurrentCommandBuffer(), - VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline_layout, 0, 1, - &g_descriptor_sets[set_idx], 0, NULL); - } - vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(), idx_count, 1, - idx - idx_count, 0, 0); + const unsigned set_idx = g_vk->getCurrentFrame() * GEVulkanShaderManager::getSamplerSize() + sampler_idx; + vkCmdBindDescriptorSets(g_vk->getCurrentCommandBuffer(), + VK_PIPELINE_BIND_POINT_GRAPHICS, g_pipeline_layout, 0, 1, + &g_descriptor_sets[set_idx], 0, NULL); } + VkRect2D scissor; + scissor.offset.x = clip.UpperLeftCorner.X; + scissor.offset.y = clip.UpperLeftCorner.Y; + scissor.extent.width = clip.getWidth(); + scissor.extent.height = clip.getHeight(); + vkCmdSetScissor(g_vk->getCurrentCommandBuffer(), 0, 1, &scissor); + + vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(), idx_count, 1, + idx - idx_count, 0, 0); + end_cmd: vkCmdEndRenderPass(g_vk->getCurrentCommandBuffer()); vkEndCommandBuffer(g_vk->getCurrentCommandBuffer()); @@ -507,6 +532,7 @@ end: g_tex_map.clear(); g_tris_queue.clear(); g_tris_index_queue.clear(); + g_tris_clip.clear(); } // render // ---------------------------------------------------------------------------- @@ -541,12 +567,28 @@ void GEVulkan2dRenderer::addVerticesIndices(irr::video::S3DVertex* vertices, t.uv = vertex.TCoords; t.sampler_idx = sampler_idx; g_tris_queue.push_back(t); + g_tris_clip.push_back(g_vk->getCurrentClip()); } + const core::recti& fclip = g_vk->getFullscreenClip(); for (unsigned idx = 0; idx < indices_count * 3; idx += 3) { g_tris_index_queue.push_back(last_index + indices[idx]); g_tris_index_queue.push_back(last_index + indices[idx + 1]); g_tris_index_queue.push_back(last_index + indices[idx + 2]); + const core::recti& cur_clip = g_tris_clip[last_index + indices[idx]]; + const core::vector3df& pos_1 = vertices[indices[idx]].Pos; + const core::vector3df& pos_2 = vertices[indices[idx + 1]].Pos; + const core::vector3df& pos_3 = vertices[indices[idx + 2]].Pos; + if (GEVulkanFeatures::supportsDifferentTexturePerDraw() && + fclip != cur_clip && + cur_clip.isPointInside(core::position2di(pos_1.X, pos_1.Y)) && + cur_clip.isPointInside(core::position2di(pos_2.X, pos_2.Y)) && + cur_clip.isPointInside(core::position2di(pos_3.X, pos_3.Y))) + { + g_tris_clip[last_index + indices[idx]] = fclip; + g_tris_clip[last_index + indices[idx + 1]] = fclip; + g_tris_clip[last_index + indices[idx + 2]] = fclip; + } } } // addVerticesIndices diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index b29155af9..6ef184a83 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -960,6 +960,7 @@ found_mode: m_swap_chain_extent = image_extent; ScreenSize.Width = m_swap_chain_extent.width; ScreenSize.Height = m_swap_chain_extent.height; + m_clip = getFullscreenClip(); for (unsigned int i = 0; i < m_vk->swap_chain_images.size(); i++) { @@ -1504,7 +1505,11 @@ void GEVulkanDriver::draw2DImage(const video::ITexture* tex, u16 indices[6] = {0,1,2,0,2,3}; + if (clipRect) + enableScissorTest(*clipRect); GEVulkan2dRenderer::addVerticesIndices(&vtx[0], 4, &indices[0], 2, texture); + if (clipRect) + disableScissorTest(); } // draw2DImage // ---------------------------------------------------------------------------- @@ -1554,7 +1559,11 @@ void GEVulkanDriver::draw2DImage(const video::ITexture* tex, u16 indices[6] = {0,1,2,0,2,3}; + if (clipRect) + enableScissorTest(*clipRect); GEVulkan2dRenderer::addVerticesIndices(&vtx[0], 4, &indices[0], 2, texture); + if (clipRect) + disableScissorTest(); } // draw2DImage // ---------------------------------------------------------------------------- @@ -1691,8 +1700,12 @@ void GEVulkanDriver::draw2DImageBatch(const video::ITexture* tex, if (vtx.size()) { + if (clipRect) + enableScissorTest(*clipRect); GEVulkan2dRenderer::addVerticesIndices(vtx.pointer(), vtx.size(), indices.pointer(), indices.size() / 3, texture); + if (clipRect) + disableScissorTest(); } } // draw2DImageBatch