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