glsl: fixup external-oes shaders by mangling the required extension
authorMatthew Waters <matthew@centricular.com>
Wed, 15 Jun 2016 02:47:05 +0000 (12:47 +1000)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:32:20 +0000 (19:32 +0000)
Newer devices require using a different GLSL extension for accessing
external-oes textures in a shader using the texture() functions.

While the GL_OES_EGL_image_external_essl3 should supposedly be supported
on a any GLES3 android device, the extension was defined after a lot of the
older drivers were built so they will not know about it.  Thus there are two
possible interpretations of which of texture[2D]() should be supported for
external-oes textures.  Strict adherence to the GL_OES_EGL_image_external
extension spec which uses texture2D() or following GLES3's pattern, also
allowing texture() as a function for accessing external-oes textures

This adds another mangling pass to convert
 #extension GL_OES_EGL_image_external : ...
into
 #extension GL_OES_EGL_image_external_essl3 : ...
on GLES3 and when the GL_OES_EGL_image_external_essl3 extension is supported.

Only uses texture() when the GLES3 and the GL_OES_EGL_image_external_essl3
extension is supported for external-oes textures.
Uses GLES2 + texture2D() + GL_OES_EGL_image_external in all other external-oes
cases.

https://bugzilla.gnome.org/show_bug.cgi?id=766993

gst-libs/gst/gl/gstglcolorconvert.c
gst-libs/gst/gl/gstglsl.c
gst-libs/gst/gl/gstglsl_private.h
gst-libs/gst/gl/gstglviewconvert.c

index ba717fa..c518bc9 100644 (file)
@@ -1723,19 +1723,14 @@ _create_shader (GstGLColorConvert * convert)
   gchar *version_str, *tmp, *tmp1;
   const gchar *strings[2];
   GError *error = NULL;
-  GstGLAPI gl_api;
-  gint gl_major, gl_minor;
   int i;
 
-  gl_api = gst_gl_context_get_gl_api (convert->context);
-  gst_gl_context_get_gl_version (convert->context, &gl_major, &gl_minor);
-
   ret = gst_gl_shader_new (convert->context);
 
   tmp =
       _gst_glsl_mangle_shader (text_vertex_shader, GL_VERTEX_SHADER,
-      info->templ->target, convert->priv->from_texture_target, gl_api, gl_major,
-      gl_minor, &version, &profile);
+      info->templ->target, convert->priv->from_texture_target, convert->context,
+      &version, &profile);
 
   tmp1 = gst_glsl_version_profile_to_string (version, profile);
   version_str = g_strdup_printf ("#version %s\n", tmp1);
@@ -1842,8 +1837,8 @@ _create_shader (GstGLColorConvert * convert)
   g_string_append (str, "\n}");
   tmp = g_string_free (str, FALSE);
   info->frag_prog = _gst_glsl_mangle_shader (tmp, GL_FRAGMENT_SHADER,
-      info->templ->target, convert->priv->from_texture_target, gl_api,
-      gl_major, gl_minor, &version, &profile);
+      info->templ->target, convert->priv->from_texture_target, convert->context,
+      &version, &profile);
   g_free (tmp);
 
   strings[1] = info->frag_prog;
index dca6edf..e3fe9c5 100644 (file)
@@ -594,10 +594,51 @@ _gst_glsl_funcs_fill (GstGLSLFuncs * vtable, GstGLContext * context)
   return TRUE;
 }
 
+static gchar *
+_mangle_external_image_extension (const gchar * str, GstGLContext * context,
+    GstGLTextureTarget from, GstGLTextureTarget to, GstGLSLVersion version,
+    GstGLSLProfile profile)
+{
+  GST_DEBUG ("is oes? %d, profile == ES? %d, version >= 300? %d, "
+      "have essl3? %d", to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES,
+      profile == GST_GLSL_PROFILE_ES, version >= GST_GLSL_VERSION_300,
+      gst_gl_context_check_feature (context,
+          "GL_OES_EGL_image_external_essl3"));
+
+  /* replace GL_OES_EGL_image_external with GL_OES_EGL_image_external_essl3 where supported */
+  if (to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES && profile == GST_GLSL_PROFILE_ES
+      && version >= GST_GLSL_VERSION_300) {
+    if (gst_gl_context_check_feature (context,
+            "GL_OES_EGL_image_external_essl3")) {
+      GRegex *regex = g_regex_new (
+          /* '#extension ' with optional spacing */
+          "(#[ \\t]*extension[ \\t]+)"
+          /* what we're looking to replace */
+          "GL_OES_EGL_image_external"
+          /* ':' with optional spacing */
+          "([ \\t]*:[ \\t]*"
+          /* some word like require, disable, etc followed by spacing and a newline */
+          "\\S+[ \\t]*\\R)",
+          0, 0, NULL);
+      gchar *tmp = g_regex_replace (regex, str, -1, 0,
+          "\\1GL_OES_EGL_image_external_essl3\\2", 0, NULL);
+      g_regex_unref (regex);
+      return tmp;
+    } else {
+      GST_FIXME ("Undefined situation detected. GLES3 supported but "
+          "GL_OES_EGL_image_external_essl3 not supported.  Falling back to the "
+          "older GL_OES_EGL_image_external extension");
+      return g_strdup (str);
+    }
+  } else {
+    return g_strdup (str);
+  }
+}
 
 static gchar *
