mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-06 23:11:25 +12:00
vk: Restructure framebuffer loop barrier management
This commit is contained in:
parent
4def7f143c
commit
110c20d25f
3 changed files with 110 additions and 44 deletions
|
@ -1,5 +1,6 @@
|
||||||
#include "VKRenderTargets.h"
|
#include "VKRenderTargets.h"
|
||||||
#include "VKResourceManager.h"
|
#include "VKResourceManager.h"
|
||||||
|
#include "Emu/RSX/rsx_methods.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
@ -797,19 +798,67 @@ namespace vk
|
||||||
|
|
||||||
void render_target::texture_barrier(vk::command_buffer& cmd)
|
void render_target::texture_barrier(vk::command_buffer& cmd)
|
||||||
{
|
{
|
||||||
if (!write_barrier_sync_tag) write_barrier_sync_tag++; // Activate barrier sync
|
const auto is_framebuffer_read_only = is_depth_surface() && !rsx::method_registers.depth_write_enabled();
|
||||||
cyclic_reference_sync_tag = write_barrier_sync_tag; // Match tags
|
|
||||||
|
|
||||||
const auto supports_fbo_loops = cmd.get_command_pool().get_owner().get_framebuffer_loops_support();
|
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
|
const auto optimal_layout = supports_fbo_loops ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT
|
||||||
: VK_IMAGE_LAYOUT_GENERAL;
|
: VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
|
||||||
|
if (is_framebuffer_read_only && current_layout == optimal_layout && m_cyclic_ref_tracker.can_skip())
|
||||||
|
{
|
||||||
|
// 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);
|
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();
|
||||||
|
if (is_framebuffer_read_only && m_cyclic_ref_tracker.can_skip())
|
||||||
|
{
|
||||||
|
// 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()
|
void render_target::reset_surface_counters()
|
||||||
{
|
{
|
||||||
frame_tag = 0;
|
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)
|
image_view* render_target::get_view(u32 remap_encoding, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap, VkImageAspectFlags mask)
|
||||||
|
@ -858,46 +907,23 @@ namespace vk
|
||||||
unspill(cmd);
|
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 (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)
|
// Flag draw barrier observed
|
||||||
{
|
m_cyclic_ref_tracker.on_insert_draw_barrier();
|
||||||
// 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;
|
|
||||||
|
|
||||||
if (!is_depth_surface()) [[likely]]
|
// Check if we've had more draws than barriers so far (fall-out condition)
|
||||||
|
if (m_cyclic_ref_tracker.requires_post_loop_barrier())
|
||||||
{
|
{
|
||||||
src_stage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
post_texture_barrier(cmd);
|
||||||
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
|
|
||||||
{
|
|
||||||
// Synced externally for this draw
|
|
||||||
write_barrier_sync_tag++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write_barrier_sync_tag = 0; // Disable
|
// Layouts changed elsewhere. Reset.
|
||||||
|
m_cyclic_ref_tracker.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,55 @@ namespace vk
|
||||||
void resolve_image(vk::command_buffer& cmd, vk::viewable_image* dst, vk::viewable_image* src);
|
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);
|
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()
|
||||||
|
{
|
||||||
|
m_draw_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*>
|
class render_target : public viewable_image, public rsx::render_target_descriptor<vk::viewable_image*>
|
||||||
{
|
{
|
||||||
u64 cyclic_reference_sync_tag = 0;
|
// Cyclic reference hazard tracking
|
||||||
u64 write_barrier_sync_tag = 0;
|
image_reference_sync_barrier m_cyclic_ref_tracker;
|
||||||
|
|
||||||
// Memory spilling support
|
// Memory spilling support
|
||||||
std::unique_ptr<vk::buffer> m_spilled_mem;
|
std::unique_ptr<vk::buffer> m_spilled_mem;
|
||||||
|
@ -75,6 +120,7 @@ namespace vk
|
||||||
|
|
||||||
// Synchronization
|
// Synchronization
|
||||||
void texture_barrier(vk::command_buffer& cmd);
|
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 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 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); }
|
void write_barrier(vk::command_buffer& cmd) { memory_barrier(cmd, rsx::surface_access::shader_write); }
|
||||||
|
|
|
@ -87,12 +87,6 @@ namespace vk
|
||||||
}
|
}
|
||||||
else
|
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_access = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
src_stage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
src_stage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue