1 /*
2 * GStreamer
3 * Copyright (C) 2015 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:gstglformat
23 * @title: GstGLFormat
24 * @short_description: utilities for dealing with OpenGL formats
25 * @see_also: #GstGLBaseMemory, #GstGLMemory, #GstGLFramebuffer, #GstGLBuffer
26 *
27 * Some useful utilities for converting between various formats and OpenGL
28 * formats.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "gstglformat.h"
36
37 #include "gstglcontext.h"
38 #include "gstglfuncs.h"
39
40 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
41 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
42 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
43 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
44 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
45
46 #ifndef GL_TEXTURE_RECTANGLE
47 #define GL_TEXTURE_RECTANGLE 0x84F5
48 #endif
49 #ifndef GL_TEXTURE_EXTERNAL_OES
50 #define GL_TEXTURE_EXTERNAL_OES 0x8D65
51 #endif
52
53 static inline guint
_gl_format_n_components(guint format)54 _gl_format_n_components (guint format)
55 {
56 switch (format) {
57 case GST_VIDEO_GL_TEXTURE_TYPE_RGBA:
58 case GST_GL_RGBA:
59 case GST_GL_RGBA8:
60 case GST_GL_RGBA16:
61 return 4;
62 case GST_VIDEO_GL_TEXTURE_TYPE_RGB:
63 case GST_VIDEO_GL_TEXTURE_TYPE_RGB16:
64 case GST_GL_RGB:
65 case GST_GL_RGB8:
66 case GST_GL_RGB16:
67 case GST_GL_RGB565:
68 return 3;
69 case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA:
70 case GST_VIDEO_GL_TEXTURE_TYPE_RG:
71 case GST_GL_LUMINANCE_ALPHA:
72 case GST_GL_RG:
73 case GST_GL_RG8:
74 return 2;
75 case GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE:
76 case GST_VIDEO_GL_TEXTURE_TYPE_R:
77 case GST_GL_LUMINANCE:
78 case GST_GL_ALPHA:
79 case GST_GL_RED:
80 case GST_GL_R8:
81 return 1;
82 default:
83 return 0;
84 }
85 }
86
87 static inline guint
_gl_type_n_components(guint type)88 _gl_type_n_components (guint type)
89 {
90 switch (type) {
91 case GL_UNSIGNED_BYTE:
92 case GL_UNSIGNED_SHORT:
93 return 1;
94 case GL_UNSIGNED_SHORT_5_6_5:
95 return 3;
96 default:
97 g_assert_not_reached ();
98 return 0;
99 }
100 }
101
102 static inline guint
_gl_type_n_bytes(guint type)103 _gl_type_n_bytes (guint type)
104 {
105 switch (type) {
106 case GL_UNSIGNED_BYTE:
107 return 1;
108 case GL_UNSIGNED_SHORT:
109 case GL_UNSIGNED_SHORT_5_6_5:
110 return 2;
111 default:
112 g_assert_not_reached ();
113 return 0;
114 }
115 }
116
117 /**
118 * gst_gl_format_type_n_bytes:
119 * @format: the OpenGL format, %GL_RGBA, %GL_LUMINANCE, etc
120 * @type: the OpenGL type, %GL_UNSIGNED_BYTE, %GL_FLOAT, etc
121 *
122 * Returns: the number of bytes the specified @format, @type combination takes
123 * per pixel
124 */
125 guint
gst_gl_format_type_n_bytes(guint format,guint type)126 gst_gl_format_type_n_bytes (guint format, guint type)
127 {
128 return _gl_format_n_components (format) / _gl_type_n_components (type) *
129 _gl_type_n_bytes (type);
130 }
131
132 /**
133 * gst_gl_format_from_video_info:
134 * @context: a #GstGLContext
135 * @vinfo: a #GstVideoInfo
136 * @plane: the plane number in @vinfo
137 *
138 * Returns: the #GstGLFormat necessary for holding the data in @plane of @vinfo
139 */
140 GstGLFormat
gst_gl_format_from_video_info(GstGLContext * context,GstVideoInfo * vinfo,guint plane)141 gst_gl_format_from_video_info (GstGLContext * context, GstVideoInfo * vinfo,
142 guint plane)
143 {
144 gboolean texture_rg =
145 gst_gl_context_check_feature (context, "GL_EXT_texture_rg")
146 || gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0)
147 || gst_gl_context_check_feature (context, "GL_ARB_texture_rg")
148 || gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 0);
149 GstVideoFormat v_format = GST_VIDEO_INFO_FORMAT (vinfo);
150 guint n_plane_components;
151
152 switch (v_format) {
153 case GST_VIDEO_FORMAT_RGBx:
154 case GST_VIDEO_FORMAT_BGRx:
155 case GST_VIDEO_FORMAT_xRGB:
156 case GST_VIDEO_FORMAT_xBGR:
157 case GST_VIDEO_FORMAT_RGBA:
158 case GST_VIDEO_FORMAT_BGRA:
159 case GST_VIDEO_FORMAT_ARGB:
160 case GST_VIDEO_FORMAT_ABGR:
161 case GST_VIDEO_FORMAT_AYUV:
162 case GST_VIDEO_FORMAT_VUYA:
163 n_plane_components = 4;
164 break;
165 case GST_VIDEO_FORMAT_ARGB64:
166 return GST_GL_RGBA16;
167 case GST_VIDEO_FORMAT_RGB:
168 case GST_VIDEO_FORMAT_BGR:
169 n_plane_components = 3;
170 break;
171 case GST_VIDEO_FORMAT_RGB16:
172 case GST_VIDEO_FORMAT_BGR16:
173 return GST_GL_RGB565;
174 break;
175 case GST_VIDEO_FORMAT_GRAY16_BE:
176 case GST_VIDEO_FORMAT_GRAY16_LE:
177 case GST_VIDEO_FORMAT_YUY2:
178 case GST_VIDEO_FORMAT_UYVY:
179 n_plane_components = 2;
180 break;
181 case GST_VIDEO_FORMAT_NV12:
182 case GST_VIDEO_FORMAT_NV21:
183 n_plane_components = plane == 0 ? 1 : 2;
184 break;
185 case GST_VIDEO_FORMAT_GRAY8:
186 case GST_VIDEO_FORMAT_Y444:
187 case GST_VIDEO_FORMAT_Y42B:
188 case GST_VIDEO_FORMAT_Y41B:
189 case GST_VIDEO_FORMAT_I420:
190 case GST_VIDEO_FORMAT_YV12:
191 n_plane_components = 1;
192 break;
193 default:
194 n_plane_components = 4;
195 g_assert_not_reached ();
196 break;
197 }
198
199 switch (n_plane_components) {
200 case 4:
201 return GST_GL_RGBA;
202 case 3:
203 return GST_GL_RGB;
204 case 2:
205 return texture_rg ? GST_GL_RG : GST_GL_LUMINANCE_ALPHA;
206 case 1:
207 return texture_rg ? GST_GL_RED : GST_GL_LUMINANCE;
208 default:
209 break;
210 }
211
212 g_critical ("Unknown video format 0x%x provided", v_format);
213 return 0;
214 }
215
216 /**
217 * gst_gl_sized_gl_format_from_gl_format_type:
218 * @context: a #GstGLContext
219 * @format: an OpenGL format, %GL_RGBA, %GL_LUMINANCE, etc
220 * @type: an OpenGL type, %GL_UNSIGNED_BYTE, %GL_FLOAT, etc
221 *
222 * Returns: the sized internal format specified by @format and @type that can
223 * be used in @context
224 */
225 guint
gst_gl_sized_gl_format_from_gl_format_type(GstGLContext * context,guint format,guint type)226 gst_gl_sized_gl_format_from_gl_format_type (GstGLContext * context,
227 guint format, guint type)
228 {
229 gboolean ext_texture_rg =
230 gst_gl_context_check_feature (context, "GL_EXT_texture_rg");
231
232 switch (format) {
233 case GST_GL_RGBA:
234 switch (type) {
235 case GL_UNSIGNED_BYTE:
236 return USING_GLES2 (context)
237 && !USING_GLES3 (context) ? GST_GL_RGBA : GST_GL_RGBA8;
238 break;
239 case GL_UNSIGNED_SHORT:
240 return GST_GL_RGBA16;
241 }
242 break;
243 case GST_GL_RGB:
244 switch (type) {
245 case GL_UNSIGNED_BYTE:
246 return USING_GLES2 (context)
247 && !USING_GLES3 (context) ? GST_GL_RGB : GST_GL_RGB8;
248 break;
249 case GL_UNSIGNED_SHORT_5_6_5:
250 return GST_GL_RGB565;
251 case GL_UNSIGNED_SHORT:
252 return GST_GL_RGB16;
253 }
254 break;
255 case GST_GL_RG:
256 switch (type) {
257 case GL_UNSIGNED_BYTE:
258 if (!USING_GLES3 (context) && USING_GLES2 (context) && ext_texture_rg)
259 return GST_GL_RG;
260 return GST_GL_RG8;
261 break;
262 }
263 break;
264 case GST_GL_RED:
265 switch (type) {
266 case GL_UNSIGNED_BYTE:
267 if (!USING_GLES3 (context) && USING_GLES2 (context) && ext_texture_rg)
268 return GST_GL_RED;
269 return GST_GL_R8;
270 break;
271 }
272 break;
273 case GST_GL_RGBA8:
274 case GST_GL_RGBA16:
275 case GST_GL_RGB8:
276 case GST_GL_RGB16:
277 case GST_GL_RGB565:
278 case GST_GL_RG8:
279 case GST_GL_R8:
280 case GST_GL_LUMINANCE:
281 case GST_GL_LUMINANCE_ALPHA:
282 case GST_GL_ALPHA:
283 case GST_GL_DEPTH_COMPONENT16:
284 case GST_GL_DEPTH24_STENCIL8:
285 return format;
286 default:
287 g_critical ("Unknown GL format 0x%x type 0x%x provided", format, type);
288 return format;
289 }
290
291 g_assert_not_reached ();
292 return 0;
293 }
294
295 /**
296 * gst_gl_format_type_from_sized_gl_format:
297 * @format: the sized internal #GstGLFormat
298 * @unsized_format: (out): location for the resulting unsized #GstGLFormat
299 * @gl_type: (out): location for the resulting GL type
300 *
301 * Get the unsized format and type from @format for usage in glReadPixels,
302 * glTex{Sub}Image*, glTexImage* and similar functions.
303 *
304 * Since: 1.16
305 */
306 void
gst_gl_format_type_from_sized_gl_format(GstGLFormat format,GstGLFormat * unsized_format,guint * gl_type)307 gst_gl_format_type_from_sized_gl_format (GstGLFormat format,
308 GstGLFormat * unsized_format, guint * gl_type)
309 {
310 g_return_if_fail (unsized_format != NULL);
311 g_return_if_fail (gl_type != NULL);
312
313 switch (format) {
314 case GST_GL_RGBA8:
315 *unsized_format = GST_GL_RGBA;
316 *gl_type = GL_UNSIGNED_BYTE;
317 break;
318 case GST_GL_RGB8:
319 *unsized_format = GST_GL_RGB;
320 *gl_type = GL_UNSIGNED_BYTE;
321 break;
322 case GST_GL_RGBA16:
323 *unsized_format = GST_GL_RGBA;
324 *gl_type = GL_UNSIGNED_SHORT;
325 break;
326 case GST_GL_RGB16:
327 *unsized_format = GST_GL_RGB;
328 *gl_type = GL_UNSIGNED_SHORT;
329 break;
330 case GST_GL_RGB565:
331 *unsized_format = GST_GL_RGB;
332 *gl_type = GL_UNSIGNED_SHORT_5_6_5;
333 break;
334 case GST_GL_RG8:
335 *unsized_format = GST_GL_RG;
336 *gl_type = GL_UNSIGNED_BYTE;
337 break;
338 case GST_GL_R8:
339 *unsized_format = GST_GL_RED;
340 *gl_type = GL_UNSIGNED_BYTE;
341 break;
342 case GST_GL_RGBA:
343 case GST_GL_RGB:
344 case GST_GL_RG:
345 case GST_GL_RED:
346 case GST_GL_LUMINANCE:
347 case GST_GL_LUMINANCE_ALPHA:
348 case GST_GL_ALPHA:
349 *unsized_format = format;
350 *gl_type = GL_UNSIGNED_BYTE;
351 break;
352 default:
353 g_critical ("Unknown GL format 0x%x provided", format);
354 *unsized_format = format;
355 *gl_type = GL_UNSIGNED_BYTE;
356 return;
357 }
358 }
359
360 /**
361 * gst_gl_format_is_supported:
362 * @context: a #GstGLContext
363 * @format: the #GstGLFormat to check is supported by @context
364 *
365 * Returns: Whether @format is supported by @context based on the OpenGL API,
366 * version, or available OpenGL extension/s.
367 *
368 * Since: 1.16
369 */
370 gboolean
gst_gl_format_is_supported(GstGLContext * context,GstGLFormat format)371 gst_gl_format_is_supported (GstGLContext * context, GstGLFormat format)
372 {
373 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
374
375 switch (format) {
376 case GST_GL_RGBA:
377 case GST_GL_RGB:
378 return TRUE;
379 case GST_GL_LUMINANCE:
380 case GST_GL_ALPHA:
381 case GST_GL_LUMINANCE_ALPHA:
382 /* deprecated/removed in core GL3 contexts */
383 return USING_OPENGL (context) || USING_GLES2 (context);
384 case GST_GL_RG:
385 case GST_GL_RED:
386 return gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0)
387 || gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 0)
388 || gst_gl_context_check_feature (context, "GL_EXT_texture_rg")
389 || gst_gl_context_check_feature (context, "GL_ARB_texture_rg");
390 case GST_GL_R8:
391 case GST_GL_RG8:
392 return USING_GLES3 (context)
393 || gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 0)
394 || gst_gl_context_check_feature (context, "GL_ARB_texture_rg");
395 case GST_GL_RGB8:
396 case GST_GL_RGBA8:
397 return (USING_GLES3 (context) && !USING_GLES2 (context))
398 || USING_OPENGL (context) || USING_OPENGL3 (context);
399 case GST_GL_RGB16:
400 case GST_GL_RGBA16:
401 return USING_OPENGL (context) || USING_OPENGL3 (context)
402 || USING_GLES3 (context);
403 case GST_GL_RGB565:
404 return USING_GLES2 (context) || (USING_OPENGL3 (context)
405 && gst_gl_context_check_feature (context,
406 "GL_ARB_ES2_compatibility"));
407 case GST_GL_DEPTH_COMPONENT16:
408 return gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 4)
409 || USING_GLES2 (context)
410 || gst_gl_context_check_feature (context, "GL_ARB_depth_texture")
411 || gst_gl_context_check_feature (context, "GL_OES_depth_texture");
412 case GST_GL_DEPTH24_STENCIL8:
413 return gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 3, 0)
414 || USING_GLES3 (context)
415 || gst_gl_context_check_feature (context,
416 "GL_OES_packed_depth_stencil")
417 || gst_gl_context_check_feature (context,
418 "GL_EXT_packed_depth_stencil");
419 default:
420 g_assert_not_reached ();
421 return FALSE;
422 }
423 }
424
425 /**
426 * gst_gl_texture_target_to_string:
427 * @target: a #GstGLTextureTarget
428 *
429 * Returns: the stringified version of @target or %NULL
430 */
431 const gchar *
gst_gl_texture_target_to_string(GstGLTextureTarget target)432 gst_gl_texture_target_to_string (GstGLTextureTarget target)
433 {
434 switch (target) {
435 case GST_GL_TEXTURE_TARGET_2D:
436 return GST_GL_TEXTURE_TARGET_2D_STR;
437 case GST_GL_TEXTURE_TARGET_RECTANGLE:
438 return GST_GL_TEXTURE_TARGET_RECTANGLE_STR;
439 case GST_GL_TEXTURE_TARGET_EXTERNAL_OES:
440 return GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR;
441 default:
442 return NULL;
443 }
444 }
445
446 /**
447 * gst_gl_texture_target_from_string:
448 * @str: a string equivalant to one of the GST_GL_TEXTURE_TARGET_*_STR values
449 *
450 * Returns: the #GstGLTextureTarget represented by @str or
451 * %GST_GL_TEXTURE_TARGET_NONE
452 */
453 GstGLTextureTarget
gst_gl_texture_target_from_string(const gchar * str)454 gst_gl_texture_target_from_string (const gchar * str)
455 {
456 if (!str)
457 return GST_GL_TEXTURE_TARGET_NONE;
458
459 if (g_strcmp0 (str, GST_GL_TEXTURE_TARGET_2D_STR) == 0)
460 return GST_GL_TEXTURE_TARGET_2D;
461 if (g_strcmp0 (str, GST_GL_TEXTURE_TARGET_RECTANGLE_STR) == 0)
462 return GST_GL_TEXTURE_TARGET_RECTANGLE;
463 if (g_strcmp0 (str, GST_GL_TEXTURE_TARGET_EXTERNAL_OES_STR) == 0)
464 return GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
465
466 return GST_GL_TEXTURE_TARGET_NONE;
467 }
468
469 /**
470 * gst_gl_texture_target_to_gl:
471 * @target: a #GstGLTextureTarget
472 *
473 * Returns: the OpenGL value for binding the @target with glBindTexture() and
474 * similar functions or 0
475 */
476 guint
gst_gl_texture_target_to_gl(GstGLTextureTarget target)477 gst_gl_texture_target_to_gl (GstGLTextureTarget target)
478 {
479 switch (target) {
480 case GST_GL_TEXTURE_TARGET_2D:
481 return GL_TEXTURE_2D;
482 case GST_GL_TEXTURE_TARGET_RECTANGLE:
483 return GL_TEXTURE_RECTANGLE;
484 case GST_GL_TEXTURE_TARGET_EXTERNAL_OES:
485 return GL_TEXTURE_EXTERNAL_OES;
486 default:
487 return 0;
488 }
489 }
490
491 /**
492 * gst_gl_texture_target_from_gl:
493 * @target: an OpenGL texture binding target
494 *
495 * Returns: the #GstGLTextureTarget that's equiavalant to @target or
496 * %GST_GL_TEXTURE_TARGET_NONE
497 */
498 GstGLTextureTarget
gst_gl_texture_target_from_gl(guint target)499 gst_gl_texture_target_from_gl (guint target)
500 {
501 switch (target) {
502 case GL_TEXTURE_2D:
503 return GST_GL_TEXTURE_TARGET_2D;
504 case GL_TEXTURE_RECTANGLE:
505 return GST_GL_TEXTURE_TARGET_RECTANGLE;
506 case GL_TEXTURE_EXTERNAL_OES:
507 return GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
508 default:
509 return GST_GL_TEXTURE_TARGET_NONE;
510 }
511 }
512
513 /**
514 * gst_gl_texture_target_to_buffer_pool_option:
515 * @target: a #GstGLTextureTarget
516 *
517 * Returns: a string representing the @GstBufferPoolOption specified by @target
518 */
519 const gchar *
gst_gl_texture_target_to_buffer_pool_option(GstGLTextureTarget target)520 gst_gl_texture_target_to_buffer_pool_option (GstGLTextureTarget target)
521 {
522 switch (target) {
523 case GST_GL_TEXTURE_TARGET_2D:
524 return GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_2D;
525 case GST_GL_TEXTURE_TARGET_RECTANGLE:
526 return GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_RECTANGLE;
527 case GST_GL_TEXTURE_TARGET_EXTERNAL_OES:
528 return GST_BUFFER_POOL_OPTION_GL_TEXTURE_TARGET_EXTERNAL_OES;
529 default:
530 return NULL;
531 }
532 }
533