diff --git a/gst-libs/gst/gl/gstglshader.c b/gst-libs/gst/gl/gstglshader.c index 8b06d6eb4c..016e47517a 100644 --- a/gst-libs/gst/gl/gstglshader.c +++ b/gst-libs/gst/gl/gstglshader.c @@ -26,6 +26,11 @@ #include "gl.h" #include "gstglshader.h" +/* FIXME: separate into separate shader stage objects that can be added/removed + * independently of the shader program */ + +static const gchar *es2_version_header = "#version 100\n"; + /* *INDENT-OFF* */ static const gchar *simple_vertex_shader_str_gles2 = "attribute vec4 a_position;\n" @@ -107,6 +112,8 @@ struct _GstGLShaderPrivate gboolean compiled; gboolean active; + GstGLAPI gl_api; + GstGLShaderVTable vtable; }; @@ -324,6 +331,9 @@ gst_gl_shader_init (GstGLShader * self) priv->compiled = FALSE; priv->active = FALSE; /* unused at the moment */ + + /* FIXME: add API to get/set this for each shader */ + priv->gl_api = GST_GL_API_ANY; } static gboolean @@ -395,6 +405,80 @@ gst_gl_shader_is_compiled (GstGLShader * shader) return shader->priv->compiled; } +static gboolean +_shader_string_has_version (const gchar * str) +{ + gboolean sl_comment = FALSE; + gboolean ml_comment = FALSE; + gboolean has_version = FALSE; + gint i = 0; + + /* search for #version to allow for preceeding comments as allowed by the + * GLSL specification */ + while (str && str[i] != '\0' && i < 1024) { + if (sl_comment) { + if (str[i] != '\n') + sl_comment = FALSE; + i++; + continue; + } + + if (ml_comment) { + if (g_strstr_len (&str[i], 2, "*/")) { + ml_comment = FALSE; + i += 2; + } else { + i++; + } + continue; + } + + if (g_strstr_len (&str[i], 2, "//")) { + sl_comment = TRUE; + i += 2; + continue; + } + + if (g_strstr_len (&str[i], 2, "/*")) { + ml_comment = TRUE; + i += 2; + continue; + } + + if (g_strstr_len (&str[i], 1, "#")) { + if (g_strstr_len (&str[i], 8, "#version")) + has_version = TRUE; + break; + } + + i++; + } + + return has_version; +} + +static void +_maybe_prepend_version (GstGLShader * shader, const gchar * shader_str, + gint * n_vertex_sources, const gchar *** vertex_sources) +{ + gint n = 1; + + /* FIXME: this all an educated guess */ + if (gst_gl_context_check_gl_version (shader->context, GST_GL_API_OPENGL3, 3, + 0) + && (shader->priv->gl_api & GST_GL_API_GLES2) != 0 + && !_shader_string_has_version (shader_str)) + n = 2; + + *vertex_sources = g_malloc0 (n * sizeof (gchar *)); + + if (n > 1) + *vertex_sources[0] = es2_version_header; + + (*vertex_sources)[n - 1] = shader_str; + *n_vertex_sources = n; +} + gboolean gst_gl_shader_compile (GstGLShader * shader, GError ** error) { @@ -423,10 +507,18 @@ gst_gl_shader_compile (GstGLShader * shader, GError ** error) g_return_val_if_fail (priv->program_handle, FALSE); if (priv->vertex_src) { + gint n_vertex_sources; + const gchar **vertex_sources; + + _maybe_prepend_version (shader, priv->vertex_src, &n_vertex_sources, + &vertex_sources); + /* create vertex object */ - const gchar *vertex_source = priv->vertex_src; priv->vertex_handle = priv->vtable.CreateShader (GL_VERTEX_SHADER); - gl->ShaderSource (priv->vertex_handle, 1, &vertex_source, NULL); + gl->ShaderSource (priv->vertex_handle, n_vertex_sources, vertex_sources, + NULL); + g_free (vertex_sources); + /* compile */ gl->CompileShader (priv->vertex_handle); /* check everything is ok */ @@ -455,10 +547,17 @@ gst_gl_shader_compile (GstGLShader * shader, GError ** error) } if (priv->fragment_src) { + gint n_fragment_sources; + const gchar **fragment_sources; + + _maybe_prepend_version (shader, priv->fragment_src, &n_fragment_sources, + &fragment_sources); + /* create fragment object */ - const gchar *fragment_source = priv->fragment_src; priv->fragment_handle = priv->vtable.CreateShader (GL_FRAGMENT_SHADER); - gl->ShaderSource (priv->fragment_handle, 1, &fragment_source, NULL); + gl->ShaderSource (priv->fragment_handle, n_fragment_sources, + fragment_sources, NULL); + g_free (fragment_sources); /* compile */ gl->CompileShader (priv->fragment_handle); /* check everything is ok */