PerformanceMetrics: Add GPU time

This commit is contained in:
Connor McLaughlin 2022-03-11 22:05:38 +10:00 committed by refractionpcsx2
parent 206f80c5f4
commit 8e08cd772b
20 changed files with 442 additions and 4 deletions

View File

@ -621,6 +621,9 @@ namespace Vulkan
vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue);
}
m_gpu_timing_supported = (queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0);
DevCon.WriteLn("GPU timing is %s", m_gpu_timing_supported ? "supported" : "not supported");
ProcessDeviceExtensions();
return true;
}
@ -823,11 +826,30 @@ namespace Vulkan
return false;
}
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_global_descriptor_pool, "Global Descriptor Pool");
if (m_gpu_timing_supported)
{
const VkQueryPoolCreateInfo query_create_info = {VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, nullptr,
0, VK_QUERY_TYPE_TIMESTAMP, NUM_COMMAND_BUFFERS * 2, 0};
res = vkCreateQueryPool(m_device, &query_create_info, nullptr, &m_timestamp_query_pool);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateQueryPool failed: ");
return false;
}
}
return true;
}
void Context::DestroyGlobalDescriptorPool()
{
if (m_timestamp_query_pool != VK_NULL_HANDLE)
{
vkDestroyQueryPool(m_device, m_timestamp_query_pool, nullptr);
m_timestamp_query_pool = VK_NULL_HANDLE;
}
if (m_global_descriptor_pool != VK_NULL_HANDLE)
{
vkDestroyDescriptorPool(m_device, m_global_descriptor_pool, nullptr);
@ -920,6 +942,18 @@ namespace Vulkan
vkDeviceWaitIdle(m_device);
}
float Context::GetAndResetAccumulatedGPUTime()
{
const float time = m_accumulated_gpu_time;
m_accumulated_gpu_time = 0.0f;
return time;
}
void Context::SetEnableGPUTiming(bool enabled)
{
m_gpu_timing_enabled = enabled && m_gpu_timing_supported;
}
void Context::WaitForCommandBufferCompletion(u32 index)
{
// Wait for this command buffer to be completed.
@ -968,6 +1002,11 @@ namespace Vulkan
}
}
if (m_gpu_timing_enabled)
{
vkCmdWriteTimestamp(m_current_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool, m_current_frame * 2 + 1);
}
res = vkEndCommandBuffer(resources.command_buffers[1]);
if (res != VK_SUCCESS)
{
@ -1145,6 +1184,29 @@ namespace Vulkan
// using the lower 32 bits of the fence index should be sufficient here, I hope...
vmaSetCurrentFrameIndex(m_allocator, static_cast<u32>(m_next_fence_counter));
if (m_gpu_timing_enabled)
{
std::array<u64, 2> timestamps;
res = vkGetQueryPoolResults(m_device, m_timestamp_query_pool, index * 2, static_cast<u32>(timestamps.size()),
sizeof(u64) * timestamps.size(), timestamps.data(), sizeof(u64), VK_QUERY_RESULT_64_BIT);
if (res == VK_SUCCESS)
{
// if we didn't write the timestamp at the start of the cmdbuffer (just enabled timing), the first TS will be zero
if (timestamps[0] > 0)
{
const u64 ns_diff = (timestamps[1] - timestamps[0]) * static_cast<u64>(m_device_properties.limits.timestampPeriod);
m_accumulated_gpu_time += static_cast<double>(ns_diff) / 1000000.0;
}
}
else
{
LOG_VULKAN_ERROR(res, "vkGetQueryPoolResults failed: ");
}
vkCmdResetQueryPool(m_current_command_buffer, m_timestamp_query_pool, index * 2, 2);
vkCmdWriteTimestamp(m_current_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool, index * 2);
}
}
void Context::ExecuteCommandBuffer(bool wait_for_completion)

View File

