1 /*
2 * GStreamer
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 "gstglutils.h"
28
29 struct _compile_shader
30 {
31 GstGLShader **shader;
32 const gchar *vertex_src;
33 const gchar *fragment_src;
34 };
35
36 static void
_compile_shader(GstGLContext * context,struct _compile_shader * data)37 _compile_shader (GstGLContext * context, struct _compile_shader *data)
38 {
39 GstGLShader *shader;
40 GstGLSLStage *vert, *frag;
41 GError *error = NULL;
42
43 shader = gst_gl_shader_new (context);
44
45 if (data->vertex_src) {
46 vert = gst_glsl_stage_new_with_string (context, GL_VERTEX_SHADER,
47 GST_GLSL_VERSION_NONE,
48 GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, data->vertex_src);
49 if (!gst_glsl_stage_compile (vert, &error)) {
50 GST_ERROR_OBJECT (vert, "%s", error->message);
51 gst_object_unref (vert);
52 gst_object_unref (shader);
53 return;
54 }
55 if (!gst_gl_shader_attach (shader, vert)) {
56 gst_object_unref (shader);
57 return;
58 }
59 }
60
61 if (data->fragment_src) {
62 frag = gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER,
63 GST_GLSL_VERSION_NONE,
64 GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
65 data->fragment_src);
66 if (!gst_glsl_stage_compile (frag, &error)) {
67 GST_ERROR_OBJECT (frag, "%s", error->message);
68 gst_object_unref (frag);
69 gst_object_unref (shader);
70 return;
71 }
72 if (!gst_gl_shader_attach (shader, frag)) {
73 gst_object_unref (shader);
74 return;
75 }
76 }
77
78 if (!gst_gl_shader_link (shader, &error)) {
79 GST_ERROR_OBJECT (shader, "%s", error->message);
80 g_error_free (error);
81 error = NULL;
82 gst_gl_context_clear_shader (context);
83 gst_object_unref (shader);
84 return;
85 }
86
87 *data->shader = shader;
88 }
89
90 /* Called by glfilter */
91 gboolean
gst_gl_context_gen_shader(GstGLContext * context,const gchar * vert_src,const gchar * frag_src,GstGLShader ** shader)92 gst_gl_context_gen_shader (GstGLContext * context, const gchar * vert_src,
93 const gchar * frag_src, GstGLShader ** shader)
94 {
95 struct _compile_shader data;
96
97 g_return_val_if_fail (frag_src != NULL || vert_src != NULL, FALSE);
98 g_return_val_if_fail (shader != NULL, FALSE);
99
100 data.shader = shader;
101 data.vertex_src = vert_src;
102 data.fragment_src = frag_src;
103
104 gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _compile_shader,
105 &data);
106
107 return *shader != NULL;
108 }
109
110 static const gfloat identity_matrix[] = {
111 1.0, 0.0, 0.0, 0.0,
112 0.0, 1.0, 0.0, 0.0,
113 0.0, 0.0, 1.0, 0.0,
114 0.0, 0.0, 0.0, 1.0,
115 };
116
117 static const gfloat from_ndc_matrix[] = {
118 0.5, 0.0, 0.0, 0.0,
119 0.0, 0.5, 0.0, 0.0,
120 0.0, 0.0, 0.5, 0.0,
121 0.5, 0.5, 0.5, 1.0,
122 };
123
124 static const gfloat to_ndc_matrix[] = {
125 2.0, 0.0, 0.0, 0.0,
126 0.0, 2.0, 0.0, 0.0,
127 0.0, 0.0, 2.0, 0.0,
128 -1.0, -1.0, -1.0, 1.0,
129 };
130
131 void
gst_gl_multiply_matrix4(const gfloat * a,const gfloat * b,gfloat * result)132 gst_gl_multiply_matrix4 (const gfloat * a, const gfloat * b, gfloat * result)
133 {
134 int i, j, k;
135 gfloat tmp[16] = { 0.0f };
136
137 if (!a || !b || !result)
138 return;
139
140 for (i = 0; i < 4; i++) { /* column */
141 for (j = 0; j < 4; j++) { /* row */
142 for (k = 0; k < 4; k++) {
143 tmp[j + (i * 4)] += a[k + (i * 4)] * b[j + (k * 4)];
144 }
145 }
146 }
147
148 for (i = 0; i < 16; i++)
149 result[i] = tmp[i];
150 }
151
gst_gl_get_affine_transformation_meta_as_ndc_ext(GstVideoAffineTransformationMeta * meta,gfloat * matrix)152 void gst_gl_get_affine_transformation_meta_as_ndc_ext
153 (GstVideoAffineTransformationMeta * meta, gfloat * matrix)
154 {
155 if (!meta) {
156 int i;
157
158 for (i = 0; i < 16; i++) {
159 matrix[i] = identity_matrix[i];
160 }
161 } else {
162 float tmp[16];
163
164 gst_gl_multiply_matrix4 (from_ndc_matrix, meta->matrix, tmp);
165 gst_gl_multiply_matrix4 (tmp, to_ndc_matrix, matrix);
166 }
167 }
168
gst_gl_set_affine_transformation_meta_from_ndc_ext(GstVideoAffineTransformationMeta * meta,const gfloat * matrix)169 void gst_gl_set_affine_transformation_meta_from_ndc_ext
170 (GstVideoAffineTransformationMeta * meta, const gfloat * matrix)
171 {
172 float tmp[16];
173
174 g_return_if_fail (meta != NULL);
175
176 gst_gl_multiply_matrix4 (to_ndc_matrix, matrix, tmp);
177 gst_gl_multiply_matrix4 (tmp, from_ndc_matrix, meta->matrix);
178 }
179