summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/StateTracker.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2016-09-11 16:37:41 +1000
committerStenzek <stenzek@gmail.com>2016-10-01 02:40:02 +1000
commitf6cdc38c8b05e1980c42e6a8fa2d8207feb9604d (patch)
tree7cb2513ffa335ef3a9274154dfd40c351a862fdd /Source/Core/VideoBackends/Vulkan/StateTracker.cpp
parentc290398320a621c97ec693775e51255ac9b50c15 (diff)
Vulkan: Use render-pass based clears where possible
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/StateTracker.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/StateTracker.cpp90
1 files changed, 75 insertions, 15 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp
index 2bb17a78dc..a1c4e5fb25 100644
--- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp
+++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp
@@ -111,24 +111,28 @@ void StateTracker::SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexT
m_dirty_flags |= DIRTY_FLAG_INDEX_BUFFER;
}
-void StateTracker::SetRenderPass(VkRenderPass render_pass)
+void StateTracker::SetRenderPass(VkRenderPass load_render_pass, VkRenderPass clear_render_pass)
{
// Should not be changed within a render pass.
- assert(!m_in_render_pass);
+ _assert_(!InRenderPass());
- if (m_pipeline_state.render_pass == render_pass)
- return;
+ // The clear and load render passes are compatible, so we don't need to change our pipeline.
+ if (m_pipeline_state.render_pass != load_render_pass)
+ {
+ m_pipeline_state.render_pass = load_render_pass;
+ m_dirty_flags |= DIRTY_FLAG_PIPELINE;
+ }
- m_pipeline_state.render_pass = render_pass;
- m_dirty_flags |= DIRTY_FLAG_PIPELINE;
+ m_load_render_pass = load_render_pass;
+ m_clear_render_pass = clear_render_pass;
}
void StateTracker::SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area)
{
// Should not be changed within a render pass.
- assert(!m_in_render_pass);
+ _assert_(!InRenderPass());
m_framebuffer = framebuffer;
- m_framebuffer_render_area = render_area;
+ m_framebuffer_size = render_area;
}
void StateTracker::SetVertexFormat(const VertexFormat* vertex_format)
@@ -508,12 +512,15 @@ void StateTracker::SetPendingRebind()
void StateTracker::BeginRenderPass()
{
- if (m_in_render_pass)
+ if (InRenderPass())
return;
+ m_current_render_pass = m_load_render_pass;
+ m_framebuffer_render_area = m_framebuffer_size;
+
VkRenderPassBeginInfo begin_info = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
nullptr,
- m_pipeline_state.render_pass,
+ m_current_render_pass,
m_framebuffer,
m_framebuffer_render_area,
0,
@@ -521,17 +528,34 @@ void StateTracker::BeginRenderPass()
vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &begin_info,
VK_SUBPASS_CONTENTS_INLINE);
-
- m_in_render_pass = true;
}
void StateTracker::EndRenderPass()
{
- if (!m_in_render_pass)
+ if (!InRenderPass())
return;
vkCmdEndRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer());
- m_in_render_pass = false;
+ m_current_render_pass = nullptr;
+}
+
+void StateTracker::BeginClearRenderPass(const VkRect2D& area, const VkClearValue clear_values[2])
+{
+ _assert_(!InRenderPass());
+
+ m_current_render_pass = m_clear_render_pass;
+ m_framebuffer_render_area = area;
+
+ VkRenderPassBeginInfo begin_info = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+ nullptr,
+ m_current_render_pass,
+ m_framebuffer,
+ m_framebuffer_render_area,
+ 2,
+ clear_values};
+
+ vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &begin_info,
+ VK_SUBPASS_CONTENTS_INLINE);
}
void StateTracker::SetViewport(const VkViewport& viewport)
@@ -554,6 +578,10 @@ void StateTracker::SetScissor(const VkRect2D& scissor)
bool StateTracker::Bind(bool rebind_all /*= false*/)
{
+ // Check the render area if we were in a clear pass.
+ if (m_current_render_pass == m_clear_render_pass && !IsViewportWithinRenderArea())
+ EndRenderPass();
+
// Get new pipeline object if any parts have changed
if (m_dirty_flags & DIRTY_FLAG_PIPELINE && !UpdatePipeline())
{
@@ -580,7 +608,7 @@ bool StateTracker::Bind(bool rebind_all /*= false*/)
}
// Start render pass if not already started
- if (!m_in_render_pass)
+ if (!InRenderPass())
BeginRenderPass();
// Re-bind parts of the pipeline
@@ -707,6 +735,38 @@ void StateTracker::SetBackgroundCommandBufferExecution(bool enabled)
m_allow_background_execution = enabled;
}
+bool StateTracker::IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const
+{
+ // Check that the viewport does not lie outside the render area.
+ // If it does, we need to switch to a normal load/store render pass.
+ s32 left = m_framebuffer_render_area.offset.x;
+ s32 top = m_framebuffer_render_area.offset.y;
+ s32 right = left + static_cast<s32>(m_framebuffer_render_area.extent.width);
+ s32 bottom = top + static_cast<s32>(m_framebuffer_render_area.extent.height);
+ s32 test_left = x;
+ s32 test_top = y;
+ s32 test_right = test_left + static_cast<s32>(width);
+ s32 test_bottom = test_top + static_cast<s32>(height);
+ return test_left >= left && test_right <= right && test_top >= top && test_bottom <= bottom;
+}
+
+bool StateTracker::IsViewportWithinRenderArea() const
+{
+ return IsWithinRenderArea(static_cast<s32>(m_viewport.x), static_cast<s32>(m_viewport.y),
+ static_cast<u32>(m_viewport.width),
+ static_cast<u32>(m_viewport.height));
+}
+
+void StateTracker::EndClearRenderPass()
+{
+ if (m_current_render_pass != m_clear_render_pass)
+ return;
+
+ // End clear render pass. Bind() will call BeginRenderPass() which
+ // will switch to the load/store render pass.
+ EndRenderPass();
+}
+
bool StateTracker::UpdatePipeline()
{
// We need at least a vertex and fragment shader