glsl: add a shader stage object GstGLSLStage
authorMatthew Waters <matthew@centricular.com>
Fri, 4 Sep 2015 04:36:47 +0000 (14:36 +1000)
committerMatthew Waters <matthew@centricular.com>
Thu, 15 Oct 2015 10:27:57 +0000 (21:27 +1100)
Represents a stage (vertex, geometry, fragment, etc) in the shader
pipeline.

gst-libs/gst/gl/Makefile.am
gst-libs/gst/gl/gl.h
gst-libs/gst/gl/gstgl_fwd.h
gst-libs/gst/gl/gstglslstage.c [new file with mode: 0644]
gst-libs/gst/gl/gstglslstage.h [new file with mode: 0644]

index 239f5c4..e4cf41d 100644 (file)
@@ -19,6 +19,7 @@ libgstgl_@GST_API_VERSION@_la_SOURCES = \
        gstglbasefilter.c \
        gstglshader.c \
        gstglsl.c \
+       gstglslstage.c \
        gstglshadervariables.c \
        gstglcolorconvert.c \
        gstgldownload.c \
@@ -49,6 +50,7 @@ libgstgl_@GST_API_VERSION@include_HEADERS = \
        gstglshadervariables.h \
        gstglshader.h \
        gstglsl.h \
+       gstglslstage.h \
        gstglcolorconvert.h \
        gstgldownload.h \
        gstgluploadmeta.h \
index ff1ff08..ca09c91 100644 (file)
@@ -35,6 +35,7 @@
 #include <gst/gl/gstglfeature.h>
 #include <gst/gl/gstglutils.h>
 #include <gst/gl/gstglwindow.h>
+#include <gst/gl/gstglslstage.h>
 #include <gst/gl/gstglshader.h>
 #include <gst/gl/gstglcolorconvert.h>
 #include <gst/gl/gstglupload.h>
index cb29c6d..f76e672 100644 (file)
@@ -47,6 +47,10 @@ typedef struct _GstGLMemory GstGLMemory;
 typedef struct _GstGLAllocator GstGLAllocator;
 typedef struct _GstGLAllocatorClass GstGLAllocatorClass;
 
+typedef struct _GstGLSLStage        GstGLSLStage;
+typedef struct _GstGLSLStagePrivate GstGLSLStagePrivate;
+typedef struct _GstGLSLStageClass   GstGLSLStageClass;
+
 typedef struct _GstGLShader        GstGLShader;
 typedef struct _GstGLShaderPrivate GstGLShaderPrivate;
 typedef struct _GstGLShaderClass   GstGLShaderClass;
