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