diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index f74ce65e38..ca9d12dfb0 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -61,14 +61,36 @@ namespace rsx template struct render_target_descriptor { + bool dirty = false; + image_storage_type old_contents = nullptr; + rsx::surface_antialiasing read_aa_mode = rsx::surface_antialiasing::center_1_sample; + GcmTileInfo *tile = nullptr; - rsx::surface_antialiasing aa_mode = rsx::surface_antialiasing::center_1_sample; + rsx::surface_antialiasing write_aa_mode = rsx::surface_antialiasing::center_1_sample; virtual image_storage_type get_surface() = 0; virtual u16 get_surface_width() const = 0; virtual u16 get_surface_height() const = 0; virtual u16 get_rsx_pitch() const = 0; virtual u16 get_native_pitch() const = 0; + + void save_aa_mode() + { + read_aa_mode = write_aa_mode; + write_aa_mode = rsx::surface_antialiasing::center_1_sample; + } + + void reset_aa_mode() + { + write_aa_mode = read_aa_mode = rsx::surface_antialiasing::center_1_sample; + } + + void on_write() + { + read_aa_mode = write_aa_mode; + dirty = false; + old_contents = nullptr; + } }; /** @@ -134,6 +156,7 @@ namespace rsx std::list invalidated_resources; u64 cache_tag = 0ull; + u64 write_tag = 0ull; surface_store() = default; ~surface_store() = default; @@ -175,6 +198,7 @@ namespace rsx surface_storage_type &rtt = It->second; if (Traits::rtt_has_format_width_height(rtt, color_format, width, height)) { + Traits::notify_surface_persist(rtt); Traits::prepare_rtt_for_drawing(command_list, Traits::get(rtt)); return Traits::get(rtt); } @@ -206,7 +230,7 @@ namespace rsx invalidated_resources.erase(It); new_surface = Traits::get(new_surface_storage); - Traits::invalidate_rtt_surface_contents(command_list, new_surface, contents_to_copy, true); + Traits::invalidate_surface_contents(command_list, new_surface, contents_to_copy); Traits::prepare_rtt_for_drawing(command_list, new_surface); break; } @@ -259,6 +283,7 @@ namespace rsx surface_storage_type &ds = It->second; if (Traits::ds_has_format_width_height(ds, depth_format, width, height)) { + Traits::notify_surface_persist(ds); Traits::prepare_ds_for_drawing(command_list, Traits::get(ds)); return Traits::get(ds); } @@ -290,7 +315,7 @@ namespace rsx new_surface = Traits::get(new_surface_storage); Traits::prepare_ds_for_drawing(command_list, new_surface); - Traits::invalidate_depth_surface_contents(command_list, new_surface, contents_to_copy, true); + Traits::invalidate_surface_contents(command_list, new_surface, contents_to_copy); break; } } @@ -527,19 +552,6 @@ namespace rsx return result; } - /** - * Invalidates cached surface data and marks surface contents as deleteable - * Called at the end of a frame (workaround, need to find the proper invalidate command) - */ - void invalidate_surface_cache_data(command_list_type command_list) - { - for (auto &rtt : m_render_targets_storage) - Traits::invalidate_rtt_surface_contents(command_list, Traits::get(std::get<1>(rtt)), nullptr, false); - - for (auto &ds : m_depth_stencil_storage) - Traits::invalidate_depth_surface_contents(command_list, Traits::get(std::get<1>(ds)), nullptr, true); - } - /** * Moves a single surface from surface storage to invalidated surface store. * Can be triggered by the texture cache's blit functionality when formats do not match @@ -653,7 +665,7 @@ namespace rsx bool doubled_x = false; bool doubled_y = false; - switch (surface->aa_mode) + switch (surface->read_aa_mode) { case rsx::surface_antialiasing::square_rotated_4_samples: case rsx::surface_antialiasing::square_centered_4_samples: @@ -741,7 +753,7 @@ namespace rsx u16 real_width = requested_width; u16 real_height = requested_height; - switch (surface->aa_mode) + switch (surface->read_aa_mode) { case rsx::surface_antialiasing::diagonal_centered_2_samples: real_width /= 2; @@ -894,5 +906,26 @@ namespace rsx process_list_function(m_depth_stencil_storage, true); return result; } + + void on_write() + { + if (write_tag == cache_tag) + return; + + for (auto &rtt : m_bound_render_targets) + { + if (auto surface = std::get<1>(rtt)) + { + surface->on_write(); + } + } + + if (auto ds = std::get<1>(m_bound_depth_stencil)) + { + ds->on_write(); + } + + write_tag = cache_tag; + } }; } diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 093055d657..c4e7474466 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -740,7 +740,7 @@ namespace rsx template inline void get_native_dimensions(T &width, T &height, U surface) { - switch (surface->aa_mode) + switch (surface->read_aa_mode) { case rsx::surface_antialiasing::center_1_sample: return; @@ -758,7 +758,7 @@ namespace rsx template inline void get_rsx_dimensions(T &width, T &height, U surface) { - switch (surface->aa_mode) + switch (surface->read_aa_mode) { case rsx::surface_antialiasing::center_1_sample: return; @@ -776,7 +776,7 @@ namespace rsx template inline f32 get_internal_scaling_x(T surface) { - switch (surface->aa_mode) + switch (surface->read_aa_mode) { default: case rsx::surface_antialiasing::center_1_sample: @@ -791,7 +791,7 @@ namespace rsx template inline f32 get_internal_scaling_y(T surface) { - switch (surface->aa_mode) + switch (surface->read_aa_mode) { default: case rsx::surface_antialiasing::center_1_sample: diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h index ef45073680..ecd60addd2 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h @@ -129,21 +129,17 @@ struct render_target_traits } static - void invalidate_rtt_surface_contents( + void invalidate_surface_contents( gsl::not_null, - ID3D12Resource*, ID3D12Resource*, bool) + ID3D12Resource*, ID3D12Resource*) {} static - void invalidate_depth_surface_contents( - gsl::not_null, - ID3D12Resource*, ID3D12Resource*, bool) - { - //TODO - } + void notify_surface_invalidated(const ComPtr&) + {} static - void notify_surface_invalidated(const ComPtr&) + void notify_surface_persist(const ComPtr&) {} static diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 0afbf517e6..5118f83a63 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -214,11 +214,8 @@ void GLGSRender::end() //Copy data from old contents onto this one const auto region = rsx::get_transferable_region(surface); gl::g_hw_blitter->scale_image(surface->old_contents, surface, { 0, 0, std::get<0>(region), std::get<1>(region) }, { 0, 0, std::get<2>(region) , std::get<3>(region) }, !is_depth, is_depth, {}); - surface->set_cleared(); } //TODO: download image contents and reupload them or do a memory cast to copy memory contents if not compatible - - surface->old_contents = nullptr; }; //Check if we have any 'recycled' surfaces in memory and if so, clear them @@ -273,15 +270,12 @@ void GLGSRender::end() if (clear_depth) gl_state.depth_mask(rsx::method_registers.depth_write_enabled()); - - ds->set_cleared(); } - if (ds && ds->old_contents != nullptr && ds->get_rsx_pitch() == ds->old_contents->get_rsx_pitch() && + if (ds && ds->old_contents != nullptr && ds->get_rsx_pitch() == static_cast(ds->old_contents)->get_rsx_pitch() && ds->old_contents->get_internal_format() == gl::texture::internal_format::rgba8) { m_depth_converter.run(ds->width(), ds->height(), ds->id(), ds->old_contents->id()); - ds->old_contents = nullptr; } if (g_cfg.video.strict_rendering_mode) @@ -298,11 +292,6 @@ void GLGSRender::end() } } } - else - { - // Old contents are one use only. Keep the depth conversion check from firing over and over - if (ds) ds->old_contents = nullptr; - } glEnable(GL_SCISSOR_TEST); @@ -571,6 +560,8 @@ void GLGSRender::end() } } + m_rtts.on_write(); + m_attrib_ring_buffer->notify(); m_index_ring_buffer->notify(); m_vertex_state_buffer->notify(); @@ -988,11 +979,9 @@ void GLGSRender::clear_surface(u32 arg) gl_state.clear_depth(f32(clear_depth) / max_depth_value); mask |= GLenum(gl::buffers::depth); - gl::render_target *ds = std::get<1>(m_rtts.m_bound_depth_stencil); - if (ds && !ds->cleared()) + if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) { - ds->set_cleared(); - ds->old_contents = nullptr; + ds->on_write(); } } @@ -1036,10 +1025,9 @@ void GLGSRender::clear_surface(u32 arg) for (auto &rtt : m_rtts.m_bound_render_targets) { - if (std::get<0>(rtt) != 0) + if (auto surface = std::get<1>(rtt)) { - std::get<1>(rtt)->set_cleared(true); - std::get<1>(rtt)->old_contents = nullptr; + surface->on_write(); } } diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp index bac2ce7bbc..6ba91eb980 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp @@ -375,13 +375,13 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk { if (auto surface = std::get<1>(m_rtts.m_bound_render_targets[index])) { - surface->aa_mode = aa_mode; + surface->write_aa_mode = aa_mode; } } if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) { - ds->aa_mode = aa_mode; + ds->write_aa_mode = aa_mode; } return; @@ -426,7 +426,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk m_surface_info[i] = { surface_addresses[i], pitchs[i], false, surface_format, depth_format, clip_horizontal, clip_vertical }; rtt->tile = find_tile(color_offsets[i], color_locations[i]); - rtt->aa_mode = aa_mode; + rtt->write_aa_mode = aa_mode; m_gl_texture_cache.notify_surface_changed(surface_addresses[i]); m_gl_texture_cache.tag_framebuffer(surface_addresses[i]); } @@ -455,7 +455,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk std::get<1>(m_rtts.m_bound_depth_stencil)->set_rsx_pitch(rsx::method_registers.surface_z_pitch()); m_depth_surface_info = { depth_address, depth_surface_pitch, true, surface_format, depth_format, clip_horizontal, clip_vertical }; - ds->aa_mode = aa_mode; + ds->write_aa_mode = aa_mode; m_gl_texture_cache.notify_surface_changed(depth_address); m_gl_texture_cache.tag_framebuffer(depth_address); diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.h b/rpcs3/Emu/RSX/GL/GLRenderTargets.h index 0c5d9dcb7f..8ee0c1471e 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.h +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.h @@ -51,8 +51,6 @@ namespace gl { class render_target : public texture, public rsx::ref_counted, public rsx::render_target_descriptor { - bool is_cleared = false; - u32 rsx_pitch = 0; u16 native_pitch = 0; @@ -65,20 +63,18 @@ namespace gl std::unordered_map> views; public: - render_target *old_contents = nullptr; - render_target(GLuint width, GLuint height, GLenum sized_format) :texture(GL_TEXTURE_2D, width, height, 1, 1, sized_format) {} void set_cleared(bool clear=true) { - is_cleared = clear; + dirty = !clear; } bool cleared() const { - return is_cleared; + return !dirty; } // Internal pitch is the actual row length in bytes of the openGL texture @@ -228,13 +224,24 @@ struct gl_render_target_traits static void prepare_ds_for_drawing(void *, gl::render_target *ds) { ds->reset_refs(); } static void prepare_ds_for_sampling(void *, gl::render_target*) {} - static void invalidate_rtt_surface_contents(void *, gl::render_target *rtt, gl::render_target* /*old*/, bool forced) { if (forced) rtt->set_cleared(false); } - static void invalidate_depth_surface_contents(void *, gl::render_target *ds, gl::render_target* /*old*/, bool) { ds->set_cleared(false); } + static + void invalidate_surface_contents(void *, gl::render_target *surface, gl::render_target* old_surface) + { + surface->set_cleared(false); + surface->old_contents = old_surface; + surface->reset_aa_mode(); + } static void notify_surface_invalidated(const std::unique_ptr&) {} + static + void notify_surface_persist(const std::unique_ptr& surface) + { + surface->save_aa_mode(); + } + static bool rtt_has_format_width_height(const std::unique_ptr &rtt, rsx::surface_color_format format, size_t width, size_t height, bool check_refs=false) { diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 7562b83ead..bd2a1fb981 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -265,7 +265,7 @@ namespace gl if (pbo_id == 0) init_buffer(); - aa_mode = static_cast(image)->aa_mode; + aa_mode = static_cast(image)->read_aa_mode; } flushed = false; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index a3506f845f..3ed4cc81ff 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1115,7 +1115,6 @@ void VKGSRender::end() VkClearValue clear_value = {}; clear_value.depthStencil = { 1.f, 255 }; buffers_to_clear.push_back({ vk::get_aspect_flags(ds->info.format), 0, clear_value }); - ds->dirty = false; } for (u32 index = 0; index < targets.size(); ++index) @@ -1125,7 +1124,6 @@ void VKGSRender::end() if (rtt->dirty) { buffers_to_clear.push_back({ VK_IMAGE_ASPECT_COLOR_BIT, index, {} }); - rtt->dirty = false; } } } @@ -1148,14 +1146,9 @@ void VKGSRender::end() { auto rp = vk::get_render_pass_location(VK_FORMAT_UNDEFINED, ds->info.format, 0); auto render_pass = m_render_passes[rp]; - m_depth_converter->run(*m_current_command_buffer, ds->width(), ds->height(), ds, ds->old_contents->get_view(0xAAE4, rsx::default_remap_vector), render_pass, m_framebuffers_to_clean); - - ds->old_contents = nullptr; - } - else if (!g_cfg.video.strict_rendering_mode) - { - //Clear this to avoid dereferencing stale ptr - ds->old_contents = nullptr; + m_depth_converter->run(*m_current_command_buffer, ds->width(), ds->height(), ds, + static_cast(ds->old_contents)->get_view(0xAAE4, rsx::default_remap_vector), + render_pass, m_framebuffers_to_clean); } } @@ -1187,14 +1180,9 @@ void VKGSRender::end() vk::change_image_layout(*m_current_command_buffer, surface->old_contents, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_depth_scaler->run(*m_current_command_buffer, { 0, 0, (f32)src_w, (f32)src_h }, { 0, 0, (f32)dst_w, (f32)dst_h }, surface, - surface->old_contents, surface->old_contents->get_view(0xAAE4, rsx::default_remap_vector), render_pass, m_framebuffers_to_clean); + surface->old_contents, static_cast(surface->old_contents)->get_view(0xAAE4, rsx::default_remap_vector), render_pass, m_framebuffers_to_clean); } - - surface->dirty = false; } - //TODO: download image contents and reupload them or do a memory cast to copy memory contents if not compatible - - surface->old_contents = nullptr; }; //Prepare surfaces if needed @@ -1519,6 +1507,8 @@ void VKGSRender::end() close_render_pass(); vk::leave_uninterruptible(); + m_rtts.on_write(); + std::chrono::time_point draw_end = steady_clock::now(); m_draw_time += std::chrono::duration_cast(draw_end - textures_end).count(); @@ -1792,10 +1782,9 @@ void VKGSRender::clear_surface(u32 mask) for (auto &rtt : m_rtts.m_bound_render_targets) { - if (std::get<0>(rtt) != 0) + if (auto surface = std::get<1>(rtt)) { - std::get<1>(rtt)->dirty = false; - std::get<1>(rtt)->old_contents = nullptr; + surface->on_write(); } } } @@ -1804,11 +1793,9 @@ void VKGSRender::clear_surface(u32 mask) if (mask & 0x3) { - if (std::get<0>(m_rtts.m_bound_depth_stencil) != 0) + if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) { - std::get<1>(m_rtts.m_bound_depth_stencil)->dirty = false; - std::get<1>(m_rtts.m_bound_depth_stencil)->old_contents = nullptr; - + ds->on_write(); clear_descriptors.push_back({ (VkImageAspectFlags)depth_stencil_mask, 0, depth_stencil_clear_values }); } } @@ -2744,13 +2731,13 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context) { if (auto surface = std::get<1>(m_rtts.m_bound_render_targets[index])) { - surface->aa_mode = aa_mode; + surface->write_aa_mode = aa_mode; } } if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) { - ds->aa_mode = aa_mode; + ds->write_aa_mode = aa_mode; } return; @@ -2820,7 +2807,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context) m_surface_info[index].pitch = surface_pitchs[index]; surface->rsx_pitch = surface_pitchs[index]; - surface->aa_mode = aa_mode; + surface->write_aa_mode = aa_mode; m_texture_cache.notify_surface_changed(surface_addresses[index]); m_texture_cache.tag_framebuffer(surface_addresses[index]); @@ -2837,7 +2824,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context) m_depth_surface_info.pitch = rsx::method_registers.surface_z_pitch(); ds->rsx_pitch = m_depth_surface_info.pitch; - ds->aa_mode = aa_mode; + ds->write_aa_mode = aa_mode; m_texture_cache.notify_surface_changed(zeta_address); m_texture_cache.tag_framebuffer(zeta_address); diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index ec49deec02..232a9cc842 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -12,7 +12,6 @@ namespace vk { struct render_target : public image, public rsx::ref_counted, public rsx::render_target_descriptor { - bool dirty = false; u16 native_pitch = 0; u16 rsx_pitch = 0; @@ -22,7 +21,6 @@ namespace vk VkImageAspectFlags attachment_aspect_flag = VK_IMAGE_ASPECT_COLOR_BIT; std::unordered_map> views; - render_target *old_contents = nullptr; //Data occupying the memory location that this surface is replacing u64 frame_tag = 0; //frame id when invalidated, 0 if not invalid render_target(vk::render_device &dev, @@ -240,19 +238,12 @@ namespace rsx change_image_layout(*pcmd, surface, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range); } - static void invalidate_rtt_surface_contents(vk::command_buffer* /*pcmd*/, vk::render_target *rtt, vk::render_target *old_surface, bool forced) + static + void invalidate_surface_contents(vk::command_buffer* /*pcmd*/, vk::render_target *surface, vk::render_target *old_surface) { - if (forced) - { - rtt->old_contents = old_surface; - rtt->dirty = true; - } - } - - static void invalidate_depth_surface_contents(vk::command_buffer* /*pcmd*/, vk::render_target *ds, vk::render_target *old_surface, bool /*forced*/) - { - ds->dirty = true; - ds->old_contents = old_surface; + surface->old_contents = old_surface; + surface->dirty = true; + surface->reset_aa_mode(); } static @@ -262,6 +253,12 @@ namespace rsx if (!surface->frame_tag) surface->frame_tag = 1; } + static + void notify_surface_persist(const std::unique_ptr &surface) + { + surface->save_aa_mode(); + } + static bool rtt_has_format_width_height(const std::unique_ptr &rtt, surface_color_format format, size_t width, size_t height, bool check_refs=false) { if (check_refs && rtt->deref_count == 0) //Surface may still have read refs from data 'copy' diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 3ca5cda174..fc9a7fff2d 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -296,7 +296,7 @@ namespace vk //Scale image to fit //usually we can just get away with nearest filtering u8 samples_u = 1, samples_v = 1; - switch (static_cast(vram_texture)->aa_mode) + switch (static_cast(vram_texture)->read_aa_mode) { case rsx::surface_antialiasing::diagonal_centered_2_samples: samples_u = 2; diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index 4d3b7401e2..b6d43363a8 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -597,7 +597,7 @@ namespace rsx u16 dst_w = src_w; u16 dst_h = src_h; - switch (surface->old_contents->aa_mode) + switch (static_cast(surface->old_contents)->read_aa_mode) { case rsx::surface_antialiasing::center_1_sample: break; @@ -611,7 +611,7 @@ namespace rsx break; } - switch (surface->aa_mode) + switch (surface->write_aa_mode) { case rsx::surface_antialiasing::center_1_sample: break;