From 1a73b0a0da30fac8d2c3726c22793955153eae8b Mon Sep 17 00:00:00 2001 From: kd-11 Date: Wed, 12 May 2021 00:44:40 +0300 Subject: [PATCH] rsx: Fix transfer barriers not triggering resolve target initialization --- rpcs3/Emu/RSX/Common/TextureUtils.h | 13 +++++++++++-- rpcs3/Emu/RSX/GL/GLRenderTargets.cpp | 6 +++--- rpcs3/Emu/RSX/GL/GLRenderTargets.h | 2 +- rpcs3/Emu/RSX/VK/VKRenderTargets.cpp | 19 +++++++++---------- rpcs3/Emu/RSX/VK/VKRenderTargets.h | 4 ++-- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.h b/rpcs3/Emu/RSX/Common/TextureUtils.h index 41b1a6b183..a50e0800f4 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.h +++ b/rpcs3/Emu/RSX/Common/TextureUtils.h @@ -46,14 +46,18 @@ namespace rsx shader_write = 1, transfer_read = 2, transfer_write = 4, + + // Arbitrary r/w flags, use with caution. + memory_write = 8, + memory_read = 16 }; private: // Meta enum { - all_writes = (shader_write | transfer_write), - all_reads = (shader_read | transfer_read), + all_writes = (shader_write | transfer_write | memory_write), + all_reads = (shader_read | transfer_read | memory_read), all_transfer = (transfer_read | transfer_write) }; @@ -80,6 +84,11 @@ namespace rsx return !(value_ & ~all_transfer); } + inline bool is_transfer_or_read() const // Special; reads and transfers generate MSAA load operations + { + return !(value_ & ~(all_transfer | all_reads)); + } + bool operator == (const surface_access& other) const { return value_ == other.value_; diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp index 605319538e..7d724d9b3a 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp @@ -438,7 +438,7 @@ void gl::render_target::load_memory(gl::command_context& cmd) } } -void gl::render_target::initialize_memory(gl::command_context& cmd, bool /*read_access*/) +void gl::render_target::initialize_memory(gl::command_context& cmd, rsx::surface_access /*access*/) { const bool memory_load = is_depth_surface() ? !!g_cfg.video.read_depth_buffer : @@ -478,7 +478,7 @@ void gl::render_target::memory_barrier(gl::command_context& cmd, rsx::surface_ac if (dirty() && (read_access || state_flags & rsx::surface_state_flags::erase_bkgnd)) { // Initialize memory contents if we did not find anything usable - initialize_memory(cmd, true); + initialize_memory(cmd, access); on_write(); } @@ -523,7 +523,7 @@ void gl::render_target::memory_barrier(gl::command_context& cmd, rsx::surface_ac const auto area = section.dst_rect(); if (area.x1 > 0 || area.y1 > 0 || unsigned(area.x2) < width() || unsigned(area.y2) < height()) { - initialize_memory(cmd, false); + initialize_memory(cmd, access); } else { diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.h b/rpcs3/Emu/RSX/GL/GLRenderTargets.h index c5315bda6a..9130475b95 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.h +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.h @@ -49,7 +49,7 @@ namespace gl { void clear_memory(gl::command_context& cmd); void load_memory(gl::command_context& cmd); - void initialize_memory(gl::command_context& cmd, bool read_access); + void initialize_memory(gl::command_context& cmd, rsx::surface_access access); public: render_target(GLuint width, GLuint height, GLenum sized_format, rsx::format_class format_class) diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.cpp b/rpcs3/Emu/RSX/VK/VKRenderTargets.cpp index 3a8ef45787..65c72ee06f 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.cpp +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.cpp @@ -279,7 +279,7 @@ namespace vk state_flags &= ~rsx::surface_state_flags::erase_bkgnd; } - void render_target::initialize_memory(vk::command_buffer& cmd, bool read_access) + void render_target::initialize_memory(vk::command_buffer& cmd, rsx::surface_access access) { const bool is_depth = is_depth_surface(); const bool should_read_buffers = is_depth ? !!g_cfg.video.read_depth_buffer : !!g_cfg.video.read_color_buffers; @@ -288,7 +288,7 @@ namespace vk { clear_memory(cmd, this); - if (read_access && samples() > 1) + if (samples() > 1 && access.is_transfer_or_read()) { // Only clear the resolve surface if reading from it, otherwise it's a waste clear_memory(cmd, get_resolve_target_safe(cmd)); @@ -369,7 +369,6 @@ namespace vk void render_target::memory_barrier(vk::command_buffer& cmd, rsx::surface_access access) { - const bool read_access = access.is_read(); const bool is_depth = is_depth_surface(); const bool should_read_buffers = is_depth ? !!g_cfg.video.read_depth_buffer : !!g_cfg.video.read_color_buffers; @@ -385,7 +384,7 @@ namespace vk } } - if (!read_access && write_barrier_sync_tag != 0) + if (access == rsx::surface_access::shader_write && write_barrier_sync_tag != 0) { if (current_layout == VK_IMAGE_LAYOUT_GENERAL) { @@ -433,7 +432,7 @@ namespace vk if (state_flags & rsx::surface_state_flags::erase_bkgnd) { // NOTE: This step CAN introduce MSAA flags! - initialize_memory(cmd, read_access); + initialize_memory(cmd, access); ensure(state_flags == rsx::surface_state_flags::ready); on_write(rsx::get_shared_tag(), static_cast(msaa_flags)); @@ -441,7 +440,7 @@ namespace vk if (msaa_flags & rsx::surface_state_flags::require_resolve) { - if (read_access) + if (access.is_transfer_or_read()) { // Only do this step when read access is required get_resolve_target_safe(cmd); @@ -450,7 +449,7 @@ namespace vk } else if (msaa_flags & rsx::surface_state_flags::require_unresolve) { - if (!read_access) + if (access == rsx::surface_access::shader_write) { // Only do this step when it is needed to start rendering ensure(resolve_surface); @@ -521,7 +520,7 @@ namespace vk else if (state_flags & rsx::surface_state_flags::erase_bkgnd) { // Might introduce MSAA flags - initialize_memory(cmd, false); + initialize_memory(cmd, rsx::surface_access::memory_write); ensure(state_flags == rsx::surface_state_flags::ready); } @@ -549,14 +548,14 @@ namespace vk clear_rw_barrier(); state_flags |= rsx::surface_state_flags::erase_bkgnd; - initialize_memory(cmd, read_access); + initialize_memory(cmd, access); ensure(state_flags == rsx::surface_state_flags::ready); } // NOTE: Optimize flag relates to stencil resolve/unresolve for NVIDIA. on_write_copy(newest_tag, optimize_copy); - if (!read_access && samples() > 1) + if (access == rsx::surface_access::shader_write && samples() > 1) { // Write barrier, must initialize unresolve(cmd); diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index 5a5a227cda..edce352fea 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -34,8 +34,8 @@ namespace vk void clear_memory(vk::command_buffer& cmd, vk::image* surface); // Load memory from cell and use to initialize the surface void load_memory(vk::command_buffer& cmd); - // Generic - chooses whether to clear or load - void initialize_memory(vk::command_buffer& cmd, bool read_access); + // Generic - chooses whether to clear or load. + void initialize_memory(vk::command_buffer& cmd, rsx::surface_access access); public: u64 frame_tag = 0; // frame id when invalidated, 0 if not invalid