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