From 02f887ede0037c4ca30c84ccc5f5b58069da2f5f Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 27 Nov 2016 18:15:02 +1000 Subject: [PATCH] OGL: Add GPUTimer class for measuring execution time of a draw/dispatch --- Source/Core/VideoBackends/OGL/GPUTimer.h | 105 ++++++++++++++++++ Source/Core/VideoBackends/OGL/OGL.vcxproj | 3 +- .../VideoBackends/OGL/OGL.vcxproj.filters | 5 +- .../Core/VideoBackends/OGL/TextureCache.cpp | 12 ++ 4 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 Source/Core/VideoBackends/OGL/GPUTimer.h diff --git a/Source/Core/VideoBackends/OGL/GPUTimer.h b/Source/Core/VideoBackends/OGL/GPUTimer.h new file mode 100644 index 0000000000..50724ab06f --- /dev/null +++ b/Source/Core/VideoBackends/OGL/GPUTimer.h @@ -0,0 +1,105 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Common/GL/GLExtensions/GLExtensions.h" + +#ifndef GL_TIME_ELAPSED +#define GL_TIME_ELAPSED 0x88BF +#endif + +namespace OGL +{ +/* + * This class can be used to measure the time it takes for the GPU to perform a draw call + * or compute dispatch. To use: + * + * - Create an instance of GPUTimer before issuing the draw call. + * (this can be before or after any binding that needs to be done) + * + * - (optionally) call Begin(). This is not needed for a single draw call. + * + * - Issue the draw call or compute dispatch as normal. + * + * - (optionally) call End(). This is not necessary for a single draw call. + * + * - Call GetTime{Seconds,Milliseconds,Nanoseconds} to determine how long the operation + * took to execute on the GPU. + * + * NOTE: When the timer is read back, this will force a GL flush, so the more often a timer is used, + * the larger of a performance impact it will have. Only one timer can be active at any time, due to + * using GL_TIME_ELAPSED. This is not enforced by the class, however. + * + */ +class GPUTimer final +{ +public: + GPUTimer() + { + glGenQueries(1, &m_query_id); + Begin(); + } + + ~GPUTimer() + { + End(); + glDeleteQueries(1, &m_query_id); + } + + void Begin() + { + if (m_started) + glEndQuery(GL_TIME_ELAPSED); + + glBeginQuery(GL_TIME_ELAPSED, m_query_id); + m_started = true; + } + + void End() + { + if (!m_started) + return; + + glEndQuery(GL_TIME_ELAPSED); + m_started = false; + } + + double GetTimeSeconds() + { + GetResult(); + return static_cast(m_result) / 1000000000.0; + } + + double GetTimeMilliseconds() + { + GetResult(); + return static_cast(m_result) / 1000000.0; + } + + u32 GetTimeNanoseconds() + { + GetResult(); + return m_result; + } + +private: + void GetResult() + { + if (m_has_result) + return; + + if (m_started) + End(); + + glGetQueryObjectuiv(m_query_id, GL_QUERY_RESULT, &m_result); + m_has_result = true; + } + + GLuint m_query_id; + GLuint m_result = 0; + bool m_started = false; + bool m_has_result = false; +}; +} // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/OGL.vcxproj b/Source/Core/VideoBackends/OGL/OGL.vcxproj index 0c234a8e71..3b945793a4 100644 --- a/Source/Core/VideoBackends/OGL/OGL.vcxproj +++ b/Source/Core/VideoBackends/OGL/OGL.vcxproj @@ -53,6 +53,7 @@ + @@ -79,4 +80,4 @@ - + \ No newline at end of file diff --git a/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters b/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters index 282934d830..201a4045f8 100644 --- a/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters +++ b/Source/Core/VideoBackends/OGL/OGL.vcxproj.filters @@ -90,8 +90,11 @@ + + GLUtil + - + \ No newline at end of file diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp index 72b04fc5b1..bd6f99b2e8 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp @@ -16,6 +16,7 @@ #include "Common/StringUtil.h" #include "VideoBackends/OGL/FramebufferManager.h" +#include "VideoBackends/OGL/GPUTimer.h" #include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/Render.h" #include "VideoBackends/OGL/SamplerCache.h" @@ -62,6 +63,8 @@ struct TextureDecodingProgramInfo bool valid = false; }; +//#define TIME_TEXTURE_DECODING 1 + static std::map, TextureDecodingProgramInfo> s_texture_decoding_program_info; static std::array s_texture_decoding_buffer_views; @@ -713,6 +716,10 @@ void TextureCache::DecodeTextureOnGPU(TCacheEntryBase* entry, u32 dst_level, con if (iter == s_texture_decoding_program_info.end()) return; +#ifdef TIME_TEXTURE_DECODING + GPUTimer timer; +#endif + // Copy to GPU-visible buffer, aligned to the data type. auto info = iter->second; u32 bytes_per_buffer_elem = @@ -775,5 +782,10 @@ void TextureCache::DecodeTextureOnGPU(TCacheEntryBase* entry, u32 dst_level, con glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT); TextureCache::SetStage(); + +#ifdef TIME_TEXTURE_DECODING + WARN_LOG(VIDEO, "Decode texture format %u size %ux%u took %.4fms", static_cast(format), + width, height, timer.GetTimeMilliseconds()); +#endif } }