GL で GPU 時間を計測するためのユーティリティクラスを作ったので載せておきます。
class GpuTimer
{
public:
GpuTimer()
: query_back_buffer_(0)
, query_front_buffer_(1)
{
}
~GpuTimer() throw()
{
DeleteAllQueries();
}
void Start(const char* query_id)
{
int query_index = GetIndex(query_id);
if (query_index == -1)
{
query_index = static_cast<int>(query_ids_.size());
AddQuery(query_id);
}
glBeginQuery(GL_TIME_ELAPSED, queries_[query_back_buffer_][query_index]);
}
void Stop()
{
glEndQuery(GL_TIME_ELAPSED);
}
void ResetAllQueries()
{
for (int query_index = 0, queryCount = GetQueryCount(); query_index < queryCount; ++query_index)
{
glBeginQuery(GL_TIME_ELAPSED, queries_[query_back_buffer_][query_index]);
glEndQuery(GL_TIME_ELAPSED);
}
}
int GetQueryCount() const
{
return static_cast<int>(query_ids_.size());
}
double GetElapsedMilliseconds(int query_index)
{
GLuint64 elapsed_gpu_time;
glGetQueryObjectui64v(queries_[query_front_buffer_][query_index],
GL_QUERY_RESULT, &elapsed_gpu_time);
return elapsed_gpu_time / 1000000.0;
}
void SwapQueryBuffers()
{
if (query_back_buffer_ == 1)
{
query_back_buffer_ = 0;
query_front_buffer_ = 1;
}
else
{
query_back_buffer_ = 1;
query_front_buffer_ = 0;
}
}
const char* GetQueryId(int query_index) const
{
return query_ids_[query_index].data();
}
private:
int GetIndex(const char* query_id) const
{
int query_index = 0;
for (std::vector<std::string>::const_iterator iter = query_ids_.begin(), end = query_ids_.end();
iter != end; ++iter, ++query_index)
{
const std::string* id = &*iter;
if (*id == query_id)
{
return query_index;
}
}
return -1;
}
void AddQuery(const char* query_id)
{
int last_index = static_cast<int>(query_ids_.size());
query_ids_.push_back(query_id);
queries_[query_front_buffer_].push_back(0);
queries_[query_back_buffer_].push_back(0);
glGenQueries(1, &queries_[query_front_buffer_][last_index]);
glGenQueries(1, &queries_[query_back_buffer_][last_index]);
}
void DeleteAllQueries()
{
GLsizei query_count = static_cast<GLsizei>(queries_[query_front_buffer_].size());
glDeleteQueries(query_count, queries_[query_front_buffer_].data());
glDeleteQueries(query_count, queries_[query_back_buffer_].data());
queries_[query_front_buffer_].clear();
queries_[query_back_buffer_].clear();
}
private:
static const int QUERY_BUFFER_COUNT = 2;
std::vector<unsigned int> queries_[QUERY_BUFFER_COUNT];
unsigned int query_back_buffer_;
unsigned int query_front_buffer_;
std::vector<std::string> query_ids_;
};
class ScopedGpuTimeLogger
{
public:
ScopedGpuTimeLogger(GpuTimer& timer, const char* query_id)
: timer_(&timer)
{
timer_->Start(query_id);
}
~ScopedGpuTimeLogger()
{
timer_->Stop();
}
private:
GpuTimer* timer_;
};
使用例
GpuTimer gpu_timer;
{
ScopedGpuTimeLogger scoped_logger(gpu_timer, "GPU time 0");
// 計測したい GPU コマンド
}
{
ScopedGpuTimeLogger scoped_logger(gpu_timer, "GPU time 1");
// 計測したい GPU コマンド
}
for (int query_index = 0, query_count = gpu_timer.GetQueryCount(); query_index < query_count; ++query_index)
{
double elapsed_ms = gpu_timer.GetElapsedMilliseconds(query_index);
printf("%s: %f ms\n", gpu_timer.GetQueryId(query_index), elapsed_ms);
}
gpu_timer.SwapQueryBuffers();
glutSwapBuffers();
参考サイト
http://www.lighthouse3d.com/tutorials/opengl-timer-query/