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