3 * Copyright (C) 2014 Matthew Waters <ystreet00@gmail.com>
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.
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.
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.
22 * SECTION:gstgldisplay_egl
23 * @short_description: EGL Display connection
24 * @title: GstGLDisplayEGL
25 * @see_also: #GstGLDisplay
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())
36 #include "gstgldisplay_egl.h"
38 #include <gst/gl/gstglfeature.h>
41 #include "gsteglimage.h"
42 #include "gstglmemoryegl.h"
44 GST_DEBUG_CATEGORY_STATIC (gst_gl_display_egl_debug);
45 #define GST_CAT_DEFAULT gst_gl_display_egl_debug
47 #ifndef EGL_PLATFORM_X11
48 #define EGL_PLATFORM_X11 0x31D5
50 #ifndef EGL_PLATFORM_WAYLAND
51 #define EGL_PLATFORM_WAYLAND 0x31D8
53 #ifndef EGL_PLATFORM_GBM_MESA
54 #define EGL_PLATFORM_GBM_MESA 0x31D7
56 #ifndef EGL_PLATFORM_ANDROID
57 #define EGL_PLATFORM_ANDROID 0x3141
59 #ifndef EGL_PLATFORM_DEVICE_EXT
60 #define EGL_PLATFORM_DEVICE_EXT 0x313F
62 #ifndef EGL_PLATFORM_ANGLE_ANGLE
63 #define EGL_PLATFORM_ANGLE_ANGLE 0x3202
66 typedef EGLDisplay (*_gst_eglGetPlatformDisplay_type) (EGLenum platform,
67 void *native_display, const EGLint * attrib_list);
69 G_DEFINE_TYPE (GstGLDisplayEGL, gst_gl_display_egl, GST_TYPE_GL_DISPLAY);
71 static void gst_gl_display_egl_finalize (GObject * object);
72 static guintptr gst_gl_display_egl_get_handle (GstGLDisplay * display);
77 static volatile gsize _init = 0;
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);
87 gst_gl_display_egl_class_init (GstGLDisplayEGLClass * klass)
89 GST_GL_DISPLAY_CLASS (klass)->get_handle =
90 GST_DEBUG_FUNCPTR (gst_gl_display_egl_get_handle);
92 G_OBJECT_CLASS (klass)->finalize = gst_gl_display_egl_finalize;
96 gst_gl_display_egl_init (GstGLDisplayEGL * display_egl)
98 GstGLDisplay *display = (GstGLDisplay *) display_egl;
100 display->type = GST_GL_DISPLAY_TYPE_EGL;
101 display_egl->foreign_display = FALSE;
103 gst_gl_memory_egl_init_once ();
107 gst_gl_display_egl_finalize (GObject * object)
109 GstGLDisplayEGL *display_egl = GST_GL_DISPLAY_EGL (object);
111 if (display_egl->display && !display_egl->foreign_display) {
112 eglTerminate (display_egl->display);
113 display_egl->display = NULL;
116 G_OBJECT_CLASS (gst_gl_display_egl_parent_class)->finalize (object);
120 * gst_gl_display_egl_get_from_native:
121 * @type: a #GstGLDisplayType
122 * @display: pointer to a display (or 0)
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.
128 * Returns: A `EGLDisplay` or `EGL_NO_DISPLAY`
133 gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display)
135 const gchar *egl_exts;
136 EGLDisplay ret = EGL_NO_DISPLAY;
137 _gst_eglGetPlatformDisplay_type _gst_eglGetPlatformDisplay = NULL;
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);
145 /* given an EGLDisplay already */
146 if (type == GST_GL_DISPLAY_TYPE_EGL)
147 return (gpointer) display;
149 egl_exts = eglQueryString (EGL_NO_DISPLAY, EGL_EXTENSIONS);
150 GST_DEBUG ("egl no display extensions: %s", egl_exts);
152 if (eglGetError () != EGL_SUCCESS || !egl_exts)
153 goto default_display;
155 /* check if we can actually choose the egl display type */
156 if (!gst_gl_check_extension ("EGL_KHR_client_get_all_proc_addresses",
158 goto default_display;
159 if (!gst_gl_check_extension ("EGL_EXT_platform_base", egl_exts))
160 goto default_display;
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");
167 if (!_gst_eglGetPlatformDisplay)
168 _gst_eglGetPlatformDisplay = (_gst_eglGetPlatformDisplay_type)
169 eglGetProcAddress ("eglGetPlatformDisplayEXT");
170 if (!_gst_eglGetPlatformDisplay)
171 goto default_display;
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,
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,
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,
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,
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,
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,
224 ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_ANGLE_ANGLE,
225 (gpointer) display, attrs);
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))) {
232 _gst_eglGetPlatformDisplay (EGL_PLATFORM_DEVICE_EXT, (gpointer) display,
235 /* android only has one winsys/display connection */
237 if (ret != EGL_NO_DISPLAY)
240 /* otherwise rely on the implementation to choose the correct display
241 * based on the pointer */
243 return (gpointer) eglGetDisplay ((EGLNativeDisplayType) display);
247 * gst_gl_display_egl_new:
249 * Create a new #GstGLDisplayEGL using the default EGL_DEFAULT_DISPLAY.
251 * Returns: (transfer full): a new #GstGLDisplayEGL or %NULL
254 gst_gl_display_egl_new (void)
256 GstGLDisplayEGL *ret;
260 ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL);
261 gst_object_ref_sink (ret);
263 gst_gl_display_egl_get_from_native (GST_GL_DISPLAY_TYPE_ANY, 0);
266 GST_INFO ("Failed to open EGL display connection");
273 * gst_gl_display_egl_new_with_display:
274 * @display: an existing and connected EGLDisplay
276 * Creates a new display connection from a EGLDisplay.
278 * Returns: (transfer full): a new #GstGLDisplayEGL
283 gst_gl_display_egl_new_with_egl_display (gpointer display)
285 GstGLDisplayEGL *ret;
287 g_return_val_if_fail (display != NULL, NULL);
291 ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL);
292 gst_object_ref_sink (ret);
294 ret->display = display;
295 ret->foreign_display = TRUE;
301 _ref_if_set (gpointer data, gpointer user_data)
304 gst_object_ref (data);
309 * gst_gl_display_egl_from_gl_display:
310 * @display: (transfer none): an existing #GstGLDisplay
312 * Creates a EGL display connection from a native Display.
314 * This function will return the same value for multiple calls with the same
317 * Returns: (transfer full): a new #GstGLDisplayEGL
322 gst_gl_display_egl_from_gl_display (GstGLDisplay * display)
324 GstGLDisplayEGL *ret;
325 GstGLDisplayType display_type;
326 guintptr native_display;
328 g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
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);
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);
348 gst_object_unref (ret);
350 display_type = gst_gl_display_get_handle_type (display);
351 native_display = gst_gl_display_get_handle (display);
353 g_return_val_if_fail (native_display != 0, NULL);
354 g_return_val_if_fail (display_type != GST_GL_DISPLAY_TYPE_NONE, NULL);
356 ret = g_object_new (GST_TYPE_GL_DISPLAY_EGL, NULL);
357 gst_object_ref_sink (ret);
360 gst_gl_display_egl_get_from_native (display_type, native_display);
363 GST_WARNING_OBJECT (ret, "failed to get EGLDisplay from native display");
364 gst_object_unref (ret);
367 g_object_set_data_full (G_OBJECT (display), GST_GL_DISPLAY_EGL_NAME,
368 gst_object_ref (ret), (GDestroyNotify) gst_object_unref);
374 gst_gl_display_egl_get_handle (GstGLDisplay * display)
376 return (guintptr) GST_GL_DISPLAY_EGL (display)->display;