glshader: port to using GstGLSLStage objects for string management
authorMatthew Waters <matthew@centricular.com>
Fri, 4 Sep 2015 06:02:32 +0000 (16:02 +1000)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:32:09 +0000 (19:32 +0000)
A GstGLShader is now simply a collection of stages that are
compiled and linked together into a program.  The uniform/attribute
interface has remained the same.

ext/gl/effects/gstgleffectidentity.c
ext/gl/gstglcolorscale.c
ext/gl/gstgldifferencematte.c
ext/gl/gstgleffects.c
ext/gl/gstglimagesink.c
gst-libs/gst/gl/gstgloverlaycompositor.c
gst-libs/gst/gl/gstglshader.c
gst-libs/gst/gl/gstglshader.h
gst-libs/gst/gl/gstglutils.c
tests/check/libs/gstglcontext.c
tests/check/libs/gstglupload.c

index 9740cc7..ce29f60 100644 (file)
@@ -42,17 +42,18 @@ gst_gl_effects_identity_callback (gint width, gint height, guint texture,
 
   shader = g_hash_table_lookup (effects->shaderstable, "identity0");
   if (!shader) {
-    shader = gst_gl_shader_new (context);
-    g_hash_table_insert (effects->shaderstable, (gchar *) "identity0", shader);
+    GError *error = NULL;
 
-    if (!gst_gl_shader_compile_with_default_vf_and_check (shader,
-            &filter->draw_attr_position_loc, &filter->draw_attr_texture_loc)) {
-      /* gst gl context error is already set */
+    if (!(shader = gst_gl_shader_new_default (context, &error))) {
       GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
-          ("Failed to initialize identity shader, %s",
-              gst_gl_context_get_error ()), (NULL));
+          ("Failed to initialize identity shader: %s", error->message), (NULL));
       return;
     }
+
+    filter->draw_attr_position_loc =
+        gst_gl_shader_get_attribute_location (shader, "a_position");
+    filter->draw_attr_texture_loc =
+        gst_gl_shader_get_attribute_location (shader, "a_texcoord");
   }
   gst_gl_shader_use (shader);
 
index f4c104c..c7df0a8 100644 (file)
@@ -142,19 +142,20 @@ gst_gl_colorscale_gl_start (GstGLBaseFilter * base_filter)
   GstGLColorscale *colorscale = GST_GL_COLORSCALE (base_filter);
   GstGLFilter *filter = GST_GL_FILTER (base_filter);
   GstGLShader *shader;
+  GError *error = NULL;
 
-  shader = gst_gl_shader_new (base_filter->context);
-
-  if (!gst_gl_shader_compile_with_default_vf_and_check (shader,
-          &filter->draw_attr_position_loc, &filter->draw_attr_texture_loc)) {
-    gst_gl_context_clear_shader (base_filter->context);
+  if (!(shader = gst_gl_shader_new_default (base_filter->context, &error))) {
+    GST_ERROR_OBJECT (colorscale, "Failed to initialize shader: %s",
+        error->message);
     gst_object_unref (shader);
-    GST_ERROR_OBJECT (colorscale, "Failed to initialize identity shader");
-    GST_ELEMENT_ERROR (colorscale, RESOURCE, NOT_FOUND, ("%s",
-            "Failed to initialize identity shader"), (NULL));
     return FALSE;
   }
 
+  filter->draw_attr_position_loc =
+      gst_gl_shader_get_attribute_location (shader, "a_position");
+  filter->draw_attr_texture_loc =
+      gst_gl_shader_get_attribute_location (shader, "a_texcoord");
+
   colorscale->shader = shader;
 
   return GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter);
index b2b5fa5..a746b3d 100644 (file)
@@ -78,7 +78,9 @@ static void
 gst_gl_differencematte_init_gl_resources (GstGLFilter * filter)
 {
   GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
-  GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable;
+  GstGLContext *context = GST_GL_BASE_FILTER (filter)->context;
+  const GstGLFuncs *gl = context->gl_vtable;
+  GError *error = NULL;
   gint i;
 
   for (i = 0; i < 4; i++) {
@@ -96,45 +98,57 @@ gst_gl_differencematte_init_gl_resources (GstGLFilter * filter)
         gst_gl_shader_new (GST_GL_BASE_FILTER (filter)->context);
   }
 
-  if (!gst_gl_shader_compile_with_default_v_and_check (differencematte->shader
-          [0], difference_fragment_source, &filter->draw_attr_position_loc,
-          &filter->draw_attr_texture_loc)) {
-    gst_gl_context_set_error (GST_GL_BASE_FILTER (differencematte)->context,
-        "Failed to initialize difference shader");
+  if (!(differencematte->shader[0] =
+          gst_gl_shader_new_link_with_stages (context, &error,
+              gst_glsl_stage_new_default_vertex (context),
+              gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+                  GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_ES,
+                  difference_fragment_source), NULL))) {
     GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND, ("%s",
             gst_gl_context_get_error ()), (NULL));
     return;
   }
 
-  if (!gst_gl_shader_compile_with_default_v_and_check (differencematte->shader
-          [1], hconv7_fragment_source_gles2, &filter->draw_attr_position_loc,
-          &filter->draw_attr_texture_loc)) {
-    gst_gl_context_set_error (GST_GL_BASE_FILTER (differencematte)->context,
-        "Failed to initialize hconv7 shader");
+  if (!(differencematte->shader[1] =
+          gst_gl_shader_new_link_with_stages (context, &error,
+              gst_glsl_stage_new_default_vertex (context),
+              gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+                  GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_ES,
+                  hconv7_fragment_source_gles2), NULL))) {
     GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND, ("%s",
             gst_gl_context_get_error ()), (NULL));
     return;
   }
 
-  if (!gst_gl_shader_compile_with_default_v_and_check (differencematte->shader
-          [2], vconv7_fragment_source_gles2, &filter->draw_attr_position_loc,
-          &filter->draw_attr_texture_loc)) {
-    gst_gl_context_set_error (GST_GL_BASE_FILTER (differencematte)->context,
-        "Failed to initialize vconv7 shader");
+  if (!(differencematte->shader[2] =
+          gst_gl_shader_new_link_with_stages (context, &error,
+              gst_glsl_stage_new_default_vertex (context),
+              gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+                  GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_ES,
+                  vconv7_fragment_source_gles2), NULL))) {
     GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND, ("%s",
             gst_gl_context_get_error ()), (NULL));
     return;
   }
 
-  if (!gst_gl_shader_compile_with_default_v_and_check (differencematte->shader
-          [3], texture_interp_fragment_source, &filter->draw_attr_position_loc,
-          &filter->draw_attr_texture_loc)) {
-    gst_gl_context_set_error (GST_GL_BASE_FILTER (differencematte)->context,
-        "Failed to initialize interp shader");
+  if (!(differencematte->shader[3] =
+          gst_gl_shader_new_link_with_stages (context, &error,
+              gst_glsl_stage_new_default_vertex (context),
+              gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+                  GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_ES,
+                  texture_interp_fragment_source), NULL))) {
     GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND, ("%s",
             gst_gl_context_get_error ()), (NULL));
     return;
   }
+
+  /* FIXME: this should really be per shader */
+  filter->draw_attr_position_loc =
+      gst_gl_shader_get_attribute_location (differencematte->shader[3],
+      "a_position");
+  filter->draw_attr_texture_loc =
+      gst_gl_shader_get_attribute_location (differencematte->shader[3],
+      "a_texcoord");
 }
 
 /* free resources that need a gl context */
index 6cf5afc..cf4de6e 100644 (file)
@@ -545,21 +545,22 @@ gst_gl_effects_get_fragment_shader (GstGLEffects * effects,
   shader = g_hash_table_lookup (effects->shaderstable, shader_name);
 
   if (!shader) {
-    shader = gst_gl_shader_new (context);
-    if (!gst_gl_shader_compile_with_default_v_and_check (shader,
-            shader_source_gles2, &filter->draw_attr_position_loc,
-            &filter->draw_attr_texture_loc)) {
-      /* gst gl context error is already set */
+    GError *error = NULL;
+
+    if (!(shader = gst_gl_shader_new_link_with_stages (context, &error,
+                gst_glsl_stage_new_default_vertex (context),
+                gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+                    GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_ES,
+                    shader_source_gles2), NULL))) {
       GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
-          ("Failed to initialize %s shader, %s",
-              shader_name, gst_gl_context_get_error ()), (NULL));
-      gst_object_unref (shader);
-      shader = NULL;
+          ("Failed to initialize %s shader", shader_name), (NULL));
     }
-  }
 
-  if (!shader)
-    return NULL;
+    filter->draw_attr_position_loc =
+        gst_gl_shader_get_attribute_location (shader, "a_position");
+    filter->draw_attr_texture_loc =
+        gst_gl_shader_get_attribute_location (shader, "a_texcoord");
+  }
 
   g_hash_table_insert (effects->shaderstable, (gchar *) shader_name, shader);
 