@ -208,6 +208,9 @@ namespace Vulkan
void WaitForGPUIdle();
float GetAndResetAccumulatedGPUTime();
void SetEnableGPUTiming(bool enabled);
private:
Context(VkInstance instance, VkPhysicalDevice physical_device);
@ -284,14 +287,19 @@ namespace Vulkan
VkDescriptorPool m_global_descriptor_pool = VK_NULL_HANDLE;
VkQueue m_graphics_queue = VK_NULL_HANDLE;
u32 m_graphics_queue_family_index = 0;
VkQueue m_present_queue = VK_NULL_HANDLE;
u32 m_graphics_queue_family_index = 0;
u32 m_present_queue_family_index = 0;
VkQueryPool m_timestamp_query_pool = VK_NULL_HANDLE;
float m_accumulated_gpu_time = 0.0f;
bool m_gpu_timing_enabled = false;
bool m_gpu_timing_supported = false;
std::array<FrameResources, NUM_COMMAND_BUFFERS> m_frame_resources;
u64 m_next_fence_counter = 1;
u64 m_completed_fence_counter = 0;
u32 m_current_frame;
u32 m_current_frame = 0;
StreamBuffer m_texture_upload_buffer;

View File

@ -104,6 +104,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowSpeed, "EmuCore/GS", "OsdShowSpeed", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowFPS, "EmuCore/GS", "OsdShowFPS", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowCPU, "EmuCore/GS", "OsdShowCPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowGPU, "EmuCore/GS", "OsdShowGPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowResolution, "EmuCore/GS", "OsdShowResolution", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowGSStats, "EmuCore/GS", "OsdShowGSStats", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowIndicators, "EmuCore/GS", "OsdShowIndicators", true);

View File

@ -929,13 +929,20 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="osdShowGPU">
<property name="text">
<string>Show GPU Usage</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="osdShowGSStats">
<property name="text">
<string>Show Statistics</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="3" column="1">
<widget class="QCheckBox" name="osdShowIndicators">
<property name="text">
<string>Show Indicators</string>

View File

@ -428,6 +428,7 @@ struct Pcsx2Config
OsdShowSpeed : 1,
OsdShowFPS : 1,
OsdShowCPU : 1,
OsdShowGPU : 1,
OsdShowResolution : 1,
OsdShowGSStats : 1,
OsdShowIndicators : 1;

View File

@ -742,11 +742,122 @@ void D3D11HostDisplay::EndPresent()
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
if (m_gpu_timing_enabled)
PopTimestampQuery();
const UINT vsync_rate = static_cast<UINT>(m_vsync_mode != VsyncMode::Off);
if (vsync_rate == 0 && m_using_allow_tearing)
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
else
m_swap_chain->Present(vsync_rate, 0);
if (m_gpu_timing_enabled)
KickTimestampQuery();
}
void D3D11HostDisplay::CreateTimestampQueries()
{
for (u32 i = 0; i < NUM_TIMESTAMP_QUERIES; i++)
{
for (u32 j = 0; j < 3; j++)
{
const CD3D11_QUERY_DESC qdesc((j == 0) ? D3D11_QUERY_TIMESTAMP_DISJOINT : D3D11_QUERY_TIMESTAMP);
const HRESULT hr = m_device->CreateQuery(&qdesc, m_timestamp_queries[i][j].ReleaseAndGetAddressOf());
if (FAILED(hr))
{
m_timestamp_queries = {};
return;
}
}
}
KickTimestampQuery();
}
void D3D11HostDisplay::DestroyTimestampQueries()
{
if (!m_timestamp_queries[0][0])
return;
if (m_timestamp_query_started)
m_context->End(m_timestamp_queries[m_write_timestamp_query][1].Get());
m_timestamp_queries = {};
m_read_timestamp_query = 0;
m_write_timestamp_query = 0;
m_waiting_timestamp_queries = 0;
m_timestamp_query_started = 0;
}
void D3D11HostDisplay::PopTimestampQuery()
{
while (m_waiting_timestamp_queries > 0)
{
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjoint;
const HRESULT disjoint_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][0].Get(), &disjoint, sizeof(disjoint), D3D11_ASYNC_GETDATA_DONOTFLUSH);
if (disjoint_hr != S_OK)
break;
if (disjoint.Disjoint)
{
DevCon.WriteLn("GPU timing disjoint, resetting.");
m_read_timestamp_query = 0;
m_write_timestamp_query = 0;
m_waiting_timestamp_queries = 0;
m_timestamp_query_started = 0;
}
else
{
u64 start = 0, end = 0;
const HRESULT start_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][1].Get(), &start, sizeof(start), D3D11_ASYNC_GETDATA_DONOTFLUSH);
const HRESULT end_hr = m_context->GetData(m_timestamp_queries[m_read_timestamp_query][2].Get(), &end, sizeof(end), D3D11_ASYNC_GETDATA_DONOTFLUSH);
if (start_hr == S_OK && end_hr == S_OK)
{
m_accumulated_gpu_time += static_cast<float>(static_cast<double>(end - start) / (static_cast<double>(disjoint.Frequency) / 1000.0));
m_read_timestamp_query = (m_read_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
m_waiting_timestamp_queries--;
}
}
}
// delay ending the current query until we've read back some
if (m_timestamp_query_started && m_waiting_timestamp_queries < (NUM_TIMESTAMP_QUERIES - 1))
{
m_context->End(m_timestamp_queries[m_write_timestamp_query][2].Get());
m_context->End(m_timestamp_queries[m_write_timestamp_query][0].Get());
m_write_timestamp_query = (m_write_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
m_timestamp_query_started = false;
m_waiting_timestamp_queries++;
}
}
void D3D11HostDisplay::KickTimestampQuery()
{
if (m_timestamp_query_started)
return;
m_context->Begin(m_timestamp_queries[m_write_timestamp_query][0].Get());
m_context->End(m_timestamp_queries[m_write_timestamp_query][1].Get());
m_timestamp_query_started = true;
}
void D3D11HostDisplay::SetGPUTimingEnabled(bool enabled)
{
if (m_gpu_timing_enabled == enabled)
return;
m_gpu_timing_enabled = enabled;
if (m_gpu_timing_enabled)
CreateTimestampQueries();
else
DestroyTimestampQueries();
}
float D3D11HostDisplay::GetAndResetAccumulatedGPUTime()
{
const float value = m_accumulated_gpu_time;
m_accumulated_gpu_time = 0.0f;
return value;
}
HostDisplay::AdapterAndModeList D3D11HostDisplay::StaticGetAdapterAndModeList()

