1 /*
2 * GStreamer
3 * Copyright (C) 2014 Matthew Waters <ystreet00@gmail.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 "gstgldisplay_egl.h"
26
27 #include <gst/gl/gstglfeature.h>
28
29 #include "gstegl.h"
30 #include "gsteglimage.h"
31 #include "gstglmemoryegl.h"
32
33 GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug);
34 #define GST_CAT_DEFAULT gst_gl_display_debug
35
36 #ifndef EGL_PLATFORM_X11
37 #define EGL_PLATFORM_X11 0x31D5
38 #endif
39 #ifndef EGL_PLATFORM_WAYLAND
40 #define EGL_PLATFORM_WAYLAND 0x31D8
41 #endif
42 #ifndef EGL_PLATFORM_GBM_MESA
43 #define EGL_PLATFORM_GBM_MESA 0x31D7
44 #endif
45 #ifndef EGL_PLATFORM_ANDROID
46 #define EGL_PLATFORM_ANDROID 0x3141
47 #endif
48
49 typedef EGLDisplay (*_gst_eglGetPlatformDisplay_type) (EGLenum platform,
50 void *native_display, const EGLint * attrib_list);
51
52 G_DEFINE_TYPE (GstGLDisplayEGL, gst_gl_display_egl, GST_TYPE_GL_DISPLAY);
53
54 static void gst_gl_display_egl_finalize (GObject * object);
55 static guintptr gst_gl_display_egl_get_handle (GstGLDisplay * display);
56
57 static void
gst_gl_display_egl_class_init(GstGLDisplayEGLClass * klass)58 gst_gl_display_egl_class_init (GstGLDisplayEGLClass * klass)
59 {
60 GST_GL_DISPLAY_CLASS (klass)->get_handle =
61 GST_DEBUG_FUNCPTR (gst_gl_display_egl_get_handle);
62
63 G_OBJECT_CLASS (klass)->finalize = gst_gl_display_egl_finalize;
64 }
65
66 static void
gst_gl_display_egl_init(GstGLDisplayEGL * display_egl)67 gst_gl_display_egl_init (GstGLDisplayEGL * display_egl)
68 {
69 GstGLDisplay *display = (GstGLDisplay *) display_egl;
70
71 display->type = GST_GL_DISPLAY_TYPE_EGL;
72 display_egl->foreign_display = FALSE;
73
74 gst_gl_memory_egl_init_once ();
75 }
76
77 static void
gst_gl_display_egl_finalize(GObject * object)78 gst_gl_display_egl_finalize (GObject * object)
79 {
80 GstGLDisplayEGL *display_egl = GST_GL_DISPLAY_EGL (object);
81
82 if (display_egl->display && !display_egl->foreign_display) {
83 eglTerminate (display_egl->display);
84 display_egl->display = NULL;
85 }
86
87 G_OBJECT_CLASS (gst_gl_display_egl_parent_class)->finalize (object);
88 }
89
90 /**
91 * gst_gl_display_egl_get_from_native:
92 * @type: a #GstGLDisplayType
93 * @display: pointer to a display (or 0)
94 *
95 * Attempts to create a new #EGLDisplay from @display. If @type is
96 * %GST_GL_DISPLAY_TYPE_ANY, then @display must be 0. @type must not be
97 * %GST_GL_DISPLAY_TYPE_NONE.
98 *
99 * Returns: A #EGLDisplay or %EGL_NO_DISPLAY
100 *
101 * Since: 1.12
102 */
103 gpointer
gst_gl_display_egl_get_from_native(GstGLDisplayType type,guintptr display)104 gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display)
105 {
106 const gchar *egl_exts;
107 EGLDisplay ret = EGL_NO_DISPLAY;
108 _gst_eglGetPlatformDisplay_type _gst_eglGetPlatformDisplay;
109
110 g_return_val_if_fail (type != GST_GL_DISPLAY_TYPE_NONE, EGL_NO_DISPLAY);
111 g_return_val_if_fail ((type != GST_GL_DISPLAY_TYPE_ANY && display != 0)
112 || (type == GST_GL_DISPLAY_TYPE_ANY && display == 0), EGL_NO_DISPLAY);
113
114 /* given an EGLDisplay already */
115 if (type == GST_GL_DISPLAY_TYPE_EGL)
116 return (gpointer) display;
117
118 egl_exts = eglQueryString (EGL_NO_DISPLAY, EGL_EXTENSIONS);
119 GST_DEBUG ("egl no display extensions: %s", egl_exts);
120
121 if (eglGetError () != EGL_SUCCESS || !egl_exts)
122 goto default_display;
123
124 /* check if we can actually choose the egl display type */
125 if (!gst_gl_check_extension ("EGL_KHR_client_get_all_proc_addresses",
126 egl_exts))
127 goto default_display;
128 if (!gst_gl_check_extension ("EGL_EXT_platform_base", egl_exts))
129 goto default_display;
130
131 _gst_eglGetPlatformDisplay = (_gst_eglGetPlatformDisplay_type)
132 eglGetProcAddress ("eglGetPlatformDisplay");
133 if (!_gst_eglGetPlatformDisplay)
134 _gst_eglGetPlatformDisplay = (_gst_eglGetPlatformDisplay_type)
135 eglGetProcAddress ("eglGetPlatformDisplayEXT");
136 if (!_gst_eglGetPlatformDisplay)
137 goto default_display;
138
139 /* try each platform in turn */
140 #if GST_GL_HAVE_WINDOW_X11
141 if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_X11) &&
142 (gst_gl_check_extension ("EGL_KHR_platform_x11", egl_exts) ||
143 gst_gl_check_extension ("EGL_EXT_platform_x11", egl_exts))) {
144 ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_X11, (gpointer) display,
145 NULL);
146 }
147 #endif
148 #if GST_GL_HAVE_WINDOW_WAYLAND
149 if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_WAYLAND) &&
150 (gst_gl_check_extension ("EGL_KHR_platform_wayland", egl_exts) ||
151 gst_gl_check_extension ("EGL_EXT_platform_wayland", egl_exts))) {
152 ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_WAYLAND, (gpointer) display,
153 NULL);
154 }
155 #endif
156 #if GST_GL_HAVE_WINDOW_GBM
157 if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_GBM) &&
158 (gst_gl_check_extension ("EGL_MESA_platform_gbm", egl_exts) ||
159 gst_gl_check_extension ("EGL_KHR_platform_gbm", egl_exts))) {
160 ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_GBM_MESA, (gpointer) display,
161 NULL);
162 }
163 #endif
164 /* android only has one winsys/display connection */
165
166 if (ret != EGL_NO_DISPLAY)
167 return ret;
168
169 /* otherwise rely on the implementation to choose the correct display
170 * based on the pointer */
171 default_display:
172 return (gpointer) eglGetDisplay ((EGLNativeDisplayType) display);
173 }
174
175 /**
176 * gst_gl_display_egl_new:
177 *
178 * Create a new #GstGLDisplayEGL using the default EGL_DEFAULT_DISPLAY.
179 *
180 * Returns: (transfer full): a new #GstGLDisplayEGL or %NULL
181 */
182 GstGLDisplayEGL *
gst_gl_display_egl_new(void)183 gst_gl_display_egl_new (void)
184 {
185 GstGLDisplayEGL *ret;
186
187 GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay");
188
189 ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL);
190 gst_object_ref_sink (ret);
191 ret->display =
192 gst_gl_display_egl_get_from_native (GST_GL_DISPLAY_TYPE_ANY, 0);
193
194 if (!ret->display) {
195 GST_INFO ("Failed to open EGL display connection");
196 }
197
198 return ret;
199 }
200
201 /**
202 * gst_gl_display_egl_new_with_display:
203 * @display: an existing and connected EGLDisplay
204 *
205 * Creates a new display connection from a EGLDisplay.
206 *
207 * Returns: (transfer full): a new #GstGLDisplayEGL
208 *
209 * Since: 1.12
210 */
211 GstGLDisplayEGL *
gst_gl_display_egl_new_with_egl_display(gpointer display)212 gst_gl_display_egl_new_with_egl_display (gpointer display)
213 {
214 GstGLDisplayEGL *ret;
215
216 g_return_val_if_fail (display != NULL, NULL);
217
218 GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay");
219
220 ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL);
221 gst_object_ref_sink (ret);
222
223 ret->display = display;
224 ret->foreign_display = TRUE;
225
226 return ret;
227 }
228
229 static gpointer
_ref_if_set(gpointer data,gpointer user_data)230 _ref_if_set (gpointer data, gpointer user_data)
231 {
232 if (data)
233 gst_object_ref (data);
234 return data;
235 }
236
237 /**
238 * gst_gl_display_egl_from_gl_display:
239 * @display: an existing #GstGLDisplay
240 *
241 * Creates a EGL display connection from a native Display.
242 *
243 * This function will return the same value for multiple calls with the same
244 * @display.
245 *
246 * Returns: (transfer full): a new #GstGLDisplayEGL
247 *
248 * Since: 1.12
249 */
250 GstGLDisplayEGL *
gst_gl_display_egl_from_gl_display(GstGLDisplay * display)251 gst_gl_display_egl_from_gl_display (GstGLDisplay * display)
252 {
253 GstGLDisplayEGL *ret;
254 GstGLDisplayType display_type;
255 guintptr native_display;
256
257 g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
258
259 GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay");
260
261 if (GST_IS_GL_DISPLAY_EGL (display)) {
262 GST_LOG_OBJECT (display, "display %" GST_PTR_FORMAT "is already a "
263 "GstGLDisplayEGL", display);
264 return gst_object_ref (display);
265 }
266
267 /* try to get a previously set GstGLDisplayEGL */
268 ret = g_object_dup_data (G_OBJECT (display), GST_GL_DISPLAY_EGL_NAME,
269 (GDuplicateFunc) _ref_if_set, NULL);
270 if (ret && GST_IS_GL_DISPLAY_EGL (ret)) {
271 GST_LOG_OBJECT (display, "display %" GST_PTR_FORMAT "already has a "
272 "GstGLDisplayEGL %" GST_PTR_FORMAT, display, ret);
273 return ret;
274 }
275
276 if (ret)
277 gst_object_unref (ret);
278
279 display_type = gst_gl_display_get_handle_type (display);
280 native_display = gst_gl_display_get_handle (display);
281
282 g_return_val_if_fail (native_display != 0, NULL);
283 g_return_val_if_fail (display_type != GST_GL_DISPLAY_TYPE_NONE, NULL);
284
285 ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL);
286 gst_object_ref_sink (ret);
287
288 ret->display =
289 gst_gl_display_egl_get_from_native (display_type, native_display);
290
291 if (!ret->display) {
292 GST_WARNING_OBJECT (ret, "failed to get EGLDisplay from native display");
293 gst_object_unref (ret);
294 return NULL;
295 }
296 g_object_set_data_full (G_OBJECT (display), GST_GL_DISPLAY_EGL_NAME,
297 gst_object_ref (ret), (GDestroyNotify) gst_object_unref);
298
299 return ret;
300 }
301
302 static guintptr
gst_gl_display_egl_get_handle(GstGLDisplay * display)303 gst_gl_display_egl_get_handle (GstGLDisplay * display)
304 {
305 return (guintptr) GST_GL_DISPLAY_EGL (display)->display;
306 }
307