diff --git a/gst-libs/gst/gl/gstglslstage.c b/gst-libs/gst/gl/gstglslstage.c
new file mode 100644 (file)
index 0000000..ed5f4fd
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * GStreamer
+ * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gl/gl.h>
+
+#include "gstglslstage.h"
+#include "gstglsl_private.h"
+
+static const gchar *es2_version_header = "#version 100\n";
+
+/* *INDENT-OFF* */
+static const gchar *simple_vertex_shader_str_gles2 =
+      "attribute vec4 a_position;\n"
+      "attribute vec2 a_texcoord;\n"
+      "varying vec2 v_texcoord;\n"
+      "void main()\n"
+      "{\n"
+      "   gl_Position = a_position;\n"
+      "   v_texcoord = a_texcoord;\n"
+      "}\n";
+
+static const gchar *simple_fragment_shader_str_gles2 =
+      "#ifdef GL_ES\n"
+      "precision mediump float;\n"
+      "#endif\n"
+      "varying vec2 v_texcoord;\n"
+      "uniform sampler2D tex;\n"
+      "void main()\n"
+      "{\n"
+      "  gl_FragColor = texture2D(tex, v_texcoord);\n"
+      "}";
+/* *INDENT-ON* */
+
+GST_DEBUG_CATEGORY_STATIC (gst_glsl_stage_debug);
+#define GST_CAT_DEFAULT gst_glsl_stage_debug
+
+G_DEFINE_TYPE_WITH_CODE (GstGLSLStage, gst_glsl_stage, GST_TYPE_OBJECT,
+    GST_DEBUG_CATEGORY_INIT (gst_glsl_stage_debug, "glslstage", 0,
+        "GLSL Stage");
+    );
+
+#define GST_GLSL_STAGE_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_TYPE_GLSL_STAGE, GstGLSLStagePrivate))
+
+struct _GstGLSLStagePrivate
+{
+  GstGLSLFuncs vtable;
+
+  GLenum type;
+  GLhandleARB handle;
+  GstGLSLVersion version;
+  GstGLSLProfile profile;
+  gchar **strings;
+  gint n_strings;
+
+  gboolean compiled;
+};
+
+static void
+gst_glsl_stage_finalize (GObject * object)
+{
+  GstGLSLStage *stage = GST_GLSL_STAGE (object);
+  gint i;
+
+  if (stage->context) {
+    gst_object_unref (stage->context);
+    stage->context = NULL;
+  }
+
+  for (i = 0; i < stage->priv->n_strings; i++) {
+    g_free (stage->priv->strings[i]);
+  }
+  g_free (stage->priv->strings);
+  stage->priv->strings = NULL;
+
+  G_OBJECT_CLASS (gst_glsl_stage_parent_class)->finalize (object);
+}
+
+static void
+gst_glsl_stage_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_glsl_stage_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+}
+
+static void
+gst_glsl_stage_class_init (GstGLSLStageClass * klass)
+{
+  GObjectClass *obj_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GstGLSLStagePrivate));
+
+  obj_class->finalize = gst_glsl_stage_finalize;
+  obj_class->set_property = gst_glsl_stage_set_property;
+  obj_class->get_property = gst_glsl_stage_get_property;
+}
+
+static void
+gst_glsl_stage_init (GstGLSLStage * stage)
+{
+  stage->priv = GST_GLSL_STAGE_GET_PRIVATE (stage);
+}
+
+static gboolean
+_is_valid_shader_type (GLenum type)
+{
+  switch (type) {
+    case GL_VERTEX_SHADER:
+    case GL_FRAGMENT_SHADER:
+#ifdef GL_TESS_CONTROL_SHADER
+    case GL_TESS_CONTROL_SHADER:
+#endif
+#ifdef GL_TESS_EVALUATION_SHADER
+    case GL_TESS_EVALUATION_SHADER:
+#endif
+#ifdef GL_GEOMETRY_SHADER
+    case GL_GEOMETRY_SHADER:
+#endif
+#ifdef GL_COMPUTE_SHADER
+    case GL_COMPUTE_SHADER:
+#endif
+      return TRUE;
+    default:
+      return FALSE;
+  }
+}
+
+static const gchar *
+_shader_type_to_string (GLenum type)
+{
+  switch (type) {
+    case GL_VERTEX_SHADER:
+      return "vertex";
+    case GL_FRAGMENT_SHADER:
+      return "fragment";
+#ifdef GL_TESS_CONTROL_SHADER
+    case GL_TESS_CONTROL_SHADER:
+      return "tesselation control";
+#endif
+#ifdef GL_TESS_EVALUATION_SHADER
+    case GL_TESS_EVALUATION_SHADER:
+      return "tesselation evaluation";
+#endif
+#ifdef GL_GEOMETRY_SHADER
+    case GL_GEOMETRY_SHADER:
+      return "geometry";
+#endif
+#ifdef GL_COMPUTE_SHADER
+    case GL_COMPUTE_SHADER:
+      return "compute";
+#endif
+    default:
+      return "unknown";
+  }
+}
+
+static gboolean
+_ensure_shader (GstGLSLStage * stage)
+{
+  if (stage->priv->handle)
+    return TRUE;
+
+  if (!(stage->priv->handle =
+          stage->priv->vtable.CreateShader (stage->priv->type)))
+    return FALSE;
+
+  return stage->priv->handle != 0;
+}
+
+/**
+ * gst_glsl_stage_new_with_strings:
+ * @context: a #GstGLContext
+ * @type: the GL enum shader stage type
+ *
+ * Returns: (transfer full): a new #GstGLSLStage of the specified @type
+ */
+GstGLSLStage *
+gst_glsl_stage_new_with_strings (GstGLContext * context, guint type,
+    GstGLSLVersion version, GstGLSLProfile profile, gint n_strings,
+    const gchar ** str)
+{
+  GstGLSLStage *stage;
+
+  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL);
+  g_return_val_if_fail (_is_valid_shader_type (type), NULL);
+
+  stage = g_object_new (GST_TYPE_GLSL_STAGE, NULL);
+  /* FIXME: GInittable */
+  if (!_gst_glsl_funcs_fill (&stage->priv->vtable, context)) {
+    gst_object_unref (stage);
+    return NULL;
+  }
+
+  stage->context = gst_object_ref (context);
+  stage->priv->type = type;
+  if (!gst_glsl_stage_set_strings (stage, version, profile, n_strings, str)) {
+    gst_object_unref (stage);
+    return NULL;
+  }
+
+  return stage;
+}
+
+/**
+ * gst_glsl_stage_new_with_strings:
+ * @context: a #GstGLContext
+ * @type: the GL enum shader stage type
+ *
+ * Returns: (transfer full): a new #GstGLSLStage of the specified @type
+ */
+GstGLSLStage *
+gst_glsl_stage_new_with_string (GstGLContext * context, guint type,
+    GstGLSLVersion version, GstGLSLProfile profile, const gchar * str)
+{
+  return gst_glsl_stage_new_with_strings (context, type, version, profile, 1,
+      &str);
+}
+
+/**
+ * gst_glsl_stage_new:
+ * @context: a #GstGLContext
+ * @type: the GL enum shader stage type
+ *
+ * Returns: (transfer full): a new #GstGLSLStage of the specified @type
+ */
+GstGLSLStage *
+gst_glsl_stage_new (GstGLContext * context, guint type)
+{
+  return gst_glsl_stage_new_with_string (context, type, GST_GLSL_VERSION_NONE,
+      GST_GLSL_PROFILE_NONE, NULL);
+}
+
+/**
+ * gst_glsl_stage_new_with_default_vertex:
+ * @context: a #GstGLContext
+ *
+ * Returns: (transfer full): a new #GstGLSLStage with the default vertex shader
+ */
+GstGLSLStage *
+gst_glsl_stage_new_default_vertex (GstGLContext * context)
+{
+  return gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
+      GST_GLSL_VERSION_NONE,
+      GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
+      simple_vertex_shader_str_gles2);
+}
+
+/**
+ * gst_glsl_stage_new_with_default_fragment:
+ * @context: a #GstGLContext
+ *
+ * Returns: (transfer full): a new #GstGLSLStage with the default fragment shader
+ */
+GstGLSLStage *
+gst_glsl_stage_new_default_fragment (GstGLContext * context)
+{
+  return gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+      GST_GLSL_VERSION_NONE,
+      GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
+      simple_fragment_shader_str_gles2);
+}
+
+/**
+ * gst_glsl_stage_set_strings:
+ * @stage: a #GstGLSLStage
+ * @version: a #GstGLSLVersion
+ * @profile: a #GstGLSLProfile
+ * @n_strings: number of strings in @str
+ * @str: (transfer none): a GLSL shader string
+ *
+ * Replaces the current shader string with @str.
+ */
+gboolean
+gst_glsl_stage_set_strings (GstGLSLStage * stage, GstGLSLVersion version,
+    GstGLSLProfile profile, gint n_strings, const gchar ** str)
+{
+  gint i;
+
+  g_return_val_if_fail (GST_IS_GLSL_STAGE (stage), FALSE);
+  g_return_val_if_fail (n_strings > 0, FALSE);
+  g_return_val_if_fail (str != NULL, FALSE);
+
+  if (!gst_gl_context_supports_glsl_profile_version (stage->context, version,
+          profile))
+    return FALSE;
+
+  stage->priv->version = version;
+  stage->priv->profile = profile;
+
+  for (i = 0; i < stage->priv->n_strings; i++) {
+    g_free (stage->priv->strings[i]);
+  }
+
+  if (stage->priv->n_strings < n_strings) {
+    /* only realloc if we need more space */
+    if (stage->priv->strings)
+      g_free (stage->priv->strings);
+    stage->priv->strings = g_new0 (gchar *, n_strings);
+  }
+
+  for (i = 0; i < n_strings; i++)
+    stage->priv->strings[i] = g_strdup (str[i]);
+  stage->priv->n_strings = n_strings;
+
+  return TRUE;
+}
+
+/**
+ * gst_glsl_stage_get_shader_type:
+ * @stage: a #GstGLSLStage
+ *
+ * Returns: The GL shader type for this shader stage
+ */
+guint
+gst_glsl_stage_get_shader_type (GstGLSLStage * stage)
+{
+  g_return_val_if_fail (GST_IS_GLSL_STAGE (stage), 0);
+
+  return stage->priv->type;
+}
+
+/**
+ * gst_glsl_stage_get_handle:
+ * @stage: a #GstGLSLStage
+ *
+ * Returns: The GL handle for this shader stage
+ */
+guint
+gst_glsl_stage_get_handle (GstGLSLStage * stage)
+{
+  g_return_val_if_fail (GST_IS_GLSL_STAGE (stage), 0);
+  g_return_val_if_fail (stage->priv->compiled, 0);
+
+  return stage->priv->handle;
+}
+
+/**
+ * gst_glsl_stage_get_version:
+ * @stage: a #GstGLSLStage
+ *
+ * Returns: The GLSL version for the current shader stage
+ */
+GstGLSLVersion
+gst_glsl_stage_get_version (GstGLSLStage * stage)
+{
+  g_return_val_if_fail (GST_IS_GLSL_STAGE (stage), 0);
+
+  return stage->priv->version;
+}
+
+/**
+ * gst_glsl_stage_get_profile:
+ * @stage: a #GstGLSLStage
+ *
+ * Returns: The GLSL profile for the current shader stage
+ */
+GstGLSLProfile
+gst_glsl_stage_get_profile (GstGLSLStage * stage)
+{
+  g_return_val_if_fail (GST_IS_GLSL_STAGE (stage), 0);
+
+  return stage->priv->profile;
+}
+
+static void
+_maybe_prepend_version (GstGLSLStage * stage, gchar ** shader_str,
+    gint * n_vertex_sources, const gchar *** vertex_sources)
+{
+  gint n = *n_vertex_sources;
+  gboolean add_header = FALSE;
+  gint i, j;
+
+  /* FIXME: this all an educated guess */
+  if (gst_gl_context_check_gl_version (stage->context, GST_GL_API_OPENGL3, 3, 0)
+      && (stage->priv->profile & GST_GLSL_PROFILE_ES) != 0
+      && !_gst_glsl_shader_string_find_version (shader_str[0])) {
+    add_header = TRUE;
+    n++;
+  }
+
+  *vertex_sources = g_malloc0 (n * sizeof (gchar *));
+
+  i = 0;
+  if (add_header)
+    *vertex_sources[i++] = es2_version_header;
+
+  for (j = 0; j < stage->priv->n_strings; i++, j++)
+    (*vertex_sources)[i] = shader_str[j];
+  *n_vertex_sources = n;
+}
+
+struct compile
+{
+  GstGLSLStage *stage;
+  GError **error;
+  gboolean result;
+};
+
+static void
+_compile_shader (GstGLContext * context, struct compile *data)
+{
+  GstGLSLStagePrivate *priv = data->stage->priv;
+  GstGLSLFuncs *vtable = &data->stage->priv->vtable;
+  const GstGLFuncs *gl = context->gl_vtable;
+  const gchar **vertex_sources;
+  gchar info_buffer[2048];
+  gint n_vertex_sources;
+  GLint status;
+  gint len;
+  gint i;
+
+  if (data->stage->priv->compiled) {
+    data->result = TRUE;
+    return;
+  }
+
+  if (!_ensure_shader (data->stage)) {
+    g_set_error (data->error, GST_GLSL_ERROR, GST_GLSL_ERROR_COMPILE,
+        "Failed to create shader object");
+    return;
+  }
+
+  n_vertex_sources = data->stage->priv->n_strings;
+  _maybe_prepend_version (data->stage, priv->strings, &n_vertex_sources,
+      &vertex_sources);
+
+  GST_TRACE_OBJECT (data->stage, "compiling shader:");
+  for (i = 0; i < n_vertex_sources; i++) {
+    GST_TRACE_OBJECT (data->stage, "%s", vertex_sources[i]);
+  }
+
+  gl->ShaderSource (priv->handle, n_vertex_sources,
+      (const gchar **) vertex_sources, NULL);
+  gl->CompileShader (priv->handle);
+  /* FIXME: supported threaded GLSL compilers and don't destroy compilation
+   * performance by getting the compilation result directly after compilation */
+  gl->GetShaderiv (priv->handle, GL_COMPILE_STATUS, &status);
+
+  vtable->GetShaderInfoLog (priv->handle, sizeof (info_buffer) - 1, &len,
+      info_buffer);
+  info_buffer[len] = '\0';
+
+  if (status != GL_TRUE) {
+    GST_ERROR_OBJECT (data->stage, "%s shader compilation failed:%s",
+        _shader_type_to_string (priv->type), info_buffer);
+
+    g_set_error (data->error, GST_GLSL_ERROR, GST_GLSL_ERROR_COMPILE,
+        "%s shader compilation failed:%s",
+        _shader_type_to_string (priv->type), info_buffer);
+
+    vtable->DeleteShader (priv->handle);
+    data->result = FALSE;
+    return;
+  } else if (len > 1) {
+    GST_FIXME_OBJECT (data->stage, "%s shader info log:%s",
+        _shader_type_to_string (priv->type), info_buffer);
+  }
+
+  data->result = TRUE;
+}
+
+/**
+ * gst_glsl_stage_compile:
+ * @stage: a #GstGLSLStage
+ *
+ * Returns: whether the compilation suceeded
+ */
+gboolean
+gst_glsl_stage_compile (GstGLSLStage * stage, GError ** error)
+{
+  struct compile data;
+
+  g_return_val_if_fail (GST_IS_GLSL_STAGE (stage), FALSE);
+
+  if (!stage->priv->strings) {
+    g_set_error (error, GST_GLSL_ERROR, GST_GLSL_ERROR_COMPILE,
+        "No shader source to compile");
+    return FALSE;
+  }
+
+  data.stage = stage;
+  data.error = error;
+
+  gst_gl_context_thread_add (stage->context,
+      (GstGLContextThreadFunc) _compile_shader, &data);
+
+  stage->priv->compiled = TRUE;
+
+  return data.result;
+}
diff --git a/gst-libs/gst/gl/gstglslstage.h b/gst-libs/gst/gl/gstglslstage.h
new file mode 100644 (file)
index 0000000..be4ef32
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * GStreamer
+ * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_GLSL_STAGE_H__
+#define __GST_GLSL_STAGE_H__
+
+#include <gst/gl/gstglsl.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstGLSLStage GstGLSLStage;
+typedef struct _GstGLSLStageClass GstGLSLStageClass;
+typedef struct _GstGLSLStagePrivate GstGLSLStagePrivate;
+
+#define GST_TYPE_GLSL_STAGE         (gst_glsl_stage_get_type())
+#define GST_GLSL_STAGE(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_GLSL_STAGE, GstGLSLStage))
+#define GST_GLSL_STAGE_CLASS(k)     (G_TYPE_CHECK_CLASS((k), GST_TYPE_GLSL_STAGE, GstGLSLStageClass))
+#define GST_IS_GLSL_STAGE(o)        (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_GLSL_STAGE))
+#define GST_IS_GLSL_STAGE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_GLSL_STAGE))
+#define GST_GLSL_STAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_GLSL_STAGE, GstGLSLStageClass))
+
+struct _GstGLSLStage
+{
+  /*< private >*/
+  GstObject parent;
+
+  GstGLContext *context;
+
+  GstGLSLStagePrivate *priv;
+
+  gpointer _padding[GST_PADDING];
+};
+
+struct _GstGLSLStageClass
+{
+  GstObjectClass parent;
+
+  /*< private >*/
+};
+
+GType          gst_glsl_stage_get_type          (void);
+GstGLSLStage * gst_glsl_stage_new               (GstGLContext * context, guint type);
+GstGLSLStage * gst_glsl_stage_new_with_string   (GstGLContext * context,
+                                                 guint type,
+                                                 GstGLSLVersion version,
+                                                 GstGLSLProfile profile,
+                                                 const gchar * str);
+GstGLSLStage * gst_glsl_stage_new_with_strings  (GstGLContext * context,
+                                                 guint type,
+                                                 GstGLSLVersion version,
+                                                 GstGLSLProfile profile,
+                                                 gint n_strings,
+                                                 const gchar ** str);
+
+GstGLSLStage * gst_glsl_stage_new_default_fragment (GstGLContext * context);
+GstGLSLStage * gst_glsl_stage_new_default_vertex   (GstGLContext * context);
+
+guint          gst_glsl_stage_get_handle        (GstGLSLStage * stage);
+GstGLSLProfile gst_glsl_stage_get_profile       (GstGLSLStage * stage);
+GstGLSLVersion gst_glsl_stage_get_version       (GstGLSLStage * stage);
+guint          gst_glsl_stage_get_shader_type   (GstGLSLStage * stage);
+gboolean       gst_glsl_stage_set_strings       (GstGLSLStage * stage,
+                                                 GstGLSLVersion version,
+                                                 GstGLSLProfile profile,
+                                                 gint n_strings,
+                                                 const gchar ** str);
+gboolean       gst_glsl_stage_compile           (GstGLSLStage * stage,
+                                                 GError ** error);
+
+G_END_DECLS
+
+#endif /* __GST_GLSL_STAGE_H__ */