diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index fc5222a6fe..340c7ec8ae 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -52,7 +52,6 @@ namespace rsx rsx::address_range m_depth_stencil_memory_range; bool m_invalidate_on_write = false; - bool m_skip_write_updates = false; rsx::surface_raster_type m_active_raster_type = rsx::surface_raster_type::linear; @@ -1118,62 +1117,31 @@ namespace rsx } } - void on_write(const bool* color, bool z) + void on_write(const std::array& color_mrt_writes_enabled, const bool depth_stencil_writes_enabled) { - if (write_tag == cache_tag && m_skip_write_updates) + if (write_tag >= cache_tag && !m_invalidate_on_write) { - // Nothing to do - ensure(!m_invalidate_on_write); return; } - write_tag = cache_tag; - m_skip_write_updates = false; - int tagged = 0; + // TODO: Take WCB/WDB into account. Should speed this up a bit by skipping sync_tag calls + write_tag = rsx::get_shared_tag(); - // Tag surfaces - if (color) + for (u8 i = m_bound_render_targets_config.first, count = 0; + count < m_bound_render_targets_config.second; + ++count, ++i) { - for (int i = m_bound_render_targets_config.first, count = 0; - count < m_bound_render_targets_config.second; - ++i, ++count) + if (auto surface = m_bound_render_targets[i].second; + surface && color_mrt_writes_enabled[i]) { - if (!color[i]) - continue; - - auto& surface = m_bound_render_targets[i].second; - if (surface->last_use_tag != write_tag) - { - m_bound_render_targets[i].second->on_write(write_tag, surface_state_flags::require_resolve, m_active_raster_type); - } - else if (m_invalidate_on_write) - { - m_bound_render_targets[i].second->on_invalidate_children(); - } - - ++tagged; + surface->on_write(write_tag); } } - if (z && m_bound_depth_stencil.first) + if (auto zsurface = m_bound_depth_stencil.second; + zsurface && depth_stencil_writes_enabled) { - auto& surface = m_bound_depth_stencil.second; - if (surface->last_use_tag != write_tag) - { - m_bound_depth_stencil.second->on_write(write_tag, surface_state_flags::require_resolve, m_active_raster_type); - } - else if (m_invalidate_on_write) - { - m_bound_depth_stencil.second->on_invalidate_children(); - } - - ++tagged; - } - - if (!m_invalidate_on_write && tagged == m_bound_buffers_count) - { - // Skip any further updates as all active surfaces have been updated - m_skip_write_updates = true; + zsurface->on_write(write_tag); } } diff --git a/rpcs3/Emu/RSX/Common/surface_utils.h b/rpcs3/Emu/RSX/Common/surface_utils.h index 0abae4e637..d96456fc5f 100644 --- a/rpcs3/Emu/RSX/Common/surface_utils.h +++ b/rpcs3/Emu/RSX/Common/surface_utils.h @@ -178,7 +178,7 @@ namespace rsx virtual bool is_depth_surface() const = 0; virtual void release_ref(image_storage_type) const = 0; - virtual u32 get_surface_width(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const + inline u32 get_surface_width(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const { switch (metrics) { @@ -193,7 +193,7 @@ namespace rsx } } - virtual u32 get_surface_height(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const + inline u32 get_surface_height(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const { switch (metrics) { @@ -207,22 +207,22 @@ namespace rsx } } - virtual u32 get_rsx_pitch() const + inline u32 get_rsx_pitch() const { return rsx_pitch; } - virtual u32 get_native_pitch() const + inline u32 get_native_pitch() const { return native_pitch; } - u8 get_bpp() const + inline u8 get_bpp() const { return u8(get_native_pitch() / get_surface_width(rsx::surface_metrics::samples)); } - u8 get_spp() const + inline u8 get_spp() const { return spp; } @@ -278,17 +278,17 @@ namespace rsx format_info.gcm_depth_format = format; } - rsx::surface_color_format get_surface_color_format() const + inline rsx::surface_color_format get_surface_color_format() const { return format_info.gcm_color_format; } - rsx::surface_depth_format2 get_surface_depth_format() const + inline rsx::surface_depth_format2 get_surface_depth_format() const { return format_info.gcm_depth_format; } - u32 get_gcm_format() const + inline u32 get_gcm_format() const { return ( @@ -298,12 +298,12 @@ namespace rsx ); } - bool dirty() const + inline bool dirty() const { return (state_flags != rsx::surface_state_flags::ready) || !old_contents.empty(); } - bool write_through() const + inline bool write_through() const { return (state_flags & rsx::surface_state_flags::erase_bkgnd) && old_contents.empty(); } diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 97e1ccd1c0..af4af2d23f 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -285,26 +285,53 @@ namespace rsx template std::pair is_expired(surface_store_type& surface_cache) { - if (upload_context != rsx::texture_upload_context::framebuffer_storage || - surface_cache_tag == surface_cache.cache_tag) + if (upload_context != rsx::texture_upload_context::framebuffer_storage) { - return { false, nullptr }; + return {}; } // Expired, but may still be valid. Check if the texture is still accessible auto ref_image = image_handle ? image_handle->image() : external_subresource_desc.external_handle; - if (ref_image) + surface_type surface = dynamic_cast(ref_image); + + // Try and grab a cache reference in case of MSAA resolve target or compositing op + if (!surface) { - if (auto surface = dynamic_cast(ref_image); - surface && surface == surface_cache.get_surface_at(ref_address)) + if (!(surface = surface_cache.get_surface_at(ref_address))) { - // Fast sync - surface_cache_tag = surface_cache.cache_tag; - is_cyclic_reference = surface_cache.address_is_bound(ref_address); + // Compositing op. Just ignore expiry for now + ensure(!ref_image); + return {}; + } + } + + ensure(surface); + if (!ref_image || surface->get_surface(rsx::surface_access::gpu_reference) == ref_image) + { + // Same image, so configuration did not change. + if (surface->last_use_tag <= surface_cache_tag) + { + external_subresource_desc.do_not_cache = false; + return {}; + } + + // Image was written to since last bind. Insert texture barrier. + surface_cache_tag = surface->last_use_tag; + is_cyclic_reference = surface_cache.address_is_bound(ref_address); + external_subresource_desc.do_not_cache = is_cyclic_reference; + + switch (external_subresource_desc.op) + { + case deferred_request_command::copy_image_dynamic: + case deferred_request_command::copy_image_static: + external_subresource_desc.op = (is_cyclic_reference) ? deferred_request_command::copy_image_dynamic : deferred_request_command::copy_image_static; + [[ fallthrough ]]; + default: return { false, surface }; } } + // Reupload return { true, nullptr }; } }; @@ -2155,7 +2182,7 @@ namespace rsx } result.ref_address = attributes.address; - result.surface_cache_tag = m_rtts.cache_tag; + result.surface_cache_tag = m_rtts.write_tag; if (subsurface_count == 1) { diff --git a/rpcs3/Emu/RSX/GL/GLDraw.cpp b/rpcs3/Emu/RSX/GL/GLDraw.cpp index dd1c645d03..0712813a5e 100644 --- a/rpcs3/Emu/RSX/GL/GLDraw.cpp +++ b/rpcs3/Emu/RSX/GL/GLDraw.cpp @@ -677,7 +677,7 @@ void GLGSRender::end() } while (rsx::method_registers.current_draw_clause.next()); - m_rtts.on_write(m_framebuffer_layout.color_write_enabled.data(), m_framebuffer_layout.zeta_write_enabled); + m_rtts.on_write(m_framebuffer_layout.color_write_enabled, m_framebuffer_layout.zeta_write_enabled); m_attrib_ring_buffer->notify(); m_index_ring_buffer->notify(); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 691ed21721..e96e164cde 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -662,8 +662,7 @@ void GLGSRender::clear_surface(u32 arg) if (update_color || update_z) { - const bool write_all_mask[] = { true, true, true, true }; - m_rtts.on_write(update_color ? write_all_mask : nullptr, update_z); + m_rtts.on_write({ update_color, update_color, update_color, update_color }, update_z); } glClear(mask); diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 5b9a219018..99a546b0e5 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -1116,7 +1116,7 @@ void VKGSRender::end() m_current_command_buffer->flags &= ~(vk::command_buffer::cb_has_conditional_render); } - m_rtts.on_write(m_framebuffer_layout.color_write_enabled.data(), m_framebuffer_layout.zeta_write_enabled); + m_rtts.on_write(m_framebuffer_layout.color_write_enabled, m_framebuffer_layout.zeta_write_enabled); rsx::thread::end(); } diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 0fcce472a3..d3357eb611 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1449,8 +1449,7 @@ void VKGSRender::clear_surface(u32 mask) if (update_color || update_z) { - const bool write_all_mask[] = { true, true, true, true }; - m_rtts.on_write(update_color ? write_all_mask : nullptr, update_z); + m_rtts.on_write({ update_color, update_color, update_color, update_color }, update_z); } if (!clear_descriptors.empty()) diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.cpp b/rpcs3/Emu/RSX/VK/VKRenderTargets.cpp index dad08ae73a..d91d204b8b 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.cpp +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.cpp @@ -772,6 +772,12 @@ namespace vk return this; } + if (access_type == rsx::surface_access::gpu_reference) + { + // WARNING: Can return MSAA data result if no read barrier was issued + return resolve_surface ? resolve_surface.get() : this; + } + // A read barrier should have been called before this! ensure(resolve_surface); // "Read access without explicit barrier" ensure(!(msaa_flags & rsx::surface_state_flags::require_resolve)); @@ -801,9 +807,15 @@ namespace vk { if (!write_barrier_sync_tag) write_barrier_sync_tag++; // Activate barrier sync cyclic_reference_sync_tag = write_barrier_sync_tag; // Match tags + + vk::insert_texture_barrier(cmd, this, VK_IMAGE_LAYOUT_GENERAL); + return; } - vk::insert_texture_barrier(cmd, this, VK_IMAGE_LAYOUT_GENERAL); + if (msaa_flags & rsx::surface_state_flags::require_resolve) + { + resolve(cmd); + } } void render_target::reset_surface_counters()