1#include "config.h"
2
3#include "gskglprofilerprivate.h"
4
5#include <epoxy/gl.h>
6
7#define N_QUERIES 4
8
9struct _GskGLProfiler
10{
11 GObject parent_instance;
12
13 GdkGLContext *gl_context;
14
15 /* Creating GL queries is kind of expensive, so we pay the
16 * price upfront and create a circular buffer of queries
17 */
18 GLuint gl_queries[N_QUERIES];
19 GLuint active_query;
20
21 gboolean has_queries : 1;
22 gboolean has_timer : 1;
23 gboolean first_frame : 1;
24};
25
26enum {
27 PROP_GL_CONTEXT = 1,
28
29 N_PROPERTIES
30};
31
32static GParamSpec *gsk_gl_profiler_properties[N_PROPERTIES];
33
34G_DEFINE_TYPE (GskGLProfiler, gsk_gl_profiler, G_TYPE_OBJECT)
35
36static void
37gsk_gl_profiler_finalize (GObject *gobject)
38{
39 GskGLProfiler *self = GSK_GL_PROFILER (ptr: gobject);
40
41 if (self->has_queries)
42 glDeleteQueries (N_QUERIES, self->gl_queries);
43
44 g_clear_object (&self->gl_context);
45
46 G_OBJECT_CLASS (gsk_gl_profiler_parent_class)->finalize (gobject);
47}
48
49static void
50gsk_gl_profiler_set_property (GObject *gobject,
51 guint prop_id,
52 const GValue *value,
53 GParamSpec *pspec)
54{
55 GskGLProfiler *self = GSK_GL_PROFILER (ptr: gobject);
56
57 switch (prop_id)
58 {
59 case PROP_GL_CONTEXT:
60 self->gl_context = g_value_dup_object (value);
61 break;
62
63 default:
64 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
65 }
66}
67
68static void
69gsk_gl_profiler_get_property (GObject *gobject,
70 guint prop_id,
71 GValue *value,
72 GParamSpec *pspec)
73{
74 GskGLProfiler *self = GSK_GL_PROFILER (ptr: gobject);
75
76 switch (prop_id)
77 {
78 case PROP_GL_CONTEXT:
79 g_value_set_object (value, v_object: self->gl_context);
80 break;
81
82 default:
83 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
84 }
85}
86
87static void
88gsk_gl_profiler_class_init (GskGLProfilerClass *klass)
89{
90 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
91
92 gobject_class->set_property = gsk_gl_profiler_set_property;
93 gobject_class->get_property = gsk_gl_profiler_get_property;
94 gobject_class->finalize = gsk_gl_profiler_finalize;
95
96 gsk_gl_profiler_properties[PROP_GL_CONTEXT] =
97 g_param_spec_object (name: "gl-context",
98 nick: "GL Context",
99 blurb: "The GdkGLContext used by the GL profiler",
100 GDK_TYPE_GL_CONTEXT,
101 flags: G_PARAM_READWRITE |
102 G_PARAM_CONSTRUCT_ONLY |
103 G_PARAM_STATIC_STRINGS);
104
105 g_object_class_install_properties (oclass: gobject_class, n_pspecs: N_PROPERTIES, pspecs: gsk_gl_profiler_properties);
106}
107
108static void
109gsk_gl_profiler_init (GskGLProfiler *self)
110{
111 self->has_queries = epoxy_is_desktop_gl();
112 self->has_timer = epoxy_is_desktop_gl() && (epoxy_gl_version () >= 33 || epoxy_has_gl_extension (extension: "GL_ARB_timer_query"));
113
114 if (!self->has_queries)
115 return;
116
117 glGenQueries (N_QUERIES, self->gl_queries);
118 self->first_frame = TRUE;
119}
120
121GskGLProfiler *
122gsk_gl_profiler_new (GdkGLContext *context)
123{
124 g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
125
126 return g_object_new (GSK_TYPE_GL_PROFILER, first_property_name: "gl-context", context, NULL);
127}
128
129void
130gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler)
131{
132 GLuint query_id;
133
134 g_return_if_fail (GSK_IS_GL_PROFILER (profiler));
135
136 if (!profiler->has_timer || !profiler->has_queries)
137 return;
138
139 query_id = profiler->gl_queries[profiler->active_query];
140 glBeginQuery (GL_TIME_ELAPSED, query_id);
141}
142
143guint64
144gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler)
145{
146 GLuint last_query_id;
147 GLint res;
148 GLuint64 elapsed;
149
150 g_return_val_if_fail (GSK_IS_GL_PROFILER (profiler), 0);
151
152 if (!profiler->has_timer || !profiler->has_queries)
153 return 0;
154
155 glEndQuery (GL_TIME_ELAPSED);
156
157 if (profiler->active_query == 0)
158 last_query_id = N_QUERIES - 1;
159 else
160 last_query_id = profiler->active_query - 1;
161
162 /* Advance iterator */
163 profiler->active_query += 1;
164 if (profiler->active_query == N_QUERIES)
165 profiler->active_query = 0;
166
167 /* If this is the first frame we already have a result */
168 if (profiler->first_frame)
169 {
170 profiler->first_frame = FALSE;
171 return 0;
172 }
173
174 glGetQueryObjectiv (profiler->gl_queries[last_query_id], GL_QUERY_RESULT_AVAILABLE, &res);
175 if (res == 1)
176 glGetQueryObjectui64v (profiler->gl_queries[last_query_id], GL_QUERY_RESULT, &elapsed);
177 else
178 elapsed = 0;
179
180 return elapsed / 1000; /* Convert to usec to match other profiler APIs */
181}
182

source code of gtk/gsk/gl/gskglprofiler.c