View File

@ -17,6 +17,7 @@
#include "HostDisplay.h"
#include "common/RedtapeWindows.h"
#include "common/WindowInfo.h"
#include <array>
#include <d3d11.h>
#include <dxgi.h>
#include <memory>
@ -68,10 +69,14 @@ public:
bool BeginPresent(bool frame_skip) override;
void EndPresent() override;
void SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override;
static AdapterAndModeList StaticGetAdapterAndModeList();
protected:
static constexpr u32 DISPLAY_CONSTANT_BUFFER_SIZE = 16;
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory);
@ -82,6 +87,11 @@ protected:
bool CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode);
bool CreateSwapChainRTV();
void CreateTimestampQueries();
void DestroyTimestampQueries();
void PopTimestampQuery();
void KickTimestampQuery();
ComPtr<ID3D11Device> m_device;
ComPtr<ID3D11DeviceContext> m_context;
@ -92,5 +102,13 @@ protected:
bool m_allow_tearing_supported = false;
bool m_using_flip_model_swap_chain = true;
bool m_using_allow_tearing = false;
std::array<std::array<ComPtr<ID3D11Query>, 3>, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
u8 m_read_timestamp_query = 0;
u8 m_write_timestamp_query = 0;
u8 m_waiting_timestamp_queries = 0;
bool m_timestamp_query_started = false;
float m_accumulated_gpu_time = 0.0f;
bool m_gpu_timing_enabled = false;
};

View File

