mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-18 05:25:46 -04:00
HostDisplay: Add GPU usage statistics
This commit is contained in:
@ -755,6 +755,13 @@ bool D3D11HostDisplay::Render(bool skip_present)
|
||||
return false;
|
||||
}
|
||||
|
||||
// When using vsync, the time here seems to include the time for the buffer to become available.
|
||||
// This blows our our GPU usage number considerably, so read the timestamp before the final blit
|
||||
// in this configuration. It does reduce accuracy a little, but better than seeing 100% all of
|
||||
// the time, when it's more like a couple of percent.
|
||||
if (m_vsync && m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
||||
static constexpr std::array<float, 4> clear_color = {};
|
||||
m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), clear_color.data());
|
||||
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
|
||||
@ -766,11 +773,17 @@ bool D3D11HostDisplay::Render(bool skip_present)
|
||||
|
||||
RenderSoftwareCursor();
|
||||
|
||||
if (!m_vsync && m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
||||
if (!m_vsync && m_using_allow_tearing)
|
||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
else
|
||||
m_swap_chain->Present(BoolToUInt32(m_vsync), 0);
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
KickTimestampQuery();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -806,7 +819,7 @@ bool D3D11HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
|
||||
{
|
||||
RenderDisplay(left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
}
|
||||
|
||||
@ -851,7 +864,7 @@ void D3D11HostDisplay::RenderDisplay()
|
||||
|
||||
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height,
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, m_display_linear_filtering);
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
@ -864,8 +877,9 @@ void D3D11HostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, v
|
||||
m_context->PSSetShaderResources(0, 1, reinterpret_cast<ID3D11ShaderResourceView**>(&texture_handle));
|
||||
m_context->PSSetSamplers(0, 1, linear_filter ? m_linear_sampler.GetAddressOf() : m_point_sampler.GetAddressOf());
|
||||
|
||||
const float position_adjust = m_display_linear_filtering ? 0.5f : 0.0f;
|
||||
const float size_adjust = m_display_linear_filtering ? 1.0f : 0.0f;
|
||||
const bool linear = IsUsingLinearFiltering();
|
||||
const float position_adjust = linear ? 0.5f : 0.0f;
|
||||
const float size_adjust = linear ? 1.0f : 0.0f;
|
||||
const float uniforms[4] = {
|
||||
(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture_height),
|
||||
@ -1102,7 +1116,7 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta
|
||||
if (!CheckPostProcessingRenderTargets(target_width, target_height))
|
||||
{
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, m_display_linear_filtering);
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1110,7 +1124,7 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta
|
||||
m_context->ClearRenderTargetView(m_post_processing_input_texture.GetD3DRTV(), clear_color.data());
|
||||
m_context->OMSetRenderTargets(1, m_post_processing_input_texture.GetD3DRTVArray(), nullptr);
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, m_display_linear_filtering);
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
|
||||
texture_handle = m_post_processing_input_texture.GetD3DSRV();
|
||||
texture_width = m_post_processing_input_texture.GetWidth();
|
||||
@ -1159,4 +1173,122 @@ void D3D11HostDisplay::ApplyPostProcessingChain(ID3D11RenderTargetView* final_ta
|
||||
m_context->PSSetShaderResources(0, 1, &null_srv);
|
||||
}
|
||||
|
||||
bool 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 false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KickTimestampQuery();
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Log_VerbosePrintf("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)
|
||||
{
|
||||
const float delta = static_cast<float>(static_cast<double>(end - start) / (static_cast<double>(disjoint.Frequency) / 1000.0));
|
||||
m_accumulated_gpu_time += delta;
|
||||
m_read_timestamp_query = (m_read_timestamp_query + 1) % NUM_TIMESTAMP_QUERIES;
|
||||
m_waiting_timestamp_queries--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_timestamp_query_started)
|
||||
{
|
||||
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 || !m_timestamp_queries[0][0] || m_waiting_timestamp_queries == NUM_TIMESTAMP_QUERIES)
|
||||
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;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
if (m_gpu_timing_enabled == enabled)
|
||||
return true;
|
||||
|
||||
m_gpu_timing_enabled = enabled;
|
||||
if (m_gpu_timing_enabled)
|
||||
{
|
||||
if (!CreateTimestampQueries())
|
||||
return false;
|
||||
|
||||
KickTimestampQuery();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyTimestampQueries();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
float D3D11HostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
const float value = m_accumulated_gpu_time;
|
||||
m_accumulated_gpu_time = 0.0f;
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace FrontendCommon
|
||||
|
@ -65,6 +65,9 @@ public:
|
||||
|
||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
bool Render(bool skip_present) override;
|
||||
@ -75,6 +78,7 @@ public:
|
||||
|
||||
protected:
|
||||
static constexpr u32 DISPLAY_UNIFORM_BUFFER_SIZE = 16;
|
||||
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
|
||||
|
||||
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory);
|
||||
|
||||
@ -111,6 +115,11 @@ protected:
|
||||
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
|
||||
u32 target_width, u32 target_height);
|
||||
|
||||
bool CreateTimestampQueries();
|
||||
void DestroyTimestampQueries();
|
||||
void PopTimestampQuery();
|
||||
void KickTimestampQuery();
|
||||
|
||||
ComPtr<ID3D11Device> m_device;
|
||||
ComPtr<ID3D11DeviceContext> m_context;
|
||||
|
||||
@ -140,6 +149,13 @@ protected:
|
||||
PostProcessingChain m_post_processing_chain;
|
||||
D3D11::Texture m_post_processing_input_texture;
|
||||
std::vector<PostProcessingStage> m_post_processing_stages;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace FrontendCommon
|
||||
|
@ -712,7 +712,7 @@ bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
|
||||
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height, 0);
|
||||
RenderDisplay(cmdlist, left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
cmdlist->OMSetRenderTargets(0, nullptr, FALSE, nullptr);
|
||||
@ -728,6 +728,18 @@ bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
|
||||
return m_readback_staging_texture.ReadPixels(0, 0, width, height, out_pixels->data(), stride);
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
g_d3d12_context->SetEnableGPUTiming(enabled);
|
||||
m_gpu_timing_enabled = enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
float D3D12HostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
return g_d3d12_context->GetAndResetAccumulatedGPUTime();
|
||||
}
|
||||
|
||||
void D3D12HostDisplay::RenderImGui(ID3D12GraphicsCommandList* cmdlist)
|
||||
{
|
||||
ImGui::Render();
|
||||
@ -752,7 +764,7 @@ void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist)
|
||||
|
||||
RenderDisplay(cmdlist, left, top, width, height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height,
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
namespace FrontendCommon {
|
||||
|
||||
class D3D12HostDisplay : public HostDisplay
|
||||
class D3D12HostDisplay final : public HostDisplay
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
@ -26,31 +26,31 @@ public:
|
||||
D3D12HostDisplay();
|
||||
~D3D12HostDisplay();
|
||||
|
||||
virtual RenderAPI GetRenderAPI() const override;
|
||||
virtual void* GetRenderDevice() const override;
|
||||
virtual void* GetRenderContext() const override;
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
|
||||
virtual bool HasRenderDevice() const override;
|
||||
virtual bool HasRenderSurface() const override;
|
||||
bool HasRenderDevice() const override;
|
||||
bool HasRenderSurface() const override;
|
||||
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device,
|
||||
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device,
|
||||
bool threaded_presentation) override;
|
||||
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device,
|
||||
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device,
|
||||
bool threaded_presentation) override;
|
||||
virtual void DestroyRenderDevice() override;
|
||||
void DestroyRenderDevice() override;
|
||||
|
||||
virtual bool MakeRenderContextCurrent() override;
|
||||
virtual bool DoneRenderContextCurrent() override;
|
||||
bool MakeRenderContextCurrent() override;
|
||||
bool DoneRenderContextCurrent() override;
|
||||
|
||||
virtual bool ChangeRenderWindow(const WindowInfo& new_wi) override;
|
||||
virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
|
||||
virtual bool SupportsFullscreen() const override;
|
||||
virtual bool IsFullscreen() override;
|
||||
virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override;
|
||||
virtual AdapterAndModeList GetAdapterAndModeList() override;
|
||||
virtual void DestroyRenderSurface() override;
|
||||
bool ChangeRenderWindow(const WindowInfo& new_wi) override;
|
||||
void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
|
||||
bool SupportsFullscreen() const override;
|
||||
bool IsFullscreen() override;
|
||||
bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override;
|
||||
AdapterAndModeList GetAdapterAndModeList() override;
|
||||
void DestroyRenderSurface() override;
|
||||
|
||||
virtual bool SetPostProcessingChain(const std::string_view& config) override;
|
||||
bool SetPostProcessingChain(const std::string_view& config) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
HostDisplayPixelFormat format, const void* data, u32 data_stride,
|
||||
@ -66,12 +66,15 @@ public:
|
||||
|
||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||
|
||||
virtual void SetVSync(bool enabled) override;
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
virtual bool Render(bool skip_present) override;
|
||||
virtual bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
bool Render(bool skip_present) override;
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
protected:
|
||||
|
@ -186,6 +186,13 @@ void ImGuiManager::DrawPerformanceOverlay()
|
||||
#endif
|
||||
}
|
||||
|
||||
if (g_settings.display_show_gpu && g_host_display->IsGPUTimingEnabled())
|
||||
{
|
||||
text.Assign("GPU: ");
|
||||
FormatProcessorStat(text, System::GetGPUUsage(), System::GetGPUAverageTime());
|
||||
DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
|
||||
if (g_settings.display_show_status_indicators)
|
||||
{
|
||||
const bool rewinding = System::IsRewinding();
|
||||
|
@ -178,14 +178,15 @@ void OpenGLHostDisplay::BindDisplayPixelsTexture()
|
||||
{
|
||||
if (m_display_pixels_texture_id == 0)
|
||||
{
|
||||
const bool linear = IsUsingLinearFiltering();
|
||||
glGenTextures(1, &m_display_pixels_texture_id);
|
||||
glBindTexture(GL_TEXTURE_2D, m_display_pixels_texture_id);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_display_linear_filtering ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_display_linear_filtering ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||
m_display_texture_is_linear_filtered = m_display_linear_filtering;
|
||||
m_display_texture_is_linear_filtered = linear;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -195,12 +196,13 @@ void OpenGLHostDisplay::BindDisplayPixelsTexture()
|
||||
|
||||
void OpenGLHostDisplay::UpdateDisplayPixelsTextureFilter()
|
||||
{
|
||||
if (m_display_linear_filtering == m_display_texture_is_linear_filtered)
|
||||
const bool linear = IsUsingLinearFiltering();
|
||||
if (linear == m_display_texture_is_linear_filtered)
|
||||
return;
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_display_linear_filtering ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_display_linear_filtering ? GL_LINEAR : GL_NEAREST);
|
||||
m_display_texture_is_linear_filtered = m_display_linear_filtering;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
m_display_texture_is_linear_filtered = linear;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
|
||||
@ -435,7 +437,7 @@ bool OpenGLHostDisplay::InitializeRenderDevice(std::string_view shader_cache_dir
|
||||
glDebugMessageCallback(GLDebugCallback, nullptr);
|
||||
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
// glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
|
||||
if (!CreateResources())
|
||||
@ -520,8 +522,7 @@ HostDisplay::AdapterAndModeList OpenGLHostDisplay::GetAdapterAndModeList()
|
||||
{
|
||||
for (const GL::Context::FullscreenModeInfo& fmi : m_gl_context->EnumerateFullscreenModes())
|
||||
{
|
||||
aml.fullscreen_modes.push_back(
|
||||
GetFullscreenModeString(fmi.width, fmi.height, fmi.refresh_rate));
|
||||
aml.fullscreen_modes.push_back(GetFullscreenModeString(fmi.width, fmi.height, fmi.refresh_rate));
|
||||
}
|
||||
}
|
||||
|
||||
@ -760,7 +761,14 @@ bool OpenGLHostDisplay::Render(bool skip_present)
|
||||
|
||||
RenderSoftwareCursor();
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
||||
m_gl_context->SwapBuffers();
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
KickTimestampQuery();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -792,7 +800,7 @@ bool OpenGLHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
||||
RenderDisplay(left, height - top - draw_height, draw_width, draw_height, m_display_texture_handle,
|
||||
m_display_texture_width, m_display_texture_height, m_display_texture_view_x,
|
||||
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||
m_display_linear_filtering);
|
||||
IsUsingLinearFiltering());
|
||||
}
|
||||
}
|
||||
|
||||
@ -830,7 +838,7 @@ void OpenGLHostDisplay::RenderDisplay()
|
||||
|
||||
RenderDisplay(left, GetWindowHeight() - top - height, width, height, m_display_texture_handle,
|
||||
m_display_texture_width, m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
static void DrawFullscreenQuadES2(s32 tex_view_x, s32 tex_view_y, s32 tex_view_width, s32 tex_view_height,
|
||||
@ -871,8 +879,9 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh
|
||||
|
||||
if (!m_use_gles2_draw_path)
|
||||
{
|
||||
const float position_adjust = m_display_linear_filtering ? 0.5f : 0.0f;
|
||||
const float size_adjust = m_display_linear_filtering ? 1.0f : 0.0f;
|
||||
const bool linear = IsUsingLinearFiltering();
|
||||
const float position_adjust = linear ? 0.5f : 0.0f;
|
||||
const float size_adjust = linear ? 1.0f : 0.0f;
|
||||
const float flip_adjust = (texture_view_height < 0) ? -1.0f : 1.0f;
|
||||
m_display_program.Uniform4f(
|
||||
0, (static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width),
|
||||
@ -1041,7 +1050,7 @@ void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_
|
||||
{
|
||||
RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture_handle,
|
||||
texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width,
|
||||
texture_view_height, m_display_linear_filtering);
|
||||
texture_view_height, IsUsingLinearFiltering());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1050,7 +1059,7 @@ void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
RenderDisplay(final_left, target_height - final_top - final_height, final_width, final_height, texture_handle,
|
||||
texture_width, texture_height, texture_view_x, texture_view_y, texture_view_width, texture_view_height,
|
||||
m_display_linear_filtering);
|
||||
IsUsingLinearFiltering());
|
||||
|
||||
texture_handle = reinterpret_cast<void*>(static_cast<uintptr_t>(m_post_processing_input_texture.GetGLId()));
|
||||
texture_width = m_post_processing_input_texture.GetWidth();
|
||||
@ -1099,4 +1108,122 @@ void OpenGLHostDisplay::ApplyPostProcessingChain(GLuint final_target, s32 final_
|
||||
m_post_processing_ubo->Unbind();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Log_VerbosePrintf("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);
|
||||
DebugAssert(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--;
|
||||
}
|
||||
|
||||
if (m_timestamp_query_started)
|
||||
{
|
||||
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 || m_waiting_timestamp_queries == NUM_TIMESTAMP_QUERIES)
|
||||
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;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
if (m_gpu_timing_enabled == enabled)
|
||||
return true;
|
||||
|
||||
if (enabled && m_gl_context->IsGLES() && !GLAD_GL_EXT_disjoint_timer_query)
|
||||
return false;
|
||||
|
||||
m_gpu_timing_enabled = enabled;
|
||||
if (m_gpu_timing_enabled)
|
||||
CreateTimestampQueries();
|
||||
else
|
||||
DestroyTimestampQueries();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float OpenGLHostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
const float value = m_accumulated_gpu_time;
|
||||
m_accumulated_gpu_time = 0.0f;
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace FrontendCommon
|
||||
|
@ -62,7 +62,12 @@ public:
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
protected:
|
||||
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
|
||||
|
||||
const char* GetGLSLVersionString() const;
|
||||
std::string GetGLSLVersionHeader() const;
|
||||
|
||||
@ -98,6 +103,11 @@ protected:
|
||||
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, u32 target_width,
|
||||
u32 target_height);
|
||||
|
||||
void CreateTimestampQueries();
|
||||
void DestroyTimestampQueries();
|
||||
void PopTimestampQuery();
|
||||
void KickTimestampQuery();
|
||||
|
||||
std::unique_ptr<GL::Context> m_gl_context;
|
||||
|
||||
GL::Program m_display_program;
|
||||
@ -118,6 +128,13 @@ protected:
|
||||
std::unique_ptr<GL::StreamBuffer> m_post_processing_ubo;
|
||||
std::vector<PostProcessingStage> m_post_processing_stages;
|
||||
|
||||
std::array<GLuint, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
|
||||
float m_accumulated_gpu_time = 0.0f;
|
||||
u8 m_read_timestamp_query = 0;
|
||||
u8 m_write_timestamp_query = 0;
|
||||
u8 m_waiting_timestamp_queries = 0;
|
||||
bool m_timestamp_query_started = false;
|
||||
|
||||
bool m_display_texture_is_linear_filtered = false;
|
||||
bool m_use_gles2_draw_path = false;
|
||||
bool m_use_pbo_for_pixels = false;
|
||||
|
@ -732,7 +732,7 @@ bool VulkanHostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>
|
||||
BeginSwapChainRenderPass(fb, width, height);
|
||||
RenderDisplay(left, top, draw_width, draw_height, m_display_texture_handle, m_display_texture_width,
|
||||
m_display_texture_height, m_display_texture_view_x, m_display_texture_view_y,
|
||||
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
|
||||
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
@ -789,7 +789,7 @@ void VulkanHostDisplay::RenderDisplay()
|
||||
BeginSwapChainRenderPass(m_swap_chain->GetCurrentFramebuffer(), m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
|
||||
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height,
|
||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||
m_display_texture_view_height, m_display_linear_filtering);
|
||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height, void* texture_handle, u32 texture_width,
|
||||
@ -816,8 +816,8 @@ void VulkanHostDisplay::RenderDisplay(s32 left, s32 top, s32 width, s32 height,
|
||||
dsupdate.Update(g_vulkan_context->GetDevice());
|
||||
}
|
||||
|
||||
const float position_adjust = m_display_linear_filtering ? 0.5f : 0.0f;
|
||||
const float size_adjust = m_display_linear_filtering ? 1.0f : 0.0f;
|
||||
const float position_adjust = IsUsingLinearFiltering() ? 0.5f : 0.0f;
|
||||
const float size_adjust = IsUsingLinearFiltering() ? 1.0f : 0.0f;
|
||||
const PushConstants pc{(static_cast<float>(texture_view_x) + position_adjust) / static_cast<float>(texture_width),
|
||||
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture_height),
|
||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width),
|
||||
@ -874,6 +874,22 @@ void VulkanHostDisplay::RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 h
|
||||
vkCmdDraw(cmdbuffer, 3, 1, 0, 0);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
if (g_vulkan_context->SetEnableGPUTiming(enabled))
|
||||
{
|
||||
m_gpu_timing_enabled = enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float VulkanHostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
{
|
||||
return g_vulkan_context->GetAndResetAccumulatedGPUTime();
|
||||
}
|
||||
|
||||
HostDisplay::AdapterAndModeList VulkanHostDisplay::StaticGetAdapterAndModeList(const WindowInfo* wi)
|
||||
{
|
||||
AdapterAndModeList ret;
|
||||
@ -907,8 +923,7 @@ HostDisplay::AdapterAndModeList VulkanHostDisplay::StaticGetAdapterAndModeList(c
|
||||
ret.fullscreen_modes.reserve(fsmodes.size());
|
||||
for (const Vulkan::SwapChain::FullscreenModeInfo& fmi : fsmodes)
|
||||
{
|
||||
ret.fullscreen_modes.push_back(
|
||||
GetFullscreenModeString(fmi.width, fmi.height, fmi.refresh_rate));
|
||||
ret.fullscreen_modes.push_back(GetFullscreenModeString(fmi.width, fmi.height, fmi.refresh_rate));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1096,7 +1111,7 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
||||
{
|
||||
BeginSwapChainRenderPass(target_fb, target_width, target_height);
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, m_display_linear_filtering);
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1104,7 +1119,7 @@ void VulkanHostDisplay::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fi
|
||||
m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
BeginSwapChainRenderPass(m_post_processing_input_framebuffer, target_width, target_height);
|
||||
RenderDisplay(final_left, final_top, final_width, final_height, texture_handle, texture_width, texture_height,
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, m_display_linear_filtering);
|
||||
texture_view_x, texture_view_y, texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||
vkCmdEndRenderPass(cmdbuffer);
|
||||
Vulkan::Util::EndDebugScope(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
m_post_processing_input_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
@ -67,6 +67,9 @@ public:
|
||||
bool RenderScreenshot(u32 width, u32 height, std::vector<u32>* out_pixels, u32* out_stride,
|
||||
HostDisplayPixelFormat* out_format) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList(const WindowInfo* wi);
|
||||
|
||||
protected:
|
||||
|
Reference in New Issue
Block a user