index 2c3b935..be2e838 100644 (file)
@@ -1682,13 +1682,23 @@ static void
 gst_glimage_sink_thread_init_redisplay (GstGLImageSink * gl_sink)
 {
   const GstGLFuncs *gl = gl_sink->context->gl_vtable;
+  GError *error = NULL;
 
-  gl_sink->redisplay_shader = gst_gl_shader_new (gl_sink->context);
-
-  if (!gst_gl_shader_compile_with_default_vf_and_check
-      (gl_sink->redisplay_shader, &gl_sink->attr_position,
-          &gl_sink->attr_texture))
+  if (!(gl_sink->redisplay_shader =
+          gst_gl_shader_new_link_with_stages (gl_sink->context, &error,
+              gst_glsl_stage_new_default_vertex (gl_sink->context),
+              gst_glsl_stage_new_default_fragment (gl_sink->context), NULL))) {
+    GST_ERROR_OBJECT (gl_sink, "Failed to link shader: %s", error->message);
     gst_glimage_sink_cleanup_glthread (gl_sink);
+    return;
+  }
+
+  gl_sink->attr_position =
+      gst_gl_shader_get_attribute_location (gl_sink->redisplay_shader,
+      "a_position");
+  gl_sink->attr_texture =
+      gst_gl_shader_get_attribute_location (gl_sink->redisplay_shader,
+      "a_texcoord");
 
   if (gl->GenVertexArrays) {
     gl->GenVertexArrays (1, &gl_sink->vao);
index 97a4aab..a1cdce6 100644 (file)
@@ -425,12 +425,24 @@ gst_gl_overlay_compositor_init_gl (GstGLContext * context,
 {
   GstGLOverlayCompositor *compositor =
       (GstGLOverlayCompositor *) compositor_pointer;
-
-  if (!gst_gl_shader_compile_with_default_v_and_check (compositor->shader,
-          fragment_shader, &compositor->position_attrib,
-          &compositor->texcoord_attrib)) {
-    GST_ERROR ("could not initialize shader.");
+  GError *error = NULL;
+
+  if (!(compositor->shader =
+          gst_gl_shader_new_link_with_stages (context, &error,
+              gst_glsl_stage_new_default_vertex (context),
+              gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+                  GST_GLSL_VERSION_NONE,
+                  GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
+                  fragment_shader), NULL))) {
+    GST_ERROR_OBJECT (compositor, "could not initialize shader: %s",
+        error->message);
+    return;
   }
+
+  compositor->position_attrib =
+      gst_gl_shader_get_attribute_location (compositor->shader, "a_position");
+  compositor->texcoord_attrib =
+      gst_gl_shader_get_attribute_location (compositor->shader, "a_texcoord");
 }
 
 GstGLOverlayCompositor *
@@ -441,8 +453,6 @@ gst_gl_overlay_compositor_new (GstGLContext * context)
 
   compositor->context = gst_object_ref (context);
 
-  compositor->shader = gst_gl_shader_new (compositor->context);
-
   gst_gl_context_thread_add (compositor->context,
       gst_gl_overlay_compositor_init_gl, compositor);
 
index a41bf38..1eea611 100644 (file)
 
 #include "gl.h"
 #include "gstglshader.h"
+#include "gstglsl_private.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"
-      "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* */
-
-#ifndef GL_COMPILE_STATUS
-#define GL_COMPILE_STATUS             0x8B81
-#endif
 #ifndef GLhandleARB
 #define GLhandleARB GLuint
 #endif
@@ -94,27 +64,17 @@ typedef struct _GstGLShaderVTable
 enum
 {
   PROP_0,
-  PROP_VERTEX_SRC,
-  PROP_FRAGMENT_SRC,
-  PROP_COMPILED,
-  PROP_ACTIVE                   /* unused */
+  PROP_LINKED,
 };
 
 struct _GstGLShaderPrivate
 {
-  gchar *vertex_src;
-  gchar *fragment_src;
-
-  GLhandleARB vertex_handle;
-  GLhandleARB fragment_handle;
   GLhandleARB program_handle;
+  GList *stages;
 
-  gboolean compiled;
-  gboolean active;
-
-  GstGLAPI gl_api;
+  gboolean linked;
 
-  GstGLShaderVTable vtable;
+  GstGLSLFuncs vtable;
 };
 
 GST_DEBUG_CATEGORY_STATIC (gst_gl_shader_debug);
@@ -130,21 +90,21 @@ _cleanup_shader (GstGLContext * context, GstGLShader * shader)
 {
   GstGLShaderPrivate *priv = shader->priv;
 
+  GST_OBJECT_LOCK (shader);
+
   /* release shader objects */
-  gst_gl_shader_release (shader);
+  gst_gl_shader_release_unlocked (shader);
 
   /* delete program */
   if (priv->program_handle) {
     GST_TRACE ("finalizing program shader %u", priv->program_handle);
 
     priv->vtable.DeleteProgram (priv->program_handle);
-    /* err = glGetError (); */
-    /* GST_WARNING ("error: 0x%x", err);  */
-    /* glGetObjectParameteriv(priv->program_handle, GL_OBJECT_DELETE_STATUS_, &status); */
-    /* GST_INFO ("program deletion status:%s", status == GL_TRUE ? "true" : "false" ); */
   }
 
   GST_DEBUG ("shader deleted %u", priv->program_handle);
+
+  GST_OBJECT_UNLOCK (shader);
 }
 
 static void
@@ -158,14 +118,9 @@ gst_gl_shader_finalize (GObject * object)
 
   GST_TRACE_OBJECT (shader, "finalizing shader %u", priv->program_handle);
 
-  g_free (priv->vertex_src);
-  g_free (priv->fragment_src);
-
   gst_gl_context_thread_add (shader->context,
       (GstGLContextThreadFunc) _cleanup_shader, shader);
 
-  priv->fragment_handle = 0;
-  priv->vertex_handle = 0;
   priv->program_handle = 0;
 
   if (shader->context) {
@@ -180,15 +135,7 @@ static void
 gst_gl_shader_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec)
 {
-  GstGLShader *shader = GST_GL_SHADER (object);
-
   switch (prop_id) {
-    case PROP_VERTEX_SRC:
-      gst_gl_shader_set_vertex_source (shader, g_value_get_string (value));
-      break;
-    case PROP_FRAGMENT_SRC:
-      gst_gl_shader_set_fragment_source (shader, g_value_get_string (value));
-      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -203,27 +150,13 @@ gst_gl_shader_get_property (GObject * object,
   GstGLShaderPrivate *priv = shader->priv;
 
   switch (prop_id) {
-    case PROP_VERTEX_SRC:
-      g_value_set_string (value, priv->vertex_src);
-      break;
-    case PROP_FRAGMENT_SRC:
-      g_value_set_string (value, priv->fragment_src);
-      break;
-    case PROP_COMPILED:
-      g_value_set_boolean (value, priv->compiled);
+    case PROP_LINKED:
+      g_value_set_boolean (value, priv->linked);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
-
-}
-
-int
-gst_gl_shader_get_program_handle (GstGLShader * shader)
-{
-  GstGLShaderPrivate *priv = shader->priv;
-  return (int) priv->program_handle;
 }
 
 static void
@@ -239,352 +172,442 @@ gst_gl_shader_class_init (GstGLShaderClass * klass)
   obj_class->get_property = gst_gl_shader_get_property;
 
   /* .. and install properties */
-
-  g_object_class_install_property (obj_class,
-      PROP_VERTEX_SRC,
-      g_param_spec_string ("vertex-src",
-          "Vertex Source",
-          "GLSL Vertex Shader source code", NULL,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (obj_class,
-      PROP_FRAGMENT_SRC,
-      g_param_spec_string ("fragment-src",
-          "Fragment Source",
-          "GLSL Fragment Shader source code", NULL,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (obj_class,
-      PROP_ACTIVE,
-      g_param_spec_string ("active",
-          "Active", "Enable/Disable the shader", NULL,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (obj_class,
-      PROP_COMPILED,
-      g_param_spec_boolean ("compiled",
-          "Compiled",
-          "Shader compile and link status", FALSE,
+      PROP_LINKED,
+      g_param_spec_boolean ("linked",
+          "Linked",
+          "Shader link status", FALSE,
           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 }
 
-void
-gst_gl_shader_set_vertex_source (GstGLShader * shader, const gchar * src)
+static void
+gst_gl_shader_init (GstGLShader * self)
 {
+  /* initialize sources and create program object */
   GstGLShaderPrivate *priv;
 
-  g_return_if_fail (GST_GL_IS_SHADER (shader));
-  g_return_if_fail (src != NULL);
+  priv = self->priv = GST_GL_SHADER_GET_PRIVATE (self);
 
-  priv = shader->priv;
+  priv->linked = FALSE;
+}
+
+static GstGLShader *
+_new_with_stages_va_list (GstGLContext * context, GError ** error,
+    va_list varargs)
+{
+  GstGLShader *shader;
+  GstGLSLStage *stage;
 
-  if (gst_gl_shader_is_compiled (shader))
-    gst_gl_shader_release (shader);
+  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL);
 
-  g_free (priv->vertex_src);
+  shader = g_object_new (GST_GL_TYPE_SHADER, NULL);
+  shader->context = gst_object_ref (context);
 
-  priv->vertex_src = g_strdup (src);
+  while ((stage = va_arg (varargs, GstGLSLStage *))) {
+    if (!gst_glsl_stage_compile (stage, error)) {
+      gst_object_unref (shader);
+      return NULL;
+    }
+    if (!gst_gl_shader_attach (shader, stage)) {
+      g_set_error (error, GST_GLSL_ERROR, GST_GLSL_ERROR_PROGRAM,
+          "Failed to attach stage to program");
+      gst_object_unref (shader);
+      return NULL;
+    }
+  }
+
+  return shader;
 }
 
-void
-gst_gl_shader_set_fragment_source (GstGLShader * shader, const gchar * src)
+/**
+ * gst_gl_shader_new_link_with_stages:
+ * @context: a #GstGLContext
+ * @error: a #GError
+ *
+ * Each stage will attempt to be compiled and attached to @shader.  Then
+ * the shader will be linked. On error, %NULL will be returned and @error will
+ * contain the details of the error.
+ *
+ * Note: must be called in the GL thread
+ *
+ * Returns: (transfer full): a new @shader with the specified stages.
+ */
+GstGLShader *
+gst_gl_shader_new_link_with_stages (GstGLContext * context, GError ** error,
+    ...)
 {
-  GstGLShaderPrivate *priv;
+  GstGLShader *shader;
+  va_list varargs;
 
-  g_return_if_fail (GST_GL_IS_SHADER (shader));
-  g_return_if_fail (src != NULL);
+  va_start (varargs, error);
+  shader = _new_with_stages_va_list (context, error, varargs);
+  va_end (varargs);
 
-  priv = shader->priv;
+  if (!shader)
+    return NULL;
 
-  if (gst_gl_shader_is_compiled (shader))
-    gst_gl_shader_release (shader);
+  if (!gst_gl_shader_link (shader, error))
+    return NULL;
 
-  g_free (priv->fragment_src);
+  return shader;
+}
 
-  priv->fragment_src = g_strdup (src);
+/**
+ * gst_gl_shader_new_with_stages:
+ * @context: a #GstGLContext
+ * @error: a #GError
+ *
+ * Each stage will attempt to be compiled and attached to @shader.  On error,
+ * %NULL will be returned and @error will contain the details of the error.
+ *
+ * Note: must be called in the GL thread
+ *
+ * Returns: (transfer full): a new @shader with the specified stages.
+ */
+GstGLShader *
+gst_gl_shader_new_with_stages (GstGLContext * context, GError ** error, ...)
+{
+  GstGLShader *shader;
+  va_list varargs;
+
+  va_start (varargs, error);
+  shader = _new_with_stages_va_list (context, error, varargs);
+  va_end (varargs);
+
+  return shader;
 }
 
-const gchar *
-gst_gl_shader_get_vertex_source (GstGLShader * shader)
+/**
+ * gst_gl_shader_new:
+ * @context: a #GstGLContext
+ *
+ * Note: must be called in the GL thread
+ *
+ * Returns: (transfer full): a new empty @shader
+ */
+GstGLShader *
+gst_gl_shader_new (GstGLContext * context)
 {
-  g_return_val_if_fail (GST_GL_IS_SHADER (shader), NULL);
-  return shader->priv->vertex_src;
+  return gst_gl_shader_new_with_stages (context, NULL, NULL);
 }
 
-const gchar *
-gst_gl_shader_get_fragment_source (GstGLShader * shader)
+/**
+ * gst_gl_shader_new_default:
+ * @context: a #GstGLContext
+ *
+ * Note: must be called in the GL thread
+ *
+ * Returns: (transfer full): a default @shader
+ */
+GstGLShader *
+gst_gl_shader_new_default (GstGLContext * context, GError ** error)
 {
-  g_return_val_if_fail (GST_GL_IS_SHADER (shader), NULL);
-  return shader->priv->fragment_src;
+  return gst_gl_shader_new_link_with_stages (context, error,
+      gst_glsl_stage_new_default_vertex (context),
+      gst_glsl_stage_new_default_fragment (context), NULL);
 }
 
-static void
-gst_gl_shader_init (GstGLShader * self)
+/**
+ * gst_gl_shader_is_linked:
+ * @shader: a #GstGLShader
+ *
+ * Note: must be called in the GL thread
+ *
+ * Returns: whether @shader has been successfully linked
+ */
+gboolean
+gst_gl_shader_is_linked (GstGLShader * shader)
 {
-  /* initialize sources and create program object */
-  GstGLShaderPrivate *priv;
+  gboolean ret;
 
-  priv = self->priv = GST_GL_SHADER_GET_PRIVATE (self);
+  g_return_val_if_fail (GST_GL_IS_SHADER (shader), FALSE);
 
-  priv->vertex_src = NULL;
-  priv->fragment_src = NULL;
+  GST_OBJECT_LOCK (shader);
+  ret = shader->priv->linked;
+  GST_OBJECT_UNLOCK (shader);
 
-  priv->fragment_handle = 0;
-  priv->vertex_handle = 0;
+  return ret;
+}
 
-  priv->compiled = FALSE;
-  priv->active = FALSE;         /* unused at the moment */
+static gboolean
+_ensure_program (GstGLShader * shader)
+{
+  if (shader->priv->program_handle)
+    return TRUE;
 
-  /* FIXME: add API to get/set this for each shader */
-  priv->gl_api = GST_GL_API_ANY;
+  shader->priv->program_handle = shader->priv->vtable.CreateProgram ();
+  return shader->priv->program_handle != 0;
 }
 
-static gboolean
-_fill_vtable (GstGLShader * shader, GstGLContext * context)
+/**
+ * gst_gl_shader_get_program_handle:
+ * @shader: a #GstGLShader
+ *
+ * Returns: the GL program handle for this shader
+ */
+int
+gst_gl_shader_get_program_handle (GstGLShader * shader)
 {
-  GstGLFuncs *gl = context->gl_vtable;
-  GstGLShaderVTable *vtable = &shader->priv->vtable;
-
-  if (gl->CreateProgram) {
-    vtable->CreateProgram = gl->CreateProgram;
-    vtable->DeleteProgram = gl->DeleteProgram;
-    vtable->UseProgram = gl->UseProgram;
-
-    vtable->CreateShader = gl->CreateShader;
-    vtable->DeleteShader = gl->DeleteShader;
-    vtable->AttachShader = gl->AttachShader;
-    vtable->DetachShader = gl->DetachShader;
-
-    vtable->GetAttachedShaders = gl->GetAttachedShaders;
-
-    vtable->GetShaderInfoLog = gl->GetShaderInfoLog;
-    vtable->GetShaderiv = gl->GetShaderiv;
-    vtable->GetProgramInfoLog = gl->GetProgramInfoLog;
-    vtable->GetProgramiv = gl->GetProgramiv;
-  } else if (gl->CreateProgramObject) {
-    vtable->CreateProgram = gl->CreateProgramObject;
-    vtable->DeleteProgram = gl->DeleteObject;
-    vtable->UseProgram = gl->UseProgramObject;
-
-    vtable->CreateShader = gl->CreateShaderObject;
-    vtable->DeleteShader = gl->DeleteObject;
-    vtable->AttachShader = gl->AttachObject;
-    vtable->DetachShader = gl->DetachObject;
-
-    vtable->GetAttachedShaders = gl->GetAttachedObjects;
-
-    vtable->GetShaderInfoLog = gl->GetInfoLog;
-    vtable->GetShaderiv = gl->GetObjectParameteriv;
-    vtable->GetProgramInfoLog = gl->GetInfoLog;
-    vtable->GetProgramiv = gl->GetObjectParameteriv;
-  } else {
-    return FALSE;
-  }
+  int ret;
 
-  return TRUE;
+  g_return_val_if_fail (GST_GL_IS_SHADER (shader), 0);
+
+  GST_OBJECT_LOCK (shader);
+  ret = (int) shader->priv->program_handle;
+  GST_OBJECT_UNLOCK (shader);
+
+  return ret;
 }
 
-GstGLShader *
-gst_gl_shader_new (GstGLContext * context)
+/**
+ * gst_gl_shader_detach_unlocked:
+ * @shader: a #GstGLShader
+ * @stage: a #GstGLSLStage to attach
+ *
+ * Detaches @stage from @shader.  @stage must have been successfully attached
+ * to @shader with gst_gl_shader_attach() or gst_gl_shader_attach_unlocked().
+ *
+ * Note: must be called in the GL thread
+ */
+void
+gst_gl_shader_detach_unlocked (GstGLShader * shader, GstGLSLStage * stage)
 {
-  GstGLShader *shader;
+  guint stage_handle;
+  GList *elem;
 
-  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL);
+  g_return_if_fail (GST_GL_IS_SHADER (shader));
+  g_return_if_fail (GST_IS_GLSL_STAGE (stage));
 
-  shader = g_object_new (GST_GL_TYPE_SHADER, NULL);
-  shader->context = gst_object_ref (context);
+  if (!_gst_glsl_funcs_fill (&shader->priv->vtable, shader->context)) {
+    GST_WARNING_OBJECT (shader, "Failed to retreive required GLSL functions");
+    return;
+  }
 
-  GST_DEBUG_OBJECT (shader, "Created new GLShader for context %" GST_PTR_FORMAT,
-      context);
+  if (!shader->priv->program_handle)
+    return;
 
-  return shader;
+  elem = g_list_find (shader->priv->stages, stage);
+  if (!elem) {
+    GST_FIXME_OBJECT (shader, "Could not find stage %p in shader %p", stage,
+        shader);
+    return;
+  }
+
+  stage_handle = gst_glsl_stage_get_handle (stage);
+  if (!stage_handle) {
+    GST_FIXME_OBJECT (shader, "Stage %p doesn't have a GL handle", stage);
+    return;
+  }
+
+  g_assert (shader->context->gl_vtable->IsProgram (shader->priv->
+          program_handle));
+  g_assert (shader->context->gl_vtable->IsShader (stage_handle));
+
+  GST_LOG_OBJECT (shader, "detaching shader %i from program %i", stage_handle,
+      (int) shader->priv->program_handle);
+  shader->priv->vtable.DetachShader (shader->priv->program_handle,
+      stage_handle);
+
+  shader->priv->stages = g_list_remove_link (shader->priv->stages, elem);
+  gst_object_unref (stage);
+  g_list_free_1 (elem);
 }
 
-gboolean
-gst_gl_shader_is_compiled (GstGLShader * shader)
+/**
+ * gst_gl_shader_detach:
+ * @shader: a #GstGLShader
+ * @stage: a #GstGLSLStage to attach
+ *
+ * Detaches @stage from @shader.  @stage must have been successfully attached
+ * to @shader with gst_gl_shader_attach() or gst_gl_shader_attach_unlocked().
+ *
+ * Note: must be called in the GL thread
+ */
+void
+gst_gl_shader_detach (GstGLShader * shader, GstGLSLStage * stage)
 {
-  g_return_val_if_fail (GST_GL_IS_SHADER (shader), FALSE);
+  g_return_if_fail (GST_GL_IS_SHADER (shader));
+  g_return_if_fail (GST_IS_GLSL_STAGE (stage));
 
-  return shader->priv->compiled;
+  GST_OBJECT_LOCK (shader);
+  gst_gl_shader_detach_unlocked (shader, stage);
+  GST_OBJECT_UNLOCK (shader);
 }
 
-static gboolean
-_shader_string_has_version (const gchar * str)
+/**
+ * gst_gl_shader_attach_unlocked:
+ * @shader: a #GstGLShader
+ * @stage: a #GstGLSLStage to attach
+ *
+ * Attaches @stage to @shader.  @stage must have been successfully compiled
+ * with gst_glsl_stage_compile().
+ *
+ * Note: must be called in the GL thread
+ *
+ * Returns: whether @stage could be attached to @shader
+ */
+gboolean
+gst_gl_shader_attach_unlocked (GstGLShader * shader, GstGLSLStage * stage)
 {
-  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;
-    }
+  guint stage_handle;
 
-    if (ml_comment) {
-      if (g_strstr_len (&str[i], 2, "*/")) {
-        ml_comment = FALSE;
-        i += 2;
-      } else {
-        i++;
-      }
-      continue;
-    }
+  g_return_val_if_fail (GST_GL_IS_SHADER (shader), FALSE);
+  g_return_val_if_fail (GST_IS_GLSL_STAGE (stage), FALSE);
 
-    if (g_strstr_len (&str[i], 2, "//")) {
-      sl_comment = TRUE;
-      i += 2;
-      continue;
-    }
+  if (!_gst_glsl_funcs_fill (&shader->priv->vtable, shader->context)) {
+    GST_WARNING_OBJECT (shader, "Failed to retreive required GLSL functions");
+    return FALSE;
+  }
 
-    if (g_strstr_len (&str[i], 2, "/*")) {
-      ml_comment = TRUE;
-      i += 2;
-      continue;
-    }
+  if (!_ensure_program (shader))
+    return FALSE;
 
-    if (g_strstr_len (&str[i], 1, "#")) {
-      if (g_strstr_len (&str[i], 8, "#version"))
-        has_version = TRUE;
-      break;
-    }
+  /* already attached? */
+  if (g_list_find (shader->priv->stages, stage))
+    return TRUE;
 
-    i++;
+  stage_handle = gst_glsl_stage_get_handle (stage);
+  if (!stage_handle) {
+    return FALSE;
   }
 
-  return has_version;
+  g_assert (shader->context->gl_vtable->IsProgram (shader->priv->
+          program_handle));
+  g_assert (shader->context->gl_vtable->IsShader (stage_handle));
+
+  shader->priv->stages =
+      g_list_prepend (shader->priv->stages, gst_object_ref_sink (stage));
+  GST_LOG_OBJECT (shader, "attaching shader %i to program %i", stage_handle,
+      (int) shader->priv->program_handle);
+  shader->priv->vtable.AttachShader (shader->priv->program_handle,
+      stage_handle);
+
+  return TRUE;
 }
 
-static void
-_maybe_prepend_version (GstGLShader * shader, const gchar * shader_str,
-    gint * n_vertex_sources, const gchar *** vertex_sources)
+/**
+ * gst_gl_shader_attach:
+ * @shader: a #GstGLShader
+ * @stage: a #GstGLSLStage to attach
+ *
+ * Attaches @stage to @shader.  @stage must have been successfully compiled
+ * with gst_glsl_stage_compile().
+ *
+ * Note: must be called in the GL thread
+ *
+ * Returns: whether @stage could be attached to @shader
+ */
+gboolean
+gst_gl_shader_attach (GstGLShader * shader, GstGLSLStage * stage)
 {
-  gint n = 1;
+  gboolean ret;
+
+  g_return_val_if_fail (GST_GL_IS_SHADER (shader), FALSE);
+  g_return_val_if_fail (GST_IS_GLSL_STAGE (stage), FALSE);
 
-  /* 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;
+  GST_OBJECT_LOCK (shader);
+  ret = gst_gl_shader_attach_unlocked (shader, stage);
+  GST_OBJECT_UNLOCK (shader);
 
-  *vertex_sources = g_malloc0 (n * sizeof (gchar *));
+  return ret;
+}
+
+/**
+ * gst_gl_shader_compile_attach_stage:
+ * @shader: a #GstGLShader
+ * @stage: a #GstGLSLStage to attach
+ * @error: a #GError
+ *
+ * Compiles @stage and attaches it to @shader.
+ *
+ * Note: must be called in the GL thread
+ *
+ * Returns: whether @stage could be compiled and attached to @shader
+ */
+gboolean
+gst_gl_shader_compile_attach_stage (GstGLShader * shader, GstGLSLStage * stage,
+    GError ** error)
+{
+  g_return_val_if_fail (GST_IS_GLSL_STAGE (stage), FALSE);
+
+  if (!gst_glsl_stage_compile (stage, error)) {
+    return FALSE;
+  }
 
-  if (n > 1)
-    *vertex_sources[0] = es2_version_header;
+  if (!gst_gl_shader_attach (shader, stage)) {
+    g_set_error (error, GST_GLSL_ERROR, GST_GLSL_ERROR_COMPILE,
+        "Failed to attach stage to shader");
+    return FALSE;
+  }
 
-  (*vertex_sources)[n - 1] = shader_str;
-  *n_vertex_sources = n;
+  return TRUE;
 }
 
+/**
+ * gst_gl_shader_link:
+ * @shader: a #GstGLShader
+ * @error: a #GError
+ *
+ * Links the current list of #GstGLSLStage's in @shader.
+ *
+ * Note: must be called in the GL thread
+ *
+ * Returns: whether @shader could be linked together.
+ */
 gboolean
-gst_gl_shader_compile (GstGLShader * shader, GError ** error)
+gst_gl_shader_link (GstGLShader * shader, GError ** error)
 {
   GstGLShaderPrivate *priv;
-  GstGLFuncs *gl;
-
+  const GstGLFuncs *gl;
   gchar info_buffer[2048];
-  gint len = 0;
   GLint status = GL_FALSE;
+  gint len = 0;
+  gboolean ret;
+  GList *elem;
 
   g_return_val_if_fail (GST_GL_IS_SHADER (shader), FALSE);
 
+  GST_OBJECT_LOCK (shader);
+
   priv = shader->priv;
   gl = shader->context->gl_vtable;
 
-  if (priv->compiled)
-    return priv->compiled;
+  if (priv->linked) {
+    GST_OBJECT_UNLOCK (shader);
+    return TRUE;
+  }
 
-  if (!_fill_vtable (shader, shader->context))
+  if (!_gst_glsl_funcs_fill (&shader->priv->vtable, shader->context)) {
+    g_set_error (error, GST_GLSL_ERROR, GST_GLSL_ERROR_PROGRAM,
+        "Failed to retreive required GLSL functions");
+    GST_OBJECT_UNLOCK (shader);
     return FALSE;
+  }
 
-  shader->priv->program_handle = shader->priv->vtable.CreateProgram ();
+  if (!_ensure_program (shader)) {
+    g_set_error (error, GST_GLSL_ERROR, GST_GLSL_ERROR_PROGRAM,
+        "Failed to create GL program object");
+    GST_OBJECT_UNLOCK (shader);
+    return FALSE;
+  }
 
   GST_TRACE ("shader created %u", shader->priv->program_handle);
 
-  g_return_val_if_fail (priv->program_handle, FALSE);
+  for (elem = shader->priv->stages; elem; elem = elem->next) {
+    GstGLSLStage *stage = elem->data;
 
-  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 */
-    priv->vertex_handle = priv->vtable.CreateShader (GL_VERTEX_SHADER);
-    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 */
-    status = GL_FALSE;
-    gl->GetShaderiv (priv->vertex_handle, GL_COMPILE_STATUS, &status);
-
-    priv->vtable.GetShaderInfoLog (priv->vertex_handle,
-        sizeof (info_buffer) - 1, &len, info_buffer);
-    info_buffer[len] = '\0';
-
-    if (status != GL_TRUE) {
-      GST_ERROR ("Vertex Shader compilation failed:\n%s", info_buffer);
-
-      g_set_error (error, GST_GL_SHADER_ERROR,
-          GST_GL_SHADER_ERROR_COMPILE,
-          "Vertex Shader compilation failed:\n%s", info_buffer);
-
-      priv->vtable.DeleteShader (priv->vertex_handle);
-      priv->compiled = FALSE;
-      return priv->compiled;
-    } else if (len > 1) {
-      GST_FIXME ("vertex shader info log:\n%s\n", info_buffer);
+    if (!gst_glsl_stage_compile (stage, error)) {
+      GST_OBJECT_UNLOCK (shader);
+      return FALSE;
     }
-    priv->vtable.AttachShader (priv->program_handle, priv->vertex_handle);
 
-    GST_LOG ("vertex shader attached %u", priv->vertex_handle);
-  }
-
-  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 */
-    priv->fragment_handle = priv->vtable.CreateShader (GL_FRAGMENT_SHADER);
-    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 */
-    status = GL_FALSE;
-    priv->vtable.GetShaderiv (priv->fragment_handle,
-        GL_COMPILE_STATUS, &status);
-
-    priv->vtable.GetShaderInfoLog (priv->fragment_handle,
-        sizeof (info_buffer) - 1, &len, info_buffer);
-    info_buffer[len] = '\0';
-    if (status != GL_TRUE) {
-      GST_ERROR ("Fragment Shader compilation failed:\n%s", info_buffer);
-
-      g_set_error (error, GST_GL_SHADER_ERROR,
-          GST_GL_SHADER_ERROR_COMPILE,
-          "Fragment Shader compilation failed:\n%s", info_buffer);
-
-      priv->vtable.DeleteShader (priv->fragment_handle);
-      priv->compiled = FALSE;
-      return priv->compiled;
-    } else if (len > 1) {
-      GST_FIXME ("vertex shader info log:\n%s\n", info_buffer);
+    if (!gst_gl_shader_attach_unlocked (shader, stage)) {
+      g_set_error (error, GST_GLSL_ERROR, GST_GLSL_ERROR_COMPILE,
+          "Failed to attach shader %" GST_PTR_FORMAT "to program %"
+          GST_PTR_FORMAT, stage, shader);
+      GST_OBJECT_UNLOCK (shader);
+      return FALSE;
     }
-    priv->vtable.AttachShader (priv->program_handle, priv->fragment_handle);
-
-    GST_LOG ("fragment shader attached %u", priv->fragment_handle);
   }
 
   /* if nothing failed link shaders */
@@ -599,53 +622,81 @@ gst_gl_shader_compile (GstGLShader * shader, GError ** error)
   if (status != GL_TRUE) {
     GST_ERROR ("Shader linking failed:\n%s", info_buffer);
 
-    g_set_error (error, GST_GL_SHADER_ERROR,
-        GST_GL_SHADER_ERROR_LINK, "Shader Linking failed:\n%s", info_buffer);
-    priv->compiled = FALSE;
-    return priv->compiled;
+    g_set_error (error, GST_GLSL_ERROR, GST_GLSL_ERROR_LINK,
+        "Shader Linking failed:\n%s", info_buffer);
+    ret = priv->linked = FALSE;
+    GST_OBJECT_UNLOCK (shader);
+    return ret;
   } else if (len > 1) {
     GST_FIXME ("shader link log:\n%s\n", info_buffer);
   }
-  /* success! */
-  priv->compiled = TRUE;
-  g_object_notify (G_OBJECT (shader), "compiled");
 
-  return priv->compiled;
+  ret = priv->linked = TRUE;
+  GST_OBJECT_UNLOCK (shader);
+
+  g_object_notify (G_OBJECT (shader), "linked");
+
+  return ret;
 }
 
+/**
+ * gst_gl_shader_release_unlocked:
+ * @shader: a #GstGLShader
+ *
+ * Releases the shader and stages.
+ *
+ * Note: must be called in the GL thread
+ */
 void
-gst_gl_shader_release (GstGLShader * shader)
+gst_gl_shader_release_unlocked (GstGLShader * shader)
 {
   GstGLShaderPrivate *priv;
+  GList *elem;
 
   g_return_if_fail (GST_GL_IS_SHADER (shader));
 
   priv = shader->priv;
 
-  if (!priv->compiled || !priv->program_handle)
-    return;
+  for (elem = shader->priv->stages; elem; elem = elem->next) {
+    GstGLSLStage *stage = elem->data;
 
-  if (priv->vertex_handle) {    /* not needed but nvidia doesn't care to respect the spec */
-    GST_TRACE ("finalizing vertex shader %u", priv->vertex_handle);
-
-    priv->vtable.DeleteShader (priv->vertex_handle);
+    gst_gl_shader_detach_unlocked (shader, stage);
   }
 
-  if (priv->fragment_handle) {
-    GST_TRACE ("finalizing fragment shader %u", priv->fragment_handle);
+  g_list_free_full (shader->priv->stages, (GDestroyNotify) gst_object_unref);
+  shader->priv->stages = NULL;
 
-    priv->vtable.DeleteShader (priv->fragment_handle);
-  }
+  priv->linked = FALSE;
 
-  if (priv->vertex_handle)
-    priv->vtable.DetachShader (priv->program_handle, priv->vertex_handle);
-  if (priv->fragment_handle)
-    priv->vtable.DetachShader (priv->program_handle, priv->fragment_handle);
+  g_object_notify (G_OBJECT (shader), "linked");
+}
 
-  priv->compiled = FALSE;
-  g_object_notify (G_OBJECT (shader), "compiled");
+/**
+ * gst_gl_shader_release:
+ * @shader: a #GstGLShader
+ *
+ * Releases the shader and stages.
+ *
+ * Note: must be called in the GL thread
+ */
+void
+gst_gl_shader_release (GstGLShader * shader)
+{
+  g_return_if_fail (GST_GL_IS_SHADER (shader));
+
+  GST_OBJECT_LOCK (shader);
+  gst_gl_shader_release_unlocked (shader);
+  GST_OBJECT_UNLOCK (shader);
 }
 
+/**
+ * gst_gl_shader_use:
+ * @shader: a #GstGLShader
+ *
+ * Mark's @shader as being used for the next GL draw command.
+ *
+ * Note: must be called in the GL thread and @shader must have been linked.
+ */
 void
 gst_gl_shader_use (GstGLShader * shader)
 {
@@ -662,6 +713,14 @@ gst_gl_shader_use (GstGLShader * shader)
   return;
 }
 
+/**
+ * gst_gl_context_clear_shader:
+ * @shader: a #GstGLShader
+ *
+ * Clear's the currently set shader from the GL state machine.
+ *
+ * Note: must be called in the GL thread.
+ */
 void
 gst_gl_context_clear_shader (GstGLContext * context)
 {
@@ -677,104 +736,6 @@ gst_gl_context_clear_shader (GstGLContext * context)
     gl->UseProgramObject (0);
 }
 
-gboolean
-gst_gl_shader_compile_and_check (GstGLShader * shader,
-    const gchar * source, GstGLShaderSourceType type)
-{
-  gboolean is_compiled = FALSE;
-
-  g_object_get (G_OBJECT (shader), "compiled", &is_compiled, NULL);
-
-  if (!is_compiled) {
-    GError *error = NULL;
-
-    switch (type) {
-      case GST_GL_SHADER_FRAGMENT_SOURCE:
-        gst_gl_shader_set_fragment_source (shader, source);
-        break;
-      case GST_GL_SHADER_VERTEX_SOURCE:
-        gst_gl_shader_set_vertex_source (shader, source);
-        break;
-      default:
-        g_assert_not_reached ();
-        break;
-    }
-
-    gst_gl_shader_compile (shader, &error);
-    if (error) {
-      gst_gl_context_set_error (shader->context, "%s", error->message);
-      g_error_free (error);
-      gst_gl_context_clear_shader (shader->context);
-
-      return FALSE;
-    }
-  }
-  return TRUE;
-}
-
-gboolean
-gst_gl_shader_compile_all_with_attribs_and_check (GstGLShader * shader,
-    const gchar * v_src, const gchar * f_src, const gint n_attribs,
-    const gchar * attrib_names[], GLint attrib_locs[])
-{
-  gint i = 0;
-  GError *error = NULL;
-
-  gst_gl_shader_set_vertex_source (shader, v_src);
-  gst_gl_shader_set_fragment_source (shader, f_src);
-
-  gst_gl_shader_compile (shader, &error);
-  if (error) {
-    gst_gl_context_set_error (shader->context, "%s", error->message);
-    g_error_free (error);
-    gst_gl_context_clear_shader (shader->context);
-
-    return FALSE;
-  }
-
-  for (i = 0; i < n_attribs; i++)
-    attrib_locs[i] =
-        gst_gl_shader_get_attribute_location (shader, attrib_names[i]);
-
-  return TRUE;
-}
-
-gboolean
-gst_gl_shader_compile_with_default_f_and_check (GstGLShader * shader,
-    const gchar * v_src, const gint n_attribs, const gchar * attrib_names[],
-    GLint attrib_locs[])
-{
-  return gst_gl_shader_compile_all_with_attribs_and_check (shader, v_src,
-      simple_fragment_shader_str_gles2, n_attribs, attrib_names, attrib_locs);
-}
-
-gboolean
-gst_gl_shader_compile_with_default_v_and_check (GstGLShader * shader,
-    const gchar * f_src, GLint * pos_loc, GLint * tex_loc)
-{
-  const gchar *attrib_names[2] = { "a_position", "a_texcoord" };
-  GLint attrib_locs[2] = { 0 };
-  gboolean ret = TRUE;
-
-  ret = gst_gl_shader_compile_all_with_attribs_and_check (shader,
-      simple_vertex_shader_str_gles2, f_src, 2, attrib_names, attrib_locs);
-
-  if (ret) {
-    *pos_loc = attrib_locs[0];
-    *tex_loc = attrib_locs[1];
-  }
-
-  return ret;
-}
-
-gboolean
-gst_gl_shader_compile_with_default_vf_and_check (GstGLShader * shader,
-    GLint * pos_loc, GLint * tex_loc)
-{
-  return gst_gl_shader_compile_with_default_v_and_check (shader,
-      simple_fragment_shader_str_gles2, pos_loc, tex_loc);
-}
-
 void
 gst_gl_shader_set_uniform_1f (GstGLShader * shader, const gchar * name,
     gfloat value)
@@ -1233,16 +1194,20 @@ gst_gl_shader_get_attribute_location (GstGLShader * shader, const gchar * name)
 {
   GstGLShaderPrivate *priv;
   GstGLFuncs *gl;
+  gint ret;
 
   g_return_val_if_fail (shader != NULL, -1);
   priv = shader->priv;
   g_return_val_if_fail (priv->program_handle != 0, -1);
-  if (0 == priv->vertex_handle)
-    return -1;
 
   gl = shader->context->gl_vtable;
 
-  return gl->GetAttribLocation (priv->program_handle, name);
+  ret = gl->GetAttribLocation (priv->program_handle, name);
+
+  GST_TRACE_OBJECT (shader, "retreived program %i attribute \'%s\' location %i",
+      (int) priv->program_handle, name, ret);
+
+  return ret;
 }
 
 void
@@ -1257,11 +1222,8 @@ gst_gl_shader_bind_attribute_location (GstGLShader * shader, GLuint index,
   g_return_if_fail (priv->program_handle != 0);
   gl = shader->context->gl_vtable;
 
-  gl->BindAttribLocation (priv->program_handle, index, name);
-}
+  GST_TRACE_OBJECT (shader, "binding program %i attribute \'%s\' location %i",
+      (int) priv->program_handle, name, index);
 
-GQuark
-gst_gl_shader_error_quark (void)
-{
-  return g_quark_from_static_string ("gst-gl-shader-error");
+  gl->BindAttribLocation (priv->program_handle, index, name);
 }
index 97f98fc..97b6c01 100644 (file)
@@ -26,6 +26,7 @@
 
 G_BEGIN_DECLS
 
+GType gst_gl_shader_get_type (void);
 #define GST_GL_TYPE_SHADER         (gst_gl_shader_get_type())
 #define GST_GL_SHADER(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_SHADER, GstGLShader))
 #define GST_GL_SHADER_CLASS(k)     (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_SHADER, GstGLShaderClass))
@@ -33,19 +34,6 @@ G_BEGIN_DECLS
 #define GST_GL_IS_SHADER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_SHADER))
 #define GST_GL_SHADER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_SHADER, GstGLShaderClass))
 
-#define GST_GL_SHADER_ERROR (gst_gl_shader_error_quark ())
-
-typedef enum {
-  GST_GL_SHADER_ERROR_COMPILE,
-  GST_GL_SHADER_ERROR_LINK,
-  GST_GL_SHADER_ERROR_PROGRAM
-} GstGLShaderError;
-
-typedef enum {
-  GST_GL_SHADER_FRAGMENT_SOURCE,
-  GST_GL_SHADER_VERTEX_SOURCE
-} GstGLShaderSourceType;
-
 struct _GstGLShader {
   /*< private >*/
   GstObject parent;
@@ -53,6 +41,8 @@ struct _GstGLShader {
   GstGLContext *context;
 
   GstGLShaderPrivate *priv;
+
+  gpointer _padding[GST_PADDING];
 };
 
 struct _GstGLShaderClass {
@@ -60,33 +50,29 @@ struct _GstGLShaderClass {
   GstObjectClass parent_class;
 };
 
-/* methods */
-
-GQuark gst_gl_shader_error_quark (void);
-GType gst_gl_shader_get_type (void);
-
-GstGLShader * gst_gl_shader_new (GstGLContext *context);
+GstGLShader * gst_gl_shader_new                     (GstGLContext *context);
+GstGLShader * gst_gl_shader_new_with_stages         (GstGLContext * context, GError ** error, ...);
+GstGLShader * gst_gl_shader_new_link_with_stages    (GstGLContext * context, GError ** error, ...);
+GstGLShader * gst_gl_shader_new_default             (GstGLContext * context, GError ** error);
 
-int gst_gl_shader_get_program_handle(GstGLShader * shader);
+gboolean gst_gl_shader_attach                       (GstGLShader * shader, GstGLSLStage * stage);
+gboolean gst_gl_shader_attach_unlocked              (GstGLShader * shader, GstGLSLStage * stage);
 
-void          gst_gl_shader_set_vertex_source   (GstGLShader *shader, const gchar *src);
-void          gst_gl_shader_set_fragment_source (GstGLShader *shader, const gchar *src);
-const gchar * gst_gl_shader_get_vertex_source   (GstGLShader *shader);
-const gchar * gst_gl_shader_get_fragment_source (GstGLShader *shader);
+void     gst_gl_shader_detach                       (GstGLShader * shader, GstGLSLStage * stage);
+void     gst_gl_shader_detach_unlocked              (GstGLShader * shader, GstGLSLStage * stage);
 
-void     gst_gl_shader_set_active        (GstGLShader *shader, gboolean active);
-gboolean gst_gl_shader_is_compiled       (GstGLShader *shader);
-gboolean gst_gl_shader_compile           (GstGLShader *shader, GError **error);
-gboolean gst_gl_shader_compile_and_check (GstGLShader *shader, const gchar *source, GstGLShaderSourceType type);
-gboolean gst_gl_shader_compile_all_with_attribs_and_check (GstGLShader *shader, const gchar *v_src, const gchar *f_src, const gint n_attribs, const gchar *attrib_names[], GLint attrib_locs[]);
+gboolean gst_gl_shader_compile_attach_stage         (GstGLShader * shader,
+                                                     GstGLSLStage *stage,
+                                                     GError ** error);
+gboolean gst_gl_shader_link                         (GstGLShader * shader, GError ** error);
+gboolean gst_gl_shader_is_linked                    (GstGLShader *shader);
 
-gboolean gst_gl_shader_compile_with_default_f_and_check   (GstGLShader *shader, const gchar *v_src, const gint n_attribs, const gchar *attrib_names[], GLint attrib_locs[]);
-gboolean gst_gl_shader_compile_with_default_v_and_check   (GstGLShader *shader, const gchar *f_src, GLint *pos_loc, GLint *tex_loc);
-gboolean gst_gl_shader_compile_with_default_vf_and_check  (GstGLShader *shader, GLint *pos_loc, GLint *tex_loc);
+int gst_gl_shader_get_program_handle                (GstGLShader * shader);
 
-void gst_gl_shader_release       (GstGLShader *shader);
-void gst_gl_shader_use           (GstGLShader *shader);
-void gst_gl_context_clear_shader (GstGLContext *context);
+void gst_gl_shader_release                          (GstGLShader *shader);
+void gst_gl_shader_release_unlocked                 (GstGLShader * shader);
+void gst_gl_shader_use                              (GstGLShader *shader);
+void gst_gl_context_clear_shader                    (GstGLContext *context);
 
 void gst_gl_shader_set_uniform_1i           (GstGLShader *shader, const gchar *name, gint value);
 void gst_gl_shader_set_uniform_1iv          (GstGLShader *shader, const gchar *name, guint count, gint *value);
index 4312ead..8acfb97 100644 (file)
@@ -375,20 +375,60 @@ gst_gl_context_del_fbo (GstGLContext * context, GLuint fbo, GLuint depth_buffer)
   gst_object_unref (frame);
 }
 
+struct _compile_shader
+{
+  GstGLShader **shader;
+  const gchar *vertex_src;
+  const gchar *fragment_src;
+};
+
 static void
-_compile_shader (GstGLContext * context, GstGLShader ** shader)
+_compile_shader (GstGLContext * context, struct _compile_shader *data)
 {
+  GstGLShader *shader;
+  GstGLSLStage *vert, *frag;
   GError *error = NULL;
 
-  gst_gl_shader_compile (*shader, &error);
-  if (error) {
-    gst_gl_context_set_error (context, "%s", error->message);
+  shader = gst_gl_shader_new (context);
+
+  if (data->vertex_src) {
+    vert = gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
+        GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_NONE, data->vertex_src);
+    if (!gst_glsl_stage_compile (vert, &error)) {
+      GST_ERROR_OBJECT (vert, "%s", error->message);
+      gst_object_unref (shader);
+      return;
+    }
+    if (!gst_gl_shader_attach (shader, vert)) {
+      gst_object_unref (shader);
+      return;
+    }
+  }
+
+  if (data->fragment_src) {
+    frag = gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+        GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_NONE, data->fragment_src);
+    if (!gst_glsl_stage_compile (frag, &error)) {
+      GST_ERROR_OBJECT (frag, "%s", error->message);
+      gst_object_unref (shader);
+      return;
+    }
+    if (!gst_gl_shader_attach (shader, frag)) {
+      gst_object_unref (shader);
+      return;
+    }
+  }
+
+  if (!gst_gl_shader_link (shader, &error)) {
+    GST_ERROR_OBJECT (shader, "%s", error->message);
     g_error_free (error);
     error = NULL;
     gst_gl_context_clear_shader (context);
-    gst_object_unref (*shader);
-    *shader = NULL;
+    gst_object_unref (shader);
+    return;
   }
+
+  *data->shader = shader;
 }
 
 /* Called by glfilter */
@@ -396,18 +436,17 @@ gboolean
 gst_gl_context_gen_shader (GstGLContext * context, const gchar * vert_src,
     const gchar * frag_src, GstGLShader ** shader)
 {
+  struct _compile_shader data;
+
   g_return_val_if_fail (frag_src != NULL || vert_src != NULL, FALSE);
   g_return_val_if_fail (shader != NULL, FALSE);
 
-  *shader = gst_gl_shader_new (context);
-
-  if (frag_src)
-    gst_gl_shader_set_fragment_source (*shader, frag_src);
-  if (vert_src)
-    gst_gl_shader_set_vertex_source (*shader, vert_src);
+  data.shader = shader;
+  data.vertex_src = vert_src;
+  data.fragment_src = frag_src;
 
   gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _compile_shader,
-      shader);
+      &data);
 
   return *shader != NULL;
 }
index 8bb5f99..6ad97b8 100644 (file)
 
 #include <stdio.h>
 
-#if GST_GL_HAVE_GLES2
-/* *INDENT-OFF* */
-static const gchar *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 *fragment_shader_str_gles2 =
-      "precision mediump float;                            \n"
-      "varying vec2 v_texCoord;                            \n"
-      "uniform sampler2D s_texture;                        \n"
-      "void main()                                         \n"
-      "{                                                   \n"
-      "  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
-      "}                                                   \n";
-/* *INDENT-ON* */
-#endif
-
 static GstGLDisplay *display;
 
 static void
@@ -67,17 +44,15 @@ teardown (void)
 
 static GLuint fbo_id, rbo, tex;
 static GstGLFramebuffer *fbo;
-#if GST_GL_HAVE_GLES2
-static GError *error;
 static GstGLShader *shader;
 static GLint shader_attr_position_loc;
 static GLint shader_attr_texture_loc;
-#endif
 
 static void
 init (gpointer data)
 {
   GstGLContext *context = data;
+  GError *error = NULL;
 
   /* has to be called in the thread that is going to use the framebuffer */
   fbo = gst_gl_framebuffer_new (context);
@@ -88,25 +63,14 @@ init (gpointer data)
   gst_gl_context_gen_texture (context, &tex, GST_VIDEO_FORMAT_RGBA, 320, 240);
   fail_if (tex == 0, "failed to create texture");
 
-#if GST_GL_HAVE_GLES2
-  if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2) {
-    shader = gst_gl_shader_new (context);
-    fail_if (shader == NULL, "failed to create shader object");
+  shader = gst_gl_shader_new_default (context, &error);
+  fail_if (shader == NULL, "failed to create shader object: %s",
+      error->message);
 
-    gst_gl_shader_set_vertex_source (shader, vertex_shader_str_gles2);
-    gst_gl_shader_set_fragment_source (shader, fragment_shader_str_gles2);
-
-    error = NULL;
-    gst_gl_shader_compile (shader, &error);
-    fail_if (error != NULL, "Error compiling shader %s\n",
-        error ? error->message : "Unknown Error");
-
-    shader_attr_position_loc =
-        gst_gl_shader_get_attribute_location (shader, "a_position");
-    shader_attr_texture_loc =
-        gst_gl_shader_get_attribute_location (shader, "a_texCoord");
-  }
-#endif
+  shader_attr_position_loc =
+      gst_gl_shader_get_attribute_location (shader, "a_position");
+  shader_attr_texture_loc =
+      gst_gl_shader_get_attribute_location (shader, "a_texcoord");
 }
 
 static void
@@ -116,10 +80,7 @@ deinit (gpointer data)
   GstGLFuncs *gl = context->gl_vtable;
   gl->DeleteTextures (1, &tex);
   gst_object_unref (fbo);
-#if GST_GL_HAVE_GLES2
-  if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
-    gst_object_unref (shader);
-#endif
+  gst_object_unref (shader);
 }
 
 static void
@@ -150,81 +111,38 @@ draw_render (gpointer data)
   GstGLContext *context = data;
   GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);
   const GstGLFuncs *gl = context->gl_vtable;
+  const GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f,
+    1.0f, 0.0f,
+    -1.0f, 1.0f, 0.0f,
+    0.0f, 0.0f,
+    -1.0f, -1.0f, 0.0f,
+    0.0f, 1.0f,
+    1.0f, -1.0f, 0.0f,
+    1.0f, 1.0f
+  };
+
+  GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
 
-  /* redraw the texture into the system provided framebuffer */
-
-#if GST_GL_HAVE_OPENGL
-  if (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL) {
-    GLfloat verts[8] = { 1.0f, 1.0f,
-      -1.0f, 1.0f,
-      -1.0f, -1.0f,
-      1.0f, -1.0f
-    };
-    GLfloat texcoords[8] = { 1.0f, 0.0f,
-      0.0f, 0.0f,
-      0.0f, 1.0f,
-      1.0f, 1.0f
-    };
-
-    gl->Viewport (0, 0, 320, 240);
-
-    gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-    gl->MatrixMode (GL_PROJECTION);
-    gl->LoadIdentity ();
-
-    gl->ActiveTexture (GL_TEXTURE0);
-    gl->BindTexture (GL_TEXTURE_2D, tex);
-
-    gl->EnableClientState (GL_VERTEX_ARRAY);
-    gl->VertexPointer (2, GL_FLOAT, 0, &verts);
-
-    gl->ClientActiveTexture (GL_TEXTURE0);
-    gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
-    gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords);
-
-    gl->DrawArrays (GL_TRIANGLE_FAN, 0, 4);
-
-    gl->DisableClientState (GL_VERTEX_ARRAY);
-    gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
-  }
-#endif
-#if GST_GL_HAVE_GLES2
-  if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2) {
-    const GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f,
-      1.0f, 0.0f,
-      -1.0f, 1.0f, 0.0f,
-      0.0f, 0.0f,
-      -1.0f, -1.0f, 0.0f,
-      0.0f, 1.0f,
-      1.0f, -1.0f, 0.0f,
-      1.0f, 1.0f
-    };
-
-    GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
-
-    gl->Clear (GL_COLOR_BUFFER_BIT);
+  gl->Clear (GL_COLOR_BUFFER_BIT);
 
-    gst_gl_shader_use (shader);
+  gst_gl_shader_use (shader);
 
-    /* Load the vertex position */
-    gl->VertexAttribPointer (shader_attr_position_loc, 3,
-        GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);
+  /* Load the vertex position */
+  gl->VertexAttribPointer (shader_attr_position_loc, 3,
+      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);
 
-    /* Load the texture coordinate */
-    gl->VertexAttribPointer (shader_attr_texture_loc, 2,
-        GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);
+  /* Load the texture coordinate */
+  gl->VertexAttribPointer (shader_attr_texture_loc, 2,
+      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);
 
-    gl->EnableVertexAttribArray (shader_attr_position_loc);
-    gl->EnableVertexAttribArray (shader_attr_texture_loc);
+  gl->EnableVertexAttribArray (shader_attr_position_loc);
+  gl->EnableVertexAttribArray (shader_attr_texture_loc);
 
-    gl->ActiveTexture (GL_TEXTURE0);
-    gl->BindTexture (GL_TEXTURE_2D, tex);
-    gst_gl_shader_set_uniform_1i (shader, "s_texture", 0);
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->BindTexture (GL_TEXTURE_2D, tex);
+  gst_gl_shader_set_uniform_1i (shader, "s_texture", 0);
 
-    gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
-  }
-#endif
+  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
 
   context_class->swap_buffers (context);
 }
@@ -314,6 +232,7 @@ check_wrapped (gpointer data)
   fail_if (!ret, "error received %s\n",
       error ? error->message : "Unknown error");
   fail_if (wrapped_context->gl_vtable->TexImage2D == NULL);
+  gst_gl_context_activate (wrapped_context, FALSE);
 }
 
 GST_START_TEST (test_wrapped_context)
index b04eb9e..fac69d0 100644 (file)
 
 #include <stdio.h>
 
-#if GST_GL_HAVE_GLES2
-/* *INDENT-OFF* */
-static const gchar *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 *fragment_shader_str_gles2 =
-      "precision mediump float;                            \n"
-      "varying vec2 v_texCoord;                            \n"
-      "uniform sampler2D s_texture;                        \n"
-      "void main()                                         \n"
-      "{                                                   \n"
-      "  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
-      "}                                                   \n";
-/* *INDENT-ON* */
-#endif
-
 static GstGLDisplay *display;
 static GstGLContext *context;
 static GstGLWindow *window;
 static GstGLUpload *upload;
 static guint tex_id;
-#if GST_GL_HAVE_GLES2
-static GError *error;
 static GstGLShader *shader;
 static GLint shader_attr_position_loc;
 static GLint shader_attr_texture_loc;
-#endif
-
 
 #define FORMAT GST_VIDEO_GL_TEXTURE_TYPE_RGBA
 #define WIDTH 10
@@ -118,25 +91,15 @@ teardown (void)
 static void
 init (gpointer data)
 {
-#if GST_GL_HAVE_GLES2
-  if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2) {
-    shader = gst_gl_shader_new (context);
-    fail_if (shader == NULL, "failed to create shader object");
-
-    gst_gl_shader_set_vertex_source (shader, vertex_shader_str_gles2);
-    gst_gl_shader_set_fragment_source (shader, fragment_shader_str_gles2);
-
-    error = NULL;
-    gst_gl_shader_compile (shader, &error);
-    fail_if (error != NULL, "Error compiling shader %s\n",
-        error ? error->message : "Unknown Error");
-
-    shader_attr_position_loc =
-        gst_gl_shader_get_attribute_location (shader, "a_position");
-    shader_attr_texture_loc =
-        gst_gl_shader_get_attribute_location (shader, "a_texCoord");
-  }
-#endif
+  GError *error = NULL;
+
+  shader = gst_gl_shader_new_default (context, &error);
+  fail_if (shader == NULL, "failed to create shader object %s", error->message);
+
+  shader_attr_position_loc =
+      gst_gl_shader_get_attribute_location (shader, "a_position");
+  shader_attr_texture_loc =
+      gst_gl_shader_get_attribute_location (shader, "a_texCoord");
 }
 
 static void
@@ -145,81 +108,38 @@ draw_render (gpointer data)
   GstGLContext *context = data;
   GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);
   const GstGLFuncs *gl = context->gl_vtable;
+  const GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f,
+    1.0f, 0.0f,
+    -1.0f, 1.0f, 0.0f,
+    0.0f, 0.0f,
+    -1.0f, -1.0f, 0.0f,
+    0.0f, 1.0f,
+    1.0f, -1.0f, 0.0f,
+    1.0f, 1.0f
+  };
 
