Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vk: Lazy evaluate renderpass scope #7784

Merged
merged 1 commit into from Mar 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions rpcs3/Emu/RSX/VK/VKCompute.h
@@ -1,5 +1,6 @@
#pragma once
#include "VKHelpers.h"
#include "VKRenderPass.h"
#include "Utilities/StrUtil.h"

#define VK_MAX_COMPUTE_TASKS 4096 // Max number of jobs per frame
Expand Down Expand Up @@ -201,6 +202,12 @@ namespace vk

void run(VkCommandBuffer cmd, u32 invocations_x, u32 invocations_y, u32 invocations_z)
{
// CmdDispatch is outside renderpass scope only
if (vk::is_renderpass_open(cmd))
{
vk::end_renderpass(cmd);
}

load_program(cmd);
vkCmdDispatch(cmd, invocations_x, invocations_y, invocations_z);
}
Expand Down
45 changes: 19 additions & 26 deletions rpcs3/Emu/RSX/VK/VKGSRender.cpp
Expand Up @@ -1062,31 +1062,26 @@ void VKGSRender::update_draw_state()

void VKGSRender::begin_render_pass()
{
if (m_render_pass_open)
return;

const auto renderpass = (m_cached_renderpass)? m_cached_renderpass : vk::get_renderpass(*m_device, m_current_renderpass_key);

VkRenderPassBeginInfo rp_begin = {};
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.renderPass = renderpass;
rp_begin.framebuffer = m_draw_fbo->value;
rp_begin.renderArea.offset.x = 0;
rp_begin.renderArea.offset.y = 0;
rp_begin.renderArea.extent.width = m_draw_fbo->width();
rp_begin.renderArea.extent.height = m_draw_fbo->height();

vkCmdBeginRenderPass(*m_current_command_buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
m_render_pass_open = true;
vk::begin_renderpass(
*m_current_command_buffer,
get_render_pass(),
m_draw_fbo->value,
{ positionu{0u, 0u}, sizeu{m_draw_fbo->width(), m_draw_fbo->height()} });
}

void VKGSRender::close_render_pass()
{
if (!m_render_pass_open)
return;
vk::end_renderpass(*m_current_command_buffer);
}

vkCmdEndRenderPass(*m_current_command_buffer);
m_render_pass_open = false;
VkRenderPass VKGSRender::get_render_pass()
{
if (!m_cached_renderpass)
{
m_cached_renderpass = vk::get_renderpass(*m_device, m_current_renderpass_key);
}

return m_cached_renderpass;
}

void VKGSRender::emit_geometry(u32 sub_index)
Expand Down Expand Up @@ -1199,7 +1194,7 @@ void VKGSRender::emit_geometry(u32 sub_index)
m_program->bind_uniform(m_vertex_layout_storage->value, binding_table.vertex_buffers_first_bind_slot + 2, m_current_frame->descriptor_set);
}

if (!m_render_pass_open)
if (!m_current_subdraw_id++)
{
vkCmdBindPipeline(*m_current_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_program->pipeline);
update_draw_state();
Expand Down Expand Up @@ -1857,6 +1852,8 @@ void VKGSRender::end()
check_heap_status(VK_HEAP_CHECK_VERTEX_STORAGE | VK_HEAP_CHECK_VERTEX_LAYOUT_STORAGE);

u32 sub_index = 0;
m_current_subdraw_id = 0;

rsx::method_registers.current_draw_clause.begin();
do
{
Expand All @@ -1870,9 +1867,6 @@ void VKGSRender::end()
m_current_command_buffer->flags &= ~(vk::command_buffer::cb_has_conditional_render);
}

// Close any open passes unconditionally
close_render_pass();

m_rtts.on_write(m_framebuffer_layout.color_write_enabled.data(), m_framebuffer_layout.zeta_write_enabled);

rsx::thread::end();
Expand Down Expand Up @@ -2157,7 +2151,6 @@ void VKGSRender::clear_surface(u32 mask)
{
begin_render_pass();
vkCmdClearAttachments(*m_current_command_buffer, ::size32(clear_descriptors), clear_descriptors.data(), 1, &region);
close_render_pass();
}
}