@ -610,6 +610,14 @@ static void DrawPerformanceOverlay()
}
}
if (GSConfig.OsdShowGPU)
{
text.Clear();
text.Write("GPU: %.1f%% (%.2fms)", PerformanceMetrics::GetGPUUsage(),
PerformanceMetrics::GetGPUAverageTime());
DRAW_LINE(s_fixed_font, text.c_str(), IM_COL32(255, 255, 255, 255));
}
if (GSConfig.OsdShowIndicators)
{
const bool is_normal_speed = (EmuConfig.GS.LimitScalar == EmuConfig.Framerate.NominalScalar);

View File

@ -374,6 +374,128 @@ void OpenGLHostDisplay::EndPresent()
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
GL::Program::ResetLastProgram();
if (m_gpu_timing_enabled)
PopTimestampQuery();
m_gl_context->SwapBuffers();
if (m_gpu_timing_enabled)
KickTimestampQuery();
}
void OpenGLHostDisplay::CreateTimestampQueries()
{
const bool gles = m_gl_context->IsGLES();
const auto GenQueries = gles ? glGenQueriesEXT : glGenQueries;
GenQueries(static_cast<u32>(m_timestamp_queries.size()), m_timestamp_queries.data());
KickTimestampQuery();
}
void OpenGLHostDisplay::DestroyTimestampQueries()
{
if (m_timestamp_queries[0] == 0)
return;
const bool gles = m_gl_context->IsGLES();
const auto DeleteQueries = gles ? glDeleteQueriesEXT : glDeleteQueries;
if (m_timestamp_query_started)
{
const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
EndQuery(m_timestamp_queries[m_write_timestamp_query]);
}
DeleteQueries(static_cast<u32>(m_timestamp_queries.size()), m_timestamp_queries.data());
m_timestamp_queries.fill(0);
m_read_timestamp_query = 0;
m_write_timestamp_query = 0;
m_waiting_timestamp_queries = 0;
m_timestamp_query_started = false;
}
void OpenGLHostDisplay::PopTimestampQuery()
{
const bool gles = m_gl_context->IsGLES();
if (gles)
{
GLint disjoint = 0;
glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint);
if (disjoint)
{
DevCon.WriteLn("GPU timing disjoint, resetting.");
if (m_timestamp_query_started)
glEndQueryEXT(GL_TIME_ELAPSED);
m_read_timestamp_query = 0;
m_write_timestamp_query = 0;
m_waiting_timestamp_queries = 0;
m_timestamp_query_started = false;
}
}
while (m_waiting_timestamp_queries > 0)
{
const auto GetQueryObjectiv = gles ? glGetQueryObjectivEXT : glGetQueryObjectiv;
const auto GetQueryObjectui64v = gles ? glGetQueryObjectui64vEXT : glGetQueryObjectui64v;
GLint available = 0;
GetQueryObjectiv(m_timestamp_queries[m_read_timestamp_query], GL_QUERY_RESULT_AVAILABLE, &available);
pxAssert(m_read_timestamp_query != m_write_timestamp_query);
if (!available)
break;
u64 result = 0;
GetQueryObjectui64v(m_timestamp_queries[m_read_timestamp_query], GL_QUERY_RESULT, &result);
m_accumulated_gpu_time += static_cast<float>(static_cast<double>(result) / 1000000.0);
m_read_timestamp_query = (m_read_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
m_waiting_timestamp_queries--;
}
// delay ending the current query until we've read back some
if (m_timestamp_query_started && m_waiting_timestamp_queries < (NUM_TIMESTAMP_QUERIES - 1))
{
const auto EndQuery = gles ? glEndQueryEXT : glEndQuery;
EndQuery(GL_TIME_ELAPSED);
m_write_timestamp_query = (m_write_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
m_timestamp_query_started = false;
m_waiting_timestamp_queries++;
}
}
void OpenGLHostDisplay::KickTimestampQuery()
{
if (m_timestamp_query_started)
return;
const bool gles = m_gl_context->IsGLES();
const auto BeginQuery = gles ? glBeginQueryEXT : glBeginQuery;
BeginQuery(GL_TIME_ELAPSED, m_timestamp_queries[m_write_timestamp_query]);
m_timestamp_query_started = true;
}
void OpenGLHostDisplay::SetGPUTimingEnabled(bool enabled)
{
enabled &= (!m_gl_context->IsGLES() || GLAD_GL_EXT_disjoint_timer_query);
if (m_gpu_timing_enabled == enabled)
return;
m_gpu_timing_enabled = enabled;
if (m_gpu_timing_enabled)
CreateTimestampQueries();
else
DestroyTimestampQueries();
}
float OpenGLHostDisplay::GetAndResetAccumulatedGPUTime()
{
const float value = m_accumulated_gpu_time;
m_accumulated_gpu_time = 0.0f;
return value;
}

View File

@ -20,6 +20,8 @@
#include "HostDisplay.h"
#include "common/GL/Context.h"
#include "common/WindowInfo.h"
#include <array>
#include <bitset>
#include <memory>
class OpenGLHostDisplay final : public HostDisplay
@ -60,7 +62,12 @@ public:
bool BeginPresent(bool frame_skip) override;
void EndPresent() override;
void SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override;
protected:
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
const char* GetGLSLVersionString() const;
std::string GetGLSLVersionHeader() const;
@ -70,6 +77,19 @@ protected:
void SetSwapInterval();
void CreateTimestampQueries();
void DestroyTimestampQueries();
void PopTimestampQuery();
void KickTimestampQuery();
std::unique_ptr<GL::Context> m_gl_context;
std::array<GLuint, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
u8 m_read_timestamp_query = 0;
u8 m_write_timestamp_query = 0;
u8 m_waiting_timestamp_queries = 0;
bool m_timestamp_query_started = false;
float m_accumulated_gpu_time = 0.0f;
bool m_gpu_timing_enabled = false;
};

