• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <gst/gl/gstglfuncs.h>
26 
27 #include "gltestsrc.h"
28 
29 #define MAX_ATTRIBUTES 4
30 
31 struct vts_color_struct
32 {
33   gfloat R, G, B;
34 };
35 
36 struct XYZWRGB
37 {
38   gfloat X, Y, Z, W, R, G, B;
39 };
40 
41 enum
42 {
43   COLOR_WHITE = 0,
44   COLOR_YELLOW,
45   COLOR_CYAN,
46   COLOR_GREEN,
47   COLOR_MAGENTA,
48   COLOR_RED,
49   COLOR_BLUE,
50   COLOR_BLACK,
51   COLOR_NEG_I,
52   COLOR_POS_Q,
53   COLOR_SUPER_BLACK,
54   COLOR_DARK_GREY
55 };
56 
57 static const struct vts_color_struct vts_colors[] = {
58   /* 100% white */
59   {1.0f, 1.0f, 1.0f},
60   /* yellow */
61   {1.0f, 1.0f, 0.0f},
62   /* cyan */
63   {0.0f, 1.0f, 1.0f},
64   /* green */
65   {0.0f, 1.0f, 0.0f},
66   /* magenta */
67   {1.0f, 0.0f, 1.0f},
68   /* red */
69   {1.0f, 0.0f, 0.0f},
70   /* blue */
71   {0.0f, 0.0f, 1.0f},
72   /* black */
73   {0.0f, 0.0f, 0.0f},
74   /* -I */
75   {0.0, 0.0f, 0.5f},
76   /* +Q */
77   {0.0f, 0.5, 1.0f},
78   /* superblack */
79   {0.0f, 0.0f, 0.0f},
80   /* 7.421875% grey */
81   {19. / 256.0f, 19. / 256.0f, 19. / 256.0},
82 };
83 
84 /* *INDENT-OFF* */
85 static const GLfloat positions[] = {
86      -1.0,  1.0,  0.0, 1.0,
87       1.0,  1.0,  0.0, 1.0,
88       1.0, -1.0,  0.0, 1.0,
89      -1.0, -1.0,  0.0, 1.0,
90 };
91 
92 static const GLushort indices_quad[] = { 0, 1, 2, 0, 2, 3 };
93 /* *INDENT-ON* */
94 
95 struct attribute
96 {
97   const gchar *name;
98   gint location;
99   guint n_elements;
100   GLenum element_type;
101   guint offset;                 /* in bytes */
102   guint stride;                 /* in bytes */
103 };
104 
105 struct SrcShader
106 {
107   struct BaseSrcImpl base;
108 
109   GstGLShader *shader;
110 
111   guint vao;
112   guint vbo;
113   guint vbo_indices;
114 
115   guint n_attributes;
116   struct attribute attributes[MAX_ATTRIBUTES];
117 
118   gconstpointer vertices;
119   gsize vertices_size;
120   const gushort *indices;
121   guint index_offset;
122   guint n_indices;
123 };
124 
125 static void
_bind_buffer(struct SrcShader * src)126 _bind_buffer (struct SrcShader *src)
127 {
128   GstGLContext *context = src->base.context;
129   const GstGLFuncs *gl = context->gl_vtable;
130   gint i;
131 
132   gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, src->vbo_indices);
133   gl->BindBuffer (GL_ARRAY_BUFFER, src->vbo);
134 
135   /* Load the vertex position */
136   for (i = 0; i < src->n_attributes; i++) {
137     struct attribute *attr = &src->attributes[i];
138 
139     if (attr->location == -1)
140       attr->location =
141           gst_gl_shader_get_attribute_location (src->shader, attr->name);
142 
143     gl->VertexAttribPointer (attr->location, attr->n_elements,
144         attr->element_type, GL_FALSE, attr->stride,
145         (void *) (gintptr) attr->offset);
146 
147     gl->EnableVertexAttribArray (attr->location);
148   }
149 }
150 
151 static void
_unbind_buffer(struct SrcShader * src)152 _unbind_buffer (struct SrcShader *src)
153 {
154   GstGLContext *context = src->base.context;
155   const GstGLFuncs *gl = context->gl_vtable;
156   gint i;
157 
158   gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
159   gl->BindBuffer (GL_ARRAY_BUFFER, 0);
160 
161   for (i = 0; i < src->n_attributes; i++) {
162     struct attribute *attr = &src->attributes[i];
163 
164     gl->DisableVertexAttribArray (attr->location);
165   }
166 }
167 
168 static gboolean
_src_shader_init(gpointer impl,GstGLContext * context,const GstVideoInfo * v_info)169 _src_shader_init (gpointer impl, GstGLContext * context,
170     const GstVideoInfo * v_info)
171 {
172   struct SrcShader *src = impl;
173   const GstGLFuncs *gl = context->gl_vtable;
174 
175   src->base.context = context;
176 
177   if (!src->vbo) {
178     if (gl->GenVertexArrays) {
179       gl->GenVertexArrays (1, &src->vao);
180       gl->BindVertexArray (src->vao);
181     }
182 
183     gl->GenBuffers (1, &src->vbo);
184     gl->BindBuffer (GL_ARRAY_BUFFER, src->vbo);
185     gl->BufferData (GL_ARRAY_BUFFER, src->vertices_size,
186         src->vertices, GL_STATIC_DRAW);
187 
188     gl->GenBuffers (1, &src->vbo_indices);
189     gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, src->vbo_indices);
190     gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, src->n_indices * sizeof (gushort),
191         src->indices, GL_STATIC_DRAW);
192 
193     if (gl->GenVertexArrays) {
194       _bind_buffer (src);
195       gl->BindVertexArray (0);
196     }
197 
198     gl->BindBuffer (GL_ARRAY_BUFFER, 0);
199     gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
200   }
201 
202   return TRUE;
203 }
204 
205 static gboolean
_src_shader_fill_bound_fbo(gpointer impl)206 _src_shader_fill_bound_fbo (gpointer impl)
207 {
208   struct SrcShader *src = impl;
209   const GstGLFuncs *gl;
210 
211   g_return_val_if_fail (src->base.context, FALSE);
212   g_return_val_if_fail (src->shader, FALSE);
213   gl = src->base.context->gl_vtable;
214 
215   gst_gl_shader_use (src->shader);
216 
217   if (gl->GenVertexArrays)
218     gl->BindVertexArray (src->vao);
219   _bind_buffer (src);
220 
221   gl->DrawElements (GL_TRIANGLES, src->n_indices, GL_UNSIGNED_SHORT,
222       (gpointer) (gintptr) src->index_offset);
223 
224   if (gl->GenVertexArrays)
225     gl->BindVertexArray (0);
226   else
227     _unbind_buffer (src);
228 
229   gst_gl_context_clear_shader (src->base.context);
230 
231   return TRUE;
232 }
233 
234 static void
_src_shader_deinit(gpointer impl)235 _src_shader_deinit (gpointer impl)
236 {
237   struct SrcShader *src = impl;
238   const GstGLFuncs *gl = src->base.context->gl_vtable;
239 
240   if (src->shader)
241     gst_object_unref (src->shader);
242   src->shader = NULL;
243 
244   if (src->vao)
245     gl->DeleteVertexArrays (1, &src->vao);
246   src->vao = 0;
247 
248   if (src->vbo)
249     gl->DeleteBuffers (1, &src->vbo);
250   src->vbo = 0;
251 
252   if (src->vbo_indices)
253     gl->DeleteBuffers (1, &src->vbo_indices);
254   src->vbo_indices = 0;
255 }
256 
257 /* *INDENT-OFF* */
258 static const gchar *smpte_vertex_src =
259     "attribute vec4 position;\n"
260     "attribute vec4 a_color;\n"
261     "varying vec4 color;\n"
262     "void main()\n"
263     "{\n"
264     "  gl_Position = position;\n"
265     "  color = a_color;\n"
266     "}";
267 
268 static const gchar *smpte_fragment_src =
269     "varying vec4 color;\n"
270     "void main()\n"
271     "{\n"
272     "  gl_FragColor = color;\n"
273     "}";
274 
275 static const gchar *snow_vertex_src =
276     "attribute vec4 position;\n"
277     "varying vec2 out_uv;\n"
278     "void main()\n"
279     "{\n"
280     "   gl_Position = position;\n"
281     "   out_uv = position.xy;\n"
282     "}";
283 
284 static const gchar *snow_fragment_src =
285     "uniform float time;\n"
286     "varying vec2 out_uv;\n"
287     "\n"
288     "float rand(vec2 co){\n"
289     "    return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);\n"
290     "}\n"
291     "void main()\n"
292     "{\n"
293     "  gl_FragColor = vec4(rand(time * out_uv));\n"
294     "}";
295 /* *INDENT-ON* */
296 
297 #define N_QUADS 21
298 struct SrcSMPTE
299 {
300   struct SrcShader base;
301 
302   GstGLShader *snow_shader;
303   GstGLShader *color_shader;
304   gint attr_snow_position;
305 };
306 
307 static gpointer
_src_smpte_new(GstGLTestSrc * test)308 _src_smpte_new (GstGLTestSrc * test)
309 {
310   struct SrcSMPTE *src = g_new0 (struct SrcSMPTE, 1);
311 
312   src->base.base.src = test;
313 
314   return src;
315 }
316 
317 static gboolean
_src_smpte_init(gpointer impl,GstGLContext * context,const GstVideoInfo * v_info)318 _src_smpte_init (gpointer impl, GstGLContext * context,
319     const GstVideoInfo * v_info)
320 {
321   struct SrcSMPTE *src = impl;
322   struct XYZWRGB *coord;
323   gushort *plane_indices;
324   GError *error = NULL;
325   int color_idx = 0;
326   const gchar *frags[2];
327   int i;
328 
329   src->base.base.context = context;
330 
331   coord = g_new0 (struct XYZWRGB, N_QUADS * 4);
332   plane_indices = g_new0 (gushort, N_QUADS * 6);
333 
334   /* top row */
335   for (i = 0; i < 7; i++) {
336     coord[color_idx * 4 + 0].X = -1.0f + i * (2.0f / 7.0f);
337     coord[color_idx * 4 + 0].Y = 1.0f / 3.0f;
338     coord[color_idx * 4 + 1].X = -1.0f + (i + 1) * (2.0f / 7.0f);
339     coord[color_idx * 4 + 1].Y = 1.0f / 3.0f;
340     coord[color_idx * 4 + 2].X = -1.0f + (i + 1) * (2.0f / 7.0f);
341     coord[color_idx * 4 + 2].Y = -1.0f;
342     coord[color_idx * 4 + 3].X = -1.0f + i * (2.0f / 7.0f);
343     coord[color_idx * 4 + 3].Y = -1.0f;
344     color_idx++;
345   }
346 
347   /* middle row */
348   for (i = 0; i < 7; i++) {
349     coord[color_idx * 4 + 0].X = -1.0f + i * (2.0f / 7.0f);
350     coord[color_idx * 4 + 0].Y = 0.5f;
351     coord[color_idx * 4 + 1].X = -1.0f + (i + 1) * (2.0f / 7.0f);
352     coord[color_idx * 4 + 1].Y = 0.5f;
353     coord[color_idx * 4 + 2].X = -1.0f + (i + 1) * (2.0f / 7.0f);
354     coord[color_idx * 4 + 2].Y = 1.0f / 3.0f;
355     coord[color_idx * 4 + 3].X = -1.0f + i * (2.0f / 7.0f);
356     coord[color_idx * 4 + 3].Y = 1.0f / 3.0f;
357     color_idx++;
358   }
359 
360   /* bottom row, left three */
361   for (i = 0; i < 3; i++) {
362     coord[color_idx * 4 + 0].X = -1.0f + i / 3.0f;
363     coord[color_idx * 4 + 0].Y = 1.0f;
364     coord[color_idx * 4 + 1].X = -1.0f + (i + 1) / 3.0f;
365     coord[color_idx * 4 + 1].Y = 1.0f;
366     coord[color_idx * 4 + 2].X = -1.0f + (i + 1) / 3.0f;
367     coord[color_idx * 4 + 2].Y = 0.5f;
368     coord[color_idx * 4 + 3].X = -1.0f + i / 3.0f;
369     coord[color_idx * 4 + 3].Y = 0.5f;
370     color_idx++;
371   }
372 
373   /* bottom row, middle three (the blacks) */
374   for (i = 0; i < 3; i++) {
375     coord[color_idx * 4 + 0].X = i / 6.0f;
376     coord[color_idx * 4 + 0].Y = 1.0f;
377     coord[color_idx * 4 + 1].X = (i + 1) / 6.0f;
378     coord[color_idx * 4 + 1].Y = 1.0f;
379     coord[color_idx * 4 + 2].X = (i + 1) / 6.0f;
380     coord[color_idx * 4 + 2].Y = 0.5f;
381     coord[color_idx * 4 + 3].X = i / 6.0f;
382     coord[color_idx * 4 + 3].Y = 0.5f;
383     color_idx++;
384   }
385 
386   g_assert (color_idx < N_QUADS);
387 
388   for (i = 0; i < N_QUADS - 1; i++) {
389     int j, k;
390     if (i < 7) {
391       k = i;
392     } else if ((i - 7) & 1) {
393       k = COLOR_BLACK;
394     } else {
395       k = 13 - i;
396     }
397 
398     if (i == 14) {
399       k = COLOR_NEG_I;
400     } else if (i == 15) {
401       k = COLOR_WHITE;
402     } else if (i == 16) {
403       k = COLOR_POS_Q;
404     } else if (i == 17) {
405       k = COLOR_SUPER_BLACK;
406     } else if (i == 18) {
407       k = COLOR_BLACK;
408     } else if (i == 19) {
409       k = COLOR_DARK_GREY;
410     }
411 
412     for (j = 0; j < 4; j++) {
413       coord[i * 4 + j].Z = 0.0f;
414       coord[i * 4 + j].W = 1.0f;
415       coord[i * 4 + j].R = vts_colors[k].R;
416       coord[i * 4 + j].G = vts_colors[k].G;
417       coord[i * 4 + j].B = vts_colors[k].B;
418     }
419 
420     for (j = 0; j < 6; j++)
421       plane_indices[i * 6 + j] = i * 4 + indices_quad[j];
422   }
423 
424   /* snow */
425   coord[color_idx * 4 + 0].X = 0.5f;
426   coord[color_idx * 4 + 0].Y = 1.0f;
427   coord[color_idx * 4 + 0].Z = 0.0f;
428   coord[color_idx * 4 + 0].W = 1.0f;
429   coord[color_idx * 4 + 1].X = 1.0f;
430   coord[color_idx * 4 + 1].Y = 1.0f;
431   coord[color_idx * 4 + 1].Z = 0.0f;
432   coord[color_idx * 4 + 1].W = 1.0f;
433   coord[color_idx * 4 + 2].X = 1.0f;
434   coord[color_idx * 4 + 2].Y = 0.5f;
435   coord[color_idx * 4 + 2].Z = 0.0f;
436   coord[color_idx * 4 + 2].W = 1.0f;
437   coord[color_idx * 4 + 3].X = 0.5f;
438   coord[color_idx * 4 + 3].Y = 0.5f;
439   coord[color_idx * 4 + 3].Z = 0.0f;
440   coord[color_idx * 4 + 3].W = 1.0f;
441   for (i = 0; i < 6; i++)
442     plane_indices[color_idx * 6 + i] = color_idx * 4 + indices_quad[i];
443   color_idx++;
444 
445   if (src->color_shader)
446     gst_object_unref (src->color_shader);
447 
448   frags[0] =
449       gst_gl_shader_string_get_highest_precision (context,
450       GST_GLSL_VERSION_NONE,
451       GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY);
452   frags[1] = smpte_fragment_src;
453 
454   src->color_shader = gst_gl_shader_new_link_with_stages (context, &error,
455       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
456           GST_GLSL_VERSION_NONE,
457           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
458           smpte_vertex_src),
459       gst_glsl_stage_new_with_strings (context, GL_FRAGMENT_SHADER,
460           GST_GLSL_VERSION_NONE,
461           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, 2,
462           frags), NULL);
463   if (!src->color_shader) {
464     GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
465     return FALSE;
466   }
467 
468   frags[1] = snow_fragment_src;
469 
470   if (src->snow_shader)
471     gst_object_unref (src->snow_shader);
472   src->snow_shader = gst_gl_shader_new_link_with_stages (context, &error,
473       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
474           GST_GLSL_VERSION_NONE,
475           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
476           snow_vertex_src),
477       gst_glsl_stage_new_with_strings (context, GL_FRAGMENT_SHADER,
478           GST_GLSL_VERSION_NONE,
479           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, 2,
480           frags), NULL);
481   if (!src->snow_shader) {
482     GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
483     return FALSE;
484   }
485 
486   src->attr_snow_position = -1;
487 
488   src->base.n_attributes = 2;
489 
490   src->base.attributes[0].name = "position";
491   src->base.attributes[0].location = -1;
492   src->base.attributes[0].n_elements = 4;
493   src->base.attributes[0].element_type = GL_FLOAT;
494   src->base.attributes[0].offset = 0;
495   src->base.attributes[0].stride = sizeof (struct XYZWRGB);
496 
497   src->base.attributes[1].name = "a_color";
498   src->base.attributes[1].location = -1;
499   src->base.attributes[1].n_elements = 3;
500   src->base.attributes[1].element_type = GL_FLOAT;
501   src->base.attributes[1].offset = 4 * sizeof (gfloat);
502   src->base.attributes[1].stride = sizeof (struct XYZWRGB);
503 
504   if (src->base.shader)
505     gst_object_unref (src->base.shader);
506   src->base.shader = gst_object_ref (src->color_shader);
507   src->base.vertices = (gfloat *) coord;
508   src->base.vertices_size = sizeof (struct XYZWRGB) * N_QUADS * 4;
509   src->base.indices = plane_indices;
510   src->base.n_indices = N_QUADS * 6;
511 
512   return _src_shader_init (impl, context, v_info);
513 }
514 
515 static gboolean
_src_smpte_fill_bound_fbo(gpointer impl)516 _src_smpte_fill_bound_fbo (gpointer impl)
517 {
518   struct SrcSMPTE *src = impl;
519   gint attr_color_position = -1;
520   GstGLBaseSrc *bsrc = GST_GL_BASE_SRC (src->base.base.src);
521 
522   src->base.n_attributes = 2;
523   if (src->base.shader)
524     gst_object_unref (src->base.shader);
525   src->base.shader = gst_object_ref (src->color_shader);
526   src->base.n_indices = (N_QUADS - 1) * 6;
527   src->base.index_offset = 0;
528   if (!_src_shader_fill_bound_fbo (impl))
529     return FALSE;
530   attr_color_position = src->base.attributes[0].location;
531 
532   src->base.attributes[0].location = src->attr_snow_position;
533   src->base.n_attributes = 1;
534   if (src->base.shader)
535     gst_object_unref (src->base.shader);
536   src->base.shader = gst_object_ref (src->snow_shader);
537   src->base.n_indices = 6;
538   src->base.index_offset = (N_QUADS - 1) * 6 * sizeof (gushort);
539   gst_gl_shader_use (src->snow_shader);
540   gst_gl_shader_set_uniform_1f (src->snow_shader, "time",
541       (gfloat) bsrc->running_time / GST_SECOND);
542   if (!_src_shader_fill_bound_fbo (impl))
543     return FALSE;
544   src->attr_snow_position = src->base.attributes[0].location;
545   src->base.attributes[0].location = attr_color_position;
546 
547   return TRUE;
548 }
549 
550 static void
_src_smpte_free(gpointer impl)551 _src_smpte_free (gpointer impl)
552 {
553   struct SrcSMPTE *src = impl;
554 
555   if (!impl)
556     return;
557 
558   _src_shader_deinit (impl);
559 
560   g_free ((gpointer) src->base.vertices);
561   g_free ((gpointer) src->base.indices);
562 
563   if (src->snow_shader)
564     gst_object_unref (src->snow_shader);
565   if (src->color_shader)
566     gst_object_unref (src->color_shader);
567 
568   g_free (impl);
569 }
570 
571 static const struct SrcFuncs src_smpte = {
572   GST_GL_TEST_SRC_SMPTE,
573   _src_smpte_new,
574   _src_smpte_init,
575   _src_smpte_fill_bound_fbo,
576   _src_smpte_free,
577 };
578 
579 #undef N_QUADS
580 
581 struct SrcUniColor
582 {
583   struct BaseSrcImpl base;
584 
585   struct vts_color_struct color;
586 };
587 
588 static gpointer
_src_uni_color_new(GstGLTestSrc * test)589 _src_uni_color_new (GstGLTestSrc * test)
590 {
591   struct SrcUniColor *src = g_new0 (struct SrcUniColor, 1);
592 
593   src->base.src = test;
594 
595   return src;
596 }
597 
598 static gboolean
_src_uni_color_init(gpointer impl,GstGLContext * context,const GstVideoInfo * v_info)599 _src_uni_color_init (gpointer impl, GstGLContext * context,
600     const GstVideoInfo * v_info)
601 {
602   struct SrcUniColor *src = impl;
603 
604   src->base.context = context;
605   src->base.v_info = *v_info;
606 
607   return TRUE;
608 }
609 
610 static gboolean
_src_uni_color_fill_bound_fbo(gpointer impl)611 _src_uni_color_fill_bound_fbo (gpointer impl)
612 {
613   struct SrcUniColor *src = impl;
614   const GstGLFuncs *gl = src->base.context->gl_vtable;
615 
616   gl->ClearColor (src->color.R, src->color.G, src->color.B, 1.0f);
617   gl->Clear (GL_COLOR_BUFFER_BIT);
618 
619   return TRUE;
620 }
621 
622 static void
_src_uni_color_free(gpointer impl)623 _src_uni_color_free (gpointer impl)
624 {
625   g_free (impl);
626 }
627 
628 #define SRC_UNICOLOR(name, cap_name) \
629 static gpointer \
630 G_PASTE(G_PASTE(_src_unicolor_,name),_new) (GstGLTestSrc * test) \
631 { \
632   struct SrcUniColor *src = _src_uni_color_new (test); \
633   src->color = vts_colors[G_PASTE(COLOR_,cap_name)]; \
634   return src; \
635 } \
636 static const struct SrcFuncs G_PASTE (src_,name) = { \
637   G_PASTE(GST_GL_TEST_SRC_,cap_name), \
638   G_PASTE(G_PASTE(_src_unicolor_,name),_new), \
639   _src_uni_color_init, \
640   _src_uni_color_fill_bound_fbo, \
641   _src_uni_color_free, \
642 }
643 
644 SRC_UNICOLOR (white, WHITE);
645 SRC_UNICOLOR (black, BLACK);
646 SRC_UNICOLOR (red, RED);
647 SRC_UNICOLOR (green, GREEN);
648 SRC_UNICOLOR (blue, BLUE);
649 
650 static gpointer
_src_blink_new(GstGLTestSrc * test)651 _src_blink_new (GstGLTestSrc * test)
652 {
653   struct SrcUniColor *src = _src_uni_color_new (test);
654 
655   src->color = vts_colors[COLOR_WHITE];
656 
657   return src;
658 }
659 
660 static gboolean
_src_blink_fill_bound_fbo(gpointer impl)661 _src_blink_fill_bound_fbo (gpointer impl)
662 {
663   struct SrcUniColor *src = impl;
664 
665   if (src->color.R > 0.5) {
666     src->color = vts_colors[COLOR_BLACK];
667   } else {
668     src->color = vts_colors[COLOR_WHITE];
669   }
670 
671   return _src_uni_color_fill_bound_fbo (impl);
672 }
673 
674 static const struct SrcFuncs src_blink = {
675   GST_GL_TEST_SRC_BLINK,
676   _src_blink_new,
677   _src_uni_color_init,
678   _src_blink_fill_bound_fbo,
679   _src_uni_color_free,
680 };
681 
682 /* *INDENT-OFF* */
683 static const gchar *checkers_vertex_src = "attribute vec4 position;\n"
684     "varying vec2 uv;\n"
685     "void main()\n"
686     "{\n"
687     "  gl_Position = position;\n"
688     /* RPi gives incorrect results for positive uv (plus it makes us start on
689      * the right pixel color i.e. red) */
690     "  uv = position.xy - 1.0;\n"
691     "}";
692 
693 static const gchar *checkers_fragment_src =
694     "uniform float checker_width;\n"
695     "uniform float width;\n"
696     "uniform float height;\n"
697     "varying vec2 uv;\n"
698     "void main()\n"
699     "{\n"
700     "  vec2 xy_mod = floor (0.5 * uv * vec2(width, height) / (checker_width));\n"
701     "  float result = mod (xy_mod.x + xy_mod.y, 2.0);\n"
702     "  gl_FragColor.r = step (result, 0.5);\n"
703     "  gl_FragColor.g = 1.0 - gl_FragColor.r;\n"
704     "  gl_FragColor.ba = vec2(0.0, 1.0);\n"
705     "}";
706 /* *INDENT-ON* */
707 
708 struct SrcCheckers
709 {
710   struct SrcShader base;
711 
712   guint checker_width;
713 };
714 
715 static gboolean
_src_checkers_init(gpointer impl,GstGLContext * context,const GstVideoInfo * v_info)716 _src_checkers_init (gpointer impl, GstGLContext * context,
717     const GstVideoInfo * v_info)
718 {
719   struct SrcCheckers *src = impl;
720   GError *error = NULL;
721   const gchar *frags[2];
722 
723   src->base.base.context = context;
724 
725   frags[0] =
726       gst_gl_shader_string_get_highest_precision (context,
727       GST_GLSL_VERSION_NONE,
728       GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY);
729   frags[1] = checkers_fragment_src;
730 
731   if (src->base.shader)
732     gst_object_unref (src->base.shader);
733   src->base.shader = gst_gl_shader_new_link_with_stages (context, &error,
734       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
735           GST_GLSL_VERSION_NONE,
736           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
737           checkers_vertex_src),
738       gst_glsl_stage_new_with_strings (context, GL_FRAGMENT_SHADER,
739           GST_GLSL_VERSION_NONE,
740           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, 2,
741           frags), NULL);
742   if (!src->base.shader) {
743     GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
744     return FALSE;
745   }
746 
747   src->base.n_attributes = 1;
748 
749   src->base.attributes[0].name = "position";
750   src->base.attributes[0].location = -1;
751   src->base.attributes[0].n_elements = 4;
752   src->base.attributes[0].element_type = GL_FLOAT;
753   src->base.attributes[0].offset = 0;
754   src->base.attributes[0].stride = 4 * sizeof (gfloat);
755 
756   src->base.vertices = positions;
757   src->base.vertices_size = sizeof (positions);
758   src->base.indices = indices_quad;
759   src->base.n_indices = 6;
760 
761   gst_gl_shader_use (src->base.shader);
762   gst_gl_shader_set_uniform_1f (src->base.shader, "checker_width",
763       src->checker_width);
764   gst_gl_shader_set_uniform_1f (src->base.shader, "width",
765       (gfloat) GST_VIDEO_INFO_WIDTH (v_info));
766   gst_gl_shader_set_uniform_1f (src->base.shader, "height",
767       (gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
768   gst_gl_context_clear_shader (src->base.base.context);
769 
770   return _src_shader_init (impl, context, v_info);
771 }
772 
773 static void
_src_checkers_free(gpointer impl)774 _src_checkers_free (gpointer impl)
775 {
776   struct SrcCheckers *src = impl;
777 
778   if (!src)
779     return;
780 
781   _src_shader_deinit (impl);
782 
783   g_free (impl);
784 }
785 
786 static gpointer
_src_checkers_new(GstGLTestSrc * test)787 _src_checkers_new (GstGLTestSrc * test)
788 {
789   struct SrcCheckers *src = g_new0 (struct SrcCheckers, 1);
790 
791   src->base.base.src = test;
792 
793   return src;
794 }
795 
796 #define SRC_CHECKERS(spacing) \
797 static gpointer \
798 G_PASTE(G_PASTE(_src_checkers,spacing),_new) (GstGLTestSrc * test) \
799 { \
800   struct SrcCheckers *src = _src_checkers_new (test); \
801   src->checker_width = spacing; \
802   return src; \
803 } \
804 static const struct SrcFuncs G_PASTE(src_checkers,spacing) = { \
805   G_PASTE(GST_GL_TEST_SRC_CHECKERS,spacing), \
806   G_PASTE(G_PASTE(_src_checkers,spacing),_new), \
807   _src_checkers_init, \
808   _src_shader_fill_bound_fbo, \
809   _src_checkers_free, \
810 }
811 
812 SRC_CHECKERS (1);
813 SRC_CHECKERS (2);
814 SRC_CHECKERS (4);
815 SRC_CHECKERS (8);
816 
817 static gboolean
_src_snow_init(gpointer impl,GstGLContext * context,const GstVideoInfo * v_info)818 _src_snow_init (gpointer impl, GstGLContext * context,
819     const GstVideoInfo * v_info)
820 {
821   struct SrcShader *src = impl;
822   GError *error = NULL;
823   const gchar *frags[2];
824 
825   src->base.context = context;
826 
827   frags[0] =
828       gst_gl_shader_string_get_highest_precision (context,
829       GST_GLSL_VERSION_NONE,
830       GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY);
831   frags[1] = snow_fragment_src;
832 
833   if (src->shader)
834     gst_object_unref (src->shader);
835   src->shader = gst_gl_shader_new_link_with_stages (context, &error,
836       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
837           GST_GLSL_VERSION_NONE,
838           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
839           snow_vertex_src),
840       gst_glsl_stage_new_with_strings (context, GL_FRAGMENT_SHADER,
841           GST_GLSL_VERSION_NONE,
842           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, 2,
843           frags), NULL);
844   if (!src->shader) {
845     GST_ERROR_OBJECT (src->base.src, "%s", error->message);
846     return FALSE;
847   }
848 
849   src->n_attributes = 1;
850 
851   src->attributes[0].name = "position";
852   src->attributes[0].location = -1;
853   src->attributes[0].n_elements = 4;
854   src->attributes[0].element_type = GL_FLOAT;
855   src->attributes[0].offset = 0;
856   src->attributes[0].stride = 4 * sizeof (gfloat);
857 
858   src->vertices = positions;
859   src->vertices_size = sizeof (positions);
860   src->indices = indices_quad;
861   src->n_indices = 6;
862 
863   return _src_shader_init (impl, context, v_info);
864 }
865 
866 static gboolean
_src_snow_fill_bound_fbo(gpointer impl)867 _src_snow_fill_bound_fbo (gpointer impl)
868 {
869   struct SrcShader *src = impl;
870   GstGLBaseSrc *bsrc = GST_GL_BASE_SRC (src->base.src);
871 
872   g_return_val_if_fail (src->base.context, FALSE);
873   g_return_val_if_fail (src->shader, FALSE);
874 
875   gst_gl_shader_use (src->shader);
876   gst_gl_shader_set_uniform_1f (src->shader, "time",
877       (gfloat) bsrc->running_time / GST_SECOND);
878 
879   return _src_shader_fill_bound_fbo (impl);
880 }
881 
882 static void
_src_snow_free(gpointer impl)883 _src_snow_free (gpointer impl)
884 {
885   struct SrcShader *src = impl;
886 
887   if (!src)
888     return;
889 
890   _src_shader_deinit (impl);
891 
892   g_free (impl);
893 }
894 
895 static gpointer
_src_snow_new(GstGLTestSrc * test)896 _src_snow_new (GstGLTestSrc * test)
897 {
898   struct SrcShader *src = g_new0 (struct SrcShader, 1);
899 
900   src->base.src = test;
901 
902   return src;
903 }
904 
905 static const struct SrcFuncs src_snow = {
906   GST_GL_TEST_SRC_SNOW,
907   _src_snow_new,
908   _src_snow_init,
909   _src_snow_fill_bound_fbo,
910   _src_snow_free,
911 };
912 
913 /* *INDENT-OFF* */
914 static const gchar *mandelbrot_vertex_src = "attribute vec4 position;\n"
915     "uniform float aspect_ratio;\n"
916     "varying vec2 fractal_position;\n"
917     "void main()\n"
918     "{\n"
919     "  gl_Position = position;\n"
920     "  fractal_position = vec2(position.y * 0.5 - 0.3, aspect_ratio * position.x * 0.5);\n"
921     "  fractal_position *= 2.5;\n"
922     "}";
923 
924 static const gchar *mandelbrot_fragment_src =
925     "uniform float time;\n"
926     "varying vec2 fractal_position;\n"
927     "const vec4 K = vec4(1.0, 0.66, 0.33, 3.0);\n"
928     "vec4 hsv_to_rgb(float hue, float saturation, float value) {\n"
929     "  vec4 p = abs(fract(vec4(hue) + K) * 6.0 - K.wwww);\n"
930     "  return value * mix(K.xxxx, clamp(p - K.xxxx, 0.0, 1.0), saturation);\n"
931     "}\n"
932     "vec4 i_to_rgb(int i) {\n"
933     "  float hue = float(i) / 100.0 + sin(time);\n"
934     "  return hsv_to_rgb(hue, 0.5, 0.8);\n"
935     "}\n"
936     "vec2 pow_2_complex(vec2 c) {\n"
937     "  return vec2(c.x*c.x - c.y*c.y, 2.0 * c.x * c.y);\n"
938     "}\n"
939     "vec2 mandelbrot(vec2 c, vec2 c0) {\n"
940     "  return pow_2_complex(c) + c0;\n"
941     "}\n"
942     "vec4 iterate_pixel(vec2 position) {\n"
943     "  vec2 c = vec2(0);\n"
944     "  for (int i=0; i < 20; i++) {\n"
945     "    if (c.x*c.x + c.y*c.y > 2.0*2.0)\n"
946     "      return i_to_rgb(i);\n"
947     "    c = mandelbrot(c, position);\n"
948     "  }\n"
949     "  return vec4(0, 0, 0, 1);\n"
950     "}\n"
951     "void main() {\n"
952     "  gl_FragColor = iterate_pixel(fractal_position);\n"
953     "}";
954 /* *INDENT-ON* */
955 
956 static gboolean
_src_mandelbrot_init(gpointer impl,GstGLContext * context,const GstVideoInfo * v_info)957 _src_mandelbrot_init (gpointer impl, GstGLContext * context,
958     const GstVideoInfo * v_info)
959 {
960   struct SrcShader *src = impl;
961   GError *error = NULL;
962   const gchar *frags[2];
963 
964   src->base.context = context;
965 
966   frags[0] =
967       gst_gl_shader_string_get_highest_precision (context,
968       GST_GLSL_VERSION_NONE,
969       GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY);
970   frags[1] = mandelbrot_fragment_src;
971 
972   if (src->shader)
973     gst_object_unref (src->shader);
974   src->shader = gst_gl_shader_new_link_with_stages (context, &error,
975       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
976           GST_GLSL_VERSION_NONE,
977           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
978           mandelbrot_vertex_src),
979       gst_glsl_stage_new_with_strings (context, GL_FRAGMENT_SHADER,
980           GST_GLSL_VERSION_NONE,
981           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, 2,
982           frags), NULL);
983   if (!src->shader) {
984     GST_ERROR_OBJECT (src->base.src, "%s", error->message);
985     return FALSE;
986   }
987 
988   src->n_attributes = 1;
989 
990   src->attributes[0].name = "position";
991   src->attributes[0].location = -1;
992   src->attributes[0].n_elements = 4;
993   src->attributes[0].element_type = GL_FLOAT;
994   src->attributes[0].offset = 0;
995   src->attributes[0].stride = 4 * sizeof (gfloat);
996 
997   src->vertices = positions;
998   src->vertices_size = sizeof (positions);
999   src->indices = indices_quad;
1000   src->n_indices = 6;
1001 
1002   gst_gl_shader_use (src->shader);
1003   gst_gl_shader_set_uniform_1f (src->shader, "aspect_ratio",
1004       (gfloat) GST_VIDEO_INFO_WIDTH (v_info) /
1005       (gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
1006   gst_gl_context_clear_shader (src->base.context);
1007 
1008   return _src_shader_init (impl, context, v_info);
1009 }
1010 
1011 static gboolean
_src_mandelbrot_fill_bound_fbo(gpointer impl)1012 _src_mandelbrot_fill_bound_fbo (gpointer impl)
1013 {
1014   struct SrcShader *src = impl;
1015   GstGLBaseSrc *bsrc = GST_GL_BASE_SRC (src->base.src);
1016 
1017   g_return_val_if_fail (src->base.context, FALSE);
1018   g_return_val_if_fail (src->shader, FALSE);
1019 
1020   gst_gl_shader_use (src->shader);
1021   gst_gl_shader_set_uniform_1f (src->shader, "time",
1022       (gfloat) bsrc->running_time / GST_SECOND);
1023 
1024   return _src_shader_fill_bound_fbo (impl);
1025 }
1026 
1027 static void
_src_mandelbrot_free(gpointer impl)1028 _src_mandelbrot_free (gpointer impl)
1029 {
1030   struct SrcShader *src = impl;
1031 
1032   if (!src)
1033     return;
1034 
1035   _src_shader_deinit (impl);
1036 
1037   g_free (impl);
1038 }
1039 
1040 static gpointer
_src_mandelbrot_new(GstGLTestSrc * test)1041 _src_mandelbrot_new (GstGLTestSrc * test)
1042 {
1043   struct SrcShader *src = g_new0 (struct SrcShader, 1);
1044 
1045   src->base.src = test;
1046 
1047   return src;
1048 }
1049 
1050 static const struct SrcFuncs src_mandelbrot = {
1051   GST_GL_TEST_SRC_MANDELBROT,
1052   _src_mandelbrot_new,
1053   _src_mandelbrot_init,
1054   _src_mandelbrot_fill_bound_fbo,
1055   _src_mandelbrot_free,
1056 };
1057 
1058 /* *INDENT-OFF* */
1059 static const gchar *circular_vertex_src =
1060     "attribute vec4 position;\n"
1061     "varying vec2 uv;\n"
1062     "void main()\n"
1063     "{\n"
1064     "  gl_Position = position;\n"
1065     "  uv = position.xy;\n"
1066     "}";
1067 
1068 static const gchar *circular_fragment_src =
1069     "uniform float aspect_ratio;\n"
1070     "varying vec2 uv;\n"
1071     "#define PI 3.14159265\n"
1072     "void main() {\n"
1073     "  float dist = 0.5 * sqrt(uv.x * uv.x + uv.y / aspect_ratio * uv.y / aspect_ratio);\n"
1074     "  float seg = floor(dist * 16.0);\n"
1075     "  if (seg <= 0.0 || seg >= 8.0) {\n"
1076     "    gl_FragColor = vec4(vec3(0.0), 1.0);\n"
1077     "  } else {\n"
1078     "    float d = floor (256.0 * dist * 200.0 * pow (2.0, - (seg - 1.0) / 4.0) + 0.5) / 128.0;\n"
1079     "    gl_FragColor = vec4 (vec3(sin (d * PI) * 0.5 + 0.5), 1.0);\n"
1080     "  }\n"
1081     "}";
1082 /* *INDENT-ON* */
1083 
1084 static gboolean
_src_circular_init(gpointer impl,GstGLContext * context,const GstVideoInfo * v_info)1085 _src_circular_init (gpointer impl, GstGLContext * context,
1086     const GstVideoInfo * v_info)
1087 {
1088   struct SrcShader *src = impl;
1089   GError *error = NULL;
1090   const gchar *frags[2];
1091 
1092   src->base.context = context;
1093 
1094   frags[0] =
1095       gst_gl_shader_string_get_highest_precision (context,
1096       GST_GLSL_VERSION_NONE,
1097       GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY);
1098   frags[1] = circular_fragment_src;
1099 
1100   if (src->shader)
1101     gst_object_unref (src->shader);
1102   src->shader = gst_gl_shader_new_link_with_stages (context, &error,
1103       gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
1104           GST_GLSL_VERSION_NONE,
1105           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
1106           circular_vertex_src),
1107       gst_glsl_stage_new_with_strings (context, GL_FRAGMENT_SHADER,
1108           GST_GLSL_VERSION_NONE,
1109           GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, 2,
1110           frags), NULL);
1111   if (!src->shader) {
1112     GST_ERROR_OBJECT (src->base.src, "%s", error->message);
1113     return FALSE;
1114   }
1115 
1116   src->n_attributes = 1;
1117 
1118   src->attributes[0].name = "position";
1119   src->attributes[0].location = -1;
1120   src->attributes[0].n_elements = 4;
1121   src->attributes[0].element_type = GL_FLOAT;
1122   src->attributes[0].offset = 0;
1123   src->attributes[0].stride = 4 * sizeof (gfloat);
1124 
1125   src->vertices = positions;
1126   src->vertices_size = sizeof (positions);
1127   src->indices = indices_quad;
1128   src->n_indices = 6;
1129 
1130   gst_gl_shader_use (src->shader);
1131   gst_gl_shader_set_uniform_1f (src->shader, "aspect_ratio",
1132       (gfloat) GST_VIDEO_INFO_WIDTH (v_info) /
1133       (gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
1134   gst_gl_context_clear_shader (src->base.context);
1135 
1136   return _src_shader_init (impl, context, v_info);
1137 }
1138 
1139 static void
_src_circular_free(gpointer impl)1140 _src_circular_free (gpointer impl)
1141 {
1142   struct SrcShader *src = impl;
1143 
1144   if (!src)
1145     return;
1146 
1147   _src_shader_deinit (impl);
1148 
1149   g_free (impl);
1150 }
1151 
1152 static gpointer
_src_circular_new(GstGLTestSrc * test)1153 _src_circular_new (GstGLTestSrc * test)
1154 {
1155   struct SrcShader *src = g_new0 (struct SrcShader, 1);
1156 
1157   src->base.src = test;
1158 
1159   return src;
1160 }
1161 
1162 static const struct SrcFuncs src_circular = {
1163   GST_GL_TEST_SRC_CIRCULAR,
1164   _src_circular_new,
1165   _src_circular_init,
1166   _src_mandelbrot_fill_bound_fbo,
1167   _src_circular_free,
1168 };
1169 
1170 static const struct SrcFuncs *src_impls[] = {
1171   &src_smpte,
1172   &src_snow,
1173   &src_black,
1174   &src_white,
1175   &src_red,
1176   &src_green,
1177   &src_blue,
1178   &src_checkers1,
1179   &src_checkers2,
1180   &src_checkers4,
1181   &src_checkers8,
1182   &src_circular,
1183   &src_blink,
1184   &src_mandelbrot,
1185 };
1186 
1187 const struct SrcFuncs *
gst_gl_test_src_get_src_funcs_for_pattern(GstGLTestSrcPattern pattern)1188 gst_gl_test_src_get_src_funcs_for_pattern (GstGLTestSrcPattern pattern)
1189 {
1190   gint i;
1191 
1192   for (i = 0; i < G_N_ELEMENTS (src_impls); i++) {
1193     if (src_impls[i]->pattern == pattern)
1194       return src_impls[i];
1195   }
1196 
1197   return NULL;
1198 }
1199