diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 0b30149354..86719d843e 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -354,6 +354,10 @@ namespace rsx std::atomic m_unreleased_texture_objects = { 0 }; //Number of invalidated objects not yet freed from memory std::atomic m_texture_memory_in_use = { 0 }; + //Other statistics + std::atomic m_num_flush_requests = { 0 }; + std::atomic m_num_cache_misses = { 0 }; + /* Helpers */ virtual void free_texture_section(section_storage_type&) = 0; virtual image_view_type create_temporary_subresource_view(commandbuffer_type&, image_resource_type* src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h) = 0; @@ -594,6 +598,8 @@ namespace rsx //TODO: Lower severity when successful to keep the cache from overworking record_cache_miss(*tex); } + + m_num_flush_requests++; } } @@ -1073,6 +1079,7 @@ namespace rsx for (auto &tex : data.sections_to_flush) { tex->flush(std::forward(extras)...); + m_num_flush_requests++; } //Restore protection on the sections to reprotect @@ -1098,6 +1105,8 @@ namespace rsx void record_cache_miss(section_storage_type &tex) { + m_num_cache_misses++; + const u32 memory_address = tex.get_section_base(); const u32 memory_size = tex.get_section_size(); const auto fmt = tex.get_format(); @@ -2028,6 +2037,12 @@ namespace rsx } } + void reset_frame_statistics() + { + m_num_flush_requests.store(0u); + m_num_cache_misses.store(0u); + } + virtual const u32 get_unreleased_textures_count() const { return m_unreleased_texture_objects; @@ -2038,6 +2053,17 @@ namespace rsx return m_texture_memory_in_use; } + virtual u32 get_num_flush_requests() const + { + return m_num_flush_requests; + } + + virtual f32 get_cache_miss_ratio() const + { + const auto num_flushes = m_num_flush_requests.load(); + return (num_flushes == 0u) ? 0.f : (f32)m_num_cache_misses.load() / num_flushes; + } + /** * The read only texture invalidate flag is set if a read only texture is trampled by framebuffer memory * If set, all cached read only textures are considered invalid and should be re-fetched from the texture cache diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 312dc61e1d..e881ddbc43 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -1373,8 +1373,11 @@ void GLGSRender::flip(int buffer) auto num_dirty_textures = m_gl_texture_cache.get_unreleased_textures_count(); auto texture_memory_size = m_gl_texture_cache.get_texture_memory_in_use() / (1024 * 1024); + auto num_flushes = m_gl_texture_cache.get_num_flush_requests(); + auto cache_miss_ratio = (u32)ceil(m_gl_texture_cache.get_cache_miss_ratio() * 100); m_text_printer.print_text(0, 108, m_frame->client_width(), m_frame->client_height(), "Unreleased textures: " + std::to_string(num_dirty_textures)); m_text_printer.print_text(0, 126, m_frame->client_width(), m_frame->client_height(), "Texture memory: " + std::to_string(texture_memory_size) + "M"); + m_text_printer.print_text(0, 144, m_frame->client_width(), m_frame->client_height(), "Flush requests: " + std::to_string(num_flushes) + " (" + std::to_string(cache_miss_ratio) + "% hard faults)"); } m_frame->flip(m_context); diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 083324a6d0..83d6bd48c5 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -988,6 +988,7 @@ namespace gl clear_temporary_subresources(); m_temporary_subresource_cache.clear(); + reset_frame_statistics(); } bool blit(rsx::blit_src_info& src, rsx::blit_dst_info& dst, bool linear_interpolate, gl_render_targets& m_rtts) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 56de9572fc..fbf4739e45 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -3144,9 +3144,12 @@ void VKGSRender::flip(int buffer) auto num_dirty_textures = m_texture_cache.get_unreleased_textures_count(); auto texture_memory_size = m_texture_cache.get_texture_memory_in_use() / (1024 * 1024); auto tmp_texture_memory_size = m_texture_cache.get_temporary_memory_in_use() / (1024 * 1024); + auto num_flushes = m_texture_cache.get_num_flush_requests(); + auto cache_miss_ratio = (u32)ceil(m_texture_cache.get_cache_miss_ratio() * 100); m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 126, direct_fbo->width(), direct_fbo->height(), "Unreleased textures: " + std::to_string(num_dirty_textures)); m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 144, direct_fbo->width(), direct_fbo->height(), "Texture cache memory: " + std::to_string(texture_memory_size) + "M"); m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 162, direct_fbo->width(), direct_fbo->height(), "Temporary texture memory: " + std::to_string(tmp_texture_memory_size) + "M"); + m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 180, direct_fbo->width(), direct_fbo->height(), "Flush requests: " + std::to_string(num_flushes) + " (" + std::to_string(cache_miss_ratio) + "% hard faults)"); } vk::change_image_layout(*m_current_command_buffer, target_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, subres); diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index e784ea1289..dd12f7652d 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -987,6 +987,7 @@ namespace vk }); m_temporary_subresource_cache.clear(); + reset_frame_statistics(); } template