diff options
Diffstat (limited to 'gsk/gl/gskglprofiler.c')
-rw-r--r-- | gsk/gl/gskglprofiler.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/gsk/gl/gskglprofiler.c b/gsk/gl/gskglprofiler.c new file mode 100644 index 0000000000..9b834e5fc8 --- /dev/null +++ b/gsk/gl/gskglprofiler.c @@ -0,0 +1,181 @@ +#include "config.h" + +#include "gskglprofilerprivate.h" + +#include <epoxy/gl.h> + +#define N_QUERIES 4 + +struct _GskGLProfiler +{ + GObject parent_instance; + + GdkGLContext *gl_context; + + /* 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_queries : 1; + gboolean has_timer : 1; + gboolean first_frame : 1; +}; + +enum { + PROP_GL_CONTEXT = 1, + + N_PROPERTIES +}; + +static GParamSpec *gsk_gl_profiler_properties[N_PROPERTIES]; + +G_DEFINE_TYPE (GskGLProfiler, gsk_gl_profiler, G_TYPE_OBJECT) + +static void +gsk_gl_profiler_finalize (GObject *gobject) +{ + GskGLProfiler *self = GSK_GL_PROFILER (gobject); + + if (self->has_queries) + glDeleteQueries (N_QUERIES, self->gl_queries); + + g_clear_object (&self->gl_context); + + G_OBJECT_CLASS (gsk_gl_profiler_parent_class)->finalize (gobject); +} + +static void +gsk_gl_profiler_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GskGLProfiler *self = GSK_GL_PROFILER (gobject); + + switch (prop_id) + { + case PROP_GL_CONTEXT: + self->gl_context = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + } +} + +static void +gsk_gl_profiler_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GskGLProfiler *self = GSK_GL_PROFILER (gobject); + + switch (prop_id) + { + case PROP_GL_CONTEXT: + g_value_set_object (value, self->gl_context); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + } +} + +static void +gsk_gl_profiler_class_init (GskGLProfilerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = gsk_gl_profiler_set_property; + gobject_class->get_property = gsk_gl_profiler_get_property; + gobject_class->finalize = gsk_gl_profiler_finalize; + + gsk_gl_profiler_properties[PROP_GL_CONTEXT] = + g_param_spec_object ("gl-context", + "GL Context", + "The GdkGLContext used by the GL profiler", + GDK_TYPE_GL_CONTEXT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, N_PROPERTIES, gsk_gl_profiler_properties); +} + +static void +gsk_gl_profiler_init (GskGLProfiler *self) +{ + self->has_queries = epoxy_is_desktop_gl(); + self->has_timer = epoxy_is_desktop_gl() && (epoxy_gl_version () >= 33 || epoxy_has_gl_extension ("GL_ARB_timer_query")); + + if (!self->has_queries) + return; + + glGenQueries (N_QUERIES, self->gl_queries); + self->first_frame = TRUE; +} + +GskGLProfiler * +gsk_gl_profiler_new (GdkGLContext *context) +{ + g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL); + + return g_object_new (GSK_TYPE_GL_PROFILER, "gl-context", context, 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 || !profiler->has_queries) + 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 || !profiler->has_queries) + 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 / 1000; /* Convert to usec to match other profiler APIs */ +} |