View File

@ -396,6 +396,16 @@ void VulkanHostDisplay::EndPresent()
g_vulkan_context->MoveToNextCommandBuffer();
}
void VulkanHostDisplay::SetGPUTimingEnabled(bool enabled)
{
g_vulkan_context->SetEnableGPUTiming(enabled);
}
float VulkanHostDisplay::GetAndResetAccumulatedGPUTime()
{
return g_vulkan_context->GetAndResetAccumulatedGPUTime();
}
HostDisplay::AdapterAndModeList VulkanHostDisplay::StaticGetAdapterAndModeList(const WindowInfo* wi)
{
AdapterAndModeList ret;

View File

@ -51,6 +51,9 @@ public:
bool BeginPresent(bool frame_skip) override;
void EndPresent() override;
void SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override;
static AdapterAndModeList StaticGetAdapterAndModeList(const WindowInfo* wi);
protected:

View File

@ -147,6 +147,9 @@ void GSclose()
g_gs_device.reset();
}
if (HostDisplay* display = Host::GetHostDisplay(); display)
display->SetGPUTimingEnabled(false);
Host::ReleaseHostDisplay();
}
@ -238,6 +241,7 @@ static bool DoGSOpen(GSRendererType renderer, u8* basemem)
s_gs->SetRegsMem(basemem);
display->SetVSync(EmuConfig.GetEffectiveVsyncMode());
display->SetGPUTimingEnabled(GSConfig.OsdShowGPU);
return true;
}
@ -820,6 +824,12 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
{
s_gs->PurgeTextureCache();
}
if (GSConfig.OsdShowGPU != old_config.OsdShowGPU)
{
if (HostDisplay* display = Host::GetHostDisplay(); display)
display->SetGPUTimingEnabled(GSConfig.OsdShowGPU);
}
}
void GSSwitchRenderer(GSRendererType new_renderer)
@ -1325,6 +1335,7 @@ void GSApp::Init()
m_default_configuration["OsdShowSpeed"] = "0";
m_default_configuration["OsdShowFPS"] = "0";
m_default_configuration["OsdShowCPU"] = "0";
m_default_configuration["OsdShowGPU"] = "0";
m_default_configuration["OsdShowResolution"] = "0";
m_default_configuration["OsdShowGSStats"] = "0";
m_default_configuration["OsdShowIndicators"] = "1";

View File

@ -463,6 +463,9 @@ void GSRenderer::VSync(u32 field, bool registers_written)
}
Host::EndPresentFrame();
if (GSConfig.OsdShowGPU)
PerformanceMetrics::OnGPUPresent(Host::GetHostDisplay()->GetAndResetAccumulatedGPUTime());
}
g_gs_device->RestoreAPIState();

View File

@ -517,6 +517,7 @@ OSDTab::OSDTab(wxWindow* parent)
m_ui.addCheckBox(log_grid, "Show Speed", "OsdShowSpeed", -1);
m_ui.addCheckBox(log_grid, "Show FPS", "OsdShowFPS", -1);
m_ui.addCheckBox(log_grid, "Show CPU Usage", "OsdShowCPU", -1);
m_ui.addCheckBox(log_grid, "Show GPU Usage", "OsdShowGPU", -1);
m_ui.addCheckBox(log_grid, "Show Resolution", "OsdShowResolution", -1);
m_ui.addCheckBox(log_grid, "Show Statistics", "OsdShowGSStats", -1);
m_ui.addCheckBox(log_grid, "Show Indicators", "OsdShowIndicators", -1);

View File