-  /* redraw the texture into the system provided framebuffer */
+  GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
 
-#if GST_GL_HAVE_OPENGL
-  if (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL) {
-    GLfloat verts[8] = { 1.0f, 1.0f,
-      -1.0f, 1.0f,
-      -1.0f, -1.0f,
-      1.0f, -1.0f
-    };
-    GLfloat texcoords[8] = { 1.0f, 0.0f,
-      0.0f, 0.0f,
-      0.0f, 1.0f,
-      1.0f, 1.0f
-    };
+  gl->Clear (GL_COLOR_BUFFER_BIT);
 
-    gl->Viewport (0, 0, 10, 10);
+  gst_gl_shader_use (shader);
 
-    gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  /* Load the vertex position */
+  gl->VertexAttribPointer (shader_attr_position_loc, 3,
+      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);
 
-    gl->MatrixMode (GL_PROJECTION);
-    gl->LoadIdentity ();
+  /* Load the texture coordinate */
+  gl->VertexAttribPointer (shader_attr_texture_loc, 2,
+      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);
 
-    gl->ActiveTexture (GL_TEXTURE_2D);
-    gl->BindTexture (GL_TEXTURE_2D, tex_id);
+  gl->EnableVertexAttribArray (shader_attr_position_loc);
+  gl->EnableVertexAttribArray (shader_attr_texture_loc);
 
-    gl->EnableClientState (GL_VERTEX_ARRAY);
-    gl->VertexPointer (2, GL_FLOAT, 0, &verts);
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->BindTexture (GL_TEXTURE_2D, tex_id);
+  gst_gl_shader_set_uniform_1i (shader, "s_texture", 0);
 
-    gl->ClientActiveTexture (GL_TEXTURE0);
-    gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
-    gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords);
-
-    gl->DrawArrays (GL_TRIANGLE_FAN, 0, 4);
-
-    gl->DisableClientState (GL_VERTEX_ARRAY);
-    gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
-  }
-#endif
-#if GST_GL_HAVE_GLES2
-  if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2) {
-    const GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f,
-      1.0f, 0.0f,
-      -1.0f, 1.0f, 0.0f,
-      0.0f, 0.0f,
-      -1.0f, -1.0f, 0.0f,
-      0.0f, 1.0f,
-      1.0f, -1.0f, 0.0f,
-      1.0f, 1.0f
-    };
-
-    GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
-
-    gl->Clear (GL_COLOR_BUFFER_BIT);
-
-    gst_gl_shader_use (shader);
-
-    /* Load the vertex position */
-    gl->VertexAttribPointer (shader_attr_position_loc, 3,
-        GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);
-
-    /* Load the texture coordinate */
-    gl->VertexAttribPointer (shader_attr_texture_loc, 2,
-        GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);
-
-    gl->EnableVertexAttribArray (shader_attr_position_loc);
-    gl->EnableVertexAttribArray (shader_attr_texture_loc);
-
-    gl->ActiveTexture (GL_TEXTURE0);
-    gl->BindTexture (GL_TEXTURE_2D, tex_id);
-    gst_gl_shader_set_uniform_1i (shader, "s_texture", 0);
-
-    gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
-  }
-#endif
+  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
 
   context_class->swap_buffers (context);
 }