• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_egl_debug);
45 #define GST_CAT_DEFAULT gst_gl_display_egl_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 #ifndef EGL_PLATFORM_DEVICE_EXT
60 #define EGL_PLATFORM_DEVICE_EXT 0x313F
61 #endif
62 #ifndef EGL_PLATFORM_ANGLE_ANGLE
63 #define EGL_PLATFORM_ANGLE_ANGLE 0x3202
64 #endif
65 
66 typedef EGLDisplay (*_gst_eglGetPlatformDisplay_type) (EGLenum platform,
67     void *native_display, const EGLint * attrib_list);
68 
69 G_DEFINE_TYPE (GstGLDisplayEGL, gst_gl_display_egl, GST_TYPE_GL_DISPLAY);
70 
71 static void gst_gl_display_egl_finalize (GObject * object);
72 static guintptr gst_gl_display_egl_get_handle (GstGLDisplay * display);
73 
74 static void
init_debug(void)75 init_debug (void)
76 {
77   static gsize _init = 0;
78 
79   if (g_once_init_enter (&_init)) {
80     GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gldisplayegl", 0,
81         "OpenGL EGL Display");
82     g_once_init_leave (&_init, 1);
83   }
84 }
85 
86 static void
gst_gl_display_egl_class_init(GstGLDisplayEGLClass * klass)87 gst_gl_display_egl_class_init (GstGLDisplayEGLClass * klass)
88 {
89   GST_GL_DISPLAY_CLASS (klass)->get_handle =
90       GST_DEBUG_FUNCPTR (gst_gl_display_egl_get_handle);
91 
92   G_OBJECT_CLASS (klass)->finalize = gst_gl_display_egl_finalize;
93 }
94 
95 static void
gst_gl_display_egl_init(GstGLDisplayEGL * display_egl)96 gst_gl_display_egl_init (GstGLDisplayEGL * display_egl)
97 {
98   GstGLDisplay *display = (GstGLDisplay *) display_egl;
99 
100   display->type = GST_GL_DISPLAY_TYPE_EGL;
101   display_egl->foreign_display = FALSE;
102 
103   gst_gl_memory_egl_init_once ();
104 }
105 
106 static void
gst_gl_display_egl_finalize(GObject * object)107 gst_gl_display_egl_finalize (GObject * object)
108 {
109   GstGLDisplayEGL *display_egl = GST_GL_DISPLAY_EGL (object);
110 
111   if (display_egl->display && !display_egl->foreign_display) {
112     eglTerminate (display_egl->display);
113     display_egl->display = NULL;
114   }
115 
116   G_OBJECT_CLASS (gst_gl_display_egl_parent_class)->finalize (object);
117 }
118 
119 /**
120  * gst_gl_display_egl_get_from_native:
121  * @type: a #GstGLDisplayType
122  * @display: pointer to a display (or 0)
123  *
124  * Attempts to create a new `EGLDisplay` from @display.  If @type is
125  * %GST_GL_DISPLAY_TYPE_ANY, then @display must be 0. @type must not be
126  * %GST_GL_DISPLAY_TYPE_NONE.
127  *
128  * Returns: A `EGLDisplay` or `EGL_NO_DISPLAY`
129  *
130  * Since: 1.12
131  */
132 gpointer
gst_gl_display_egl_get_from_native(GstGLDisplayType type,guintptr display)133 gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display)
134 {
135   const gchar *egl_exts;
136   EGLDisplay ret = EGL_NO_DISPLAY;
137   _gst_eglGetPlatformDisplay_type _gst_eglGetPlatformDisplay = NULL;
138 
139   g_return_val_if_fail (type != GST_GL_DISPLAY_TYPE_NONE, EGL_NO_DISPLAY);
140   g_return_val_if_fail ((type != GST_GL_DISPLAY_TYPE_ANY && display != 0)
141       || (type == GST_GL_DISPLAY_TYPE_ANY && display == 0), EGL_NO_DISPLAY);
142 
143   init_debug ();
144 
145   /* given an EGLDisplay already */
146   if (type == GST_GL_DISPLAY_TYPE_EGL)
147     return (gpointer) display;
148 
149   egl_exts = eglQueryString (EGL_NO_DISPLAY, EGL_EXTENSIONS);
150   GST_DEBUG ("egl no display extensions: %s", egl_exts);
151 
152   if (eglGetError () != EGL_SUCCESS || !egl_exts)
153     goto default_display;
154 
155   /* check if we can actually choose the egl display type */
156   if (!gst_gl_check_extension ("EGL_KHR_client_get_all_proc_addresses",
157           egl_exts))
158     goto default_display;
159   if (!gst_gl_check_extension ("EGL_EXT_platform_base", egl_exts))
160     goto default_display;
161 
162   /* we need EXT for WinRT to pass attributes */
163 #if !GST_GL_HAVE_WINDOW_WINRT
164   _gst_eglGetPlatformDisplay = (_gst_eglGetPlatformDisplay_type)
165       eglGetProcAddress ("eglGetPlatformDisplay");
166 #endif
167   if (!_gst_eglGetPlatformDisplay)
168     _gst_eglGetPlatformDisplay = (_gst_eglGetPlatformDisplay_type)
169         eglGetProcAddress ("eglGetPlatformDisplayEXT");
170   if (!_gst_eglGetPlatformDisplay)
171     goto default_display;
172 
173   /* try each platform in turn */
174 #if GST_GL_HAVE_WINDOW_X11
175   if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_X11) &&
176       (gst_gl_check_extension ("EGL_KHR_platform_x11", egl_exts) ||
177           gst_gl_check_extension ("EGL_EXT_platform_x11", egl_exts))) {
178     ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_X11, (gpointer) display,
179         NULL);
180   }
181 #endif
182 #if GST_GL_HAVE_WINDOW_WAYLAND
183   if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_WAYLAND) &&
184       (gst_gl_check_extension ("EGL_KHR_platform_wayland", egl_exts) ||
185           gst_gl_check_extension ("EGL_EXT_platform_wayland", egl_exts))) {
186     ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_WAYLAND, (gpointer) display,
187         NULL);
188   }
189 #endif
190 #if GST_GL_HAVE_WINDOW_GBM
191   if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_GBM) &&
192       (gst_gl_check_extension ("EGL_MESA_platform_gbm", egl_exts) ||
193           gst_gl_check_extension ("EGL_KHR_platform_gbm", egl_exts))) {
194     ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_GBM_MESA, (gpointer) display,
195         NULL);
196   }
197 #endif
198 #if GST_GL_HAVE_WINDOW_WINRT
199   if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_EGL) &&
200       (gst_gl_check_extension ("EGL_ANGLE_platform_angle", egl_exts) ||
201           gst_gl_check_extension ("EGL_ANGLE_platform_angle", egl_exts))) {
202     const EGLint attrs[] = {
203       /* These are the default display attributes, used to request ANGLE's
204        * D3D11 renderer. eglInitialize will only succeed with these
205        * attributes if the hardware supports D3D11 Feature Level 10_0+. */
206       EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
207 
208 #ifdef EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER
209       /* EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization
210        * that can have large performance benefits on mobile devices. Its
211        * syntax is subject to change, though. Please update your Visual
212        * Studio templates if you experience compilation issues with it. */
213       EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
214 #endif
215 
216       /* EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that
217        * enables ANGLE to automatically call the IDXGIDevice3::Trim method
218        * on behalf of the application when it gets suspended. Calling
219        * IDXGIDevice3::Trim when an application is suspended is a Windows
220        * Store application certification requirement. */
221       EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
222       EGL_NONE,
223     };
224     ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_ANGLE_ANGLE,
225         (gpointer) display, attrs);
226   }
227 #endif
228   if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_EGL_DEVICE) &&
229       (gst_gl_check_extension ("EGL_EXT_device_base", egl_exts) &&
230           gst_gl_check_extension ("EGL_EXT_platform_device", egl_exts))) {
231     ret =
232         _gst_eglGetPlatformDisplay (EGL_PLATFORM_DEVICE_EXT, (gpointer) display,
233         NULL);
234   }
235   /* android only has one winsys/display connection */
236 
237   if (ret != EGL_NO_DISPLAY)
238     return ret;
239 
240   /* otherwise rely on the implementation to choose the correct display
241    * based on the pointer */
242 default_display:
243   return (gpointer) eglGetDisplay ((EGLNativeDisplayType) display);
244 }
245 
246 /**
247  * gst_gl_display_egl_new:
248  *
249  * Create a new #GstGLDisplayEGL using the default EGL_DEFAULT_DISPLAY.
250  *
251  * Returns: (transfer full): a new #GstGLDisplayEGL or %NULL
252  */
253 GstGLDisplayEGL *
gst_gl_display_egl_new(void)254 gst_gl_display_egl_new (void)
255 {
256   GstGLDisplayEGL *ret;
257 
258   init_debug ();
259 
260   ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL);
261   gst_object_ref_sink (ret);
262   ret->display =
263       gst_gl_display_egl_get_from_native (GST_GL_DISPLAY_TYPE_ANY, 0);
264 
265   if (!ret->display) {
266     GST_INFO ("Failed to open EGL display connection");
267   }
268 
269   return ret;
270 }
271 
272 /**
273  * gst_gl_display_egl_new_with_display:
274  * @display: an existing and connected EGLDisplay
275  *
276  * Creates a new display connection from a EGLDisplay.
277  *
278  * Returns: (transfer full): a new #GstGLDisplayEGL
279  *
280  * Since: 1.12
281  */
282 GstGLDisplayEGL *
gst_gl_display_egl_new_with_egl_display(gpointer display)283 gst_gl_display_egl_new_with_egl_display (gpointer display)
284 {
285   GstGLDisplayEGL *ret;
286 
287   g_return_val_if_fail (display != NULL, NULL);
288 
289   init_debug ();
290 
291   ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL);
292   gst_object_ref_sink (ret);
293 
294   ret->display = display;
295   ret->foreign_display = TRUE;
296 
297   return ret;
298 }
299 
300 static gpointer
_ref_if_set(gpointer data,gpointer user_data)301 _ref_if_set (gpointer data, gpointer user_data)
302 {
303   if (data)
304     gst_object_ref (data);
305   return data;
306 }
307 
308 /**
309  * gst_gl_display_egl_from_gl_display:
310  * @display: (transfer none): an existing #GstGLDisplay
311  *
312  * Creates a EGL display connection from a native Display.
313  *
314  * This function will return the same value for multiple calls with the same
315  * @display.
316  *
317  * Returns: (transfer full): a new #GstGLDisplayEGL
318  *
319  * Since: 1.12
320  */
321 GstGLDisplayEGL *
gst_gl_display_egl_from_gl_display(GstGLDisplay * display)322 gst_gl_display_egl_from_gl_display (GstGLDisplay * display)
323 {
324   GstGLDisplayEGL *ret;
325   GstGLDisplayType display_type;
326   guintptr native_display;
327 
328   g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
329 
330   init_debug ();
331 
332   if (GST_IS_GL_DISPLAY_EGL (display)) {
333     GST_LOG_OBJECT (display, "display %" GST_PTR_FORMAT "is already a "
334         "GstGLDisplayEGL", display);
335     return gst_object_ref (display);
336   }
337 
338   /* try to get a previously set GstGLDisplayEGL */
339   ret = g_object_dup_data (G_OBJECT (display), GST_GL_DISPLAY_EGL_NAME,
340       (GDuplicateFunc) _ref_if_set, NULL);
341   if (ret && GST_IS_GL_DISPLAY_EGL (ret)) {
342     GST_LOG_OBJECT (display, "display %" GST_PTR_FORMAT "already has a "
343         "GstGLDisplayEGL %" GST_PTR_FORMAT, display, ret);
344     return ret;
345   }
346 
347   if (ret)
348     gst_object_unref (ret);
349 
350   display_type = gst_gl_display_get_handle_type (display);
351   native_display = gst_gl_display_get_handle (display);
352 
353   g_return_val_if_fail (native_display != 0, NULL);
354   g_return_val_if_fail (display_type != GST_GL_DISPLAY_TYPE_NONE, NULL);
355 
356   ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL);
357   gst_object_ref_sink (ret);
358 
359   ret->display =
360       gst_gl_display_egl_get_from_native (display_type, native_display);
361 
362   if (!ret->display) {
363     GST_WARNING_OBJECT (ret, "failed to get EGLDisplay from native display");
364     gst_object_unref (ret);
365     return NULL;
366   }
367   g_object_set_data_full (G_OBJECT (display), GST_GL_DISPLAY_EGL_NAME,
368       gst_object_ref (ret), (GDestroyNotify) gst_object_unref);
369 
370   return ret;
371 }
372 
373 static guintptr
gst_gl_display_egl_get_handle(GstGLDisplay * display)374 gst_gl_display_egl_get_handle (GstGLDisplay * display)
375 {
376   return (guintptr) GST_GL_DISPLAY_EGL (display)->display;
377 }
378