1 /*
2 * Copyright (C) 2018-2019 the xine project
3 * Copyright (C) 2018-2019 Petri Hintukainen <phintuka@users.sourceforge.net>
4 *
5 * This file is part of xine, a free video player.
6 *
7 * xine is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * xine is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 * xine_egl.c, EGL bindings for OpenGL video output
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "xine_gl.h"
30
31 #include <stdlib.h>
32
33 #include <xine.h> /* visual types */
34 #include <xine/xine_internal.h>
35
36 #include "xine_gl_plugin.h"
37
38 #if defined(XINE_EGL_USE_X11)
39 #elif defined(XINE_EGL_USE_WAYLAND)
40 # include <wayland-egl.h>
41 #else
42 # error EGL platform undefined
43 #endif
44
45 #include <EGL/egl.h>
46
47 #define EGL(_gl) xine_container_of(_gl, xine_egl_t, p.gl)
48
49 typedef struct {
50 xine_gl_plugin_t p;
51
52 EGLDisplay display;
53 EGLContext context;
54 EGLSurface surface;
55 EGLConfig config;
56
57 #if defined(XINE_EGL_USE_WAYLAND)
58 struct wl_egl_window *window;
59 int width, height;
60 #endif
61
62 /* DEBUG */
63 int is_current;
64 } xine_egl_t;
65
_egl_error_str(EGLint error)66 static const char *_egl_error_str(EGLint error)
67 {
68 switch (error) {
69 case EGL_SUCCESS: return "No error";
70 case EGL_NOT_INITIALIZED: return "EGL not initialized or failed to initialize";
71 case EGL_BAD_ACCESS: return "Resource inaccessible";
72 case EGL_BAD_ALLOC: return "Cannot allocate resources";
73 case EGL_BAD_ATTRIBUTE: return "Unrecognized attribute or attribute value";
74 case EGL_BAD_CONTEXT: return "Invalid EGL context";
75 case EGL_BAD_CONFIG: return "Invalid EGL frame buffer configuration";
76 case EGL_BAD_CURRENT_SURFACE: return "Current surface is no longer valid";
77 case EGL_BAD_DISPLAY: return "Invalid EGL display";
78 case EGL_BAD_SURFACE: return "Invalid surface";
79 case EGL_BAD_MATCH: return "Inconsistent arguments";
80 case EGL_BAD_PARAMETER: return "Invalid argument";
81 case EGL_BAD_NATIVE_PIXMAP: return "Invalid native pixmap";
82 case EGL_BAD_NATIVE_WINDOW: return "Invalid native window";
83 case EGL_CONTEXT_LOST: return "Context lost";
84 }
85 return "Unknown error ";
86 }
87
_egl_log_error(xine_t * xine,const char * msg)88 static inline void _egl_log_error(xine_t *xine, const char *msg)
89 {
90 EGLint error = eglGetError();
91 xprintf(xine, XINE_VERBOSITY_LOG, "egl: %s : %s (%d)\n",
92 msg, _egl_error_str(error), error);
93 }
94
_egl_make_current(xine_gl_t * gl)95 static int _egl_make_current(xine_gl_t *gl)
96 {
97 xine_egl_t *egl = EGL(gl);
98 int result;
99
100 _x_assert(!egl->is_current);
101
102 result = eglMakeCurrent(egl->display, egl->surface, egl->surface, egl->context);
103 if (!result) {
104 _egl_log_error(egl->p.xine, "eglMakeCurrent() failed");
105 return 0;
106 }
107
108 egl->is_current = 1;
109 return result;
110 }
111
_egl_release_current(xine_gl_t * gl)112 static void _egl_release_current(xine_gl_t *gl)
113 {
114 xine_egl_t *egl = EGL(gl);
115
116 _x_assert(egl->is_current);
117
118 eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
119 egl->is_current = 0;
120 }
121
_egl_swap_buffers(xine_gl_t * gl)122 static void _egl_swap_buffers(xine_gl_t *gl)
123 {
124 xine_egl_t *egl = EGL(gl);
125
126 eglSwapBuffers(egl->display, egl->surface);
127 }
128
_egl_set_native_window(xine_gl_t * gl,void * drawable)129 static void _egl_set_native_window(xine_gl_t *gl, void *drawable)
130 {
131 xine_egl_t *egl = EGL(gl);
132 EGLNativeWindowType window;
133
134 _x_assert(!egl->is_current);
135
136 eglDestroySurface (egl->display, egl->surface);
137 #if defined(XINE_EGL_USE_X11)
138 window = (intptr_t)drawable;
139 #elif defined(XINE_EGL_USE_WAYLAND)
140 wl_egl_window_destroy(egl->window);
141 window = egl->window = wl_egl_window_create(drawable, egl->width, egl->height);
142 #endif
143 egl->surface = eglCreateWindowSurface(egl->display, egl->config, window, NULL);
144
145 if (egl->surface == EGL_NO_SURFACE) {
146 _egl_log_error(egl->p.xine, "eglCreateWindowSurface() failed");
147 }
148 }
149
_egl_resize(xine_gl_t * gl,int w,int h)150 static void _egl_resize(xine_gl_t *gl, int w, int h)
151 {
152 #if defined(XINE_EGL_USE_WAYLAND)
153 xine_egl_t *egl = EGL(gl);
154 wl_egl_window_resize(egl->window, w, h, 0, 0);
155 egl->width = w;
156 egl->height = h;
157 #else
158 (void)gl;
159 (void)w;
160 (void)h;
161 #endif
162 }
163
_egl_init(xine_egl_t * egl,EGLNativeDisplayType native_display)164 static int _egl_init(xine_egl_t *egl, EGLNativeDisplayType native_display)
165 {
166 static const EGLint attributes[] = {
167 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
168 EGL_RED_SIZE, 8,
169 EGL_GREEN_SIZE, 8,
170 EGL_BLUE_SIZE, 8,
171 EGL_DEPTH_SIZE, 16,
172 EGL_NONE
173 };
174 static const EGLint context_attribs[] = {
175 //EGL_CONTEXT_CLIENT_VERSION, 2,
176 EGL_NONE
177 };
178 EGLint num_config;
179
180 egl->display = eglGetDisplay(native_display);
181 if (egl->display == EGL_NO_DISPLAY) {
182 _egl_log_error(egl->p.xine, "eglGetDisplay() failed");
183 return 0;
184 }
185
186 if (!eglInitialize (egl->display, NULL, NULL)) {
187 _egl_log_error(egl->p.xine, "eglInitialize() failed");
188 goto fail;
189 }
190
191 eglChooseConfig(egl->display, attributes, &egl->config, 1, &num_config);
192
193 if (!eglBindAPI (EGL_OPENGL_API)) {
194 _egl_log_error(egl->p.xine, "OpenGL API unavailable");
195 goto fail;
196 }
197
198 egl->context = eglCreateContext(egl->display, egl->config, EGL_NO_CONTEXT, context_attribs);
199 if (egl->context == EGL_NO_CONTEXT) {
200 _egl_log_error(egl->p.xine, "eglCreateContext() failed");
201 goto fail;
202 }
203
204 return 1;
205
206 fail:
207 eglTerminate(egl->display);
208 return 0;
209 }
210
_egl_dispose(xine_gl_t * gl)211 static void _egl_dispose(xine_gl_t *gl)
212 {
213 xine_egl_t *egl = EGL(gl);
214
215 lprintf("Destroying egl context %p\n", (void*)egl->context);
216
217 _x_assert(!egl->is_current);
218
219 if (egl->is_current) {
220 eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
221 }
222
223 eglDestroySurface (egl->display, egl->surface);
224 #if defined(XINE_EGL_USE_WAYLAND)
225 wl_egl_window_destroy(egl->window);
226 #endif
227 eglDestroyContext(egl->display, egl->context);
228 eglTerminate(egl->display);
229 free(egl);
230 }
231
232 /*
233 * xine module
234 */
235
_module_dispose(xine_module_t * module)236 static void _module_dispose(xine_module_t *module)
237 {
238 xine_egl_t *egl = xine_container_of(module, xine_egl_t, p.module);
239
240 _egl_dispose(&egl->p.gl);
241 }
242
_egl_get_instance(xine_module_class_t * class_gen,const void * data)243 static xine_module_t *_egl_get_instance(xine_module_class_t *class_gen, const void *data)
244 {
245 const gl_plugin_params_t *params = data;
246 EGLNativeWindowType native_window;
247 xine_egl_t *egl;
248
249 #if defined(XINE_EGL_USE_X11)
250 const x11_visual_t *vis = params->visual;
251 _x_assert(params->visual_type == XINE_VISUAL_TYPE_X11 ||
252 params->visual_type == XINE_VISUAL_TYPE_X11_2);
253 #elif defined(XINE_EGL_USE_WAYLAND)
254 const xine_wayland_visual_t *vis = params->visual;
255 _x_assert (params->visual_type == XINE_VISUAL_TYPE_WAYLAND);
256 #endif
257
258 (void)class_gen;
259
260 if (!(params->flags & XINE_GL_API_OPENGL)) {
261 return NULL;
262 }
263 _x_assert(params->visual);
264 _x_assert(vis->display);
265
266 egl = calloc(1, sizeof(*egl));
267 if (!egl) {
268 return NULL;
269 }
270
271 egl->p.module.dispose = _module_dispose;
272
273 egl->p.gl.make_current = _egl_make_current;
274 egl->p.gl.release_current = _egl_release_current;
275 egl->p.gl.swap_buffers = _egl_swap_buffers;
276 egl->p.gl.resize = _egl_resize;
277 egl->p.gl.set_native_window = _egl_set_native_window;
278 egl->p.gl.dispose = NULL;
279
280 egl->p.xine = params->xine;
281
282 if (!_egl_init(egl, vis->display)) {
283 free(egl);
284 return NULL;
285 }
286
287 #if defined(XINE_EGL_USE_X11)
288 native_window = vis->d;
289 #elif defined(XINE_EGL_USE_WAYLAND)
290 egl->width = 720;
291 egl->height = 576;
292 native_window = wl_egl_window_create(vis->surface, egl->width, egl->height);
293 egl->window = native_window;
294 egl->surface = vis->surface;
295 #endif
296
297 egl->surface = eglCreateWindowSurface(egl->display, egl->config, native_window, NULL);
298 if (egl->surface == EGL_NO_SURFACE) {
299 _egl_log_error(egl->p.xine, "eglCreateWindowSurface() failed");
300 goto fail;
301 }
302
303 return &egl->p.module;
304
305 fail:
306 eglDestroyContext(egl->display, egl->context);
307 eglTerminate(egl->display);
308 free(egl);
309 return NULL;
310 }
311
312 /*
313 * plugin
314 */
315
egl_init_class(xine_t * xine,const void * params)316 static void *egl_init_class(xine_t *xine, const void *params)
317 {
318 static const xine_module_class_t xine_egl_class = {
319 .get_instance = _egl_get_instance,
320 #if defined(XINE_EGL_USE_X11)
321 .description = "GL provider (EGL/X11)",
322 #elif defined(XINE_EGL_USE_WAYLAND)
323 .description = "GL provider (EGL/Wayland)",
324 #endif
325 .identifier = "egl",
326 .dispose = NULL,
327 };
328
329 (void)xine;
330 (void)params;
331
332 return (void *)&xine_egl_class;
333 }
334
335 #if defined(XINE_EGL_USE_X11)
336 static const xine_module_info_t module_info_egl = {
337 .priority = 9,
338 .type = "gl_v1",
339 .sub_type = XINE_VISUAL_TYPE_X11,
340 };
341 #elif defined(XINE_EGL_USE_WAYLAND)
342 static const xine_module_info_t module_info_egl = {
343 .priority = 10,
344 .type = "gl_v1",
345 .sub_type = XINE_VISUAL_TYPE_WAYLAND,
346 };
347 #endif
348
349 const plugin_info_t xine_plugin_info[] EXPORTED = {
350 /* type, API, "name", version, special_info, init_function */
351 { PLUGIN_XINE_MODULE, 1, "egl", XINE_VERSION_CODE, &module_info_egl, egl_init_class },
352 { PLUGIN_NONE, 0, NULL, 0, NULL, NULL },
353 };
354