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