Expand Down Expand Up @@ -2728,7 +2721,7 @@ void VKGSRender::close_and_submit_command_buffer(vk::fence* pFence, VkSemaphore
#endif

// End any active renderpasses; the caller should handle reopening
if (m_render_pass_open)
if (vk::is_renderpass_open(*m_current_command_buffer))
{
close_render_pass();
}
Expand Down
5 changes: 3 additions & 2 deletions rpcs3/Emu/RSX/VK/VKGSRender.h
Expand Up @@ -456,8 +456,8 @@ class VKGSRender : public GSRender, public ::rsx::reports::ZCULL_control
utils::address_range m_offloader_fault_range;
rsx::invalidation_cause m_offloader_fault_cause;

bool m_render_pass_open = false;
u64 m_current_renderpass_key = 0;
u32 m_current_subdraw_id = 0;
u64 m_current_renderpass_key = 0;
VkRenderPass m_cached_renderpass = VK_NULL_HANDLE;
std::vector<vk::image*> m_fbo_images;

Expand Down Expand Up @@ -494,6 +494,7 @@ class VKGSRender : public GSRender, public ::rsx::reports::ZCULL_control

void begin_render_pass();
void close_render_pass();
VkRenderPass get_render_pass();

void update_draw_state();

Expand Down
25 changes: 25 additions & 0 deletions rpcs3/Emu/RSX/VK/VKHelpers.cpp
Expand Up @@ -8,6 +8,7 @@
#include "VKResourceManager.h"
#include "VKDMA.h"
#include "VKCommandStream.h"
#include "VKRenderPass.h"

#include "Utilities/mutex.h"
#include "Utilities/lockless.h"
Expand Down Expand Up @@ -567,6 +568,11 @@ namespace vk

void insert_buffer_memory_barrier(VkCommandBuffer cmd, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize length, VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage, VkAccessFlags src_mask, VkAccessFlags dst_mask)
{
if (vk::is_renderpass_open(cmd))
{
vk::end_renderpass(cmd);
}

VkBufferMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barrier.buffer = buffer;
Expand All @@ -587,6 +593,11 @@ namespace vk
VkAccessFlags src_mask, VkAccessFlags dst_mask,
const VkImageSubresourceRange& range)
{
if (vk::is_renderpass_open(cmd))
{
vk::end_renderpass(cmd);
}

VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.newLayout = new_layout;
Expand All @@ -603,11 +614,21 @@ namespace vk

void insert_execution_barrier(VkCommandBuffer cmd, VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage)
{
if (vk::is_renderpass_open(cmd))
{
vk::end_renderpass(cmd);
}

vkCmdPipelineBarrier(cmd, src_stage, dst_stage, 0, 0, nullptr, 0, nullptr, 0, nullptr);
}

void change_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout, const VkImageSubresourceRange& range)
{
if (vk::is_renderpass_open(cmd))
{
vk::end_renderpass(cmd);
}

//Prepare an image to match the new layout..
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
Expand Down Expand Up @@ -766,6 +787,10 @@ namespace vk
// Transition to GENERAL if this resource is both input and output
// TODO: This implicitly makes the target incompatible with the renderpass declaration; investigate a proper workaround
// TODO: This likely throws out hw optimizations on the rest of the renderpass, manage carefully
if (vk::is_renderpass_open(cmd))
{
vk::end_renderpass(cmd);
}

VkAccessFlags src_access;
VkPipelineStageFlags src_stage;
Expand Down
13 changes: 2 additions & 11 deletions rpcs3/Emu/RSX/VK/VKOverlays.h
Expand Up @@ -5,6 +5,7 @@
#include "VKRenderTargets.h"
#include "VKFramebuffer.h"
#include "VKResourceManager.h"
#include "VKRenderPass.h"

#include "../Overlays/overlays.h"

Expand Down Expand Up @@ -374,18 +375,8 @@ namespace vk
load_program(cmd, render_pass, src);
set_up_viewport(cmd, viewport.x1, viewport.y1, viewport.width(), viewport.height());

VkRenderPassBeginInfo rp_begin = {};
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.renderPass = render_pass;
rp_begin.framebuffer = fbo->value;
rp_begin.renderArea.offset.x = static_cast<s32>(viewport.x1);
rp_begin.renderArea.offset.y = static_cast<s32>(viewport.y1);
rp_begin.renderArea.extent.width = viewport.width();
rp_begin.renderArea.extent.height = viewport.height();

vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
vk::begin_renderpass(cmd, render_pass, fbo->value, viewport);
emit_geometry(cmd);
vkCmdEndRenderPass(cmd);
}

void run(vk::command_buffer &cmd, const areau& viewport, vk::image* target, const std::vector<vk::image_view*>& src, VkRenderPass render_pass)
Expand Down
57 changes: 57 additions & 0 deletions rpcs3/Emu/RSX/VK/VKRenderPass.cpp
Expand Up @@ -5,6 +5,16 @@

namespace vk
{
struct active_renderpass_info_t
{
VkRenderPass pass = VK_NULL_HANDLE;
VkFramebuffer fbo = VK_NULL_HANDLE;
};

atomic_t<u64> g_cached_renderpass_key = 0;
VkRenderPass g_cached_renderpass = VK_NULL_HANDLE;
std::unordered_map<VkCommandBuffer, active_renderpass_info_t> g_current_renderpass;

shared_mutex g_renderpass_cache_mutex;
std::unordered_map<u64, VkRenderPass> g_renderpass_cache;

Expand Down Expand Up @@ -248,4 +258,51 @@ namespace vk

g_renderpass_cache.clear();
}

void begin_renderpass(VkCommandBuffer cmd, VkRenderPass pass, VkFramebuffer target, const coordu& framebuffer_region)
{
auto& renderpass_info = g_current_renderpass[cmd];
if (renderpass_info.pass == pass && renderpass_info.fbo == target)
{
return;
}
else if (renderpass_info.pass != VK_NULL_HANDLE)
{
end_renderpass(cmd);
}

VkRenderPassBeginInfo rp_begin = {};
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.renderPass = pass;
rp_begin.framebuffer = target;
rp_begin.renderArea.offset.x = static_cast<int32_t>(framebuffer_region.x);
rp_begin.renderArea.offset.y = static_cast<int32_t>(framebuffer_region.y);
rp_begin.renderArea.extent.width = framebuffer_region.width;
rp_begin.renderArea.extent.height = framebuffer_region.height;

vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
renderpass_info = { pass, target };
}

void begin_renderpass(VkDevice dev, VkCommandBuffer cmd, u64 renderpass_key, VkFramebuffer target, const coordu& framebuffer_region)
{
if (renderpass_key != g_cached_renderpass_key)
{
g_cached_renderpass = get_renderpass(dev, renderpass_key);
g_cached_renderpass_key = renderpass_key;
}

begin_renderpass(cmd, g_cached_renderpass, target, framebuffer_region);
}

void end_renderpass(VkCommandBuffer cmd)
{
vkCmdEndRenderPass(cmd);
g_current_renderpass[cmd] = {};
}

bool is_renderpass_open(VkCommandBuffer cmd)
{
return g_current_renderpass[cmd].pass != VK_NULL_HANDLE;
}
}
7 changes: 7 additions & 0 deletions rpcs3/Emu/RSX/VK/VKRenderPass.h
Expand Up @@ -10,4 +10,11 @@ namespace vk
VkRenderPass get_renderpass(VkDevice dev, u64 renderpass_key);

