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

@ -137,9 +137,19 @@ bool FramebufferManager::CreateEFBRenderPass()
0, 0,
nullptr}; nullptr};
VkResult res = VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr,
vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, &m_efb_render_pass); &m_efb_load_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass (EFB) failed: ");
return false;
}
// render pass for clearing color/depth on load, as opposed to loading it
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr,
&m_efb_clear_render_pass);
if (res != VK_SUCCESS) if (res != VK_SUCCESS)
{ {
LOG_VULKAN_ERROR(res, "vkCreateRenderPass (EFB) failed: "); LOG_VULKAN_ERROR(res, "vkCreateRenderPass (EFB) failed: ");
@ -189,10 +199,10 @@ bool FramebufferManager::CreateEFBRenderPass()
void FramebufferManager::DestroyEFBRenderPass() void FramebufferManager::DestroyEFBRenderPass()
{ {
if (m_efb_render_pass != VK_NULL_HANDLE) if (m_efb_load_render_pass != VK_NULL_HANDLE)
{ {
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_efb_render_pass, nullptr); vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_efb_load_render_pass, nullptr);
m_efb_render_pass = VK_NULL_HANDLE; m_efb_load_render_pass = VK_NULL_HANDLE;
} }
if (m_depth_resolve_render_pass != VK_NULL_HANDLE) if (m_depth_resolve_render_pass != VK_NULL_HANDLE)
@ -280,7 +290,7 @@ bool FramebufferManager::CreateEFBFramebuffer()
VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr, nullptr,
0, 0,
m_efb_render_pass, m_efb_load_render_pass,
static_cast<u32>(ArraySize(framebuffer_attachments)), static_cast<u32>(ArraySize(framebuffer_attachments)),
framebuffer_attachments, framebuffer_attachments,
m_efb_width, m_efb_width,
@ -398,7 +408,7 @@ void FramebufferManager::ReinterpretPixelData(int convtype)
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
g_object_cache->GetStandardPipelineLayout(), m_efb_render_pass, g_object_cache->GetStandardPipelineLayout(), m_efb_load_render_pass,
g_object_cache->GetScreenQuadVertexShader(), g_object_cache->GetScreenQuadVertexShader(),
g_object_cache->GetScreenQuadGeometryShader(), pixel_shader); g_object_cache->GetScreenQuadGeometryShader(), pixel_shader);
@ -1136,7 +1146,7 @@ void FramebufferManager::DrawPokeVertices(StateTracker* state_tracker,
pipeline_info.vs = m_poke_vertex_shader; pipeline_info.vs = m_poke_vertex_shader;
pipeline_info.gs = (m_efb_layers > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE; pipeline_info.gs = (m_efb_layers > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE;
pipeline_info.ps = m_poke_fragment_shader; pipeline_info.ps = m_poke_fragment_shader;
pipeline_info.render_pass = m_efb_render_pass; pipeline_info.render_pass = m_efb_load_render_pass;
pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits; pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits;
pipeline_info.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits; pipeline_info.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits;
pipeline_info.blend_state.bits = Util::GetNoBlendingBlendState().bits; pipeline_info.blend_state.bits = Util::GetNoBlendingBlendState().bits;
@ -1184,6 +1194,7 @@ void FramebufferManager::DrawPokeVertices(StateTracker* state_tracker,
m_poke_vertex_stream_buffer->CommitMemory(vertices_size); m_poke_vertex_stream_buffer->CommitMemory(vertices_size);
// Set up state. // Set up state.
state_tracker->EndClearRenderPass();
state_tracker->BeginRenderPass(); state_tracker->BeginRenderPass();
state_tracker->SetPendingRebind(); state_tracker->SetPendingRebind();
Util::SetViewportAndScissor(command_buffer, 0, 0, m_efb_width, m_efb_height); Util::SetViewportAndScissor(command_buffer, 0, 0, m_efb_width, m_efb_height);

View File

@ -30,7 +30,8 @@ public:
bool Initialize(); bool Initialize();
VkRenderPass GetEFBRenderPass() const { return m_efb_render_pass; } VkRenderPass GetEFBLoadRenderPass() const { return m_efb_load_render_pass; }
VkRenderPass GetEFBClearRenderPass() const { return m_efb_clear_render_pass; }
u32 GetEFBWidth() const { return m_efb_width; } u32 GetEFBWidth() const { return m_efb_width; }
u32 GetEFBHeight() const { return m_efb_height; } u32 GetEFBHeight() const { return m_efb_height; }
u32 GetEFBLayers() const { return m_efb_layers; } u32 GetEFBLayers() const { return m_efb_layers; }
@ -118,7 +119,8 @@ private:
void DrawPokeVertices(StateTracker* state_tracker, const EFBPokeVertex* vertices, void DrawPokeVertices(StateTracker* state_tracker, const EFBPokeVertex* vertices,
size_t vertex_count, bool write_color, bool write_depth); size_t vertex_count, bool write_color, bool write_depth);
VkRenderPass m_efb_render_pass = VK_NULL_HANDLE; VkRenderPass m_efb_load_render_pass = VK_NULL_HANDLE;
VkRenderPass m_efb_clear_render_pass = VK_NULL_HANDLE;
VkRenderPass m_depth_resolve_render_pass = VK_NULL_HANDLE; VkRenderPass m_depth_resolve_render_pass = VK_NULL_HANDLE;
u32 m_efb_width = 0; u32 m_efb_width = 0;

View File

@ -336,6 +336,18 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
{ {
// Native -> EFB coordinates // Native -> EFB coordinates
TargetRectangle target_rc = Renderer::ConvertEFBRectangle(rc); TargetRectangle target_rc = Renderer::ConvertEFBRectangle(rc);
VkRect2D target_vk_rc = {
{target_rc.left, target_rc.top},
{static_cast<uint32_t>(target_rc.GetWidth()), static_cast<uint32_t>(target_rc.GetHeight())}};
// Convert RGBA8 -> floating-point values.
VkClearValue clear_color_value = {};
VkClearValue clear_depth_value = {};
clear_color_value.color.float32[0] = static_cast<float>((color >> 16) & 0xFF) / 255.0f;
clear_color_value.color.float32[1] = static_cast<float>((color >> 8) & 0xFF) / 255.0f;
clear_color_value.color.float32[2] = static_cast<float>((color >> 0) & 0xFF) / 255.0f;
clear_color_value.color.float32[3] = static_cast<float>((color >> 24) & 0xFF) / 255.0f;
clear_depth_value.depthStencil.depth = (1.0f - (static_cast<float>(z & 0xFFFFFF) / 16777216.0f));
// Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha // Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha
// channel to 0xFF. This hopefully allows us to use the fast path in most cases. // channel to 0xFF. This hopefully allows us to use the fast path in most cases.
@ -348,55 +360,71 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
color |= 0xFF000000; color |= 0xFF000000;
} }
// Fast path: when both color and alpha are enabled, we can blow away the entire buffer // If we're not in a render pass (start of the frame), we can use a clear render pass
VkClearAttachment clear_attachments[2]; // to discard the data, rather than loading and then clearing.
uint32_t num_clear_attachments = 0; bool use_clear_render_pass = (color_enable && alpha_enable && z_enable);
if (color_enable && alpha_enable) if (m_state_tracker->InRenderPass())
{ {
clear_attachments[num_clear_attachments].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // Prefer not to end a render pass just to do a clear.
clear_attachments[num_clear_attachments].colorAttachment = 0; use_clear_render_pass = false;
clear_attachments[num_clear_attachments].clearValue.color.float32[0] =
float((color >> 16) & 0xFF) / 255.0f;
clear_attachments[num_clear_attachments].clearValue.color.float32[1] =
float((color >> 8) & 0xFF) / 255.0f;
clear_attachments[num_clear_attachments].clearValue.color.float32[2] =
float((color >> 0) & 0xFF) / 255.0f;
clear_attachments[num_clear_attachments].clearValue.color.float32[3] =
float((color >> 24) & 0xFF) / 255.0f;
num_clear_attachments++;
color_enable = false;
alpha_enable = false;
}
if (z_enable)
{
clear_attachments[num_clear_attachments].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
clear_attachments[num_clear_attachments].colorAttachment = 0;
clear_attachments[num_clear_attachments].clearValue.depthStencil.depth =
1.0f - (float(z & 0xFFFFFF) / 16777216.0f);
clear_attachments[num_clear_attachments].clearValue.depthStencil.stencil = 0;
num_clear_attachments++;
z_enable = false;
}
if (num_clear_attachments > 0)
{
VkClearRect rect = {};
rect.rect.offset = {target_rc.left, target_rc.top};
rect.rect.extent = {static_cast<uint32_t>(target_rc.GetWidth()),
static_cast<uint32_t>(target_rc.GetHeight())};
rect.baseArrayLayer = 0;
rect.layerCount = m_framebuffer_mgr->GetEFBLayers();
m_state_tracker->BeginRenderPass();
vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_clear_attachments,
clear_attachments, 1, &rect);
} }
// Fastest path: Use a render pass to clear the buffers.
if (use_clear_render_pass)
{
VkClearValue clear_values[2] = {clear_color_value, clear_depth_value};
m_state_tracker->BeginClearRenderPass(target_vk_rc, clear_values);
return;
}
// Fast path: Use vkCmdClearAttachments to clear the buffers within a render path
// We can't use this when preserving alpha but clearing color.
{
VkClearAttachment clear_attachments[2];
uint32_t num_clear_attachments = 0;
if (color_enable && alpha_enable)
{
clear_attachments[num_clear_attachments].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clear_attachments[num_clear_attachments].colorAttachment = 0;
clear_attachments[num_clear_attachments].clearValue = clear_color_value;
num_clear_attachments++;
color_enable = false;
alpha_enable = false;
}
if (z_enable)
{
clear_attachments[num_clear_attachments].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
clear_attachments[num_clear_attachments].colorAttachment = 0;
clear_attachments[num_clear_attachments].clearValue = clear_depth_value;
num_clear_attachments++;
z_enable = false;
}
if (num_clear_attachments > 0)
{
VkClearRect clear_rect = {target_vk_rc, 0, m_framebuffer_mgr->GetEFBLayers()};
if (!m_state_tracker->IsWithinRenderArea(target_vk_rc.offset.x, target_vk_rc.offset.y,
target_vk_rc.extent.width,
target_vk_rc.extent.height))
{
m_state_tracker->EndClearRenderPass();
}
m_state_tracker->BeginRenderPass();
vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_clear_attachments,
clear_attachments, 1, &clear_rect);
}
}
// Anything left over for the slow path?
if (!color_enable && !alpha_enable && !z_enable) if (!color_enable && !alpha_enable && !z_enable)
return; return;
// Clearing must occur within a render pass. // Clearing must occur within a render pass.
if (!m_state_tracker->IsWithinRenderArea(target_vk_rc.offset.x, target_vk_rc.offset.y,
target_vk_rc.extent.width, target_vk_rc.extent.height))
{
m_state_tracker->EndClearRenderPass();
}
m_state_tracker->BeginRenderPass(); m_state_tracker->BeginRenderPass();
m_state_tracker->SetPendingRebind(); m_state_tracker->SetPendingRebind();
@ -421,21 +449,17 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
// No need to start a new render pass, but we do need to restore viewport state // No need to start a new render pass, but we do need to restore viewport state
UtilityShaderDraw draw( UtilityShaderDraw draw(
g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetStandardPipelineLayout(), g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetStandardPipelineLayout(),
m_framebuffer_mgr->GetEFBRenderPass(), g_object_cache->GetPassthroughVertexShader(), m_framebuffer_mgr->GetEFBLoadRenderPass(), g_object_cache->GetPassthroughVertexShader(),
g_object_cache->GetPassthroughGeometryShader(), m_clear_fragment_shader); g_object_cache->GetPassthroughGeometryShader(), m_clear_fragment_shader);
draw.SetRasterizationState(rs_state); draw.SetRasterizationState(rs_state);
draw.SetDepthStencilState(depth_state); draw.SetDepthStencilState(depth_state);
draw.SetBlendState(blend_state); draw.SetBlendState(blend_state);
float vertex_r = float((color >> 16) & 0xFF) / 255.0f;
float vertex_g = float((color >> 8) & 0xFF) / 255.0f;
float vertex_b = float((color >> 0) & 0xFF) / 255.0f;
float vertex_a = float((color >> 24) & 0xFF) / 255.0f;
float vertex_z = 1.0f - (float(z & 0xFFFFFF) / 16777216.0f);
draw.DrawColoredQuad(target_rc.left, target_rc.top, target_rc.GetWidth(), target_rc.GetHeight(), draw.DrawColoredQuad(target_rc.left, target_rc.top, target_rc.GetWidth(), target_rc.GetHeight(),
vertex_r, vertex_g, vertex_b, vertex_a, vertex_z); clear_color_value.color.float32[0], clear_color_value.color.float32[1],
clear_color_value.color.float32[2], clear_color_value.color.float32[3],
clear_depth_value.depthStencil.depth);
} }
void Renderer::ReinterpretPixelData(unsigned int convtype) void Renderer::ReinterpretPixelData(unsigned int convtype)
@ -952,10 +976,11 @@ void Renderer::OnSwapChainResized()
void Renderer::BindEFBToStateTracker() void Renderer::BindEFBToStateTracker()
{ {
// Update framebuffer in state tracker // Update framebuffer in state tracker
VkRect2D framebuffer_render_area = { VkRect2D framebuffer_size = {
{0, 0}, {m_framebuffer_mgr->GetEFBWidth(), m_framebuffer_mgr->GetEFBHeight()}}; {0, 0}, {m_framebuffer_mgr->GetEFBWidth(), m_framebuffer_mgr->GetEFBHeight()}};
m_state_tracker->SetRenderPass(m_framebuffer_mgr->GetEFBRenderPass()); m_state_tracker->SetRenderPass(m_framebuffer_mgr->GetEFBLoadRenderPass(),
m_state_tracker->SetFramebuffer(m_framebuffer_mgr->GetEFBFramebuffer(), framebuffer_render_area); m_framebuffer_mgr->GetEFBClearRenderPass());
m_state_tracker->SetFramebuffer(m_framebuffer_mgr->GetEFBFramebuffer(), framebuffer_size);
// Update rasterization state with MSAA info // Update rasterization state with MSAA info
RasterizationState rs_state = {}; RasterizationState rs_state = {};

View File

@ -111,24 +111,28 @@ void StateTracker::SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexT
m_dirty_flags |= DIRTY_FLAG_INDEX_BUFFER; 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. // Should not be changed within a render pass.
assert(!m_in_render_pass); _assert_(!InRenderPass());
if (m_pipeline_state.render_pass == render_pass) // The clear and load render passes are compatible, so we don't need to change our pipeline.
return; 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_load_render_pass = load_render_pass;
m_dirty_flags |= DIRTY_FLAG_PIPELINE; m_clear_render_pass = clear_render_pass;
} }
void StateTracker::SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area) void StateTracker::SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area)
{ {
// Should not be changed within a render pass. // Should not be changed within a render pass.
assert(!m_in_render_pass); _assert_(!InRenderPass());
m_framebuffer = framebuffer; m_framebuffer = framebuffer;
m_framebuffer_render_area = render_area; m_framebuffer_size = render_area;
} }
void StateTracker::SetVertexFormat(const VertexFormat* vertex_format) void StateTracker::SetVertexFormat(const VertexFormat* vertex_format)
@ -508,12 +512,15 @@ void StateTracker::SetPendingRebind()
void StateTracker::BeginRenderPass() void StateTracker::BeginRenderPass()
{ {
if (m_in_render_pass) if (InRenderPass())
return; 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, VkRenderPassBeginInfo begin_info = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
nullptr, nullptr,
m_pipeline_state.render_pass, m_current_render_pass,
m_framebuffer, m_framebuffer,
m_framebuffer_render_area, m_framebuffer_render_area,
0, 0,
@ -521,17 +528,34 @@ void StateTracker::BeginRenderPass()
vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &begin_info, vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &begin_info,
VK_SUBPASS_CONTENTS_INLINE); VK_SUBPASS_CONTENTS_INLINE);
m_in_render_pass = true;
} }
void StateTracker::EndRenderPass() void StateTracker::EndRenderPass()
{ {
if (!m_in_render_pass) if (!InRenderPass())
return; return;
vkCmdEndRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer()); 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) void StateTracker::SetViewport(const VkViewport& viewport)
@ -554,6 +578,10 @@ void StateTracker::SetScissor(const VkRect2D& scissor)
bool StateTracker::Bind(bool rebind_all /*= false*/) 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 // Get new pipeline object if any parts have changed
if (m_dirty_flags & DIRTY_FLAG_PIPELINE && !UpdatePipeline()) 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 // Start render pass if not already started
if (!m_in_render_pass) if (!InRenderPass())
BeginRenderPass(); BeginRenderPass();
// Re-bind parts of the pipeline // Re-bind parts of the pipeline
@ -707,6 +735,38 @@ void StateTracker::SetBackgroundCommandBufferExecution(bool enabled)
m_allow_background_execution = 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() bool StateTracker::UpdatePipeline()
{ {
// We need at least a vertex and fragment shader // We need at least a vertex and fragment shader

View File

@ -35,7 +35,8 @@ public:
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset); void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type); void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
void SetRenderPass(VkRenderPass render_pass); void SetRenderPass(VkRenderPass load_render_pass, VkRenderPass clear_render_pass);
void SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area); void SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area);
void SetVertexFormat(const VertexFormat* vertex_format); void SetVertexFormat(const VertexFormat* vertex_format);
@ -76,6 +77,10 @@ public:
void BeginRenderPass(); void BeginRenderPass();
void EndRenderPass(); void EndRenderPass();
// Ends the current render pass if it was a clear render pass.
void BeginClearRenderPass(const VkRect2D& area, const VkClearValue clear_values[2]);
void EndClearRenderPass();
void SetViewport(const VkViewport& viewport); void SetViewport(const VkViewport& viewport);
void SetScissor(const VkRect2D& scissor); void SetScissor(const VkRect2D& scissor);
@ -96,7 +101,12 @@ public:
// Use when queries are active. // Use when queries are active.
void SetBackgroundCommandBufferExecution(bool enabled); void SetBackgroundCommandBufferExecution(bool enabled);
bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const;
private: private:
// Check that the specified viewport is within the render area.
// If not, ends the render pass if it is a clear render pass.
bool IsViewportWithinRenderArea() const;
bool UpdatePipeline(); bool UpdatePipeline();
bool UpdateDescriptorSet(); bool UpdateDescriptorSet();
void UploadAllConstants(); void UploadAllConstants();
@ -162,8 +172,11 @@ private:
std::unique_ptr<StreamBuffer> m_uniform_stream_buffer; std::unique_ptr<StreamBuffer> m_uniform_stream_buffer;
VkFramebuffer m_framebuffer = VK_NULL_HANDLE; VkFramebuffer m_framebuffer = VK_NULL_HANDLE;
VkRenderPass m_load_render_pass = VK_NULL_HANDLE;
VkRenderPass m_clear_render_pass = VK_NULL_HANDLE;
VkRenderPass m_current_render_pass = VK_NULL_HANDLE;
VkRect2D m_framebuffer_size = {};
VkRect2D m_framebuffer_render_area = {}; VkRect2D m_framebuffer_render_area = {};
bool m_in_render_pass = false;
bool m_bbox_enabled = false; bool m_bbox_enabled = false;
// CPU access tracking // CPU access tracking