@ -53,6 +53,15 @@ bool HostDisplay::GetHostRefreshRate(float* refresh_rate)
return WindowInfo::QueryRefreshRateForWindow(m_window_info, refresh_rate);
}
void HostDisplay::SetGPUTimingEnabled(bool enabled)
{
}
float HostDisplay::GetAndResetAccumulatedGPUTime()
{
return 0.0f;
}
bool HostDisplay::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate)
{
if (!mode.empty())

View File

@ -133,6 +133,12 @@ public:
/// Returns the effective refresh rate of this display.
virtual bool GetHostRefreshRate(float* refresh_rate);
/// Enables/disables GPU frame timing.
virtual void SetGPUTimingEnabled(bool enabled);
/// Returns the amount of GPU time utilized since the last time this method was called.
virtual float GetAndResetAccumulatedGPUTime();
/// Returns true if it's an OpenGL-based renderer.
bool UsesLowerLeftOrigin() const;

View File

@ -300,6 +300,7 @@ Pcsx2Config::GSOptions::GSOptions()
OsdShowSpeed = false;
OsdShowFPS = false;
OsdShowCPU = false;
OsdShowGPU = false;
OsdShowResolution = false;
OsdShowGSStats = false;
OsdShowIndicators = true;
@ -501,6 +502,7 @@ void Pcsx2Config::GSOptions::ReloadIniSettings()
GSSettingBool(OsdShowSpeed);
GSSettingBool(OsdShowFPS);
GSSettingBool(OsdShowCPU);
GSSettingBool(OsdShowGPU);
GSSettingBool(OsdShowResolution);
GSSettingBool(OsdShowGSStats);
GSSettingBool(OsdShowIndicators);

View File

@ -66,6 +66,11 @@ struct GSSWThreadStats
};
std::vector<GSSWThreadStats> s_gs_sw_threads;
static float s_average_gpu_time = 0.0f;
static float s_accumulated_gpu_time = 0.0f;
static float s_gpu_usage = 0.0f;
static u32 s_presents_since_last_update = 0;
void PerformanceMetrics::Clear()
{
Reset();
@ -83,6 +88,9 @@ void PerformanceMetrics::Clear()
s_vu_thread_usage = 0.0f;
s_vu_thread_time = 0.0f;
s_average_gpu_time = 0.0f;
s_gpu_usage = 0.0f;
s_frame_number = 0;
}
@ -94,6 +102,9 @@ void PerformanceMetrics::Reset()
s_average_frame_time_accumulator = 0.0f;
s_worst_frame_time_accumulator = 0.0f;
s_accumulated_gpu_time = 0.0f;
s_presents_since_last_update = 0;
s_last_update_time.Reset();
s_last_frame_time.Reset();
@ -124,6 +135,9 @@ void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit)
s_average_frame_time = s_average_frame_time_accumulator / static_cast<float>(s_frames_since_last_update);
s_average_frame_time_accumulator = 0.0f;
s_fps = static_cast<float>(s_frames_since_last_update) / time;
s_average_gpu_time = s_accumulated_gpu_time / static_cast<float>(s_frames_since_last_update);
s_gpu_usage = s_accumulated_gpu_time / (time * 10.0f);
s_accumulated_gpu_time = 0.0f;
// prefer privileged register write based framerate detection, it's less likely to have false positives
if (s_gs_privileged_register_writes_since_last_update > 0)
@ -179,6 +193,13 @@ void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit)
s_last_update_time.ResetTo(now_ticks);
s_frames_since_last_update = 0;
s_presents_since_last_update = 0;
}
void PerformanceMetrics::OnGPUPresent(float gpu_time)
{
s_accumulated_gpu_time += gpu_time;
s_presents_since_last_update++;
}
void PerformanceMetrics::SetCPUThreadTimer(Common::ThreadCPUTimer timer)
@ -286,3 +307,13 @@ double PerformanceMetrics::GetGSSWThreadAverageTime(u32 index)
{
return s_gs_sw_threads[index].time;
}
float PerformanceMetrics::GetGPUUsage()
{
return s_gpu_usage;
}
float PerformanceMetrics::GetGPUAverageTime()
{
return s_average_gpu_time;
}

View File

@ -28,6 +28,7 @@ namespace PerformanceMetrics
void Clear();
void Reset();
void Update(bool gs_register_write, bool fb_blit);
void OnGPUPresent(float gpu_time);
/// Sets the EE thread for CPU usage calculations.
void SetCPUThreadTimer(Common::ThreadCPUTimer timer);
@ -60,4 +61,7 @@ namespace PerformanceMetrics
u32 GetGSSWThreadCount();
double GetGSSWThreadUsage(u32 index);
double GetGSSWThreadAverageTime(u32 index);
} // namespace PerformanceMetrics
float GetGPUUsage();
float GetGPUAverageTime();
} // namespace PerformanceMetrics