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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/gl/gl.h>
26
27 #include "gstglsl.h"
28 #include "gstglsl_private.h"
29
30 /**
31 * SECTION:gstglsl
32 * @title: GstGLSL
33 * @short_description: helpers for dealing with OpenGL shaders
34 * @see_also: #GstGLSLStage, #GstGLShader
35 */
36
37 #define GST_CAT_DEFAULT gst_glsl_debug
38 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
39
40 static void
_init_debug(void)41 _init_debug (void)
42 {
43 static volatile gsize _init = 0;
44
45 if (g_once_init_enter (&_init)) {
46 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glsl", 0,
47 "OpenGL Shading Language");
48 g_once_init_leave (&_init, 1);
49 }
50 }
51
52 GQuark
gst_glsl_error_quark(void)53 gst_glsl_error_quark (void)
54 {
55 return g_quark_from_static_string ("gst-glsl-error-quark");
56 }
57
58 struct glsl_version_string
59 {
60 GstGLSLVersion version;
61 const gchar *name;
62 };
63
64 static const struct glsl_version_string glsl_versions[] = {
65 /* keep in sync with definition in the header */
66 {GST_GLSL_VERSION_100, "100"},
67 {GST_GLSL_VERSION_110, "110"},
68 {GST_GLSL_VERSION_120, "120"},
69 {GST_GLSL_VERSION_130, "130"},
70 {GST_GLSL_VERSION_140, "140"},
71 {GST_GLSL_VERSION_150, "150"},
72 {GST_GLSL_VERSION_300, "300"},
73 {GST_GLSL_VERSION_310, "310"},
74 {GST_GLSL_VERSION_320, "320"},
75 {GST_GLSL_VERSION_330, "330"},
76 {GST_GLSL_VERSION_400, "400"},
77 {GST_GLSL_VERSION_410, "410"},
78 {GST_GLSL_VERSION_420, "420"},
79 {GST_GLSL_VERSION_430, "430"},
80 {GST_GLSL_VERSION_440, "440"},
81 {GST_GLSL_VERSION_450, "450"},
82 };
83
84 struct glsl_profile_string
85 {
86 GstGLSLProfile profile;
87 const gchar *name;
88 };
89
90 static const struct glsl_profile_string glsl_profiles[] = {
91 /* keep in sync with definition in the header */
92 {GST_GLSL_PROFILE_ES, "es"},
93 {GST_GLSL_PROFILE_CORE, "core"},
94 {GST_GLSL_PROFILE_COMPATIBILITY, "compatibility"},
95 };
96
97 /**
98 * gst_glsl_version_to_string:
99 * @version: a #GstGLSLVersion
100 *
101 * Returns: (nullable): the name of @version or %NULL on error
102 */
103 const gchar *
gst_glsl_version_to_string(GstGLSLVersion version)104 gst_glsl_version_to_string (GstGLSLVersion version)
105 {
106 int i;
107
108 if (version == GST_GLSL_VERSION_NONE)
109 return NULL;
110
111 for (i = 0; i < G_N_ELEMENTS (glsl_versions); i++) {
112 if (version == glsl_versions[i].version)
113 return glsl_versions[i].name;
114 }
115
116 return NULL;
117 }
118
119 /**
120 * gst_glsl_version_from_string:
121 * @string: a GLSL version string
122 *
123 * Returns: the #GstGLSLVersion of @string or %GST_GLSL_VERSION_NONE on error
124 */
125 GstGLSLVersion
gst_glsl_version_from_string(const gchar * string)126 gst_glsl_version_from_string (const gchar * string)
127 {
128 gchar *str;
129 int i;
130
131 if (string == NULL)
132 return 0;
133
134 str = g_strdup (string);
135 str = g_strstrip (str);
136
137 for (i = 0; i < G_N_ELEMENTS (glsl_versions); i++) {
138 if (g_strcmp0 (str, glsl_versions[i].name) == 0) {
139 g_free (str);
140 return glsl_versions[i].version;
141 }
142 }
143
144 g_free (str);
145 return 0;
146 }
147
148 /**
149 * gst_glsl_profile_to_string:
150 * @profile: a #GstGLSLProfile
151 *
152 * Returns: (nullable): the name for @profile or %NULL on error
153 */
154 const gchar *
gst_glsl_profile_to_string(GstGLSLProfile profile)155 gst_glsl_profile_to_string (GstGLSLProfile profile)
156 {
157 int i;
158
159 if (profile == GST_GLSL_PROFILE_NONE)
160 return NULL;
161
162 /* multiple profiles are not allowed */
163 if ((profile & (profile - 1)) != 0)
164 return NULL;
165
166 for (i = 0; i < G_N_ELEMENTS (glsl_profiles); i++) {
167 if (profile == glsl_profiles[i].profile)
168 return glsl_profiles[i].name;
169 }
170
171 return NULL;
172 }
173
174 /**
175 * gst_glsl_profile_from_string:
176 * @string: a GLSL version string
177 *
178 * Returns: the #GstGLSLProfile of @string or %GST_GLSL_PROFILE_NONE on error
179 */
180 GstGLSLProfile
gst_glsl_profile_from_string(const gchar * string)181 gst_glsl_profile_from_string (const gchar * string)
182 {
183 gchar *str;
184 int i;
185
186 if (string == NULL)
187 return GST_GLSL_PROFILE_NONE;
188
189 str = g_strdup (string);
190 str = g_strstrip (str);
191
192 for (i = 0; i < G_N_ELEMENTS (glsl_profiles); i++) {
193 if (g_strcmp0 (str, glsl_profiles[i].name) == 0) {
194 g_free (str);
195 return glsl_profiles[i].profile;
196 }
197 }
198
199 g_free (str);
200 return GST_GLSL_PROFILE_NONE;
201 }
202
203 static gboolean
_is_valid_version_profile(GstGLSLVersion version,GstGLSLProfile profile)204 _is_valid_version_profile (GstGLSLVersion version, GstGLSLProfile profile)
205 {
206 if (version == GST_GLSL_VERSION_NONE)
207 return TRUE;
208
209 /* versions that may not need an explicit profile */
210 if (version <= GST_GLSL_VERSION_150 && profile == GST_GLSL_PROFILE_NONE)
211 return TRUE;
212
213 /* ES versions require an ES profile */
214 if (version == GST_GLSL_VERSION_100 || version == GST_GLSL_VERSION_300
215 || version == GST_GLSL_VERSION_310 || version == GST_GLSL_VERSION_320)
216 return profile == GST_GLSL_PROFILE_ES;
217
218 /* required profile and no ES profile for normal GL contexts */
219 if (version == GST_GLSL_VERSION_150 || version >= GST_GLSL_VERSION_330)
220 return profile == GST_GLSL_PROFILE_NONE || profile == GST_GLSL_PROFILE_CORE
221 || profile == GST_GLSL_PROFILE_COMPATIBILITY;
222
223 if (version <= GST_GLSL_VERSION_140)
224 return profile == GST_GLSL_PROFILE_NONE
225 || profile == GST_GLSL_PROFILE_COMPATIBILITY;
226
227 return FALSE;
228 }
229
230 /**
231 * gst_glsl_version_profile_to_string:
232 * @version: a #GstGLSLVersion
233 * @profile: a #GstGLSLVersion
234 *
235 * Returns: the combined GLSL #version string for @version and @profile
236 */
237 gchar *
gst_glsl_version_profile_to_string(GstGLSLVersion version,GstGLSLProfile profile)238 gst_glsl_version_profile_to_string (GstGLSLVersion version,
239 GstGLSLProfile profile)
240 {
241 const gchar *version_s, *profile_s;
242
243 if (!_is_valid_version_profile (version, profile))
244 return NULL;
245
246 version_s = gst_glsl_version_to_string (version);
247 /* no profiles in GL/ES <= 150 */
248 if (version <= GST_GLSL_VERSION_140)
249 profile_s = NULL;
250 else
251 profile_s = gst_glsl_profile_to_string (profile);
252
253 if (!version_s)
254 return NULL;
255
256 if (profile_s)
257 return g_strdup_printf ("%s %s", version_s, profile_s);
258
259 return g_strdup (version_s);
260 }
261
262 static void
_fixup_version_profile(GstGLSLVersion * version,GstGLSLProfile * profile)263 _fixup_version_profile (GstGLSLVersion * version, GstGLSLProfile * profile)
264 {
265 if (*version == GST_GLSL_VERSION_100 || *version == GST_GLSL_VERSION_300
266 || *version == GST_GLSL_VERSION_310 || *version == GST_GLSL_VERSION_320)
267 *profile = GST_GLSL_PROFILE_ES;
268 else if (*version <= GST_GLSL_VERSION_140)
269 *profile = GST_GLSL_PROFILE_COMPATIBILITY;
270 else if (*profile == GST_GLSL_PROFILE_NONE
271 && (*version >= GST_GLSL_VERSION_150 || *version >= GST_GLSL_VERSION_330))
272 *profile = GST_GLSL_PROFILE_CORE;
273 }
274
275 /* @str points to the start of "#version", "# version" or "#\tversion", etc */
276 static const gchar *
_check_valid_version_preprocessor_string(const gchar * str)277 _check_valid_version_preprocessor_string (const gchar * str)
278 {
279 gint i = 0;
280
281 if (!str || !str[i])
282 return NULL;
283
284 /* there can be whitespace between the '#' and 'version' */
285 do {
286 i++;
287 if (str[i] == '\0' || str[i] == '\n' || str[i] == '\r')
288 return NULL;
289 } while (g_ascii_isspace (str[i]));
290 if (g_strstr_len (&str[i], 7, "version"))
291 return &str[i + 7];
292
293 return NULL;
294 }
295
296 /**
297 * gst_glsl_version_profile_from_string:
298 * @string: a valid GLSL #version string
299 * @version_ret: (out): resulting #GstGLSLVersion
300 * @profile_ret: (out): resulting #GstGLSLVersion
301 *
302 * Note: this function expects either a #version GLSL preprocesser directive
303 * or a valid GLSL version and/or profile.
304 *
305 * Returns: TRUE if a valid #version string was found, FALSE otherwise
306 */
307 gboolean
gst_glsl_version_profile_from_string(const gchar * string,GstGLSLVersion * version_ret,GstGLSLProfile * profile_ret)308 gst_glsl_version_profile_from_string (const gchar * string,
309 GstGLSLVersion * version_ret, GstGLSLProfile * profile_ret)
310 {
311 gchar *str, *version_s, *profile_s;
312 GstGLSLVersion version = GST_GLSL_VERSION_NONE;
313 GstGLSLProfile profile = GST_GLSL_PROFILE_NONE;
314 gint i;
315
316 _init_debug ();
317
318 if (!string)
319 goto error;
320
321 str = g_strdup (string);
322 version_s = g_strstrip (str);
323
324 /* skip possible #version prefix */
325 if (str[0] == '#') {
326 if (!(version_s =
327 (gchar *) _check_valid_version_preprocessor_string (version_s))) {
328 GST_WARNING ("Invalid preprocesser directive detected: %s", version_s);
329 g_free (str);
330 goto error;
331 }
332 }
333
334 version_s = g_strstrip (version_s);
335
336 i = 0;
337 while (version_s && version_s[i] != '\0' && g_ascii_isdigit (version_s[i]))
338 i++;
339 /* wrong version length */
340 if (i != 3) {
341 GST_WARNING ("version number has the wrong number of digits: %s",
342 version_s);
343 g_free (str);
344 goto error;
345 }
346
347 if (version_s[i] != 0) {
348 version_s[i] = '\0';
349 i++;
350 profile_s = &version_s[i];
351 profile_s = g_strstrip (profile_s);
352
353 profile = gst_glsl_profile_from_string (profile_s);
354 }
355 version = gst_glsl_version_from_string (version_s);
356 g_free (str);
357
358 /* check whether the parsed data is valid */
359 if (!version) {
360 GST_WARNING ("Could not map the version number to a valid GLSL version:");
361 goto error;
362 }
363 if (!_is_valid_version_profile (version, profile)) {
364 GST_WARNING ("Invalid version/profile combination specified: %s %s",
365 gst_glsl_version_to_string (version),
366 gst_glsl_profile_to_string (profile));
367 goto error;
368 }
369 /* got a profile when none was expected */
370 if (version <= GST_GLSL_VERSION_140 && profile != GST_GLSL_PROFILE_NONE) {
371 GST_WARNING
372 ("Found a profile (%s) with a version (%s) that does not support "
373 "profiles", gst_glsl_version_to_string (version),
374 gst_glsl_profile_to_string (profile));
375 goto error;
376 }
377
378 _fixup_version_profile (&version, &profile);
379
380 if (profile_ret)
381 *profile_ret = profile;
382 if (version_ret)
383 *version_ret = version;
384
385 return TRUE;
386
387 error:
388 {
389 if (profile_ret)
390 *profile_ret = GST_GLSL_PROFILE_NONE;
391 if (version_ret)
392 *version_ret = GST_GLSL_VERSION_NONE;
393 return FALSE;
394 }
395 }
396
397 /* returns the pointer in @str to the #version declaration */
398 const gchar *
_gst_glsl_shader_string_find_version(const gchar * str)399 _gst_glsl_shader_string_find_version (const gchar * str)
400 {
401 gboolean sl_comment = FALSE;
402 gboolean ml_comment = FALSE;
403 gboolean newline = TRUE;
404 gint i = 0;
405
406 _init_debug ();
407
408 /* search for #version while allowing for preceeding comments/whitespace as
409 * permitted by the GLSL specification */
410 while (str && str[i] != '\0' && i < 1024) {
411 if (str[i] == '\n' || str[i] == '\r') {
412 newline = TRUE;
413 sl_comment = FALSE;
414 i++;
415 continue;
416 }
417
418 if (g_ascii_isspace (str[i]))
419 goto next;
420
421 if (sl_comment)
422 goto next;
423
424 if (ml_comment) {
425 if (g_strstr_len (&str[i], 2, "*/")) {
426 ml_comment = FALSE;
427 i++;
428 }
429 goto next;
430 }
431
432 if (g_strstr_len (&str[i], 2, "//")) {
433 sl_comment = TRUE;
434 i++;
435 goto next;
436 }
437
438 if (g_strstr_len (&str[i], 2, "/*")) {
439 ml_comment = TRUE;
440 i++;
441 goto next;
442 }
443
444 if (str[i] == '#') {
445 if (newline && _check_valid_version_preprocessor_string (&str[i])) {
446 GST_DEBUG ("found #version declaration at index %i", i);
447 return &str[i];
448 }
449 break;
450 }
451
452 next:
453 newline = FALSE;
454 i++;
455 }
456
457 GST_DEBUG ("no #version declaration found in the first 1K");
458
459 return NULL;
460 }
461
462 /**
463 * gst_glsl_string_get_version_profile:
464 * @s: string to search for a valid #version string
465 * @version: (out): resulting #GstGLSLVersion
466 * @profile: (out): resulting #GstGLSLProfile
467 *
468 * Note: this function first searches the first 1 kilobytes for a #version
469 * preprocessor directive and then executes gst_glsl_version_profile_from_string().
470 *
471 * Returns: TRUE if a valid #version string was found, FALSE otherwise
472 */
473 gboolean
gst_glsl_string_get_version_profile(const gchar * s,GstGLSLVersion * version,GstGLSLProfile * profile)474 gst_glsl_string_get_version_profile (const gchar * s, GstGLSLVersion * version,
475 GstGLSLProfile * profile)
476 {
477 const gchar *version_profile_s;
478
479 version_profile_s = _gst_glsl_shader_string_find_version (s);
480 if (!version_profile_s)
481 goto error;
482
483 if (!gst_glsl_version_profile_from_string (version_profile_s, version,
484 profile))
485 goto error;
486
487 return TRUE;
488
489 error:
490 {
491 if (version)
492 *version = GST_GLSL_VERSION_NONE;
493 if (profile)
494 *profile = GST_GLSL_PROFILE_NONE;
495 return FALSE;
496 }
497 }
498
499 /**
500 * gst_gl_version_to_glsl_version:
501 * @gl_api: the #GstGLAPI
502 * @maj: the major GL version
503 * @min: the minor GL version
504 *
505 * Returns: The minimum supported #GstGLSLVersion available for @gl_api, @maj and @min
506 */
507 GstGLSLVersion
gst_gl_version_to_glsl_version(GstGLAPI gl_api,gint maj,gint min)508 gst_gl_version_to_glsl_version (GstGLAPI gl_api, gint maj, gint min)
509 {
510 g_return_val_if_fail (gl_api != GST_GL_API_NONE, 0);
511
512 _init_debug ();
513
514 if (gl_api & GST_GL_API_GLES2) {
515 if (maj == 2 && min == 0)
516 return 100;
517
518 if (maj == 3 && min >= 0 && min <= 2)
519 return maj * 100 + min * 10;
520
521 GST_WARNING ("unknown GLES version");
522 return 0;
523 }
524
525 /* versions match for >= 3.3 */
526 if (gl_api & (GST_GL_API_OPENGL3 | GST_GL_API_OPENGL)) {
527 if (maj > 3 || (maj == 3 && min >= 3))
528 return maj * 100 + min * 10;
529
530 if (maj == 3 && min == 2)
531 return 150;
532 if (maj == 3 && min == 1)
533 return 140;
534 if (maj == 3 && min == 0)
535 return 130;
536 if (maj == 2 && min == 1)
537 return 120;
538 if (maj == 2 && min == 0)
539 return 110;
540
541 GST_WARNING ("unknown GL version");
542 return 0;
543 }
544
545 GST_WARNING ("unknown GL API");
546 return 0;
547 }
548
549 /**
550 * gst_gl_context_supports_glsl_profile_version:
551 * @context: a #GstGLContext
552 * @version: a #GstGLSLVersion
553 * @profile: a #GstGLSLProfile
554 *
555 * Returns: Whether @context supports the combination of @version with @profile
556 */
557 gboolean
gst_gl_context_supports_glsl_profile_version(GstGLContext * context,GstGLSLVersion version,GstGLSLProfile profile)558 gst_gl_context_supports_glsl_profile_version (GstGLContext * context,
559 GstGLSLVersion version, GstGLSLProfile profile)
560 {
561 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
562
563 if (!_is_valid_version_profile (version, profile))
564 return FALSE;
565
566 if (profile != GST_GLSL_PROFILE_NONE) {
567 if (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0)) {
568 if ((profile & GST_GLSL_PROFILE_ES) == 0)
569 return FALSE;
570 } else if ((gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL) != 0) {
571 if ((profile & GST_GLSL_PROFILE_COMPATIBILITY) == 0)
572 return FALSE;
573 } else if ((gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3) != 0) {
574 /* GL_ARB_es2_compatibility is requried for GL3 contexts */
575 if ((profile & (GST_GLSL_PROFILE_CORE | GST_GLSL_PROFILE_ES)) == 0)
576 return FALSE;
577 } else {
578 g_assert_not_reached ();
579 }
580 }
581
582 if (version != GST_GLSL_VERSION_NONE) {
583 GstGLAPI gl_api;
584 gint maj, min, glsl_version;
585
586 if (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 1)) {
587 if (version > GST_GLSL_VERSION_310)
588 return FALSE;
589 } else if (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3,
590 0)) {
591 if (version > GST_GLSL_VERSION_300)
592 return FALSE;
593 } else if (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2,
594 0)) {
595 if (version > GST_GLSL_VERSION_100)
596 return FALSE;
597 }
598
599 gl_api = gst_gl_context_get_gl_api (context);
600 gst_gl_context_get_gl_version (context, &maj, &min);
601 glsl_version = gst_gl_version_to_glsl_version (gl_api, maj, min);
602 if (version > glsl_version)
603 return FALSE;
604
605 if (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 1, 0))
606 /* GL_ARB_es2_compatibility is requried for GL3 contexts */
607 if (version < GST_GLSL_VERSION_150 && version != GST_GLSL_VERSION_100)
608 return FALSE;
609
610 if (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0)
611 && version < GST_GLSL_VERSION_110)
612 return FALSE;
613 }
614
615 return TRUE;
616 }
617
618 gboolean
_gst_glsl_funcs_fill(GstGLSLFuncs * vtable,GstGLContext * context)619 _gst_glsl_funcs_fill (GstGLSLFuncs * vtable, GstGLContext * context)
620 {
621 GstGLFuncs *gl = context->gl_vtable;
622
623 if (vtable->initialized)
624 return TRUE;
625
626 if (gl->CreateProgram) {
627 vtable->CreateProgram = gl->CreateProgram;
628 vtable->DeleteProgram = gl->DeleteProgram;
629 vtable->UseProgram = gl->UseProgram;
630
631 vtable->CreateShader = gl->CreateShader;
632 vtable->DeleteShader = gl->DeleteShader;
633 vtable->AttachShader = gl->AttachShader;
634 vtable->DetachShader = gl->DetachShader;
635
636 vtable->GetAttachedShaders = gl->GetAttachedShaders;
637
638 vtable->GetShaderInfoLog = gl->GetShaderInfoLog;
639 vtable->GetShaderiv = gl->GetShaderiv;
640 vtable->GetProgramInfoLog = gl->GetProgramInfoLog;
641 vtable->GetProgramiv = gl->GetProgramiv;
642 } else if (gl->CreateProgramObject) {
643 vtable->CreateProgram = gl->CreateProgramObject;
644 vtable->DeleteProgram = gl->DeleteObject;
645 vtable->UseProgram = gl->UseProgramObject;
646
647 vtable->CreateShader = gl->CreateShaderObject;
648 vtable->DeleteShader = gl->DeleteObject;
649 vtable->AttachShader = gl->AttachObject;
650 vtable->DetachShader = gl->DetachObject;
651
652 vtable->GetAttachedShaders = gl->GetAttachedObjects;
653
654 vtable->GetShaderInfoLog = gl->GetInfoLog;
655 vtable->GetShaderiv = gl->GetObjectParameteriv;
656 vtable->GetProgramInfoLog = gl->GetInfoLog;
657 vtable->GetProgramiv = gl->GetObjectParameteriv;
658 } else {
659 vtable->initialized = FALSE;
660 return FALSE;
661 }
662
663 vtable->initialized = TRUE;
664 return TRUE;
665 }
666
667 static gchar *
_mangle_external_image_extension(const gchar * str,GstGLContext * context,GstGLTextureTarget from,GstGLTextureTarget to,GstGLSLVersion version,GstGLSLProfile profile)668 _mangle_external_image_extension (const gchar * str, GstGLContext * context,
669 GstGLTextureTarget from, GstGLTextureTarget to, GstGLSLVersion version,
670 GstGLSLProfile profile)
671 {
672 GST_DEBUG ("is oes? %d, profile == ES? %d, version >= 300? %d, "
673 "have essl3? %d", to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES,
674 profile == GST_GLSL_PROFILE_ES, version >= GST_GLSL_VERSION_300,
675 gst_gl_context_check_feature (context,
676 "GL_OES_EGL_image_external_essl3"));
677
678 /* replace GL_OES_EGL_image_external with GL_OES_EGL_image_external_essl3 where supported */
679 if (to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES && profile == GST_GLSL_PROFILE_ES
680 && version >= GST_GLSL_VERSION_300) {
681 if (gst_gl_context_check_feature (context,
682 "GL_OES_EGL_image_external_essl3")) {
683 GRegex *regex = g_regex_new (
684 /* '#extension ' with optional spacing */
685 "(#[ \\t]*extension[ \\t]+)"
686 /* what we're looking to replace */
687 "GL_OES_EGL_image_external"
688 /* ':' with optional spacing */
689 "([ \\t]*:[ \\t]*"
690 /* some word like require, disable, etc followed by spacing and a newline */
691 "\\S+[ \\t]*\\R)",
692 0, 0, NULL);
693 gchar *tmp = g_regex_replace (regex, str, -1, 0,
694 "\\1GL_OES_EGL_image_external_essl3\\2", 0, NULL);
695 g_regex_unref (regex);
696 return tmp;
697 } else {
698 GST_FIXME ("Undefined situation detected. GLES3 supported but "
699 "GL_OES_EGL_image_external_essl3 not supported. Falling back to the "
700 "older GL_OES_EGL_image_external extension");
701 return g_strdup (str);
702 }
703 } else {
704 return g_strdup (str);
705 }
706 }
707
708 static gchar *
_mangle_texture_access(const gchar * str,GstGLContext * context,GstGLTextureTarget from,GstGLTextureTarget to,GstGLSLVersion version,GstGLSLProfile profile)709 _mangle_texture_access (const gchar * str, GstGLContext * context,
710 GstGLTextureTarget from, GstGLTextureTarget to, GstGLSLVersion version,
711 GstGLSLProfile profile)
712 {
713 const gchar *from_str = NULL, *to_str = NULL;
714 gchar *ret, *tmp;
715 gchar *regex_find;
716 GRegex *regex;
717
718 if (from == GST_GL_TEXTURE_TARGET_2D)
719 from_str = "texture2D";
720 if (from == GST_GL_TEXTURE_TARGET_RECTANGLE)
721 from_str = "texture2DRect";
722 if (from == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
723 from_str = "texture2D";
724
725 /* GL3 || gles3 but not when external-oes unless the image_external_essl3 extension is supported */
726 if (profile == GST_GLSL_PROFILE_CORE || (profile == GST_GLSL_PROFILE_ES
727 && version >= GST_GLSL_VERSION_300
728 && (to != GST_GL_TEXTURE_TARGET_EXTERNAL_OES
729 || gst_gl_context_check_feature (context,
730 "GL_OES_EGL_image_external_essl3")))) {
731 to_str = "texture";
732 } else {
733 if (to == GST_GL_TEXTURE_TARGET_2D)
734 to_str = "texture2D";
735 if (to == GST_GL_TEXTURE_TARGET_RECTANGLE)
736 to_str = "texture2DRect";
737 if (to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
738 to_str = "texture2D";
739 }
740
741 /* followed by any amount of whitespace then a bracket */
742 regex_find = g_strdup_printf ("%s(?=\\s*\\()", from_str);
743 regex = g_regex_new (regex_find, 0, 0, NULL);
744 tmp = g_regex_replace_literal (regex, str, -1, 0, to_str, 0, NULL);
745 g_free (regex_find);
746 g_regex_unref (regex);
747
748 if (tmp) {
749 ret = tmp;
750 } else {
751 GST_FIXME ("Couldn't mangle texture access successfully from %s to %s",
752 from_str, to_str);
753 ret = g_strdup (str);
754 }
755
756 return ret;
757 }
758
759 static gchar *
_mangle_sampler_type(const gchar * str,GstGLTextureTarget from,GstGLTextureTarget to)760 _mangle_sampler_type (const gchar * str, GstGLTextureTarget from,
761 GstGLTextureTarget to)
762 {
763 const gchar *from_str = NULL, *to_str = NULL;
764 gchar *ret, *tmp;
765 gchar *regex_find;
766 GRegex *regex;
767
768 if (from == GST_GL_TEXTURE_TARGET_2D)
769 from_str = "sampler2D";
770 if (from == GST_GL_TEXTURE_TARGET_RECTANGLE)
771 from_str = "sampler2DRect";
772 if (from == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
773 from_str = "samplerExternalOES";
774
775 if (to == GST_GL_TEXTURE_TARGET_2D)
776 to_str = "sampler2D";
777 if (to == GST_GL_TEXTURE_TARGET_RECTANGLE)
778 to_str = "sampler2DRect";
779 if (to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
780 to_str = "samplerExternalOES";
781
782 /* followed by some whitespace */
783 regex_find = g_strdup_printf ("%s(?=\\s)", from_str);
784 regex = g_regex_new (regex_find, 0, 0, NULL);
785 tmp = g_regex_replace_literal (regex, str, -1, 0, to_str, 0, NULL);
786 g_free (regex_find);
787 g_regex_unref (regex);
788
789 if (tmp) {
790 ret = tmp;
791 } else {
792 GST_FIXME ("Couldn't mangle sampler type successfully from %s to %s",
793 from_str, to_str);
794 ret = g_strdup (str);
795 }
796
797 return ret;
798 }
799
800 static gchar *
_mangle_varying_attribute(const gchar * str,guint shader_type,GstGLSLVersion version,GstGLSLProfile profile)801 _mangle_varying_attribute (const gchar * str, guint shader_type,
802 GstGLSLVersion version, GstGLSLProfile profile)
803 {
804 if (shader_type == GL_VERTEX_SHADER) {
805 if (profile == GST_GLSL_PROFILE_CORE || (profile == GST_GLSL_PROFILE_ES
806 && version >= GST_GLSL_VERSION_300)) {
807 gchar *tmp, *tmp2;
808 GRegex *regex;
809
810 /* followed by some whitespace */
811 regex = g_regex_new ("varying(?=\\s)", 0, 0, NULL);
812 tmp = g_regex_replace_literal (regex, str, -1, 0, "out", 0, NULL);
813 g_regex_unref (regex);
814
815 /* followed by some whitespace */
816 regex = g_regex_new ("attribute(?=\\s)", 0, 0, NULL);
817 tmp2 = g_regex_replace_literal (regex, tmp, -1, 0, "in", 0, NULL);
818 g_regex_unref (regex);
819
820 g_free (tmp);
821 return tmp2;
822 }
823 } else if (shader_type == GL_FRAGMENT_SHADER) {
824 if (profile == GST_GLSL_PROFILE_CORE || (profile == GST_GLSL_PROFILE_ES
825 && version >= GST_GLSL_VERSION_300)) {
826 gchar *tmp;
827 GRegex *regex;
828
829 /* followed by some whitespace */
830 regex = g_regex_new ("varying(?=\\s)", 0, 0, NULL);
831 tmp = g_regex_replace_literal (regex, str, -1, 0, "in", 0, NULL);
832 g_regex_unref (regex);
833
834 return tmp;
835 }
836 }
837 return g_strdup (str);
838 }
839
840 static gchar *
_mangle_frag_color_data(const gchar * str)841 _mangle_frag_color_data (const gchar * str)
842 {
843 GRegex *regex;
844 gchar *ret, *tmp;
845
846 regex = g_regex_new ("gl_FragColor", 0, 0, NULL);
847 ret = g_regex_replace_literal (regex, str, -1, 0, "fragColor", 0, NULL);
848 g_regex_unref (regex);
849
850 tmp = ret;
851 /* search and replace 'gl_FragData[NUM]' into fragColor_NUM */
852 regex = g_regex_new ("gl_FragData\\[(\\d+)\\]", 0, 0, NULL);
853 ret = g_regex_replace (regex, tmp, -1, 0, "fragColor_\\1", 0, NULL);
854 g_regex_unref (regex);
855 g_free (tmp);
856
857 return ret;
858 }
859
860 static void
_mangle_version_profile_from_gl_api(GstGLContext * context,GstGLTextureTarget from,GstGLTextureTarget to,GstGLSLVersion * version,GstGLSLProfile * profile)861 _mangle_version_profile_from_gl_api (GstGLContext * context,
862 GstGLTextureTarget from, GstGLTextureTarget to, GstGLSLVersion * version,
863 GstGLSLProfile * profile)
864 {
865 GstGLAPI gl_api;
866 gint gl_major, gl_minor;
867
868 gl_api = gst_gl_context_get_gl_api (context);
869 gst_gl_context_get_gl_version (context, &gl_major, &gl_minor);
870
871 *version = GST_GLSL_VERSION_NONE;
872 *profile = GST_GLSL_PROFILE_NONE;
873
874 if (gl_api & GST_GL_API_OPENGL3) {
875 if (gl_major > 3 || gl_minor >= 3) {
876 *version = GST_GLSL_VERSION_330;
877 *profile = GST_GLSL_PROFILE_CORE;
878 } else {
879 *version = GST_GLSL_VERSION_150;
880 *profile = GST_GLSL_PROFILE_NONE;
881 }
882 } else if (gl_api & GST_GL_API_GLES2) {
883 /* We don't know which texture function to use if we have GLES3 and
884 * don't have the essl3 extension */
885 if (gl_major >= 3 && (to != GST_GL_TEXTURE_TARGET_EXTERNAL_OES
886 || gst_gl_context_check_feature (context,
887 "GL_OES_EGL_image_external_essl3"))) {
888 *version = GST_GLSL_VERSION_300;
889 *profile = GST_GLSL_PROFILE_ES;
890 } else if (gl_major >= 2) {
891 *version = GST_GLSL_VERSION_100;
892 *profile = GST_GLSL_PROFILE_ES;
893 }
894 } else if (gl_api & GST_GL_API_OPENGL) {
895 *version = GST_GLSL_VERSION_110;
896 *profile = GST_GLSL_PROFILE_COMPATIBILITY;
897 }
898 }
899
900 gchar *
_gst_glsl_mangle_shader(const gchar * str,guint shader_type,GstGLTextureTarget from,GstGLTextureTarget to,GstGLContext * context,GstGLSLVersion * version,GstGLSLProfile * profile)901 _gst_glsl_mangle_shader (const gchar * str, guint shader_type,
902 GstGLTextureTarget from, GstGLTextureTarget to, GstGLContext * context,
903 GstGLSLVersion * version, GstGLSLProfile * profile)
904 {
905 gchar *tmp, *tmp2;
906
907 _init_debug ();
908
909 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
910
911 _mangle_version_profile_from_gl_api (context, from, to, version, profile);
912 tmp2 =
913 _mangle_external_image_extension (str, context, from, to, *version,
914 *profile);
915 tmp = _mangle_texture_access (tmp2, context, from, to, *version, *profile);
916 g_free (tmp2);
917 tmp2 = _mangle_sampler_type (tmp, from, to);
918 g_free (tmp);
919 tmp = _mangle_varying_attribute (tmp2, shader_type, *version, *profile);
920 g_free (tmp2);
921 if (shader_type == GL_FRAGMENT_SHADER) {
922 if ((*profile == GST_GLSL_PROFILE_ES && *version >= GST_GLSL_VERSION_300)
923 || (*profile == GST_GLSL_PROFILE_CORE
924 && *version >= GST_GLSL_VERSION_150)) {
925 tmp2 = _mangle_frag_color_data (tmp);
926 g_free (tmp);
927 tmp = tmp2;
928 }
929 }
930 return tmp;
931 }
932
933 /**
934 * gst_gl_context_supports_precision:
935 * @context: a #GstGLContext
936 * @version: a #GstGLSLVersion
937 * @profile: a #GstGLSLProfile
938 *
939 * Returns: whether @context supports the 'precision' specifier in GLSL shaders
940 *
941 * Since: 1.16
942 */
943 gboolean
gst_gl_context_supports_precision(GstGLContext * context,GstGLSLVersion version,GstGLSLProfile profile)944 gst_gl_context_supports_precision (GstGLContext * context,
945 GstGLSLVersion version, GstGLSLProfile profile)
946 {
947 gboolean es2 = FALSE;
948
949 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
950
951 if ((profile & GST_GLSL_PROFILE_ES) == 0)
952 return FALSE;
953
954 es2 = gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0)
955 || gst_gl_context_check_feature (context, "GL_ARB_ES2_compatibility");
956
957 return es2 && context->gl_vtable->GetShaderPrecisionFormat;
958 }
959
960 /**
961 * gst_gl_context_supports_precision_highp:
962 * @context: a #GstGLContext
963 * @version: a #GstGLSLVersion
964 * @profile: a #GstGLSLProfile
965 *
966 * Returns: whether @context supports the 'precision highp' specifier in GLSL shaders
967 *
968 * Since: 1.16
969 */
970 gboolean
gst_gl_context_supports_precision_highp(GstGLContext * context,GstGLSLVersion version,GstGLSLProfile profile)971 gst_gl_context_supports_precision_highp (GstGLContext * context,
972 GstGLSLVersion version, GstGLSLProfile profile)
973 {
974 gint v_range[2] = { 0, }
975 , v_precision = 0;
976 gint f_range[2] = { 0, }
977 , f_precision = 0;
978
979 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
980
981 if (!gst_gl_context_supports_precision (context, version, profile))
982 return FALSE;
983
984 context->gl_vtable->GetShaderPrecisionFormat (GL_VERTEX_SHADER, GL_HIGH_FLOAT,
985 v_range, &v_precision);
986 context->gl_vtable->GetShaderPrecisionFormat (GL_FRAGMENT_SHADER,
987 GL_HIGH_FLOAT, f_range, &f_precision);
988
989 return v_range[0] != 0 && v_range[1] != 0 && v_precision != 0 &&
990 f_range[0] != 0 && f_range[1] != 0 && f_precision != 0;
991 }
992