void clear_renderpass_cache(VkDevice dev);

// Renderpass scope management helpers.
// NOTE: These are not thread safe by design.
void begin_renderpass(VkDevice dev, VkCommandBuffer cmd, u64 renderpass_key, VkFramebuffer target, const coordu& framebuffer_region);
void begin_renderpass(VkCommandBuffer cmd, VkRenderPass pass, VkFramebuffer target, const coordu& framebuffer_region);
void end_renderpass(VkCommandBuffer cmd);
bool is_renderpass_open(VkCommandBuffer cmd);
Megamouse marked this conversation as resolved.
Show resolved Hide resolved
}
15 changes: 3 additions & 12 deletions rpcs3/Emu/RSX/VK/VKTextOut.h
Expand Up @@ -2,6 +2,7 @@
#include "VKHelpers.h"
#include "VKVertexProgram.h"
#include "VKFragmentProgram.h"
#include "VKRenderPass.h"
#include "../Common/TextGlyphs.h"

namespace vk
Expand Down Expand Up @@ -346,23 +347,13 @@ namespace vk
//TODO: Add drop shadow if deemed necessary for visibility
load_program(cmd, scale_x, scale_y, shader_offsets.data(), counts.size(), color);

VkRenderPassBeginInfo rp_begin = {};
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rp_begin.renderPass = m_render_pass;
rp_begin.framebuffer = target.value;
rp_begin.renderArea.offset.x = 0;
rp_begin.renderArea.offset.y = 0;
rp_begin.renderArea.extent.width = target.width();
rp_begin.renderArea.extent.height = target.height();

vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
const coordu viewport = { positionu{0u, 0u}, sizeu{target.width(), target.height() } };
vk::begin_renderpass(cmd, m_render_pass, target.value, viewport);

for (uint i = 0; i < counts.size(); ++i)
{
vkCmdDraw(cmd, counts[i], 1, offsets[i], i);
}

vkCmdEndRenderPass(cmd);
}

void reset_descriptors()
Expand Down