Skip to content

Instantly share code, notes, and snippets.

@rbnelr
Created August 23, 2021 15:20
Show Gist options
  • Save rbnelr/d9ac1831b9e5a7fddfa864d70c2f2416 to your computer and use it in GitHub Desktop.
Save rbnelr/d9ac1831b9e5a7fddfa864d70c2f2416 to your computer and use it in GitHub Desktop.
#if RENDERER_PROFILING
template <int N=4>
struct TimerZone {
int next = 0; // next timer to be used for measurement
int count = 0; // number of timers 'buffered', ie measurement was started by result not read yet
GLuint queries[N];
TimerZone () {
glGenQueries(N, queries);
// could check the timer res here, but not sure what to do if it ever overflowed, just ignore since it's only for profiling anyway
//GLint bits;
//glGetQueryiv(GL_TIME_ELAPSED, GL_QUERY_COUNTER_BITS, &bits);
}
~TimerZone () {
glDeleteQueries(N, queries);
}
// always call end() after start() and never call read_seconds inbetween
void start () {
glBeginQuery(GL_TIME_ELAPSED, queries[next]);
}
void end () {
glEndQuery(GL_TIME_ELAPSED);
next = (next + 1) % N;
count++;
}
// try to read oldest timing
// returns false if it is still not ready to be read
// returns true if result was ready, result in out_seconds
// in case that a result takes so long to be readable (or you don't read them)
// timers will start to be reused, thus overwriting results
// in the case that this happend count will become larger than N and this function will return 'fake' 0 results
bool read_seconds (float* out_seconds) {
if (count == 0) return false;
if (count > N) {
// we overflowed our buffer, so this sample is overwritten, return 0 dummy value
count--; // pop timing
*out_seconds = 0;
return true;
}
int idx = (next + N - count) % N;
ZoneScoped;
GLint avail;
glGetQueryObjectiv(queries[idx], GL_QUERY_RESULT_AVAILABLE, &avail);
if (avail == 0) return false;
count--; // pop timing
uint64_t elapsed_ns = 99;
glGetQueryObjectui64v(queries[idx], GL_QUERY_RESULT, &elapsed_ns);
*out_seconds = (float)elapsed_ns * (1.0f / NSEC);
return true;
}
};
struct TimerZoneScoped {
TimerZone<>& zone;
TimerZoneScoped (TimerZone<>& zone): zone{zone} {
zone.start();
}
~TimerZoneScoped () {
zone.end();
}
};
#define OGL_TIMER(name) TimerZone<> name
#define OGL_TIMER_ZONE(zone) TimerZoneScoped __scoped_glzone_##__COUNTER__(zone)
#else
#define OGL_TIMER(name)
#define OGL_TIMER_ZONE(zone)
#endif
// somewhere start of frame
TimerZone<> timer_rt;
float seconds;
while (timer_rt.read_seconds(&seconds))
histo_rt.push_timing(seconds);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment