1 /*
2 * GStreamer
3 * Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 /**
22 * SECTION:gstglquery
23 * @short_description: OpenGL query abstraction
24 * @title: GstGLQuery
25 *
26 * A #GstGLQuery represents and holds an OpenGL query object. Various types of
27 * queries can be run or counters retrieved.
28 *
29 * Since: 1.10
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <string.h>
37
38 #include "gstglquery.h"
39
40 #include "gstglcontext.h"
41 #include "gstglfuncs.h"
42
43 #ifndef GL_TIME_ELAPSED
44 #define GL_TIME_ELAPSED 0x88BF
45 #endif
46
47 #ifndef GL_TIMESTAMP
48 #define GL_TIMESTAMP 0x8E28
49 #endif
50
51 #ifndef GL_QUERY_RESULT
52 #define GL_QUERY_RESULT 0x8866
53 #endif
54
55 #define GST_CAT_DEFAULT gst_gl_query_debug
56 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
57
58 static void
_init_debug(void)59 _init_debug (void)
60 {
61 static gsize _init = 0;
62
63 if (g_once_init_enter (&_init)) {
64 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glquery", 0, "glquery element");
65 g_once_init_leave (&_init, 1);
66 }
67 }
68
69 static const gchar *
_query_type_to_string(guint query_type)70 _query_type_to_string (guint query_type)
71 {
72 switch (query_type) {
73 case GST_GL_QUERY_TIME_ELAPSED:
74 case GL_TIME_ELAPSED:
75 return "time elapsed";
76 case GL_TIMESTAMP:
77 case GST_GL_QUERY_TIMESTAMP:
78 return "timestamp";
79 default:
80 return "unknown";
81 }
82 }
83
84 static guint
_gst_gl_query_type_to_gl(GstGLQueryType query_type)85 _gst_gl_query_type_to_gl (GstGLQueryType query_type)
86 {
87 if (query_type == GST_GL_QUERY_TIME_ELAPSED)
88 return GL_TIME_ELAPSED;
89 if (query_type == GST_GL_QUERY_TIMESTAMP)
90 return GL_TIMESTAMP;
91
92 return 0;
93 }
94
95 static gboolean
_query_type_supports_counter(guint gl_query_type)96 _query_type_supports_counter (guint gl_query_type)
97 {
98 return gl_query_type == GL_TIMESTAMP;
99 }
100
101 static gboolean
_query_type_supports_begin_end(guint gl_query_type)102 _query_type_supports_begin_end (guint gl_query_type)
103 {
104 return gl_query_type == GL_TIME_ELAPSED;
105 }
106
107 static gboolean
_context_supports_query_type(GstGLContext * context,guint gl_query_type)108 _context_supports_query_type (GstGLContext * context, guint gl_query_type)
109 {
110 return gl_query_type != 0 && context->gl_vtable->GenQueries != NULL;
111 }
112
113 static gchar *
_log_time(gpointer user_data)114 _log_time (gpointer user_data)
115 {
116 GstGLQuery *query = user_data;
117 guint64 result = 0;
118
119 result = gst_gl_query_result (query);
120
121 return gst_info_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (result));
122 }
123
124 /**
125 * gst_gl_query_init:
126 * @query: a #GstGLQuery
127 * @context: a #GstGLContext
128 * @query_type: the #GstGLQueryType
129 *
130 * Since: 1.10
131 */
132 void
gst_gl_query_init(GstGLQuery * query,GstGLContext * context,GstGLQueryType query_type)133 gst_gl_query_init (GstGLQuery * query, GstGLContext * context,
134 GstGLQueryType query_type)
135 {
136 const GstGLFuncs *gl;
137 GLenum gl_query_type;
138
139 g_return_if_fail (query != NULL);
140 g_return_if_fail (GST_IS_GL_CONTEXT (context));
141 gl = context->gl_vtable;
142 gl_query_type = _gst_gl_query_type_to_gl (query_type);
143 g_return_if_fail (gl_query_type != GL_NONE);
144
145 memset (query, 0, sizeof (*query));
146
147 _init_debug ();
148
149 query->query_type = gl_query_type;
150 query->context = gst_object_ref (context);
151 query->supported = _context_supports_query_type (context, query->query_type);
152
153 if (query->supported)
154 gl->GenQueries (1, &query->query_id);
155
156 gst_gl_async_debug_init (&query->debug);
157 query->debug.callback = _log_time;
158 query->debug.user_data = query;
159 }
160
161 /**
162 * gst_gl_query_unset:
163 * @query: a #GstGLQuery
164 *
165 * Free any dynamically allocated resources
166 *
167 * Since: 1.10
168 */
169 void
gst_gl_query_unset(GstGLQuery * query)170 gst_gl_query_unset (GstGLQuery * query)
171 {
172 const GstGLFuncs *gl;
173
174 g_return_if_fail (query != NULL);
175 if (query->start_called)
176 g_critical ("Unsetting a running query. This may not be what you wanted."
177 "Be sure to pair calls to gst_gl_query_start() and gst_gl_query_end()");
178
179 GST_TRACE ("%p unsetting query %u", query, query->query_id);
180
181 gl = query->context->gl_vtable;
182
183 /* unset the debug object as it may callback to print the last message */
184 gst_gl_async_debug_unset (&query->debug);
185
186 if (query->query_id)
187 gl->DeleteQueries (1, &query->query_id);
188
189 gst_object_unref (query->context);
190 }
191
192 /**
193 * gst_gl_query_new: (skip)
194 * @context: a #GstGLContext
195 * @query_type: the #GstGLQueryType to create
196 *
197 * Free with gst_gl_query_free()
198 *
199 * Returns: a new #GstGLQuery
200 *
201 * Since: 1.10
202 */
203 GstGLQuery *
gst_gl_query_new(GstGLContext * context,GstGLQueryType query_type)204 gst_gl_query_new (GstGLContext * context, GstGLQueryType query_type)
205 {
206 GstGLQuery *query = g_new0 (GstGLQuery, 1);
207
208 gst_gl_query_init (query, context, query_type);
209
210 return query;
211 }
212
213 /**
214 * gst_gl_query_free:
215 * @query: a #GstGLQuery
216 *
217 * Frees a #GstGLQuery
218 *
219 * Since: 1.10
220 */
221 void
gst_gl_query_free(GstGLQuery * query)222 gst_gl_query_free (GstGLQuery * query)
223 {
224 g_return_if_fail (query != NULL);
225
226 gst_gl_query_unset (query);
227 g_free (query);
228 }
229
230 /**
231 * gst_gl_query_start:
232 * @query: a #GstGLQuery
233 *
234 * Start counting the query
235 *
236 * Since: 1.10
237 */
238 void
gst_gl_query_start(GstGLQuery * query)239 gst_gl_query_start (GstGLQuery * query)
240 {
241 const GstGLFuncs *gl;
242
243 g_return_if_fail (query != NULL);
244 g_return_if_fail (_query_type_supports_begin_end (query->query_type));
245 g_return_if_fail (query->start_called == FALSE);
246
247 query->start_called = TRUE;
248
249 if (!query->supported)
250 return;
251
252 gst_gl_async_debug_output_log_msg (&query->debug);
253
254 GST_TRACE ("%p start query type \'%s\' id %u", query,
255 _query_type_to_string (query->query_type), query->query_id);
256
257 gl = query->context->gl_vtable;
258 gl->BeginQuery (query->query_type, query->query_id);
259 }
260
261 /**
262 * gst_gl_query_end:
263 * @query: a #GstGLQuery
264 *
265 * End counting the query
266 *
267 * Since: 1.10
268 */
269 void
gst_gl_query_end(GstGLQuery * query)270 gst_gl_query_end (GstGLQuery * query)
271 {
272 const GstGLFuncs *gl;
273
274 g_return_if_fail (query != NULL);
275 g_return_if_fail (_query_type_supports_begin_end (query->query_type));
276 g_return_if_fail (query->start_called);
277
278 query->start_called = FALSE;
279
280 if (!query->supported)
281 return;
282
283 GST_TRACE ("%p end query type \'%s\' id %u", query,
284 _query_type_to_string (query->query_type), query->query_id);
285
286 gl = query->context->gl_vtable;
287
288 gl->EndQuery (query->query_type);
289 }
290
291 /**
292 * gst_gl_query_counter:
293 * @query: a #GstGLQuery
294 *
295 * Record the result of a counter
296 *
297 * Since: 1.10
298 */
299 void
gst_gl_query_counter(GstGLQuery * query)300 gst_gl_query_counter (GstGLQuery * query)
301 {
302 const GstGLFuncs *gl;
303
304 g_return_if_fail (query != NULL);
305 g_return_if_fail (_query_type_supports_counter (query->query_type));
306
307 if (!query->supported)
308 return;
309
310 GST_TRACE ("%p query counter type \'%s\' id %u", query,
311 _query_type_to_string (query->query_type), query->query_id);
312
313 gst_gl_async_debug_output_log_msg (&query->debug);
314
315 gl = query->context->gl_vtable;
316 gl->QueryCounter (query->query_id, query->query_type);
317 }
318
319 /**
320 * gst_gl_query_result:
321 * @query: a #GstGLQuery
322 *
323 * Returns: the result of the query
324 *
325 * Since: 1.10
326 */
327 guint64
gst_gl_query_result(GstGLQuery * query)328 gst_gl_query_result (GstGLQuery * query)
329 {
330 const GstGLFuncs *gl;
331 guint64 ret;
332
333 g_return_val_if_fail (query != NULL, 0);
334 g_return_val_if_fail (!query->start_called, 0);
335
336 if (!query->supported)
337 return 0;
338
339 gl = query->context->gl_vtable;
340 if (gl->GetQueryObjectui64v) {
341 GLuint64 tmp = 0;
342 gl->GetQueryObjectui64v (query->query_id, GL_QUERY_RESULT, &tmp);
343 ret = tmp;
344 } else {
345 guint tmp = 0;
346 gl->GetQueryObjectuiv (query->query_id, GL_QUERY_RESULT, &tmp);
347 ret = tmp;
348 }
349
350 GST_TRACE ("%p get result %" G_GUINT64_FORMAT " type \'%s\' id %u", query,
351 ret, _query_type_to_string (query->query_type), query->query_id);
352
353 return ret;
354 }
355