gl: move internal.h to converter.h
[vlc.git] / modules / video_output / opengl / converter_android.c
blob6fce87955614431cd36a53cb81ff2a7f25434dcb
1 /*****************************************************************************
2 * converter_android.c: OpenGL Android opaque converter
3 *****************************************************************************
4 * Copyright (C) 2016 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #ifndef __ANDROID__
26 # error this file must be built from android
27 #endif
29 #include <GLES2/gl2ext.h>
30 #include "converter.h"
31 #include "../android/display.h"
32 #include "../android/utils.h"
34 struct priv
36 AWindowHandler *awh;
37 const float *transform_mtx;
38 bool stex_attached;
40 struct {
41 GLint uSTMatrix;
42 } uloc;
45 static int
46 pool_lock_pic(picture_t *p_pic)
48 picture_sys_t *p_picsys = p_pic->p_sys;
50 p_picsys->b_locked = true;
51 return 0;
54 static void
55 pool_unlock_pic(picture_t *p_pic)
57 picture_sys_t *p_picsys = p_pic->p_sys;
58 if (p_picsys->b_locked)
60 AndroidOpaquePicture_Release(p_picsys, false);
61 p_picsys->b_locked = false;
65 static int
66 tc_anop_allocate_textures(const opengl_tex_converter_t *tc, GLuint *textures,
67 const GLsizei *tex_width, const GLsizei *tex_height)
69 (void) tex_width; (void) tex_height;
70 struct priv *priv = tc->priv;
71 assert(textures[0] != 0);
72 if (SurfaceTexture_attachToGLContext(priv->awh, textures[0]) != 0)
74 msg_Err(tc->gl, "SurfaceTexture_attachToGLContext failed");
75 return VLC_EGENERIC;
77 priv->stex_attached = true;
78 return VLC_SUCCESS;
81 static picture_pool_t *
82 tc_anop_get_pool(const opengl_tex_converter_t *tc, unsigned requested_count)
84 struct priv *priv = tc->priv;
85 #define FORCED_COUNT 31
86 requested_count = FORCED_COUNT;
87 picture_t *picture[FORCED_COUNT] = {NULL, };
88 unsigned count;
90 for (count = 0; count < requested_count; count++)
92 picture_sys_t *p_picsys = calloc(1, sizeof(*p_picsys));
93 if (unlikely(p_picsys == NULL))
94 goto error;
95 picture_resource_t rsc = {
96 .p_sys = p_picsys,
97 .pf_destroy = AndroidOpaquePicture_DetachVout,
100 p_picsys->hw.b_vd_ref = true;
101 p_picsys->hw.p_surface = SurfaceTexture_getANativeWindow(priv->awh);
102 p_picsys->hw.p_jsurface = SurfaceTexture_getSurface(priv->awh);
103 p_picsys->hw.i_index = -1;
104 vlc_mutex_init(&p_picsys->hw.lock);
106 picture[count] = picture_NewFromResource(&tc->fmt, &rsc);
107 if (!picture[count])
109 free(p_picsys);
110 goto error;
114 /* Wrap the pictures into a pool */
115 picture_pool_configuration_t pool_cfg = {
116 .picture_count = requested_count,
117 .picture = picture,
118 .lock = pool_lock_pic,
119 .unlock = pool_unlock_pic,
121 picture_pool_t *pool = picture_pool_NewExtended(&pool_cfg);
122 if (!pool)
123 goto error;
125 return pool;
126 error:
127 for (unsigned i = 0; i < count; i++)
128 picture_Release(picture[i]);
129 return NULL;
132 static int
133 tc_anop_update(const opengl_tex_converter_t *tc, GLuint *textures,
134 const GLsizei *tex_width, const GLsizei *tex_height,
135 picture_t *pic, const size_t *plane_offset)
137 (void) tex_width; (void) tex_height; (void) plane_offset;
138 assert(textures[0] != 0);
140 if (plane_offset != NULL)
141 return VLC_EGENERIC;
143 if (!pic->p_sys->b_locked)
144 return VLC_SUCCESS;
146 struct priv *priv = tc->priv;
148 AndroidOpaquePicture_Release(pic->p_sys, true);
150 if (SurfaceTexture_waitAndUpdateTexImage(priv->awh, &priv->transform_mtx)
151 != VLC_SUCCESS)
153 priv->transform_mtx = NULL;
154 return VLC_EGENERIC;
157 tc->vt->ActiveTexture(GL_TEXTURE0);
158 tc->vt->BindTexture(tc->tex_target, textures[0]);
160 return VLC_SUCCESS;
163 static int
164 tc_anop_fetch_locations(opengl_tex_converter_t *tc, GLuint program)
166 struct priv *priv = tc->priv;
167 priv->uloc.uSTMatrix = tc->vt->GetUniformLocation(program, "uSTMatrix");
168 return priv->uloc.uSTMatrix != -1 ? VLC_SUCCESS : VLC_EGENERIC;
171 static void
172 tc_anop_prepare_shader(const opengl_tex_converter_t *tc,
173 const GLsizei *tex_width, const GLsizei *tex_height,
174 float alpha)
176 (void) tex_width; (void) tex_height; (void) alpha;
177 struct priv *priv = tc->priv;
178 if (priv->transform_mtx != NULL)
179 tc->vt->UniformMatrix4fv(priv->uloc.uSTMatrix, 1, GL_FALSE,
180 priv->transform_mtx);
183 static void
184 tc_anop_release(const opengl_tex_converter_t *tc)
186 struct priv *priv = tc->priv;
188 if (priv->stex_attached)
189 SurfaceTexture_detachFromGLContext(priv->awh);
191 free(priv);
195 opengl_tex_converter_anop_init(opengl_tex_converter_t *tc)
197 if (tc->fmt.i_chroma != VLC_CODEC_ANDROID_OPAQUE
198 || !tc->gl->surface->handle.anativewindow)
199 return VLC_EGENERIC;
201 tc->priv = malloc(sizeof(struct priv));
202 if (unlikely(tc->priv == NULL))
203 return VLC_ENOMEM;
205 struct priv *priv = tc->priv;
206 priv->awh = tc->gl->surface->handle.anativewindow;
207 priv->transform_mtx = NULL;
208 priv->stex_attached = false;
210 tc->pf_allocate_textures = tc_anop_allocate_textures;
211 tc->pf_get_pool = tc_anop_get_pool;
212 tc->pf_update = tc_anop_update;
213 tc->pf_fetch_locations = tc_anop_fetch_locations;
214 tc->pf_prepare_shader = tc_anop_prepare_shader;
215 tc->pf_release = tc_anop_release;
217 tc->tex_count = 1;
218 tc->texs[0] = (struct opengl_tex_cfg) { { 1, 1 }, { 1, 1 } };
220 tc->tex_target = GL_TEXTURE_EXTERNAL_OES;
222 /* The transform Matrix (uSTMatrix) given by the SurfaceTexture is not
223 * using the same origin than us. Ask the caller to rotate textures
224 * coordinates, via the vertex shader, by forcing an orientation. */
225 switch (tc->fmt.orientation)
227 case ORIENT_TOP_LEFT:
228 tc->fmt.orientation = ORIENT_BOTTOM_LEFT;
229 break;
230 case ORIENT_TOP_RIGHT:
231 tc->fmt.orientation = ORIENT_BOTTOM_RIGHT;
232 break;
233 case ORIENT_BOTTOM_LEFT:
234 tc->fmt.orientation = ORIENT_TOP_LEFT;
235 break;
236 case ORIENT_BOTTOM_RIGHT:
237 tc->fmt.orientation = ORIENT_TOP_RIGHT;
238 break;
239 case ORIENT_LEFT_TOP:
240 tc->fmt.orientation = ORIENT_RIGHT_TOP;
241 break;
242 case ORIENT_LEFT_BOTTOM:
243 tc->fmt.orientation = ORIENT_RIGHT_BOTTOM;
244 break;
245 case ORIENT_RIGHT_TOP:
246 tc->fmt.orientation = ORIENT_LEFT_TOP;
247 break;
248 case ORIENT_RIGHT_BOTTOM:
249 tc->fmt.orientation = ORIENT_LEFT_BOTTOM;
250 break;
253 static const char *template =
254 "#version %u\n"
255 "#extension GL_OES_EGL_image_external : require\n"
256 "%s" /* precision */
257 "varying vec2 TexCoord0;"
258 "uniform samplerExternalOES sTexture;"
259 "uniform mat4 uSTMatrix;"
260 "void main()"
261 "{ "
262 " gl_FragColor = texture2D(sTexture, (uSTMatrix * vec4(TexCoord0, 1, 1)).xy);"
263 "}";
265 char *code;
266 if (asprintf(&code, template, tc->glsl_version, tc->glsl_precision_header) < 0)
267 return 0;
268 GLuint fragment_shader = tc->vt->CreateShader(GL_FRAGMENT_SHADER);
269 tc->vt->ShaderSource(fragment_shader, 1, (const char **) &code, NULL);
270 tc->vt->CompileShader(fragment_shader);
271 tc->fshader = fragment_shader;
272 free(code);
274 return VLC_SUCCESS;