Vulkan: Use render-pass based clears where possible

This commit is contained in:
Stenzek
2016-09-11 16:37:41 +10:00
parent c290398320
commit f6cdc38c8b
5 changed files with 191 additions and 80 deletions

View File

@ -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