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