-_mangle_texture_access (const gchar * str, GstGLTextureTarget from,
-    GstGLTextureTarget to, GstGLAPI gl_api, guint gl_major, guint gl_minor)
+_mangle_texture_access (const gchar * str, GstGLContext * context,
+    GstGLTextureTarget from, GstGLTextureTarget to, GstGLSLVersion version,
+    GstGLSLProfile profile)
 {
   const gchar *from_str = NULL, *to_str = NULL;
   gchar *ret, *tmp;
@@ -611,8 +652,12 @@ _mangle_texture_access (const gchar * str, GstGLTextureTarget from,
   if (from == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
     from_str = "texture2D";
 
-  if ((gl_api & GST_GL_API_OPENGL3) || (gl_api & GST_GL_API_GLES2
-          && gl_major >= 3)) {
+  /* GL3 || gles3 but not when external-oes unless the image_external_essl3 extension is supported */
+  if (profile == GST_GLSL_PROFILE_CORE || (profile == GST_GLSL_PROFILE_ES
+          && version >= GST_GLSL_VERSION_300
+          && (to != GST_GL_TEXTURE_TARGET_EXTERNAL_OES
+              || gst_gl_context_check_feature (context,
+                  "GL_OES_EGL_image_external_essl3")))) {
     to_str = "texture";
   } else {
     if (to == GST_GL_TEXTURE_TARGET_2D)
@@ -684,11 +729,11 @@ _mangle_sampler_type (const gchar * str, GstGLTextureTarget from,
 
 static gchar *
 _mangle_varying_attribute (const gchar * str, guint shader_type,
-    GstGLAPI gl_api, guint gl_major, guint gl_minor)
+    GstGLSLVersion version, GstGLSLProfile profile)
 {
   if (shader_type == GL_VERTEX_SHADER) {
-    if ((gl_api & GST_GL_API_OPENGL3) || (gl_api & GST_GL_API_GLES2
-            && gl_major >= 3)) {
+    if (profile == GST_GLSL_PROFILE_CORE || (profile == GST_GLSL_PROFILE_ES
+            && version >= GST_GLSL_VERSION_300)) {
       gchar *tmp, *tmp2;
       GRegex *regex;
 
@@ -706,8 +751,8 @@ _mangle_varying_attribute (const gchar * str, guint shader_type,
       return tmp2;
     }
   } else if (shader_type == GL_FRAGMENT_SHADER) {
-    if ((gl_api & GST_GL_API_OPENGL3) || (gl_api & GST_GL_API_GLES2
-            && gl_major > 3)) {
+    if (profile == GST_GLSL_PROFILE_CORE || (profile == GST_GLSL_PROFILE_ES
+            && version >= GST_GLSL_VERSION_300)) {
       gchar *tmp;
       GRegex *regex;
 
@@ -743,9 +788,16 @@ _mangle_frag_color_data (const gchar * str)
 }
 
 static void
-_mangle_version_profile_from_gl_api (GstGLAPI gl_api, gint gl_major,
-    gint gl_minor, GstGLSLVersion * version, GstGLSLProfile * profile)
+_mangle_version_profile_from_gl_api (GstGLContext * context,
+    GstGLTextureTarget from, GstGLTextureTarget to, GstGLSLVersion * version,
+    GstGLSLProfile * profile)
 {
+  GstGLAPI gl_api;
+  gint gl_major, gl_minor;
+
+  gl_api = gst_gl_context_get_gl_api (context);
+  gst_gl_context_get_gl_version (context, &gl_major, &gl_minor);
+
   *version = GST_GLSL_VERSION_NONE;
   *profile = GST_GLSL_PROFILE_NONE;
 
@@ -758,7 +810,11 @@ _mangle_version_profile_from_gl_api (GstGLAPI gl_api, gint gl_major,
       *profile = GST_GLSL_PROFILE_NONE;
     }
   } else if (gl_api & GST_GL_API_GLES2) {
-    if (gl_major >= 3) {
+    /* We don't know which texture function to use if we have GLES3 and
+     * don't have the essl3 extension */
+    if (gl_major >= 3 && (to != GST_GL_TEXTURE_TARGET_EXTERNAL_OES
+            || gst_gl_context_check_feature (context,
+                "GL_OES_EGL_image_external_essl3"))) {
       *version = GST_GLSL_VERSION_300;
       *profile = GST_GLSL_PROFILE_ES;
     } else if (gl_major >= 2) {
@@ -773,21 +829,24 @@ _mangle_version_profile_from_gl_api (GstGLAPI gl_api, gint gl_major,
 
 gchar *
 _gst_glsl_mangle_shader (const gchar * str, guint shader_type,
-    GstGLTextureTarget from, GstGLTextureTarget to, GstGLAPI gl_api,
-    gint gl_major, gint gl_minor, GstGLSLVersion * version,
-    GstGLSLProfile * profile)
+    GstGLTextureTarget from, GstGLTextureTarget to, GstGLContext * context,
+    GstGLSLVersion * version, GstGLSLProfile * profile)
 {
   gchar *tmp, *tmp2;
 
   _init_debug ();
 
-  _mangle_version_profile_from_gl_api (gl_api, gl_major, gl_minor, version,
-      profile);
-  tmp = _mangle_texture_access (str, from, to, gl_api, gl_major, gl_minor);
+  g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
+
+  _mangle_version_profile_from_gl_api (context, from, to, version, profile);
+  tmp2 =
+      _mangle_external_image_extension (str, context, from, to, *version,
+      *profile);
+  tmp = _mangle_texture_access (tmp2, context, from, to, *version, *profile);
+  g_free (tmp2);
   tmp2 = _mangle_sampler_type (tmp, from, to);
   g_free (tmp);
-  tmp =
-      _mangle_varying_attribute (tmp2, shader_type, gl_api, gl_major, gl_minor);
+  tmp = _mangle_varying_attribute (tmp2, shader_type, *version, *profile);
   g_free (tmp2);
   if (shader_type == GL_FRAGMENT_SHADER) {
     if ((*profile == GST_GLSL_PROFILE_ES && *version >= GST_GLSL_VERSION_300)
index 49c6b38..755170d 100644 (file)
@@ -60,8 +60,7 @@ G_GNUC_INTERNAL const gchar * _gst_glsl_shader_string_find_version (const gchar
 
 G_GNUC_INTERNAL gchar *
 _gst_glsl_mangle_shader (const gchar * str, guint shader_type, GstGLTextureTarget from,
-    GstGLTextureTarget to, GstGLAPI gl_api, gint gl_major, gint gl_minor,
-    GstGLSLVersion * version, GstGLSLProfile * profile);
+    GstGLTextureTarget to, GstGLContext * context, GstGLSLVersion * version, GstGLSLProfile * profile);
 
 G_END_DECLS
 
index ff770af..2fcbb81 100644 (file)
@@ -1457,7 +1457,6 @@ _init_view_convert_fbo (GstGLViewConvert * viewconvert)
 static gchar *
 _get_shader_string (GstGLViewConvert * viewconvert, GstGLShader * shader,
     GstVideoMultiviewMode in_mode, GstVideoMultiviewMode out_mode,
-    GstGLAPI gl_api, gint gl_major, gint gl_minor,
     GstGLSLVersion version, GstGLSLProfile profile)
 {
   const gchar *input_str, *output_str;
@@ -1574,8 +1573,8 @@ _get_shader_string (GstGLViewConvert * viewconvert, GstGLShader * shader,
 
   tmp2 =
       _gst_glsl_mangle_shader (tmp, GL_FRAGMENT_SHADER,
-      GST_GL_TEXTURE_TARGET_2D, viewconvert->from_texture_target, gl_api,
-      gl_major, gl_minor, &version, &profile);
+      GST_GL_TEXTURE_TARGET_2D, viewconvert->from_texture_target,
+      viewconvert->context, &version, &profile);
 
   return tmp2;
 }
@@ -1730,21 +1729,16 @@ _init_view_convert (GstGLViewConvert * viewconvert)
   {
     GstGLSLVersion version;
     GstGLSLProfile profile;
-    GstGLAPI gl_api;
-    gint gl_major, gl_minor;
     GstGLSLStage *vert, *frag;
     gchar *tmp, *tmp1, *version_str;
     const gchar *strings[2];
     GError *error = NULL;
 
-    gl_api = gst_gl_context_get_gl_api (viewconvert->context);
-    gst_gl_context_get_gl_version (viewconvert->context, &gl_major, &gl_minor);
-
     tmp =
         _gst_glsl_mangle_shader
         (gst_gl_shader_string_vertex_mat4_vertex_transform, GL_VERTEX_SHADER,
-        GST_GL_TEXTURE_TARGET_2D, viewconvert->from_texture_target, gl_api,
-        gl_major, gl_minor, &version, &profile);
+        GST_GL_TEXTURE_TARGET_2D, viewconvert->from_texture_target,
+        viewconvert->context, &version, &profile);
 
     tmp1 = gst_glsl_version_profile_to_string (version, profile);
     version_str = g_strdup_printf ("#version %s\n", tmp1);
@@ -1767,7 +1761,7 @@ _init_view_convert (GstGLViewConvert * viewconvert)
     }
 
     fragment_source_str = _get_shader_string (viewconvert, viewconvert->shader,
-        in_mode, out_mode, gl_api, gl_major, gl_minor, version, profile);
+        in_mode, out_mode, version, profile);
     strings[1] = fragment_source_str;
 
     frag =