diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 0bad51a6e2..5d8afadfc5 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -1370,20 +1370,21 @@ void GLGSRender::flip(int buffer) gl::screen.bind(); glViewport(0, 0, m_frame->client_width(), m_frame->client_height()); - m_text_printer.print_text(0, 0, m_frame->client_width(), m_frame->client_height(), "draw calls: " + std::to_string(m_draw_calls)); - m_text_printer.print_text(0, 18, m_frame->client_width(), m_frame->client_height(), "draw call setup: " + std::to_string(m_begin_time) + "us"); - m_text_printer.print_text(0, 36, m_frame->client_width(), m_frame->client_height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us"); - m_text_printer.print_text(0, 54, m_frame->client_width(), m_frame->client_height(), "textures upload time: " + std::to_string(m_textures_upload_time) + "us"); - m_text_printer.print_text(0, 72, m_frame->client_width(), m_frame->client_height(), "draw call execution: " + std::to_string(m_draw_time) + "us"); + m_text_printer.print_text(0, 0, m_frame->client_width(), m_frame->client_height(), "RSX Load: " + std::to_string(get_load()) + "%"); + m_text_printer.print_text(0, 18, m_frame->client_width(), m_frame->client_height(), "draw calls: " + std::to_string(m_draw_calls)); + m_text_printer.print_text(0, 36, m_frame->client_width(), m_frame->client_height(), "draw call setup: " + std::to_string(m_begin_time) + "us"); + m_text_printer.print_text(0, 54, m_frame->client_width(), m_frame->client_height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us"); + m_text_printer.print_text(0, 72, m_frame->client_width(), m_frame->client_height(), "textures upload time: " + std::to_string(m_textures_upload_time) + "us"); + m_text_printer.print_text(0, 90, m_frame->client_width(), m_frame->client_height(), "draw call execution: " + std::to_string(m_draw_time) + "us"); const auto num_dirty_textures = m_gl_texture_cache.get_unreleased_textures_count(); const auto texture_memory_size = m_gl_texture_cache.get_texture_memory_in_use() / (1024 * 1024); const auto num_flushes = m_gl_texture_cache.get_num_flush_requests(); const auto num_mispredict = m_gl_texture_cache.get_num_cache_mispredictions(); const 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(), fmt::format("Flush requests: %d (%d%% hard faults, %d mispedictions)", num_flushes, cache_miss_ratio, num_mispredict)); + m_text_printer.print_text(0, 126, m_frame->client_width(), m_frame->client_height(), "Unreleased textures: " + std::to_string(num_dirty_textures)); + m_text_printer.print_text(0, 144, m_frame->client_width(), m_frame->client_height(), "Texture memory: " + std::to_string(texture_memory_size) + "M"); + m_text_printer.print_text(0, 162, m_frame->client_width(), m_frame->client_height(), fmt::format("Flush requests: %d (%d%% hard faults, %d mispedictions)", num_flushes, cache_miss_ratio, num_mispredict)); } m_frame->flip(m_context); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 08623b5577..2181b07c23 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -527,12 +527,26 @@ namespace rsx if (put == internal_get || !Emu.IsRunning()) { if (has_deferred_call) + { flush_command_queue(); + } + else if (!performance_counters.FIFO_is_idle) + { + performance_counters.FIFO_idle_timestamp = get_system_time(); + performance_counters.FIFO_is_idle = true; + } do_internal_task(); continue; } + if (performance_counters.FIFO_is_idle) + { + //Update performance counters with time spent in idle mode + performance_counters.FIFO_is_idle = false; + performance_counters.idle_time += (get_system_time() - performance_counters.FIFO_idle_timestamp); + } + //Validate put and get registers //TODO: Who should handle graphics exceptions?? const u32 get_address = RSXIOMem.RealAddr(internal_get); @@ -2027,6 +2041,8 @@ namespace rsx skip_frame = (m_skip_frame_ctr < 0); } + + performance_counters.sampled_frames++; } void thread::check_zcull_status(bool framebuffer_swap, bool force_read) @@ -2223,6 +2239,28 @@ namespace rsx external_interrupt_lock.store(false); } + u32 thread::get_load() + { + //Average load over around 30 frames + if (!performance_counters.last_update_timestamp || performance_counters.sampled_frames > 30) + { + const auto timestamp = get_system_time(); + const auto idle = performance_counters.idle_time.load(); + const auto elapsed = timestamp - performance_counters.last_update_timestamp; + + if (elapsed > idle) + performance_counters.approximate_load = (elapsed - idle) * 100 / elapsed; + else + performance_counters.approximate_load = 0; + + performance_counters.idle_time = 0; + performance_counters.sampled_frames = 0; + performance_counters.last_update_timestamp = timestamp; + } + + return performance_counters.approximate_load; + } + //TODO: Move these helpers into a better class dedicated to shell interface handling (use idm?) //They are not dependent on rsx at all rsx::overlays::save_dialog* thread::shell_open_save_dialog() diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 7645c1fe0b..1da838e34a 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -257,6 +257,18 @@ namespace rsx atomic_t external_interrupt_lock{ false }; atomic_t external_interrupt_ack{ false }; + //performance approximation counters + struct + { + atomic_t idle_time{ 0 }; //Time spent idling in microseconds + u64 last_update_timestamp = 0; //Timestamp of last load update + u64 FIFO_idle_timestamp = 0; //Timestamp of when FIFO queue becomes idle + bool FIFO_is_idle = false; //True if FIFO is in idle state + u32 approximate_load = 0; + u32 sampled_frames = 0; + } + performance_counters; + //native UI interrupts atomic_t native_ui_flip_request{ false }; @@ -510,6 +522,9 @@ namespace rsx void pause(); void unpause(); + //Get RSX approximate load in % + u32 get_load(); + //HLE vsh stuff //TODO: Move into a separate helper virtual rsx::overlays::save_dialog* shell_open_save_dialog(); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index d36faaf7c3..12027840b3 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -3106,12 +3106,13 @@ void VKGSRender::flip(int buffer) if (g_cfg.video.overlay) { - m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 0, direct_fbo->width(), direct_fbo->height(), "draw calls: " + std::to_string(m_draw_calls)); - m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 18, direct_fbo->width(), direct_fbo->height(), "draw call setup: " + std::to_string(m_setup_time) + "us"); - m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 36, direct_fbo->width(), direct_fbo->height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us"); - m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 54, direct_fbo->width(), direct_fbo->height(), "texture upload time: " + std::to_string(m_textures_upload_time) + "us"); - m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 72, direct_fbo->width(), direct_fbo->height(), "draw call execution: " + std::to_string(m_draw_time) + "us"); - m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 90, direct_fbo->width(), direct_fbo->height(), "submit and flip: " + std::to_string(m_flip_time) + "us"); + m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 0, direct_fbo->width(), direct_fbo->height(), "RSX Load: " + std::to_string(get_load()) + "%"); + m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 18, direct_fbo->width(), direct_fbo->height(), "draw calls: " + std::to_string(m_draw_calls)); + m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 36, direct_fbo->width(), direct_fbo->height(), "draw call setup: " + std::to_string(m_setup_time) + "us"); + m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 54, direct_fbo->width(), direct_fbo->height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us"); + m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 72, direct_fbo->width(), direct_fbo->height(), "texture upload time: " + std::to_string(m_textures_upload_time) + "us"); + m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 90, direct_fbo->width(), direct_fbo->height(), "draw call execution: " + std::to_string(m_draw_time) + "us"); + m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 108, direct_fbo->width(), direct_fbo->height(), "submit and flip: " + std::to_string(m_flip_time) + "us"); const auto num_dirty_textures = m_texture_cache.get_unreleased_textures_count(); const auto texture_memory_size = m_texture_cache.get_texture_memory_in_use() / (1024 * 1024); @@ -3119,10 +3120,10 @@ void VKGSRender::flip(int buffer) const auto num_flushes = m_texture_cache.get_num_flush_requests(); const auto num_mispredict = m_texture_cache.get_num_cache_mispredictions(); const 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(), fmt::format("Flush requests: %d (%d%% hard faults, %d mispedictions)", num_flushes, cache_miss_ratio, num_mispredict)); + m_text_writer->print_text(*m_current_command_buffer, *direct_fbo, 0, 144, 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, 162, 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, 180, 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, 198, direct_fbo->width(), direct_fbo->height(), fmt::format("Flush requests: %d (%d%% hard faults, %d mispedictions)", num_flushes, cache_miss_ratio, num_mispredict)); } vk::change_image_layout(*m_current_command_buffer, target_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, present_layout, subres); diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index ace1a0dd0c..549c10c2c9 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -71,10 +71,10 @@ namespace rsx { // todo: LLE: why does this one keep hanging? is it vsh system semaphore? whats actually pushing this to the command buffer?! if (addr == 0x40000030) - break; + return; if (Emu.IsStopped()) - break; + return; const auto tdr = (s64)g_cfg.video.driver_recovery_timeout; if (tdr == 0) @@ -106,6 +106,8 @@ namespace rsx std::this_thread::yield(); } } + + rsx->performance_counters.idle_time += (get_system_time() - start); } void semaphore_release(thread* rsx, u32 _reg, u32 arg) @@ -1024,7 +1026,9 @@ namespace rsx if (expected > time + 1000) { - std::this_thread::sleep_for(std::chrono::milliseconds{static_cast(expected - time) / 1000}); + const auto delay_us = static_cast(expected - time); + std::this_thread::sleep_for(std::chrono::milliseconds{delay_us / 1000}); + rsx->performance_counters.idle_time += delay_us; } } }