OGL: Add GPUTimer class for measuring execution time of a draw/dispatch

This commit is contained in:
Stenzek 2016-11-27 18:15:02 +10:00
parent b01bcb80f4
commit 02f887ede0
4 changed files with 123 additions and 2 deletions

View File

@ -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<double>(m_result) / 1000000000.0;
}
double GetTimeMilliseconds()
{
GetResult();
return static_cast<double>(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

View File

@ -53,6 +53,7 @@
<ItemGroup>
<ClInclude Include="BoundingBox.h" />
<ClInclude Include="FramebufferManager.h" />
<ClInclude Include="GPUTimer.h" />
<ClInclude Include="PerfQuery.h" />
<ClInclude Include="PostProcessing.h" />
<ClInclude Include="ProgramShaderCache.h" />
@ -79,4 +80,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -90,8 +90,11 @@
</ClInclude>
<ClInclude Include="SamplerCache.h" />
<ClInclude Include="VideoBackend.h" />
<ClInclude Include="GPUTimer.h">
<Filter>GLUtil</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
</Project>
</Project>

View File

@ -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<std::pair<u32, u32>, TextureDecodingProgramInfo> s_texture_decoding_program_info;
static std::array<GLuint, TextureConversionShader::BUFFER_FORMAT_COUNT>
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<u32>(format),
width, height, timer.GetTimeMilliseconds());
#endif
}
}