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: Restructure framebuffer loop barrier management #13136

Merged
merged 3 commits into from Dec 28, 2022
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
96 changes: 61 additions & 35 deletions rpcs3/Emu/RSX/VK/VKRenderTargets.cpp
@@ -1,5 +1,6 @@
#include "VKRenderTargets.h"
#include "VKResourceManager.h"
#include "Emu/RSX/rsx_methods.h"

namespace vk
{
Expand Down Expand Up @@ -797,19 +798,67 @@ namespace vk

void render_target::texture_barrier(vk::command_buffer& cmd)
{
if (!write_barrier_sync_tag) write_barrier_sync_tag++; // Activate barrier sync
cyclic_reference_sync_tag = write_barrier_sync_tag; // Match tags

const auto is_framebuffer_read_only = is_depth_surface() && !rsx::method_registers.depth_write_enabled();
const auto supports_fbo_loops = cmd.get_command_pool().get_owner().get_framebuffer_loops_support();
const auto optimal_layout = supports_fbo_loops ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT
: VK_IMAGE_LAYOUT_GENERAL;

if (m_cyclic_ref_tracker.can_skip() && current_layout == optimal_layout && is_framebuffer_read_only)
{
// If we have back-to-back depth-read barriers, skip subsequent ones
// If an actual write is happening, this flag will be automatically reset
return;
}

vk::insert_texture_barrier(cmd, this, optimal_layout);
m_cyclic_ref_tracker.on_insert_texture_barrier();

if (is_framebuffer_read_only)
{
m_cyclic_ref_tracker.allow_skip();
}
}

void render_target::post_texture_barrier(vk::command_buffer& cmd)
{
// This is a fall-out barrier after a cyclic ref when the same surface is still bound.
// In this case, we're just checking that the previous read completes before the next write.
const bool is_framebuffer_read_only = is_depth_surface() && !rsx::method_registers.depth_write_enabled();
kd-11 marked this conversation as resolved.
Show resolved Hide resolved
if (m_cyclic_ref_tracker.can_skip() && is_framebuffer_read_only)
{
// Barrier ellided if triggered by a chain of cyclic references with no actual writes
m_cyclic_ref_tracker.reset();
return;
}

VkPipelineStageFlags src_stage, dst_stage;
VkAccessFlags src_access, dst_access;

if (!is_depth_surface()) [[likely]]
{
src_stage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dst_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
src_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dst_access = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
}
else
{
src_stage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dst_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
src_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dst_access = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}

vk::insert_image_memory_barrier(cmd, value, current_layout, current_layout,
src_stage, dst_stage, src_access, dst_access, { aspect(), 0, 1, 0, 1 });

m_cyclic_ref_tracker.reset();
}

void render_target::reset_surface_counters()
{
frame_tag = 0;
write_barrier_sync_tag = 0;
m_cyclic_ref_tracker.reset();
}

image_view* render_target::get_view(u32 remap_encoding, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap, VkImageAspectFlags mask)
Expand Down Expand Up @@ -858,46 +907,23 @@ namespace vk
unspill(cmd);
}

if (access == rsx::surface_access::shader_write && write_barrier_sync_tag != 0)
if (access == rsx::surface_access::shader_write && m_cyclic_ref_tracker.is_enabled())
{
if (current_layout == VK_IMAGE_LAYOUT_GENERAL || current_layout == VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT)
{
if (write_barrier_sync_tag != cyclic_reference_sync_tag)
{
// This barrier catches a very specific case where 2 draw calls are executed with general layout (cyclic ref) but no texture barrier in between.
// This happens when a cyclic ref is broken. In this case previous draw must finish drawing before the new one renders to avoid current draw breaking previous one.
VkPipelineStageFlags src_stage, dst_stage;
VkAccessFlags src_access, dst_access;
// Flag draw barrier observed
m_cyclic_ref_tracker.on_insert_draw_barrier();

if (!is_depth_surface()) [[likely]]
{
src_stage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dst_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
src_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dst_access = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
}
else
{
src_stage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dst_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
src_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dst_access = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}

vk::insert_image_memory_barrier(cmd, value, current_layout, current_layout,
src_stage, dst_stage, src_access, dst_access, { aspect(), 0, 1, 0, 1 });

write_barrier_sync_tag = 0; // Disable for next draw
}
else
// Check if we've had more draws than barriers so far (fall-out condition)
if (m_cyclic_ref_tracker.requires_post_loop_barrier())
{
// Synced externally for this draw
write_barrier_sync_tag++;
post_texture_barrier(cmd);
}
}
else
{
write_barrier_sync_tag = 0; // Disable
// Layouts changed elsewhere. Reset.
m_cyclic_ref_tracker.reset();
}
}

Expand Down
51 changes: 49 additions & 2 deletions rpcs3/Emu/RSX/VK/VKRenderTargets.h
Expand Up @@ -24,10 +24,56 @@ namespace vk
void resolve_image(vk::command_buffer& cmd, vk::viewable_image* dst, vk::viewable_image* src);
void unresolve_image(vk::command_buffer& cmd, vk::viewable_image* dst, vk::viewable_image* src);

class image_reference_sync_barrier
{
u32 m_texture_barrier_count = 0;
u32 m_draw_barrier_count = 0;
bool m_allow_skip_barrier = true;

public:
void on_insert_texture_barrier()
{
m_texture_barrier_count++;
m_allow_skip_barrier = false;
}

void on_insert_draw_barrier()
{
// Account for corner case where the same texture can be bound to more than 1 slot
m_draw_barrier_count = std::max(m_draw_barrier_count + 1, m_texture_barrier_count);
}

void allow_skip()
{
m_allow_skip_barrier = true;
}

void reset()
{
m_texture_barrier_count = m_draw_barrier_count = 0ull;
m_allow_skip_barrier = false;
}

bool can_skip() const
{
return m_allow_skip_barrier;
}

bool is_enabled() const
{
return !!m_texture_barrier_count;
}

bool requires_post_loop_barrier() const
{
return is_enabled() && m_texture_barrier_count < m_draw_barrier_count;
}
};

class render_target : public viewable_image, public rsx::render_target_descriptor<vk::viewable_image*>
{
u64 cyclic_reference_sync_tag = 0;
u64 write_barrier_sync_tag = 0;
// Cyclic reference hazard tracking
image_reference_sync_barrier m_cyclic_ref_tracker;

// Memory spilling support
std::unique_ptr<vk::buffer> m_spilled_mem;
Expand Down Expand Up @@ -75,6 +121,7 @@ namespace vk

// Synchronization
void texture_barrier(vk::command_buffer& cmd);
void post_texture_barrier(vk::command_buffer& cmd);
void memory_barrier(vk::command_buffer& cmd, rsx::surface_access access);
void read_barrier(vk::command_buffer& cmd) { memory_barrier(cmd, rsx::surface_access::shader_read); }
void write_barrier(vk::command_buffer& cmd) { memory_barrier(cmd, rsx::surface_access::shader_write); }
Expand Down
6 changes: 0 additions & 6 deletions rpcs3/Emu/RSX/VK/vkutils/barriers.cpp
Expand Up @@ -87,12 +87,6 @@ namespace vk
}
else
{
if (!rsx::method_registers.depth_write_enabled() && current_layout == new_layout)
{
// Nothing to do
return;
}

src_access = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
src_stage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
}
Expand Down