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