forked from AuroraMiddleware/gtk
30be7bd543
We can use the GL_ARB_timer_query extension (available since OpenGL 3.2, and part of the OpenGL specification since version 3.3) to query the time elapsed when drawing each frame. This allows us to gather timing information on our use of the GPU.
109 lines
2.3 KiB
C
109 lines
2.3 KiB
C
#include "config.h"
|
|
|
|
#include "gskglprofilerprivate.h"
|
|
|
|
#include <epoxy/gl.h>
|
|
|
|
#define N_QUERIES 4
|
|
|
|
struct _GskGLProfiler
|
|
{
|
|
GObject parent_instance;
|
|
|
|
/* Creating GL queries is kind of expensive, so we pay the
|
|
* price upfront and create a circular buffer of queries
|
|
*/
|
|
GLuint gl_queries[N_QUERIES];
|
|
GLuint active_query;
|
|
|
|
gboolean has_timer : 1;
|
|
gboolean first_frame : 1;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GskGLProfiler, gsk_gl_profiler, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
gsk_gl_profiler_finalize (GObject *gobject)
|
|
{
|
|
GskGLProfiler *self = GSK_GL_PROFILER (gobject);
|
|
|
|
glDeleteQueries (N_QUERIES, self->gl_queries);
|
|
|
|
G_OBJECT_CLASS (gsk_gl_profiler_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static void
|
|
gsk_gl_profiler_class_init (GskGLProfilerClass *klass)
|
|
{
|
|
G_OBJECT_CLASS (klass)->finalize = gsk_gl_profiler_finalize;
|
|
}
|
|
|
|
static void
|
|
gsk_gl_profiler_init (GskGLProfiler *self)
|
|
{
|
|
glGenQueries (N_QUERIES, self->gl_queries);
|
|
|
|
self->first_frame = TRUE;
|
|
self->has_timer = epoxy_has_gl_extension ("GL_ARB_timer_query");
|
|
}
|
|
|
|
GskGLProfiler *
|
|
gsk_gl_profiler_new (void)
|
|
{
|
|
return g_object_new (GSK_TYPE_GL_PROFILER, NULL);
|
|
}
|
|
|
|
void
|
|
gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler)
|
|
{
|
|
GLuint query_id;
|
|
|
|
g_return_if_fail (GSK_IS_GL_PROFILER (profiler));
|
|
|
|
if (!profiler->has_timer)
|
|
return;
|
|
|
|
query_id = profiler->gl_queries[profiler->active_query];
|
|
glBeginQuery (GL_TIME_ELAPSED, query_id);
|
|
}
|
|
|
|
guint64
|
|
gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler)
|
|
{
|
|
GLuint last_query_id;
|
|
GLint res;
|
|
GLuint64 elapsed;
|
|
|
|
g_return_val_if_fail (GSK_IS_GL_PROFILER (profiler), 0);
|
|
|
|
if (!profiler->has_timer)
|
|
return 0;
|
|
|
|
glEndQuery (GL_TIME_ELAPSED);
|
|
|
|
if (profiler->active_query == 0)
|
|
last_query_id = N_QUERIES - 1;
|
|
else
|
|
last_query_id = profiler->active_query - 1;
|
|
|
|
/* Advance iterator */
|
|
profiler->active_query += 1;
|
|
if (profiler->active_query == N_QUERIES)
|
|
profiler->active_query = 0;
|
|
|
|
/* If this is the first frame we already have a result */
|
|
if (profiler->first_frame)
|
|
{
|
|
profiler->first_frame = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
glGetQueryObjectiv (profiler->gl_queries[last_query_id], GL_QUERY_RESULT_AVAILABLE, &res);
|
|
if (res == 1)
|
|
glGetQueryObjectui64v (profiler->gl_queries[last_query_id], GL_QUERY_RESULT, &elapsed);
|
|
else
|
|
elapsed = 0;
|
|
|
|
return elapsed;
|
|
}
|