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