gltestsrc: add a generic src framework
authorMatthew Waters <matthew@centricular.com>
Thu, 25 Feb 2016 10:18:31 +0000 (21:18 +1100)
committerMatthew Waters <matthew@centricular.com>
Thu, 31 Mar 2016 09:53:18 +0000 (20:53 +1100)
Any unsupported pattern (circular) results in an error

ext/gl/gltestsrc.c
ext/gl/gltestsrc.h
ext/gl/gstgltestsrc.c
ext/gl/gstgltestsrc.h

index c4a2765..d1cd583 100644 (file)
 #include "config.h"
 #endif
 
-/* non-GST-specific stuff */
-
 #include "gltestsrc.h"
 
-#include <string.h>
-#include <stdlib.h>
 #include <math.h>
 
 #ifndef M_PI
 #define M_PI  3.14159265358979323846
 #endif
 
+struct vts_color_struct
+{
+  gfloat R, G, B;
+};
+
 enum
 {
   COLOR_WHITE = 0,
@@ -51,42 +52,75 @@ enum
 
 static const struct vts_color_struct vts_colors[] = {
   /* 100% white */
-  {255, 128, 128, 255, 255, 255, 255},
+  {1.0f, 1.0f, 1.0f},
   /* yellow */
-  {226, 0, 155, 255, 255, 0, 255},
+  {1.0f, 1.0f, 0.0f},
   /* cyan */
-  {179, 170, 0, 0, 255, 255, 255},
+  {0.0f, 1.0f, 1.0f},
   /* green */
-  {150, 46, 21, 0, 255, 0, 255},
+  {0.0f, 1.0f, 0.0f},
   /* magenta */
-  {105, 212, 235, 255, 0, 255, 255},
+  {1.0f, 0.0f, 1.0f},
   /* red */
-  {76, 85, 255, 255, 0, 0, 255},
+  {1.0f, 0.0f, 0.0f},
   /* blue */
-  {29, 255, 107, 0, 0, 255, 255},
+  {0.0f, 0.0f, 1.0f},
   /* black */
-  {16, 128, 128, 0, 0, 0, 255},
+  {0.0f, 0.0f, 0.0f},
   /* -I */
-  {16, 198, 21, 0, 0, 128, 255},
+  {0.0, 0.0f, 0.5f},
   /* +Q */
-  {16, 235, 198, 0, 128, 255, 255},
+  {0.0f, 0.5, 1.0f},
   /* superblack */
-  {0, 128, 128, 0, 0, 0, 255},
-  /* 5% grey */
-  {32, 128, 128, 32, 32, 32, 255},
+  {0.0f, 0.0f, 0.0f},
+  /* 7.421875% grey */
+  {19. / 256.0f, 19. / 256.0f, 19. / 256.0},
 };
 
-static void
-gst_gl_test_src_unicolor (GstGLTestSrc * v, GstBuffer * buffer, int w,
-    int h, const struct vts_color_struct *color);
+/* *INDENT-OFF* */
+static const GLfloat positions[] = {
+     -1.0,  1.0,  0.0, 1.0,
+      1.0,  1.0,  0.0, 1.0,
+      1.0, -1.0,  0.0, 1.0,
+     -1.0, -1.0,  0.0, 1.0,
+};
 
-void
-gst_gl_test_src_smpte (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+static const GLushort indices_quad[] = { 0, 1, 2, 0, 2, 3 };
+/* *INDENT-ON* */
+
+struct SrcSMPTE
+{
+  struct BaseSrcImpl base;
+};
+
+static gpointer
+_src_smpte_new (GstGLTestSrc * test)
+{
+  struct SrcSMPTE *src = g_new0 (struct SrcSMPTE, 1);
+
+  src->base.src = test;
+
+  return src;
+}
+
+static gboolean
+_src_smpte_init (gpointer impl, GstGLContext * context, GstVideoInfo * v_info)
+{
+  struct SrcSMPTE *src = impl;
+
+  src->base.context = context;
+
+  return TRUE;
+}
+
+static gboolean
+_src_smpte_fill_bound_fbo (gpointer impl)
 {
 #if GST_GL_HAVE_OPENGL
+  struct SrcSMPTE *src = impl;
   int i;
 
-  if (gst_gl_context_get_gl_api (v->context) & GST_GL_API_OPENGL) {
+  if (gst_gl_context_get_gl_api (src->base.context) & GST_GL_API_OPENGL) {
 
     glClearColor (0.0, 0.0, 0.0, 1.0);
     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -97,8 +131,7 @@ gst_gl_test_src_smpte (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
     glLoadIdentity ();
 
     for (i = 0; i < 7; i++) {
-      glColor4f (vts_colors[i].R * (1 / 255.0f), vts_colors[i].G * (1 / 255.0f),
-          vts_colors[i].B * (1 / 255.0f), 1.0f);
+      glColor4f (vts_colors[i].R, vts_colors[i].G, vts_colors[i].B, 1.0f);
       glBegin (GL_QUADS);
       glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f + 2.0 * (2.0f / 3.0f), 0);
       glVertex3f (-1.0f + (i + 1.0f) * (2.0f / 7.0f),
@@ -117,8 +150,7 @@ gst_gl_test_src_smpte (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
         k = 6 - i;
       }
 
-      glColor4f (vts_colors[k].R * (1 / 255.0f), vts_colors[k].G * (1 / 255.0f),
-          vts_colors[k].B * (1 / 255.0f), 1.0f);
+      glColor4f (vts_colors[k].R, vts_colors[k].G, vts_colors[k].B, 1.0f);
       glBegin (GL_QUADS);
       glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f + 2.0f * (3.0f / 4.0f), 0);
       glVertex3f (-1.0f + (i + 1) * (2.0f / 7.0f), -1.0f + 2.0f * (3.0f / 4.0f),
@@ -140,8 +172,7 @@ gst_gl_test_src_smpte (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
         k = 9;
       }
 
-      glColor4f (vts_colors[k].R * (1 / 255.0f), vts_colors[k].G * (1 / 255.0f),
-          vts_colors[k].B * (1 / 255.0f), 1.0f);
+      glColor4f (vts_colors[k].R, vts_colors[k].G, vts_colors[k].B, 1.0f);
       glBegin (GL_QUADS);
       glVertex3f (-1.0f + i * (2.0f / 6.0f), -1.0f + 2.0f * 1, 0);
       glVertex3f (-1.0f + (i + 1) * (2.0f / 6.0f), -1.0f + 2.0f * 1, 0);
@@ -162,8 +193,7 @@ gst_gl_test_src_smpte (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
         k = COLOR_DARK_GREY;
       }
 
-      glColor4f (vts_colors[k].R * (1 / 255.0f), vts_colors[k].G * (1 / 255.0f),
-          vts_colors[k].B * (1 / 255.0f), 1.0f);
+      glColor4f (vts_colors[k].R, vts_colors[k].G, vts_colors[k].B, 1.0f);
       glBegin (GL_QUADS);
       glVertex3f (-1.0f + 2.0f * (0.5f + i * (1.0f / 12.0f)), -1.0 + 2.0f * 1,
           0);
@@ -185,193 +215,540 @@ gst_gl_test_src_smpte (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
     glEnd ();
   }
 #endif
+
+  return TRUE;
 }
 
-/* *INDENT-OFF* */
+static void
+_src_smpte_free (gpointer impl)
+{
+  g_free (impl);
+}
 
-static const GLfloat positions[] = {
-     -1.0,  1.0,  0.0, 1.0,
-      1.0,  1.0,  0.0, 1.0,
-      1.0, -1.0,  0.0, 1.0,
-     -1.0, -1.0,  0.0, 1.0,
-  };
-static const GLfloat identitiy_matrix[] = {
-      1.0,  0.0,  0.0, 0.0,
-      0.0,  1.0,  0.0, 0.0,
-      0.0,  0.0,  1.0, 0.0,
-      0.0,  0.0,  0.0, 1.0,
-  };
 
-/* *INDENT-ON* */
+static const struct SrcFuncs src_smpte = {
+  GST_GL_TEST_SRC_SMPTE,
+  _src_smpte_new,
+  _src_smpte_init,
+  _src_smpte_fill_bound_fbo,
+  _src_smpte_free,
+};
 
-void
-gst_gl_test_src_shader (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+struct SrcUniColor
 {
+  struct BaseSrcImpl base;
 
-  GstGLFuncs *gl = v->context->gl_vtable;
+  struct vts_color_struct color;
+};
 
-/* *INDENT-OFF* */
-  const GLfloat uvs[] = {
-     0.0,  1.0,
-     1.0,  1.0,
-     1.0,  0.0,
-     0.0,  0.0,
-  };
-/* *INDENT-ON* */
+static gpointer
+_src_uni_color_new (GstGLTestSrc * test)
+{
+  struct SrcUniColor *src = g_new0 (struct SrcUniColor, 1);
 
-  GLushort indices[] = { 0, 1, 2, 3, 0 };
+  src->base.src = test;
 
-  GLint attr_position_loc = -1;
-  GLint attr_uv_loc = -1;
+  return src;
+}
 
-  if (gst_gl_context_get_gl_api (v->context)) {
+static gboolean
+_src_uni_color_init (gpointer impl, GstGLContext * context,
+    GstVideoInfo * v_info)
+{
+  struct SrcUniColor *src = impl;
 
-    gst_gl_context_clear_shader (v->context);
-    gl->BindTexture (GL_TEXTURE_2D, 0);
+  src->base.context = context;
+  src->base.v_info = *v_info;
 
-    gst_gl_shader_use (v->shader);
+  return TRUE;
+}
 
-    attr_position_loc =
-        gst_gl_shader_get_attribute_location (v->shader, "position");
+static gboolean
+_src_uni_color_fill_bound_fbo (gpointer impl)
+{
+  struct SrcUniColor *src = impl;
+  const GstGLFuncs *gl = src->base.context->gl_vtable;
 
-    attr_uv_loc = gst_gl_shader_get_attribute_location (v->shader, "uv");
+  gl->ClearColor (src->color.R, src->color.G, src->color.B, 1.0f);
+  gl->Clear (GL_COLOR_BUFFER_BIT);
 
-    /* Load the vertex position */
-    gl->VertexAttribPointer (attr_position_loc, 4, GL_FLOAT,
-        GL_FALSE, 0, positions);
-    /* Load the texture coordinate */
-    gl->VertexAttribPointer (attr_uv_loc, 2, GL_FLOAT, GL_FALSE, 0, uvs);
+  return TRUE;
+}
+
+static void
+_src_uni_color_free (gpointer impl)
+{
+  g_free (impl);
+}
 
-    gl->EnableVertexAttribArray (attr_position_loc);
-    gl->EnableVertexAttribArray (attr_uv_loc);
+#define SRC_UNICOLOR(name, cap_name) \
+static gpointer \
+G_PASTE(G_PASTE(_src_unicolor_,name),_new) (GstGLTestSrc * test) \
+{ \
+  struct SrcUniColor *src = _src_uni_color_new (test); \
+  src->color = vts_colors[G_PASTE(COLOR_,cap_name)]; \
+  return src; \
+} \
+static const struct SrcFuncs G_PASTE (src_,name) = { \
+  G_PASTE(GST_GL_TEST_SRC_,cap_name), \
+  G_PASTE(G_PASTE(_src_unicolor_,name),_new), \
+  _src_uni_color_init, \
+  _src_uni_color_fill_bound_fbo, \
+  _src_uni_color_free, \
+}
 
-    gst_gl_shader_set_uniform_matrix_4fv (v->shader, "mvp",
-        1, GL_FALSE, identitiy_matrix);
+SRC_UNICOLOR (white, WHITE);
+SRC_UNICOLOR (black, BLACK);
+SRC_UNICOLOR (red, RED);
+SRC_UNICOLOR (green, GREEN);
+SRC_UNICOLOR (blue, BLUE);
 
-    gst_gl_shader_set_uniform_1f (v->shader, "time",
-        (gfloat) v->running_time / GST_SECOND);
+static gpointer
+_src_blink_new (GstGLTestSrc * test)
+{
+  struct SrcUniColor *src = _src_uni_color_new (test);
 
-    gst_gl_shader_set_uniform_1f (v->shader, "aspect_ratio",
-        (gfloat) w / (gfloat) h);
+  src->color = vts_colors[COLOR_WHITE];
 
-    gl->DrawElements (GL_TRIANGLE_STRIP, 5, GL_UNSIGNED_SHORT, indices);
+  return src;
+}
 
-    gl->DisableVertexAttribArray (attr_position_loc);
-    gl->DisableVertexAttribArray (attr_uv_loc);
+static gboolean
+_src_blink_fill_bound_fbo (gpointer impl)
+{
+  struct SrcUniColor *src = impl;
 
-    gst_gl_context_clear_shader (v->context);
+  if (src->color.R > 0.5) {
+    src->color = vts_colors[COLOR_BLACK];
+  } else {
+    src->color = vts_colors[COLOR_WHITE];
   }
+
+  return _src_uni_color_fill_bound_fbo (impl);
 }
 
-static void
-gst_gl_test_src_unicolor (GstGLTestSrc * v, GstBuffer * buffer, int w,
-    int h, const struct vts_color_struct *color)
+static const struct SrcFuncs src_blink = {
+  GST_GL_TEST_SRC_BLINK,
+  _src_blink_new,
+  _src_uni_color_init,
+  _src_blink_fill_bound_fbo,
+  _src_uni_color_free,
+};
+
+struct SrcShader
 {
-#if GST_GL_HAVE_OPENGL
-  if (gst_gl_context_get_gl_api (v->context) & GST_GL_API_OPENGL) {
-    glClearColor (color->R * (1 / 255.0f), color->G * (1 / 255.0f),
-        color->B * (1 / 255.0f), 1.0f);
-    glClear (GL_COLOR_BUFFER_BIT);
+  struct BaseSrcImpl base;
+
+  GstGLShader *shader;
+
+  gint attr_position;
+  gint attr_texcoord;
+  /* x, y, z, w */
+  const gfloat *vertices;
+  guint n_vertices;
+  const gushort *indices;
+  guint n_indices;
+};
+
+static gboolean
+_src_shader_fill_bound_fbo (gpointer impl)
+{
+  struct SrcShader *src = impl;
+  const GstGLFuncs *gl;
+
+  g_return_val_if_fail (src->base.context, FALSE);
+  g_return_val_if_fail (src->shader, FALSE);
+  gl = src->base.context->gl_vtable;
+
+  gst_gl_shader_use (src->shader);
+
+  if (src->attr_position != -1) {
+    gl->VertexAttribPointer (src->attr_position, 4, GL_FLOAT, GL_FALSE, 0,
+        src->vertices);
+    gl->EnableVertexAttribArray (src->attr_position);
   }
-#endif
+  gl->DrawElements (GL_TRIANGLES, src->n_indices, GL_UNSIGNED_SHORT,
+      src->indices);
+
+  if (src->attr_position != -1)
+    gl->DisableVertexAttribArray (src->attr_position);
+  gst_gl_context_clear_shader (src->base.context);
+
+  return TRUE;
 }
 
-void
-gst_gl_test_src_black (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+/* *INDENT-OFF* */
+static const gchar *checkers_vertex_src = "attribute vec4 position;\n"
+    "void main()\n"
+    "{\n"
+    "   gl_Position = position;\n"
+    "}";
+
+static const gchar *checkers_fragment_src =
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#endif\n"
+    "uniform float checker_width;\n"
+    "void main()\n"
+    "{\n"
+    "  vec2 xy_index= floor((gl_FragCoord.xy-vec2(0.5,0.5))/checker_width);\n"
+    "  vec2 xy_mod=mod(xy_index,vec2(2.0,2.0));\n"
+    "  float result=mod(xy_mod.x+xy_mod.y,2.0);\n"
+    "  gl_FragColor.r=step(result,0.5);\n"
+    "  gl_FragColor.g=1.0-gl_FragColor.r;\n"
+    "  gl_FragColor.ba=vec2(0,1);\n"
+    "}";
+/* *INDENT-ON* */
+
+struct SrcCheckers
 {
-  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_BLACK);
-}
+  struct SrcShader base;
 
-void
-gst_gl_test_src_white (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+  guint checker_width;
+};
+
+static gboolean
+_src_checkers_init (gpointer impl, GstGLContext * context,
+    GstVideoInfo * v_info)
 {
-  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_WHITE);
+  struct SrcCheckers *src = impl;
+  GError *error = NULL;
+
+  src->base.base.context = context;
+
+  if (src->base.shader)
+    gst_object_unref (src->base.shader);
+  src->base.shader = gst_gl_shader_new_link_with_stages (context, &error,
+      gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
+          GST_GLSL_VERSION_NONE,
+          GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
+          checkers_vertex_src),
+      gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+          GST_GLSL_VERSION_NONE,
+          GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
+          checkers_fragment_src), NULL);
+  if (!src->base.shader) {
+    GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
+    return FALSE;
+  }
+
+  src->base.attr_position =
+      gst_gl_shader_get_attribute_location (src->base.shader, "position");
+  if (src->base.attr_position == -1) {
+    GST_ERROR_OBJECT (src->base.base.src, "No position attribute");
+    return FALSE;
+  }
+  src->base.vertices = positions;
+  src->base.n_vertices = 4;
+  src->base.indices = indices_quad;
+  src->base.n_indices = 6;
+
+  gst_gl_shader_use (src->base.shader);
+  gst_gl_shader_set_uniform_1f (src->base.shader, "checker_width",
+      src->checker_width);
+  gst_gl_context_clear_shader (src->base.base.context);
+
+  return TRUE;
 }
 
-void
-gst_gl_test_src_red (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+static void
+_src_checkers_free (gpointer impl)
 {
-  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_RED);
+  struct SrcCheckers *src = impl;
+
+  if (!src)
+    return;
+
+  if (src->base.shader)
+    gst_object_unref (src->base.shader);
+  src->base.shader = NULL;
+
+  g_free (impl);
 }
 
-void
-gst_gl_test_src_green (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+static gpointer
+_src_checkers_new (GstGLTestSrc * test)
 {
-  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_GREEN);
+  struct SrcCheckers *src = g_new0 (struct SrcCheckers, 1);
+
+  src->base.base.src = test;
+
+  return src;
 }
 
-void
-gst_gl_test_src_blue (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+#define SRC_CHECKERS(spacing) \
+static gpointer \
+G_PASTE(G_PASTE(_src_checkers,spacing),_new) (GstGLTestSrc * test) \
+{ \
+  struct SrcCheckers *src = _src_checkers_new (test); \
+  src->checker_width = spacing; \
+  return src; \
+} \
+static const struct SrcFuncs G_PASTE(src_checkers,spacing) = { \
+  G_PASTE(GST_GL_TEST_SRC_CHECKERS,spacing), \
+  G_PASTE(G_PASTE(_src_checkers,spacing),_new), \
+  _src_checkers_init, \
+  _src_shader_fill_bound_fbo, \
+  _src_checkers_free, \
+}
+
+SRC_CHECKERS (1);
+SRC_CHECKERS (2);
+SRC_CHECKERS (4);
+SRC_CHECKERS (8);
+
+/* *INDENT-OFF* */
+static const gchar *snow_vertex_src =
+    "attribute vec4 position;\n"
+    "varying vec2 out_uv;\n"
+    "void main()\n"
+    "{\n"
+    "   gl_Position = position;\n"
+    "   out_uv = position.xy;\n"
+    "}";
+
+static const gchar *snow_fragment_src = 
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#endif\n"
+    "uniform float time;\n"
+    "varying vec2 out_uv;\n"
+    "\n"
+    "float rand(vec2 co){\n"
+    "    return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);\n"
+    "}\n"
+    "void main()\n"
+    "{\n"
+    "  gl_FragColor = vec4(rand(time * out_uv));\n"
+    "}";
+/* *INDENT-ON* */
+
+static gboolean
+_src_snow_init (gpointer impl, GstGLContext * context, GstVideoInfo * v_info)
 {
-  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_BLUE);
+  struct SrcShader *src = impl;
+  GError *error = NULL;
+
+  src->base.context = context;
+
+  if (src->shader)
+    gst_object_unref (src->shader);
+  src->shader = gst_gl_shader_new_link_with_stages (context, &error,
+      gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
+          GST_GLSL_VERSION_NONE,
+          GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
+          snow_vertex_src),
+      gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+          GST_GLSL_VERSION_NONE,
+          GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
+          snow_fragment_src), NULL);
+  if (!src->shader) {
+    GST_ERROR_OBJECT (src->base.src, "%s", error->message);
+    return FALSE;
+  }
+
+  src->attr_position =
+      gst_gl_shader_get_attribute_location (src->shader, "position");
+  if (src->attr_position == -1) {
+    GST_ERROR_OBJECT (src->base.src, "No position attribute");
+    return FALSE;
+  }
+  src->vertices = positions;
+  src->n_vertices = 4;
+  src->indices = indices_quad;
+  src->n_indices = 6;
+
+  return TRUE;
 }
 
-static void
-gst_gl_test_src_checkers (GstGLTestSrc * v, gint checker_width)
+static gboolean
+_src_snow_fill_bound_fbo (gpointer impl)
 {
+  struct SrcShader *src = impl;
 
-  GstGLFuncs *gl = v->context->gl_vtable;
+  g_return_val_if_fail (src->base.context, FALSE);
+  g_return_val_if_fail (src->shader, FALSE);
 
-  GLushort indices[] = { 0, 1, 2, 3, 0 };
+  gst_gl_shader_use (src->shader);
+  gst_gl_shader_set_uniform_1f (src->shader, "time",
+      (gfloat) src->base.src->running_time / GST_SECOND);
 
-  GLint attr_position_loc = -1;
+  return _src_shader_fill_bound_fbo (impl);
+}
 
-  if (gst_gl_context_get_gl_api (v->context)) {
+static void
+_src_snow_free (gpointer impl)
+{
+  struct SrcShader *src = impl;
 
-    gst_gl_context_clear_shader (v->context);
-    gl->BindTexture (GL_TEXTURE_2D, 0);
+  if (!src)
+    return;
 
-    gst_gl_shader_use (v->shader);
+  if (src->shader)
+    gst_object_unref (src->shader);
+  src->shader = NULL;
 
-    attr_position_loc =
-        gst_gl_shader_get_attribute_location (v->shader, "position");
+  g_free (impl);
+}
 
-    /* Load the vertex position */
-    gl->VertexAttribPointer (attr_position_loc, 4, GL_FLOAT,
-        GL_FALSE, 0, positions);
+static gpointer
+_src_snow_new (GstGLTestSrc * test)
+{
+  struct SrcShader *src = g_new0 (struct SrcShader, 1);
 
-    gl->EnableVertexAttribArray (attr_position_loc);
+  src->base.src = test;
 
-    gst_gl_shader_set_uniform_matrix_4fv (v->shader, "mvp",
-        1, GL_FALSE, identitiy_matrix);
+  return src;
+}
 
-    gst_gl_shader_set_uniform_1f (v->shader, "checker_width", checker_width);
+static const struct SrcFuncs src_snow = {
+  GST_GL_TEST_SRC_SNOW,
+  _src_snow_new,
+  _src_snow_init,
+  _src_snow_fill_bound_fbo,
+  _src_snow_free,
+};
 
-    gl->DrawElements (GL_TRIANGLE_STRIP, 5, GL_UNSIGNED_SHORT, indices);
+/* *INDENT-OFF* */
+static const gchar *mandelbrot_vertex_src = "attribute vec4 position;\n"
+    "uniform float aspect_ratio;\n"
+    "varying vec2 fractal_position;\n"
+    "void main()\n"
+    "{\n"
+    "  gl_Position = position;\n"
+    "  fractal_position = vec2(position.y * 0.5 - 0.3, aspect_ratio * position.x * 0.5);\n"
+    "  fractal_position *= 2.5;\n"
+    "}";
+
+static const gchar *mandelbrot_fragment_src = 
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#endif\n"
+    "uniform float time;\n"
+    "varying vec2 fractal_position;\n"
+    "const vec4 K = vec4(1.0, 0.66, 0.33, 3.0);\n"
+    "vec4 hsv_to_rgb(float hue, float saturation, float value) {\n"
+    "  vec4 p = abs(fract(vec4(hue) + K) * 6.0 - K.wwww);\n"
+    "  return value * mix(K.xxxx, clamp(p - K.xxxx, 0.0, 1.0), saturation);\n"
+    "}\n"
+    "vec4 i_to_rgb(int i) {\n"
+    "  float hue = float(i) / 100.0 + sin(time);\n"
+    "  return hsv_to_rgb(hue, 0.5, 0.8);\n"
+    "}\n"
+    "vec2 pow_2_complex(vec2 c) {\n"
+    "  return vec2(c.x*c.x - c.y*c.y, 2.0 * c.x * c.y);\n"
+    "}\n"
+    "vec2 mandelbrot(vec2 c, vec2 c0) {\n"
+    "  return pow_2_complex(c) + c0;\n"
+    "}\n"
+    "vec4 iterate_pixel(vec2 position) {\n"
+    "  vec2 c = vec2(0);\n"
+    "  for (int i=0; i < 100; i++) {\n"
+    "    if (c.x*c.x + c.y*c.y > 2.0*2.0)\n"
+    "      return i_to_rgb(i);\n"
+    "    c = mandelbrot(c, position);\n"
+    "  }\n"
+    "  return vec4(0, 0, 0, 1);\n"
+    "}\n"
+    "void main() {\n"
+    "  gl_FragColor = iterate_pixel(fractal_position);\n"
+    "}";
+/* *INDENT-ON* */
 
-    gl->DisableVertexAttribArray (attr_position_loc);
+static gboolean
+_src_mandelbrot_init (gpointer impl, GstGLContext * context,
+    GstVideoInfo * v_info)
+{
+  struct SrcShader *src = impl;
+  GError *error = NULL;
+
+  src->base.context = context;
+
+  if (src->shader)
+    gst_object_unref (src->shader);
+  src->shader = gst_gl_shader_new_link_with_stages (context, &error,
+      gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
+          GST_GLSL_VERSION_NONE,
+          GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
+          mandelbrot_vertex_src),
+      gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
+          GST_GLSL_VERSION_NONE,
+          GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
+          mandelbrot_fragment_src), NULL);
+  if (!src->shader) {
+    GST_ERROR_OBJECT (src->base.src, "%s", error->message);
+    return FALSE;
+  }
 
-    gst_gl_context_clear_shader (v->context);
+  src->attr_position =
+      gst_gl_shader_get_attribute_location (src->shader, "position");
+  if (src->attr_position == -1) {
+    GST_ERROR_OBJECT (src->base.src, "No position attribute");
+    return FALSE;
   }
+  src->vertices = positions;
+  src->n_vertices = 4;
+  src->indices = indices_quad;
+  src->n_indices = 6;
+
+  gst_gl_shader_use (src->shader);
+  gst_gl_shader_set_uniform_1f (src->shader, "aspect_ratio",
+      (gfloat) GST_VIDEO_INFO_WIDTH (v_info) /
+      (gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
+  gst_gl_context_clear_shader (src->base.context);
+
+  return TRUE;
 }
 
-
-void
-gst_gl_test_src_checkers1 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+static gboolean
+_src_mandelbrot_fill_bound_fbo (gpointer impl)
 {
-  gst_gl_test_src_checkers (v, 1);
-}
+  struct SrcShader *src = impl;
 
+  g_return_val_if_fail (src->base.context, FALSE);
+  g_return_val_if_fail (src->shader, FALSE);
 
-void
-gst_gl_test_src_checkers2 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
-{
-  gst_gl_test_src_checkers (v, 2);
+  gst_gl_shader_use (src->shader);
+  gst_gl_shader_set_uniform_1f (src->shader, "time",
+      (gfloat) src->base.src->running_time / GST_SECOND);
+
+  return _src_shader_fill_bound_fbo (impl);
 }
 
-void
-gst_gl_test_src_checkers4 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+static void
+_src_mandelbrot_free (gpointer impl)
 {
-  gst_gl_test_src_checkers (v, 4);
+  struct SrcShader *src = impl;
+
+  if (!src)
+    return;
 
+  if (src->shader)
+    gst_object_unref (src->shader);
+  src->shader = NULL;
+
+  g_free (impl);
 }
 
-void
-gst_gl_test_src_checkers8 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+static gpointer
+_src_mandelbrot_new (GstGLTestSrc * test)
 {
-  gst_gl_test_src_checkers (v, 8);
+  struct SrcShader *src = g_new0 (struct SrcShader, 1);
+
+  src->base.src = test;
+
+  return src;
 }
 
+static const struct SrcFuncs src_mandelbrot = {
+  GST_GL_TEST_SRC_MANDELBROT,
+  _src_mandelbrot_new,
+  _src_mandelbrot_init,
+  _src_mandelbrot_fill_bound_fbo,
+  _src_mandelbrot_free,
+};
+
+#if 0
 void
 gst_gl_test_src_circular (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
 {
@@ -456,3 +833,32 @@ gst_gl_test_src_circular (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
   }
 #endif
 }
+#endif
+static const struct SrcFuncs *src_impls[] = {
+  &src_smpte,
+  &src_snow,
+  &src_black,
+  &src_white,
+  &src_red,
+  &src_green,
+  &src_blue,
+  &src_checkers1,
+  &src_checkers2,
+  &src_checkers4,
+  &src_checkers8,
+  &src_blink,
+  &src_mandelbrot,
+};
+
+const struct SrcFuncs *
+gst_gl_test_src_get_src_funcs_for_pattern (GstGLTestSrcPattern pattern)
+{
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS (src_impls); i++) {
+    if (src_impls[i]->pattern == pattern)
+      return src_impls[i];
+  }
+
+  return NULL;
+}
index 102109e..dbcab0c 100644 (file)
 
 #include <glib.h>
 
+typedef struct _GstGLTestSrc GstGLTestSrc;
+
+/**
+ * GstGLTestSrcPattern:
+ * @GST_GL_TEST_SRC_SMPTE: A standard SMPTE test pattern
+ * @GST_GL_TEST_SRC_SNOW: Random noise
+ * @GST_GL_TEST_SRC_BLACK: A black image
+ * @GST_GL_TEST_SRC_WHITE: A white image
+ * @GST_GL_TEST_SRC_RED: A red image
+ * @GST_GL_TEST_SRC_GREEN: A green image
+ * @GST_GL_TEST_SRC_BLUE: A blue image
+ * @GST_GL_TEST_SRC_CHECKERS1: Checkers pattern (1px)
+ * @GST_GL_TEST_SRC_CHECKERS2: Checkers pattern (2px)
+ * @GST_GL_TEST_SRC_CHECKERS4: Checkers pattern (4px)
+ * @GST_GL_TEST_SRC_CHECKERS8: Checkers pattern (8px)
+ * @GST_GL_TEST_SRC_CIRCULAR: Circular pattern
+ * @GST_GL_TEST_SRC_BLINK: Alternate between black and white
+ *
+ * The test pattern to produce.
+ */
+typedef enum {
+    GST_GL_TEST_SRC_SMPTE,
+    GST_GL_TEST_SRC_SNOW,
+    GST_GL_TEST_SRC_BLACK,
+    GST_GL_TEST_SRC_WHITE,
+    GST_GL_TEST_SRC_RED,
+    GST_GL_TEST_SRC_GREEN,
+    GST_GL_TEST_SRC_BLUE,
+    GST_GL_TEST_SRC_CHECKERS1,
+    GST_GL_TEST_SRC_CHECKERS2,
+    GST_GL_TEST_SRC_CHECKERS4,
+    GST_GL_TEST_SRC_CHECKERS8,
+    GST_GL_TEST_SRC_CIRCULAR,
+    GST_GL_TEST_SRC_BLINK,
+    GST_GL_TEST_SRC_MANDELBROT
+} GstGLTestSrcPattern;
+
 #include "gstgltestsrc.h"
 
-struct vts_color_struct {
-        guint8 Y, U, V;
-        guint8 R, G, B;
-       guint8 A;
+struct BaseSrcImpl {
+  GstGLTestSrc *src;
+  GstGLContext *context;
+  GstVideoInfo v_info;
+};
+
+struct SrcFuncs
+{
+  GstGLTestSrcPattern pattern;
+  gpointer (*new) (GstGLTestSrc * src);
+  gboolean (*init) (gpointer impl, GstGLContext * context, GstVideoInfo * v_info);
+  gboolean (*fill_bound_fbo) (gpointer impl);
+  void (*free) (gpointer impl);
 };
 
-void    gst_gl_test_src_smpte        (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_shader       (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_black        (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_white        (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_red          (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_green        (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_blue         (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_checkers1    (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_checkers2    (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_checkers4    (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_checkers8    (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
-void    gst_gl_test_src_circular     (GstGLTestSrc * v,
-                                         GstBuffer *buffer, int w, int h);
+const struct SrcFuncs * gst_gl_test_src_get_src_funcs_for_pattern (GstGLTestSrcPattern pattern);
 
 #endif
index f7059ac..91f7258 100644 (file)
@@ -228,162 +228,10 @@ gst_gl_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
   return caps;
 }
 
-const gchar *snow_vertex_src = "attribute vec4 position; \
-    attribute vec2 uv; \
-    uniform mat4 mvp; \
-    varying vec2 out_uv; \
-    void main() \
-    { \
-       gl_Position = mvp * position; \
-       out_uv = uv; \
-    }";
-
-const gchar *snow_fragment_src = "uniform float time; \
-    varying vec2 out_uv; \
-    \
-    float rand(vec2 co){ \
-        return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453); \
-    } \
-    void main() \
-    { \
-      gl_FragColor = rand(time * out_uv) * vec4(1); \
-    }";
-
-const gchar *mandelbrot_vertex_src = "attribute vec4 position; \
-    attribute vec2 uv; \
-    uniform mat4 mvp; \
-    uniform float aspect_ratio; \
-    varying vec2 fractal_position; \
-    \
-    void main() \
-    { \
-       gl_Position = mvp * position; \
-       fractal_position = vec2(uv.y - 0.8, aspect_ratio * (uv.x - 0.5)); \
-       fractal_position *= 2.5; \
-    }";
-
-const gchar *mandelbrot_fragment_src = "uniform float time; \
-    varying vec2 fractal_position; \
-    \
-    const vec4 K = vec4(1.0, 0.66, 0.33, 3.0); \
-    \
-    vec4 hsv_to_rgb(float hue, float saturation, float value) { \
-      vec4 p = abs(fract(vec4(hue) + K) * 6.0 - K.wwww); \
-      return value * mix(K.xxxx, clamp(p - K.xxxx, 0.0, 1.0), saturation); \
-    } \
-    \
-    vec4 i_to_rgb(int i) { \
-      float hue = float(i) / 100.0 + sin(time); \
-      return hsv_to_rgb(hue, 0.5, 0.8); \
-    } \
-    \
-    vec2 pow_2_complex(vec2 c) { \
-      return vec2(c.x*c.x - c.y*c.y, 2.0 * c.x * c.y); \
-    } \
-    \
-    vec2 mandelbrot(vec2 c, vec2 c0) { \
-      return pow_2_complex(c) + c0; \
-    } \
-    \
-    vec4 iterate_pixel(vec2 position) { \
-      vec2 c = vec2(0); \
-      for (int i=0; i < 100; i++) { \
-        if (c.x*c.x + c.y*c.y > 2.0*2.0) \
-          return i_to_rgb(i); \
-        c = mandelbrot(c, position); \
-      } \
-      return vec4(0, 0, 0, 1); \
-    } \
-    \
-    void main() { \
-      gl_FragColor = iterate_pixel(fractal_position); \
-    }";
-
-
-const gchar *checkers_vertex_src = "attribute vec4 position; \
-    uniform mat4 mvp; \
-    void main() \
-    { \
-       gl_Position = mvp * position; \
-    }";
-
-const gchar *checkers_fragment_src = "uniform float checker_width; \
-    void main() \
-    { \
-      vec2 xy_index= floor((gl_FragCoord.xy-vec2(0.5,0.5))/checker_width); \
-      vec2 xy_mod=mod(xy_index,vec2(2.0,2.0)); \
-      float result=mod(xy_mod.x+xy_mod.y,2.0); \
-      gl_FragColor.r=step(result,0.5); \
-      gl_FragColor.g=1.0-gl_FragColor.r; \
-      gl_FragColor.ba=vec2(0,1); \
-    }";
-
-
 static void
 gst_gl_test_src_set_pattern (GstGLTestSrc * gltestsrc, gint pattern_type)
 {
-  gltestsrc->pattern_type = pattern_type;
-
-  GST_DEBUG_OBJECT (gltestsrc, "setting pattern to %d", pattern_type);
-
-  switch (pattern_type) {
-    case GST_GL_TEST_SRC_SMPTE:
-      gltestsrc->make_image = gst_gl_test_src_smpte;
-      break;
-    case GST_GL_TEST_SRC_SNOW:
-      gltestsrc->vertex_src = snow_vertex_src;
-      gltestsrc->fragment_src = snow_fragment_src;
-      gltestsrc->make_image = gst_gl_test_src_shader;
-      break;
-    case GST_GL_TEST_SRC_BLACK:
-      gltestsrc->make_image = gst_gl_test_src_black;
-      break;
-    case GST_GL_TEST_SRC_WHITE:
-      gltestsrc->make_image = gst_gl_test_src_white;
-      break;
-    case GST_GL_TEST_SRC_RED:
-      gltestsrc->make_image = gst_gl_test_src_red;
-      break;
-    case GST_GL_TEST_SRC_GREEN:
-      gltestsrc->make_image = gst_gl_test_src_green;
-      break;
-    case GST_GL_TEST_SRC_BLUE:
-      gltestsrc->make_image = gst_gl_test_src_blue;
-      break;
-    case GST_GL_TEST_SRC_CHECKERS1:
-      gltestsrc->vertex_src = checkers_vertex_src;
-      gltestsrc->fragment_src = checkers_fragment_src;
-      gltestsrc->make_image = gst_gl_test_src_checkers1;
-      break;
-    case GST_GL_TEST_SRC_CHECKERS2:
-      gltestsrc->vertex_src = checkers_vertex_src;
-      gltestsrc->fragment_src = checkers_fragment_src;
-      gltestsrc->make_image = gst_gl_test_src_checkers2;
-      break;
-    case GST_GL_TEST_SRC_CHECKERS4:
-      gltestsrc->vertex_src = checkers_vertex_src;
-      gltestsrc->fragment_src = checkers_fragment_src;
-      gltestsrc->make_image = gst_gl_test_src_checkers4;
-      break;
-    case GST_GL_TEST_SRC_CHECKERS8:
-      gltestsrc->vertex_src = checkers_vertex_src;
-      gltestsrc->fragment_src = checkers_fragment_src;
-      gltestsrc->make_image = gst_gl_test_src_checkers8;
-      break;
-    case GST_GL_TEST_SRC_CIRCULAR:
-      gltestsrc->make_image = gst_gl_test_src_circular;
-      break;
-    case GST_GL_TEST_SRC_BLINK:
-      gltestsrc->make_image = gst_gl_test_src_black;
-      break;
-    case GST_GL_TEST_SRC_MANDELBROT:
-      gltestsrc->vertex_src = mandelbrot_vertex_src;
-      gltestsrc->fragment_src = mandelbrot_fragment_src;
-      gltestsrc->make_image = gst_gl_test_src_shader;
-      break;
-    default:
-      g_assert_not_reached ();
-  }
+  gltestsrc->set_pattern = pattern_type;
 }
 
 static void
@@ -415,7 +263,7 @@ gst_gl_test_src_get_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_PATTERN:
-      g_value_set_enum (value, src->pattern_type);
+      g_value_set_enum (value, src->set_pattern);
       break;
     case PROP_TIMESTAMP_OFFSET:
       g_value_set_int64 (value, src->timestamp_offset);
@@ -598,10 +446,10 @@ gst_gl_test_src_init_shader (GstGLTestSrc * gltestsrc)
 {
   if (gst_gl_context_get_gl_api (gltestsrc->context)) {
     /* blocking call, wait until the opengl thread has compiled the shader */
-    if (gltestsrc->vertex_src == NULL)
-      return FALSE;
-    return gst_gl_context_gen_shader (gltestsrc->context, gltestsrc->vertex_src,
-        gltestsrc->fragment_src, &gltestsrc->shader);
+//    if (gltestsrc->vertex_src == NULL)
+//      return FALSE;
+//    return gst_gl_context_gen_shader (gltestsrc->context, gltestsrc->vertex_src,
+//        gltestsrc->fragment_src, &gltestsrc->shader);
   }
   return TRUE;
 }
@@ -627,13 +475,6 @@ gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
           && src->n_frames == 1))
     goto eos;
 
-  if (src->pattern_type == GST_GL_TEST_SRC_BLINK) {
-    if (src->n_frames & 0x1)
-      src->make_image = gst_gl_test_src_white;
-    else
-      src->make_image = gst_gl_test_src_black;
-  }
-
   if (!gst_video_frame_map (&out_frame, &src->out_info, buffer,
           GST_MAP_WRITE | GST_MAP_GL)) {
     return GST_FLOW_NOT_NEGOTIATED;
@@ -641,15 +482,15 @@ gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
 
   out_tex = *(guint *) out_frame.data[0];
 
-  gst_buffer_replace (&src->buffer, buffer);
-
   if (!gst_gl_context_use_fbo_v2 (src->context, width, height, src->fbo,
           src->depthbuffer, out_tex, gst_gl_test_src_callback,
           (gpointer) src)) {
-    goto not_negotiated;
+    gst_video_frame_unmap (&out_frame);
+    goto gl_error;
   }
-
   gst_video_frame_unmap (&out_frame);
+  if (!src->gl_result)
+    goto gl_error;
 
   sync_meta = gst_buffer_get_gl_sync_meta (buffer);
   if (sync_meta)
@@ -673,6 +514,12 @@ gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
 
   return GST_FLOW_OK;
 
+gl_error:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (_("failed to draw pattern")),
+        (_("A GL error occured")));
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
 not_negotiated:
   {
     GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL),
@@ -888,12 +735,33 @@ static void
 gst_gl_test_src_callback (gpointer stuff)
 {
   GstGLTestSrc *src = GST_GL_TEST_SRC (stuff);
+  const struct SrcFuncs *funcs;
+
+  funcs = src->src_funcs;
+
+  if (!funcs || src->set_pattern != src->active_pattern) {
+    if (src->src_impl)
+      funcs->free (src->src_impl);
+    src->src_funcs = funcs =
+        gst_gl_test_src_get_src_funcs_for_pattern (src->set_pattern);
+    if (funcs == NULL) {
+      GST_ERROR_OBJECT (src, "Could not find an implementation of the "
+          "requested pattern");
+      src->gl_result = FALSE;
+      return;
+    }
+    src->src_impl = funcs->new (src);
+    if (!(src->gl_result =
+            funcs->init (src->src_impl, src->context, &src->out_info))) {
+      GST_ERROR_OBJECT (src, "Failed to initialize pattern");
+      return;
+    }
+    src->active_pattern = src->set_pattern;
+  }
 
-  src->make_image (src, src->buffer, GST_VIDEO_INFO_WIDTH (&src->out_info),
-      GST_VIDEO_INFO_HEIGHT (&src->out_info));
-
-  gst_buffer_unref (src->buffer);
-  src->buffer = NULL;
+  src->gl_result = funcs->fill_bound_fbo (src->src_impl);
+  if (!src->gl_result)
+    GST_ERROR_OBJECT (src, "Failed to render the pattern");
 }
 
 static GstStateChangeReturn
index 1c045c7..8aab84f 100644 (file)
@@ -28,6 +28,8 @@
 
 #include <gst/gl/gl.h>
 
+#include "gltestsrc.h"
+
 G_BEGIN_DECLS
 
 #define GST_TYPE_GL_TEST_SRC \
@@ -41,41 +43,6 @@ G_BEGIN_DECLS
 #define GST_IS_GL_TEST_SRC_CLASS(klass) \
     (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_TEST_SRC))
 
-/**
- * GstGLTestSrcPattern:
- * @GST_GL_TEST_SRC_SMPTE: A standard SMPTE test pattern
- * @GST_GL_TEST_SRC_SNOW: Random noise
- * @GST_GL_TEST_SRC_BLACK: A black image
- * @GST_GL_TEST_SRC_WHITE: A white image
- * @GST_GL_TEST_SRC_RED: A red image
- * @GST_GL_TEST_SRC_GREEN: A green image
- * @GST_GL_TEST_SRC_BLUE: A blue image
- * @GST_GL_TEST_SRC_CHECKERS1: Checkers pattern (1px)
- * @GST_GL_TEST_SRC_CHECKERS2: Checkers pattern (2px)
- * @GST_GL_TEST_SRC_CHECKERS4: Checkers pattern (4px)
- * @GST_GL_TEST_SRC_CHECKERS8: Checkers pattern (8px)
- * @GST_GL_TEST_SRC_CIRCULAR: Circular pattern
- * @GST_GL_TEST_SRC_BLINK: Alternate between black and white
- *
- * The test pattern to produce.
- */
-typedef enum {
-    GST_GL_TEST_SRC_SMPTE,
-    GST_GL_TEST_SRC_SNOW,
-    GST_GL_TEST_SRC_BLACK,
-    GST_GL_TEST_SRC_WHITE,
-    GST_GL_TEST_SRC_RED,
-    GST_GL_TEST_SRC_GREEN,
-    GST_GL_TEST_SRC_BLUE,
-    GST_GL_TEST_SRC_CHECKERS1,
-    GST_GL_TEST_SRC_CHECKERS2,
-    GST_GL_TEST_SRC_CHECKERS4,
-    GST_GL_TEST_SRC_CHECKERS8,
-    GST_GL_TEST_SRC_CIRCULAR,
-    GST_GL_TEST_SRC_BLINK,
-    GST_GL_TEST_SRC_MANDELBROT
-} GstGLTestSrcPattern;
-
 typedef struct _GstGLTestSrc GstGLTestSrc;
 typedef struct _GstGLTestSrcClass GstGLTestSrcClass;
 
@@ -90,10 +57,10 @@ struct _GstGLTestSrc {
     /*< private >*/
 
     /* type of output */
-    GstGLTestSrcPattern pattern_type;
+    GstGLTestSrcPattern set_pattern;
+    GstGLTestSrcPattern active_pattern;
 
     /* video state */
-    char *format_name;
     GstVideoInfo out_info;
 
     GLuint fbo;
@@ -101,7 +68,6 @@ struct _GstGLTestSrc {
 
     GstGLShader *shader;
 
-    GstBuffer* buffer;
     GstBufferPool *pool;
 
     GstGLDisplay *display;
@@ -111,10 +77,9 @@ struct _GstGLTestSrc {
     gint64 n_frames;                      /* total frames sent */
     gboolean negotiated;
 
-    const gchar *vertex_src;
-    const gchar *fragment_src;
-
-    void (*make_image) (GstGLTestSrc* v, GstBuffer* buffer, gint w, gint h);
+    gboolean gl_result;
+    const struct SrcFuncs *src_funcs;
+    gpointer src_impl;
 
     GstCaps *out_caps;
 };