mirror of https://github.com/PCSX2/pcsx2.git
PerformanceMetrics: Add GPU time
This commit is contained in:
parent
206f80c5f4
commit
8e08cd772b
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -428,6 +428,7 @@ struct Pcsx2Config
|
|||
OsdShowSpeed : 1,
|
||||
OsdShowFPS : 1,
|
||||
OsdShowCPU : 1,
|
||||
OsdShowGPU : 1,
|
||||
OsdShowResolution : 1,
|
||||
OsdShowGSStats : 1,
|
||||
OsdShowIndicators : 1;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue