mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-25 03:01:03 +00:00
acc098a736
Binding the vertex array to 0 will unbind everything else already. In the previous order older versions of the Intel GL driver caused errors to be printed for every single call when disabling the vertex attrib arrays after binding the vertex array to 0.
1169 lines
29 KiB
C
1169 lines
29 KiB
C
/* GStreamer
|
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
|
* Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <gst/gl/gstglfuncs.h>
|
|
|
|
#include "gltestsrc.h"
|
|
|
|
#define MAX_ATTRIBUTES 4
|
|
|
|
struct vts_color_struct
|
|
{
|
|
gfloat R, G, B;
|
|
};
|
|
|
|
struct XYZWRGB
|
|
{
|
|
gfloat X, Y, Z, W, R, G, B;
|
|
};
|
|
|
|
enum
|
|
{
|
|
COLOR_WHITE = 0,
|
|
COLOR_YELLOW,
|
|
COLOR_CYAN,
|
|
COLOR_GREEN,
|
|
COLOR_MAGENTA,
|
|
COLOR_RED,
|
|
COLOR_BLUE,
|
|
COLOR_BLACK,
|
|
COLOR_NEG_I,
|
|
COLOR_POS_Q,
|
|
COLOR_SUPER_BLACK,
|
|
COLOR_DARK_GREY
|
|
};
|
|
|
|
static const struct vts_color_struct vts_colors[] = {
|
|
/* 100% white */
|
|
{1.0f, 1.0f, 1.0f},
|
|
/* yellow */
|
|
{1.0f, 1.0f, 0.0f},
|
|
/* cyan */
|
|
{0.0f, 1.0f, 1.0f},
|
|
/* green */
|
|
{0.0f, 1.0f, 0.0f},
|
|
/* magenta */
|
|
{1.0f, 0.0f, 1.0f},
|
|
/* red */
|
|
{1.0f, 0.0f, 0.0f},
|
|
/* blue */
|
|
{0.0f, 0.0f, 1.0f},
|
|
/* black */
|
|
{0.0f, 0.0f, 0.0f},
|
|
/* -I */
|
|
{0.0, 0.0f, 0.5f},
|
|
/* +Q */
|
|
{0.0f, 0.5, 1.0f},
|
|
/* superblack */
|
|
{0.0f, 0.0f, 0.0f},
|
|
/* 7.421875% grey */
|
|
{19. / 256.0f, 19. / 256.0f, 19. / 256.0},
|
|
};
|
|
|
|
/* *INDENT-OFF* */
|
|
static const GLfloat positions[] = {
|
|
-1.0, 1.0, 0.0, 1.0,
|
|
1.0, 1.0, 0.0, 1.0,
|
|
1.0, -1.0, 0.0, 1.0,
|
|
-1.0, -1.0, 0.0, 1.0,
|
|
};
|
|
|
|
static const GLushort indices_quad[] = { 0, 1, 2, 0, 2, 3 };
|
|
/* *INDENT-ON* */
|
|
|
|
struct attribute
|
|
{
|
|
const gchar *name;
|
|
gint location;
|
|
guint n_elements;
|
|
GLenum element_type;
|
|
guint offset; /* in bytes */
|
|
guint stride; /* in bytes */
|
|
};
|
|
|
|
struct SrcShader
|
|
{
|
|
struct BaseSrcImpl base;
|
|
|
|
GstGLShader *shader;
|
|
|
|
guint vao;
|
|
guint vbo;
|
|
guint vbo_indices;
|
|
|
|
guint n_attributes;
|
|
struct attribute attributes[MAX_ATTRIBUTES];
|
|
|
|
gconstpointer vertices;
|
|
gsize vertices_size;
|
|
const gushort *indices;
|
|
guint index_offset;
|
|
guint n_indices;
|
|
};
|
|
|
|
static void
|
|
_bind_buffer (struct SrcShader *src)
|
|
{
|
|
GstGLContext *context = src->base.context;
|
|
const GstGLFuncs *gl = context->gl_vtable;
|
|
gint i;
|
|
|
|
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, src->vbo_indices);
|
|
gl->BindBuffer (GL_ARRAY_BUFFER, src->vbo);
|
|
|
|
/* Load the vertex position */
|
|
for (i = 0; i < src->n_attributes; i++) {
|
|
struct attribute *attr = &src->attributes[i];
|
|
|
|
if (attr->location == -1)
|
|
attr->location =
|
|
gst_gl_shader_get_attribute_location (src->shader, attr->name);
|
|
|
|
gl->VertexAttribPointer (attr->location, attr->n_elements,
|
|
attr->element_type, GL_FALSE, attr->stride,
|
|
(void *) (gintptr) attr->offset);
|
|
|
|
gl->EnableVertexAttribArray (attr->location);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_unbind_buffer (struct SrcShader *src)
|
|
{
|
|
GstGLContext *context = src->base.context;
|
|
const GstGLFuncs *gl = context->gl_vtable;
|
|
gint i;
|
|
|
|
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
|
|
|
|
for (i = 0; i < src->n_attributes; i++) {
|
|
struct attribute *attr = &src->attributes[i];
|
|
|
|
gl->DisableVertexAttribArray (attr->location);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
_src_shader_init (gpointer impl, GstGLContext * context, GstVideoInfo * v_info)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
const GstGLFuncs *gl = context->gl_vtable;
|
|
|
|
src->base.context = context;
|
|
|
|
if (!src->vbo) {
|
|
if (gl->GenVertexArrays) {
|
|
gl->GenVertexArrays (1, &src->vao);
|
|
gl->BindVertexArray (src->vao);
|
|
}
|
|
|
|
gl->GenBuffers (1, &src->vbo);
|
|
gl->BindBuffer (GL_ARRAY_BUFFER, src->vbo);
|
|
gl->BufferData (GL_ARRAY_BUFFER, src->vertices_size,
|
|
src->vertices, GL_STATIC_DRAW);
|
|
|
|
gl->GenBuffers (1, &src->vbo_indices);
|
|
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, src->vbo_indices);
|
|
gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, src->n_indices * sizeof (gushort),
|
|
src->indices, GL_STATIC_DRAW);
|
|
|
|
if (gl->GenVertexArrays) {
|
|
_bind_buffer (src);
|
|
gl->BindVertexArray (0);
|
|
}
|
|
|
|
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
|
|
gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
_src_shader_fill_bound_fbo (gpointer impl)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
const GstGLFuncs *gl;
|
|
|
|
g_return_val_if_fail (src->base.context, FALSE);
|
|
g_return_val_if_fail (src->shader, FALSE);
|
|
gl = src->base.context->gl_vtable;
|
|
|
|
gst_gl_shader_use (src->shader);
|
|
|
|
if (gl->GenVertexArrays)
|
|
gl->BindVertexArray (src->vao);
|
|
_bind_buffer (src);
|
|
|
|
gl->DrawElements (GL_TRIANGLES, src->n_indices, GL_UNSIGNED_SHORT,
|
|
(gpointer) (gintptr) src->index_offset);
|
|
|
|
if (gl->GenVertexArrays)
|
|
gl->BindVertexArray (0);
|
|
else
|
|
_unbind_buffer (src);
|
|
|
|
gst_gl_context_clear_shader (src->base.context);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
_src_shader_deinit (gpointer impl)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
const GstGLFuncs *gl = src->base.context->gl_vtable;
|
|
|
|
if (src->shader)
|
|
gst_object_unref (src->shader);
|
|
src->shader = NULL;
|
|
|
|
if (src->vao)
|
|
gl->DeleteVertexArrays (1, &src->vao);
|
|
src->vao = 0;
|
|
|
|
if (src->vbo)
|
|
gl->DeleteBuffers (1, &src->vbo);
|
|
src->vbo = 0;
|
|
|
|
if (src->vbo_indices)
|
|
gl->DeleteBuffers (1, &src->vbo_indices);
|
|
src->vbo_indices = 0;
|
|
}
|
|
|
|
/* *INDENT-OFF* */
|
|
static const gchar *smpte_vertex_src =
|
|
"attribute vec4 position;\n"
|
|
"attribute vec4 a_color;\n"
|
|
"varying vec4 color;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = position;\n"
|
|
" color = a_color;\n"
|
|
"}";
|
|
|
|
static const gchar *smpte_fragment_src =
|
|
"#ifdef GL_ES\n"
|
|
"precision mediump float;\n"
|
|
"#endif\n"
|
|
"varying vec4 color;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_FragColor = color;\n"
|
|
"}";
|
|
|
|
static const gchar *snow_vertex_src =
|
|
"attribute vec4 position;\n"
|
|
"varying vec2 out_uv;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = position;\n"
|
|
" out_uv = position.xy;\n"
|
|
"}";
|
|
|
|
static const gchar *snow_fragment_src =
|
|
"#ifdef GL_ES\n"
|
|
"precision mediump float;\n"
|
|
"#endif\n"
|
|
"uniform float time;\n"
|
|
"varying vec2 out_uv;\n"
|
|
"\n"
|
|
"float rand(vec2 co){\n"
|
|
" return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);\n"
|
|
"}\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_FragColor = vec4(rand(time * out_uv));\n"
|
|
"}";
|
|
/* *INDENT-ON* */
|
|
|
|
#define N_QUADS 21
|
|
struct SrcSMPTE
|
|
{
|
|
struct SrcShader base;
|
|
|
|
GstGLShader *snow_shader;
|
|
GstGLShader *color_shader;
|
|
gint attr_snow_position;
|
|
};
|
|
|
|
static gpointer
|
|
_src_smpte_new (GstGLTestSrc * test)
|
|
{
|
|
struct SrcSMPTE *src = g_new0 (struct SrcSMPTE, 1);
|
|
|
|
src->base.base.src = test;
|
|
|
|
return src;
|
|
}
|
|
|
|
static gboolean
|
|
_src_smpte_init (gpointer impl, GstGLContext * context, GstVideoInfo * v_info)
|
|
{
|
|
struct SrcSMPTE *src = impl;
|
|
struct XYZWRGB *coord;
|
|
gushort *plane_indices;
|
|
GError *error = NULL;
|
|
int color_idx = 0;
|
|
int i;
|
|
|
|
src->base.base.context = context;
|
|
|
|
coord = g_new0 (struct XYZWRGB, N_QUADS * 4);
|
|
plane_indices = g_new0 (gushort, N_QUADS * 6);
|
|
|
|
/* top row */
|
|
for (i = 0; i < 7; i++) {
|
|
coord[color_idx * 4 + 0].X = -1.0f + i * (2.0f / 7.0f);
|
|
coord[color_idx * 4 + 0].Y = 1.0f / 3.0f;
|
|
coord[color_idx * 4 + 1].X = -1.0f + (i + 1) * (2.0f / 7.0f);
|
|
coord[color_idx * 4 + 1].Y = 1.0f / 3.0f;
|
|
coord[color_idx * 4 + 2].X = -1.0f + (i + 1) * (2.0f / 7.0f);
|
|
coord[color_idx * 4 + 2].Y = -1.0f;
|
|
coord[color_idx * 4 + 3].X = -1.0f + i * (2.0f / 7.0f);
|
|
coord[color_idx * 4 + 3].Y = -1.0f;
|
|
color_idx++;
|
|
}
|
|
|
|
/* middle row */
|
|
for (i = 0; i < 7; i++) {
|
|
coord[color_idx * 4 + 0].X = -1.0f + i * (2.0f / 7.0f);
|
|
coord[color_idx * 4 + 0].Y = 0.5f;
|
|
coord[color_idx * 4 + 1].X = -1.0f + (i + 1) * (2.0f / 7.0f);
|
|
coord[color_idx * 4 + 1].Y = 0.5f;
|
|
coord[color_idx * 4 + 2].X = -1.0f + (i + 1) * (2.0f / 7.0f);
|
|
coord[color_idx * 4 + 2].Y = 1.0f / 3.0f;
|
|
coord[color_idx * 4 + 3].X = -1.0f + i * (2.0f / 7.0f);
|
|
coord[color_idx * 4 + 3].Y = 1.0f / 3.0f;
|
|
color_idx++;
|
|
}
|
|
|
|
/* bottom row, left three */
|
|
for (i = 0; i < 3; i++) {
|
|
coord[color_idx * 4 + 0].X = -1.0f + i / 3.0f;
|
|
coord[color_idx * 4 + 0].Y = 1.0f;
|
|
coord[color_idx * 4 + 1].X = -1.0f + (i + 1) / 3.0f;
|
|
coord[color_idx * 4 + 1].Y = 1.0f;
|
|
coord[color_idx * 4 + 2].X = -1.0f + (i + 1) / 3.0f;
|
|
coord[color_idx * 4 + 2].Y = 0.5f;
|
|
coord[color_idx * 4 + 3].X = -1.0f + i / 3.0f;
|
|
coord[color_idx * 4 + 3].Y = 0.5f;
|
|
color_idx++;
|
|
}
|
|
|
|
/* bottom row, middle three (the blacks) */
|
|
for (i = 0; i < 3; i++) {
|
|
coord[color_idx * 4 + 0].X = i / 6.0f;
|
|
coord[color_idx * 4 + 0].Y = 1.0f;
|
|
coord[color_idx * 4 + 1].X = (i + 1) / 6.0f;
|
|
coord[color_idx * 4 + 1].Y = 1.0f;
|
|
coord[color_idx * 4 + 2].X = (i + 1) / 6.0f;
|
|
coord[color_idx * 4 + 2].Y = 0.5f;
|
|
coord[color_idx * 4 + 3].X = i / 6.0f;
|
|
coord[color_idx * 4 + 3].Y = 0.5f;
|
|
color_idx++;
|
|
}
|
|
|
|
g_assert (color_idx < N_QUADS);
|
|
|
|
for (i = 0; i < N_QUADS - 1; i++) {
|
|
int j, k;
|
|
if (i < 7) {
|
|
k = i;
|
|
} else if ((i - 7) & 1) {
|
|
k = COLOR_BLACK;
|
|
} else {
|
|
k = 13 - i;
|
|
}
|
|
|
|
if (i == 14) {
|
|
k = COLOR_NEG_I;
|
|
} else if (i == 15) {
|
|
k = COLOR_WHITE;
|
|
} else if (i == 16) {
|
|
k = COLOR_POS_Q;
|
|
} else if (i == 17) {
|
|
k = COLOR_SUPER_BLACK;
|
|
} else if (i == 18) {
|
|
k = COLOR_BLACK;
|
|
} else if (i == 19) {
|
|
k = COLOR_DARK_GREY;
|
|
}
|
|
|
|
for (j = 0; j < 4; j++) {
|
|
coord[i * 4 + j].Z = 0.0f;
|
|
coord[i * 4 + j].W = 1.0f;
|
|
coord[i * 4 + j].R = vts_colors[k].R;
|
|
coord[i * 4 + j].G = vts_colors[k].G;
|
|
coord[i * 4 + j].B = vts_colors[k].B;
|
|
}
|
|
|
|
for (j = 0; j < 6; j++)
|
|
plane_indices[i * 6 + j] = i * 4 + indices_quad[j];
|
|
}
|
|
|
|
/* snow */
|
|
coord[color_idx * 4 + 0].X = 0.5f;
|
|
coord[color_idx * 4 + 0].Y = 1.0f;
|
|
coord[color_idx * 4 + 0].Z = 0.0f;
|
|
coord[color_idx * 4 + 0].W = 1.0f;
|
|
coord[color_idx * 4 + 1].X = 1.0f;
|
|
coord[color_idx * 4 + 1].Y = 1.0f;
|
|
coord[color_idx * 4 + 1].Z = 0.0f;
|
|
coord[color_idx * 4 + 1].W = 1.0f;
|
|
coord[color_idx * 4 + 2].X = 1.0f;
|
|
coord[color_idx * 4 + 2].Y = 0.5f;
|
|
coord[color_idx * 4 + 2].Z = 0.0f;
|
|
coord[color_idx * 4 + 2].W = 1.0f;
|
|
coord[color_idx * 4 + 3].X = 0.5f;
|
|
coord[color_idx * 4 + 3].Y = 0.5f;
|
|
coord[color_idx * 4 + 3].Z = 0.0f;
|
|
coord[color_idx * 4 + 3].W = 1.0f;
|
|
for (i = 0; i < 6; i++)
|
|
plane_indices[color_idx * 6 + i] = color_idx * 4 + indices_quad[i];
|
|
color_idx++;
|
|
|
|
if (src->color_shader)
|
|
gst_object_unref (src->color_shader);
|
|
src->color_shader = gst_gl_shader_new_link_with_stages (context, &error,
|
|
gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
smpte_vertex_src),
|
|
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
smpte_fragment_src), NULL);
|
|
if (!src->color_shader) {
|
|
GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
|
|
return FALSE;
|
|
}
|
|
|
|
if (src->snow_shader)
|
|
gst_object_unref (src->snow_shader);
|
|
src->snow_shader = gst_gl_shader_new_link_with_stages (context, &error,
|
|
gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
snow_vertex_src),
|
|
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
snow_fragment_src), NULL);
|
|
if (!src->snow_shader) {
|
|
GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
|
|
return FALSE;
|
|
}
|
|
|
|
src->attr_snow_position = -1;
|
|
|
|
src->base.n_attributes = 2;
|
|
|
|
src->base.attributes[0].name = "position";
|
|
src->base.attributes[0].location = -1;
|
|
src->base.attributes[0].n_elements = 4;
|
|
src->base.attributes[0].element_type = GL_FLOAT;
|
|
src->base.attributes[0].offset = 0;
|
|
src->base.attributes[0].stride = sizeof (struct XYZWRGB);
|
|
|
|
src->base.attributes[1].name = "a_color";
|
|
src->base.attributes[1].location = -1;
|
|
src->base.attributes[1].n_elements = 3;
|
|
src->base.attributes[1].element_type = GL_FLOAT;
|
|
src->base.attributes[1].offset = 4 * sizeof (gfloat);
|
|
src->base.attributes[1].stride = sizeof (struct XYZWRGB);
|
|
|
|
if (src->base.shader)
|
|
gst_object_unref (src->base.shader);
|
|
src->base.shader = gst_object_ref (src->color_shader);
|
|
src->base.vertices = (gfloat *) coord;
|
|
src->base.vertices_size = sizeof (struct XYZWRGB) * N_QUADS * 4;
|
|
src->base.indices = plane_indices;
|
|
src->base.n_indices = N_QUADS * 6;
|
|
|
|
return _src_shader_init (impl, context, v_info);
|
|
}
|
|
|
|
static gboolean
|
|
_src_smpte_fill_bound_fbo (gpointer impl)
|
|
{
|
|
struct SrcSMPTE *src = impl;
|
|
gint attr_color_position = -1;
|
|
|
|
src->base.n_attributes = 2;
|
|
if (src->base.shader)
|
|
gst_object_unref (src->base.shader);
|
|
src->base.shader = gst_object_ref (src->color_shader);
|
|
src->base.n_indices = (N_QUADS - 1) * 6;
|
|
src->base.index_offset = 0;
|
|
if (!_src_shader_fill_bound_fbo (impl))
|
|
return FALSE;
|
|
attr_color_position = src->base.attributes[0].location;
|
|
|
|
src->base.attributes[0].location = src->attr_snow_position;
|
|
src->base.n_attributes = 1;
|
|
if (src->base.shader)
|
|
gst_object_unref (src->base.shader);
|
|
src->base.shader = gst_object_ref (src->snow_shader);
|
|
src->base.n_indices = 6;
|
|
src->base.index_offset = (N_QUADS - 1) * 6 * sizeof (gushort);
|
|
gst_gl_shader_use (src->snow_shader);
|
|
gst_gl_shader_set_uniform_1f (src->snow_shader, "time",
|
|
(gfloat) src->base.base.src->running_time / GST_SECOND);
|
|
if (!_src_shader_fill_bound_fbo (impl))
|
|
return FALSE;
|
|
src->attr_snow_position = src->base.attributes[0].location;
|
|
src->base.attributes[0].location = attr_color_position;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
_src_smpte_free (gpointer impl)
|
|
{
|
|
struct SrcSMPTE *src = impl;
|
|
|
|
if (!impl)
|
|
return;
|
|
|
|
_src_shader_deinit (impl);
|
|
|
|
g_free ((gpointer) src->base.vertices);
|
|
g_free ((gpointer) src->base.indices);
|
|
|
|
if (src->snow_shader)
|
|
gst_object_unref (src->snow_shader);
|
|
if (src->color_shader)
|
|
gst_object_unref (src->color_shader);
|
|
|
|
g_free (impl);
|
|
}
|
|
|
|
static const struct SrcFuncs src_smpte = {
|
|
GST_GL_TEST_SRC_SMPTE,
|
|
_src_smpte_new,
|
|
_src_smpte_init,
|
|
_src_smpte_fill_bound_fbo,
|
|
_src_smpte_free,
|
|
};
|
|
|
|
#undef N_QUADS
|
|
|
|
struct SrcUniColor
|
|
{
|
|
struct BaseSrcImpl base;
|
|
|
|
struct vts_color_struct color;
|
|
};
|
|
|
|
static gpointer
|
|
_src_uni_color_new (GstGLTestSrc * test)
|
|
{
|
|
struct SrcUniColor *src = g_new0 (struct SrcUniColor, 1);
|
|
|
|
src->base.src = test;
|
|
|
|
return src;
|
|
}
|
|
|
|
static gboolean
|
|
_src_uni_color_init (gpointer impl, GstGLContext * context,
|
|
GstVideoInfo * v_info)
|
|
{
|
|
struct SrcUniColor *src = impl;
|
|
|
|
src->base.context = context;
|
|
src->base.v_info = *v_info;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
_src_uni_color_fill_bound_fbo (gpointer impl)
|
|
{
|
|
struct SrcUniColor *src = impl;
|
|
const GstGLFuncs *gl = src->base.context->gl_vtable;
|
|
|
|
gl->ClearColor (src->color.R, src->color.G, src->color.B, 1.0f);
|
|
gl->Clear (GL_COLOR_BUFFER_BIT);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
_src_uni_color_free (gpointer impl)
|
|
{
|
|
g_free (impl);
|
|
}
|
|
|
|
#define SRC_UNICOLOR(name, cap_name) \
|
|
static gpointer \
|
|
G_PASTE(G_PASTE(_src_unicolor_,name),_new) (GstGLTestSrc * test) \
|
|
{ \
|
|
struct SrcUniColor *src = _src_uni_color_new (test); \
|
|
src->color = vts_colors[G_PASTE(COLOR_,cap_name)]; \
|
|
return src; \
|
|
} \
|
|
static const struct SrcFuncs G_PASTE (src_,name) = { \
|
|
G_PASTE(GST_GL_TEST_SRC_,cap_name), \
|
|
G_PASTE(G_PASTE(_src_unicolor_,name),_new), \
|
|
_src_uni_color_init, \
|
|
_src_uni_color_fill_bound_fbo, \
|
|
_src_uni_color_free, \
|
|
}
|
|
|
|
SRC_UNICOLOR (white, WHITE);
|
|
SRC_UNICOLOR (black, BLACK);
|
|
SRC_UNICOLOR (red, RED);
|
|
SRC_UNICOLOR (green, GREEN);
|
|
SRC_UNICOLOR (blue, BLUE);
|
|
|
|
static gpointer
|
|
_src_blink_new (GstGLTestSrc * test)
|
|
{
|
|
struct SrcUniColor *src = _src_uni_color_new (test);
|
|
|
|
src->color = vts_colors[COLOR_WHITE];
|
|
|
|
return src;
|
|
}
|
|
|
|
static gboolean
|
|
_src_blink_fill_bound_fbo (gpointer impl)
|
|
{
|
|
struct SrcUniColor *src = impl;
|
|
|
|
if (src->color.R > 0.5) {
|
|
src->color = vts_colors[COLOR_BLACK];
|
|
} else {
|
|
src->color = vts_colors[COLOR_WHITE];
|
|
}
|
|
|
|
return _src_uni_color_fill_bound_fbo (impl);
|
|
}
|
|
|
|
static const struct SrcFuncs src_blink = {
|
|
GST_GL_TEST_SRC_BLINK,
|
|
_src_blink_new,
|
|
_src_uni_color_init,
|
|
_src_blink_fill_bound_fbo,
|
|
_src_uni_color_free,
|
|
};
|
|
|
|
/* *INDENT-OFF* */
|
|
static const gchar *checkers_vertex_src = "attribute vec4 position;\n"
|
|
"varying vec2 uv;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = position;\n"
|
|
/* RPi gives incorrect results for positive uv (plus it makes us start on
|
|
* the right pixel color i.e. red) */
|
|
" uv = position.xy - 1.0;\n"
|
|
"}";
|
|
|
|
static const gchar *checkers_fragment_src =
|
|
"#ifdef GL_ES\n"
|
|
"precision mediump float;\n"
|
|
"#endif\n"
|
|
"uniform float checker_width;\n"
|
|
"uniform float width;\n"
|
|
"uniform float height;\n"
|
|
"varying vec2 uv;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" vec2 xy_mod = floor (0.5 * uv * vec2(width, height) / (checker_width));\n"
|
|
" float result = mod (xy_mod.x + xy_mod.y, 2.0);\n"
|
|
" gl_FragColor.r = step (result, 0.5);\n"
|
|
" gl_FragColor.g = 1.0 - gl_FragColor.r;\n"
|
|
" gl_FragColor.ba = vec2(0.0, 1.0);\n"
|
|
"}";
|
|
/* *INDENT-ON* */
|
|
|
|
struct SrcCheckers
|
|
{
|
|
struct SrcShader base;
|
|
|
|
guint checker_width;
|
|
};
|
|
|
|
static gboolean
|
|
_src_checkers_init (gpointer impl, GstGLContext * context,
|
|
GstVideoInfo * v_info)
|
|
{
|
|
struct SrcCheckers *src = impl;
|
|
GError *error = NULL;
|
|
|
|
src->base.base.context = context;
|
|
|
|
if (src->base.shader)
|
|
gst_object_unref (src->base.shader);
|
|
src->base.shader = gst_gl_shader_new_link_with_stages (context, &error,
|
|
gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
checkers_vertex_src),
|
|
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
checkers_fragment_src), NULL);
|
|
if (!src->base.shader) {
|
|
GST_ERROR_OBJECT (src->base.base.src, "%s", error->message);
|
|
return FALSE;
|
|
}
|
|
|
|
src->base.n_attributes = 1;
|
|
|
|
src->base.attributes[0].name = "position";
|
|
src->base.attributes[0].location = -1;
|
|
src->base.attributes[0].n_elements = 4;
|
|
src->base.attributes[0].element_type = GL_FLOAT;
|
|
src->base.attributes[0].offset = 0;
|
|
src->base.attributes[0].stride = 4 * sizeof (gfloat);
|
|
|
|
src->base.vertices = positions;
|
|
src->base.vertices_size = sizeof (positions);
|
|
src->base.indices = indices_quad;
|
|
src->base.n_indices = 6;
|
|
|
|
gst_gl_shader_use (src->base.shader);
|
|
gst_gl_shader_set_uniform_1f (src->base.shader, "checker_width",
|
|
src->checker_width);
|
|
gst_gl_shader_set_uniform_1f (src->base.shader, "width",
|
|
(gfloat) GST_VIDEO_INFO_WIDTH (v_info));
|
|
gst_gl_shader_set_uniform_1f (src->base.shader, "height",
|
|
(gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
|
|
gst_gl_context_clear_shader (src->base.base.context);
|
|
|
|
return _src_shader_init (impl, context, v_info);
|
|
}
|
|
|
|
static void
|
|
_src_checkers_free (gpointer impl)
|
|
{
|
|
struct SrcCheckers *src = impl;
|
|
|
|
if (!src)
|
|
return;
|
|
|
|
_src_shader_deinit (impl);
|
|
|
|
g_free (impl);
|
|
}
|
|
|
|
static gpointer
|
|
_src_checkers_new (GstGLTestSrc * test)
|
|
{
|
|
struct SrcCheckers *src = g_new0 (struct SrcCheckers, 1);
|
|
|
|
src->base.base.src = test;
|
|
|
|
return src;
|
|
}
|
|
|
|
#define SRC_CHECKERS(spacing) \
|
|
static gpointer \
|
|
G_PASTE(G_PASTE(_src_checkers,spacing),_new) (GstGLTestSrc * test) \
|
|
{ \
|
|
struct SrcCheckers *src = _src_checkers_new (test); \
|
|
src->checker_width = spacing; \
|
|
return src; \
|
|
} \
|
|
static const struct SrcFuncs G_PASTE(src_checkers,spacing) = { \
|
|
G_PASTE(GST_GL_TEST_SRC_CHECKERS,spacing), \
|
|
G_PASTE(G_PASTE(_src_checkers,spacing),_new), \
|
|
_src_checkers_init, \
|
|
_src_shader_fill_bound_fbo, \
|
|
_src_checkers_free, \
|
|
}
|
|
|
|
SRC_CHECKERS (1);
|
|
SRC_CHECKERS (2);
|
|
SRC_CHECKERS (4);
|
|
SRC_CHECKERS (8);
|
|
|
|
static gboolean
|
|
_src_snow_init (gpointer impl, GstGLContext * context, GstVideoInfo * v_info)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
GError *error = NULL;
|
|
|
|
src->base.context = context;
|
|
|
|
if (src->shader)
|
|
gst_object_unref (src->shader);
|
|
src->shader = gst_gl_shader_new_link_with_stages (context, &error,
|
|
gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
snow_vertex_src),
|
|
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
snow_fragment_src), NULL);
|
|
if (!src->shader) {
|
|
GST_ERROR_OBJECT (src->base.src, "%s", error->message);
|
|
return FALSE;
|
|
}
|
|
|
|
src->n_attributes = 1;
|
|
|
|
src->attributes[0].name = "position";
|
|
src->attributes[0].location = -1;
|
|
src->attributes[0].n_elements = 4;
|
|
src->attributes[0].element_type = GL_FLOAT;
|
|
src->attributes[0].offset = 0;
|
|
src->attributes[0].stride = 4 * sizeof (gfloat);
|
|
|
|
src->vertices = positions;
|
|
src->vertices_size = sizeof (positions);
|
|
src->indices = indices_quad;
|
|
src->n_indices = 6;
|
|
|
|
return _src_shader_init (impl, context, v_info);
|
|
}
|
|
|
|
static gboolean
|
|
_src_snow_fill_bound_fbo (gpointer impl)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
|
|
g_return_val_if_fail (src->base.context, FALSE);
|
|
g_return_val_if_fail (src->shader, FALSE);
|
|
|
|
gst_gl_shader_use (src->shader);
|
|
gst_gl_shader_set_uniform_1f (src->shader, "time",
|
|
(gfloat) src->base.src->running_time / GST_SECOND);
|
|
|
|
return _src_shader_fill_bound_fbo (impl);
|
|
}
|
|
|
|
static void
|
|
_src_snow_free (gpointer impl)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
|
|
if (!src)
|
|
return;
|
|
|
|
_src_shader_deinit (impl);
|
|
|
|
g_free (impl);
|
|
}
|
|
|
|
static gpointer
|
|
_src_snow_new (GstGLTestSrc * test)
|
|
{
|
|
struct SrcShader *src = g_new0 (struct SrcShader, 1);
|
|
|
|
src->base.src = test;
|
|
|
|
return src;
|
|
}
|
|
|
|
static const struct SrcFuncs src_snow = {
|
|
GST_GL_TEST_SRC_SNOW,
|
|
_src_snow_new,
|
|
_src_snow_init,
|
|
_src_snow_fill_bound_fbo,
|
|
_src_snow_free,
|
|
};
|
|
|
|
/* *INDENT-OFF* */
|
|
static const gchar *mandelbrot_vertex_src = "attribute vec4 position;\n"
|
|
"uniform float aspect_ratio;\n"
|
|
"varying vec2 fractal_position;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = position;\n"
|
|
" fractal_position = vec2(position.y * 0.5 - 0.3, aspect_ratio * position.x * 0.5);\n"
|
|
" fractal_position *= 2.5;\n"
|
|
"}";
|
|
|
|
static const gchar *mandelbrot_fragment_src =
|
|
"#ifdef GL_ES\n"
|
|
"precision mediump float;\n"
|
|
"#endif\n"
|
|
"uniform float time;\n"
|
|
"varying vec2 fractal_position;\n"
|
|
"const vec4 K = vec4(1.0, 0.66, 0.33, 3.0);\n"
|
|
"vec4 hsv_to_rgb(float hue, float saturation, float value) {\n"
|
|
" vec4 p = abs(fract(vec4(hue) + K) * 6.0 - K.wwww);\n"
|
|
" return value * mix(K.xxxx, clamp(p - K.xxxx, 0.0, 1.0), saturation);\n"
|
|
"}\n"
|
|
"vec4 i_to_rgb(int i) {\n"
|
|
" float hue = float(i) / 100.0 + sin(time);\n"
|
|
" return hsv_to_rgb(hue, 0.5, 0.8);\n"
|
|
"}\n"
|
|
"vec2 pow_2_complex(vec2 c) {\n"
|
|
" return vec2(c.x*c.x - c.y*c.y, 2.0 * c.x * c.y);\n"
|
|
"}\n"
|
|
"vec2 mandelbrot(vec2 c, vec2 c0) {\n"
|
|
" return pow_2_complex(c) + c0;\n"
|
|
"}\n"
|
|
"vec4 iterate_pixel(vec2 position) {\n"
|
|
" vec2 c = vec2(0);\n"
|
|
" for (int i=0; i < 20; i++) {\n"
|
|
" if (c.x*c.x + c.y*c.y > 2.0*2.0)\n"
|
|
" return i_to_rgb(i);\n"
|
|
" c = mandelbrot(c, position);\n"
|
|
" }\n"
|
|
" return vec4(0, 0, 0, 1);\n"
|
|
"}\n"
|
|
"void main() {\n"
|
|
" gl_FragColor = iterate_pixel(fractal_position);\n"
|
|
"}";
|
|
/* *INDENT-ON* */
|
|
|
|
static gboolean
|
|
_src_mandelbrot_init (gpointer impl, GstGLContext * context,
|
|
GstVideoInfo * v_info)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
GError *error = NULL;
|
|
|
|
src->base.context = context;
|
|
|
|
if (src->shader)
|
|
gst_object_unref (src->shader);
|
|
src->shader = gst_gl_shader_new_link_with_stages (context, &error,
|
|
gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
mandelbrot_vertex_src),
|
|
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
mandelbrot_fragment_src), NULL);
|
|
if (!src->shader) {
|
|
GST_ERROR_OBJECT (src->base.src, "%s", error->message);
|
|
return FALSE;
|
|
}
|
|
|
|
src->n_attributes = 1;
|
|
|
|
src->attributes[0].name = "position";
|
|
src->attributes[0].location = -1;
|
|
src->attributes[0].n_elements = 4;
|
|
src->attributes[0].element_type = GL_FLOAT;
|
|
src->attributes[0].offset = 0;
|
|
src->attributes[0].stride = 4 * sizeof (gfloat);
|
|
|
|
src->vertices = positions;
|
|
src->vertices_size = sizeof (positions);
|
|
src->indices = indices_quad;
|
|
src->n_indices = 6;
|
|
|
|
gst_gl_shader_use (src->shader);
|
|
gst_gl_shader_set_uniform_1f (src->shader, "aspect_ratio",
|
|
(gfloat) GST_VIDEO_INFO_WIDTH (v_info) /
|
|
(gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
|
|
gst_gl_context_clear_shader (src->base.context);
|
|
|
|
return _src_shader_init (impl, context, v_info);
|
|
}
|
|
|
|
static gboolean
|
|
_src_mandelbrot_fill_bound_fbo (gpointer impl)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
|
|
g_return_val_if_fail (src->base.context, FALSE);
|
|
g_return_val_if_fail (src->shader, FALSE);
|
|
|
|
gst_gl_shader_use (src->shader);
|
|
gst_gl_shader_set_uniform_1f (src->shader, "time",
|
|
(gfloat) src->base.src->running_time / GST_SECOND);
|
|
|
|
return _src_shader_fill_bound_fbo (impl);
|
|
}
|
|
|
|
static void
|
|
_src_mandelbrot_free (gpointer impl)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
|
|
if (!src)
|
|
return;
|
|
|
|
_src_shader_deinit (impl);
|
|
|
|
g_free (impl);
|
|
}
|
|
|
|
static gpointer
|
|
_src_mandelbrot_new (GstGLTestSrc * test)
|
|
{
|
|
struct SrcShader *src = g_new0 (struct SrcShader, 1);
|
|
|
|
src->base.src = test;
|
|
|
|
return src;
|
|
}
|
|
|
|
static const struct SrcFuncs src_mandelbrot = {
|
|
GST_GL_TEST_SRC_MANDELBROT,
|
|
_src_mandelbrot_new,
|
|
_src_mandelbrot_init,
|
|
_src_mandelbrot_fill_bound_fbo,
|
|
_src_mandelbrot_free,
|
|
};
|
|
|
|
/* *INDENT-OFF* */
|
|
static const gchar *circular_vertex_src =
|
|
"attribute vec4 position;\n"
|
|
"varying vec2 uv;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = position;\n"
|
|
" uv = position.xy;\n"
|
|
"}";
|
|
|
|
static const gchar *circular_fragment_src =
|
|
"#ifdef GL_ES\n"
|
|
"precision mediump float;\n"
|
|
"#endif\n"
|
|
"uniform float aspect_ratio;\n"
|
|
"varying vec2 uv;\n"
|
|
"#define PI 3.14159265\n"
|
|
"void main() {\n"
|
|
" float dist = 0.5 * sqrt(uv.x * uv.x + uv.y / aspect_ratio * uv.y / aspect_ratio);\n"
|
|
" float seg = floor(dist * 16.0);\n"
|
|
" if (seg <= 0.0 || seg >= 8.0) {\n"
|
|
" gl_FragColor = vec4(vec3(0.0), 1.0);\n"
|
|
" } else {\n"
|
|
" float d = floor (256.0 * dist * 200.0 * pow (2.0, - (seg - 1.0) / 4.0) + 0.5) / 128.0;\n"
|
|
" gl_FragColor = vec4 (vec3(sin (d * PI) * 0.5 + 0.5), 1.0);\n"
|
|
" }\n"
|
|
"}";
|
|
/* *INDENT-ON* */
|
|
|
|
static gboolean
|
|
_src_circular_init (gpointer impl, GstGLContext * context,
|
|
GstVideoInfo * v_info)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
GError *error = NULL;
|
|
|
|
src->base.context = context;
|
|
|
|
if (src->shader)
|
|
gst_object_unref (src->shader);
|
|
src->shader = gst_gl_shader_new_link_with_stages (context, &error,
|
|
gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
circular_vertex_src),
|
|
gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
|
|
GST_GLSL_VERSION_NONE,
|
|
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
|
|
circular_fragment_src), NULL);
|
|
if (!src->shader) {
|
|
GST_ERROR_OBJECT (src->base.src, "%s", error->message);
|
|
return FALSE;
|
|
}
|
|
|
|
src->n_attributes = 1;
|
|
|
|
src->attributes[0].name = "position";
|
|
src->attributes[0].location = -1;
|
|
src->attributes[0].n_elements = 4;
|
|
src->attributes[0].element_type = GL_FLOAT;
|
|
src->attributes[0].offset = 0;
|
|
src->attributes[0].stride = 4 * sizeof (gfloat);
|
|
|
|
src->vertices = positions;
|
|
src->vertices_size = sizeof (positions);
|
|
src->indices = indices_quad;
|
|
src->n_indices = 6;
|
|
|
|
gst_gl_shader_use (src->shader);
|
|
gst_gl_shader_set_uniform_1f (src->shader, "aspect_ratio",
|
|
(gfloat) GST_VIDEO_INFO_WIDTH (v_info) /
|
|
(gfloat) GST_VIDEO_INFO_HEIGHT (v_info));
|
|
gst_gl_context_clear_shader (src->base.context);
|
|
|
|
return _src_shader_init (impl, context, v_info);
|
|
}
|
|
|
|
static void
|
|
_src_circular_free (gpointer impl)
|
|
{
|
|
struct SrcShader *src = impl;
|
|
|
|
if (!src)
|
|
return;
|
|
|
|
_src_shader_deinit (impl);
|
|
|
|
g_free (impl);
|
|
}
|
|
|
|
static gpointer
|
|
_src_circular_new (GstGLTestSrc * test)
|
|
{
|
|
struct SrcShader *src = g_new0 (struct SrcShader, 1);
|
|
|
|
src->base.src = test;
|
|
|
|
return src;
|
|
}
|
|
|
|
static const struct SrcFuncs src_circular = {
|
|
GST_GL_TEST_SRC_CIRCULAR,
|
|
_src_circular_new,
|
|
_src_circular_init,
|
|
_src_mandelbrot_fill_bound_fbo,
|
|
_src_circular_free,
|
|
};
|
|
|
|
static const struct SrcFuncs *src_impls[] = {
|
|
&src_smpte,
|
|
&src_snow,
|
|
&src_black,
|
|
&src_white,
|
|
&src_red,
|
|
&src_green,
|
|
&src_blue,
|
|
&src_checkers1,
|
|
&src_checkers2,
|
|
&src_checkers4,
|
|
&src_checkers8,
|
|
&src_circular,
|
|
&src_blink,
|
|
&src_mandelbrot,
|
|
};
|
|
|
|
const struct SrcFuncs *
|
|
gst_gl_test_src_get_src_funcs_for_pattern (GstGLTestSrcPattern pattern)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (src_impls); i++) {
|
|
if (src_impls[i]->pattern == pattern)
|
|
return src_impls[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|