Skip to content

Commit

Permalink
gstgl: Add a new window type for WinRT
Browse files Browse the repository at this point in the history
This is needed for using GstGL with ANGLE as the GLES implementation
in Universal Windows Platform apps that use the Windows Runtime
(WinRT) instead of Win32, which is deprecated and not allowed in
Windows Store apps.

This has been tested with Servo on the Microsoft HoloLens 2, and seems
to work quite well.
  • Loading branch information
nirbheek committed Aug 27, 2019
1 parent 97426fd commit 564ab30
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 9 deletions.
25 changes: 23 additions & 2 deletions gst-libs/gst/gl/egl/gstglcontext_egl.c
Expand Up @@ -804,11 +804,22 @@ gst_gl_context_egl_create_context (GstGLContext * context,
window_handle = gst_gl_window_get_window_handle (window);

if (window_handle) {
#if GST_GL_HAVE_WINDOW_WINRT
const EGLint attrs[] = {
/* EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is an optimization that can
* have large performance benefits on mobile devices. */
EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
EGL_NONE
};
#else
const EGLint *attrs = NULL;
#endif

GST_DEBUG ("Creating EGLSurface from window_handle %p",
(void *) window_handle);
egl->egl_surface =
eglCreateWindowSurface (egl->egl_display, egl->egl_config,
(EGLNativeWindowType) window_handle, NULL);
(EGLNativeWindowType) window_handle, attrs);
/* Store window handle for later comparision */
egl->window_handle = window_handle;
} else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context",
Expand Down Expand Up @@ -906,6 +917,16 @@ gst_gl_context_egl_activate (GstGLContext * context, gboolean activate)
gst_object_unref (window);
}
if (handle && handle != egl->window_handle) {
#if GST_GL_HAVE_WINDOW_WINRT
const EGLint attrs[] = {
/* EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is an optimization that can
* have large performance benefits on mobile devices. */
EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
EGL_NONE
};
#else
const EGLint *attrs = NULL;
#endif
GST_DEBUG_OBJECT (context,
"Handle changed (have:%p, now:%p), switching surface",
(void *) egl->window_handle, (void *) handle);
Expand All @@ -920,7 +941,7 @@ gst_gl_context_egl_activate (GstGLContext * context, gboolean activate)
}
egl->egl_surface =
eglCreateWindowSurface (egl->egl_display, egl->egl_config,
(EGLNativeWindowType) handle, NULL);
(EGLNativeWindowType) handle, attrs);
egl->window_handle = handle;

if (egl->egl_surface == EGL_NO_SURFACE) {
Expand Down
37 changes: 35 additions & 2 deletions gst-libs/gst/gl/egl/gstgldisplay_egl.c
Expand Up @@ -59,6 +59,9 @@ GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug);
#ifndef EGL_PLATFORM_DEVICE_EXT
#define EGL_PLATFORM_DEVICE_EXT 0x313F
#endif
#ifndef EGL_PLATFORM_ANGLE_ANGLE
#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
#endif

typedef EGLDisplay (*_gst_eglGetPlatformDisplay_type) (EGLenum platform,
void *native_display, const EGLint * attrib_list);
Expand Down Expand Up @@ -122,7 +125,7 @@ gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display)
{
const gchar *egl_exts;
EGLDisplay ret = EGL_NO_DISPLAY;
_gst_eglGetPlatformDisplay_type _gst_eglGetPlatformDisplay;
_gst_eglGetPlatformDisplay_type _gst_eglGetPlatformDisplay = NULL;

g_return_val_if_fail (type != GST_GL_DISPLAY_TYPE_NONE, EGL_NO_DISPLAY);
g_return_val_if_fail ((type != GST_GL_DISPLAY_TYPE_ANY && display != 0)
Expand All @@ -147,8 +150,11 @@ gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display)
if (!gst_gl_check_extension ("EGL_EXT_platform_base", egl_exts))
goto default_display;

/* we need EXT for WinRT to pass attributes */
#if !GST_GL_HAVE_WINDOW_WINRT
_gst_eglGetPlatformDisplay = (_gst_eglGetPlatformDisplay_type)
eglGetProcAddress ("eglGetPlatformDisplay");
#endif
if (!_gst_eglGetPlatformDisplay)
_gst_eglGetPlatformDisplay = (_gst_eglGetPlatformDisplay_type)
eglGetProcAddress ("eglGetPlatformDisplayEXT");
Expand Down Expand Up @@ -179,6 +185,34 @@ gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display)
ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_GBM_MESA, (gpointer) display,
NULL);
}
#endif
#if GST_GL_HAVE_WINDOW_WINRT
if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_EGL) &&
(gst_gl_check_extension ("EGL_ANGLE_platform_angle", egl_exts) ||
gst_gl_check_extension ("EGL_ANGLE_platform_angle", egl_exts))) {
const EGLint attrs[] = {
/* These are the default display attributes, used to request ANGLE's
* D3D11 renderer. eglInitialize will only succeed with these
* attributes if the hardware supports D3D11 Feature Level 10_0+. */
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,

/* EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization
* that can have large performance benefits on mobile devices. Its
* syntax is subject to change, though. Please update your Visual
* Studio templates if you experience compilation issues with it. */
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,

/* EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that
* enables ANGLE to automatically call the IDXGIDevice3::Trim method
* on behalf of the application when it gets suspended. Calling
* IDXGIDevice3::Trim when an application is suspended is a Windows
* Store application certification requirement. */
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
EGL_NONE,
};
ret = _gst_eglGetPlatformDisplay (EGL_PLATFORM_ANGLE_ANGLE,
(gpointer) display, attrs);
}
#endif
if (ret == EGL_NO_DISPLAY && (type & GST_GL_DISPLAY_TYPE_EGL_DEVICE) &&
(gst_gl_check_extension ("EGL_EXT_device_base", egl_exts) &&
Expand All @@ -187,7 +221,6 @@ gst_gl_display_egl_get_from_native (GstGLDisplayType type, guintptr display)
_gst_eglGetPlatformDisplay (EGL_PLATFORM_DEVICE_EXT, (gpointer) display,
NULL);
}

/* android only has one winsys/display connection */

if (ret != EGL_NO_DISPLAY)
Expand Down
3 changes: 1 addition & 2 deletions gst-libs/gst/gl/gstglconfig.h.meson
@@ -1,6 +1,4 @@
/* gstglconfig.h
*
* This is a generated file. Please modify `configure.ac'
*/

#ifndef __GST_GL_CONFIG_H__
Expand All @@ -19,6 +17,7 @@ G_BEGIN_DECLS
#mesondefine GST_GL_HAVE_WINDOW_X11
#mesondefine GST_GL_HAVE_WINDOW_COCOA
#mesondefine GST_GL_HAVE_WINDOW_WIN32
#mesondefine GST_GL_HAVE_WINDOW_WINRT
#mesondefine GST_GL_HAVE_WINDOW_WAYLAND
#mesondefine GST_GL_HAVE_WINDOW_ANDROID
#mesondefine GST_GL_HAVE_WINDOW_DISPMANX
Expand Down
7 changes: 7 additions & 0 deletions gst-libs/gst/gl/gstglwindow.c
Expand Up @@ -68,6 +68,9 @@
#if GST_GL_HAVE_WINDOW_DISPMANX
#include "dispmanx/gstglwindow_dispmanx_egl.h"
#endif
#if GST_GL_HAVE_WINDOW_WINRT
#include "winrt/gstglwindow_winrt_egl.h"
#endif

#define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
#define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
Expand Down Expand Up @@ -290,6 +293,10 @@ gst_gl_window_new (GstGLDisplay * display)
if (!window && (!user_choice || g_strstr_len (user_choice, 3, "gbm")))
window = GST_GL_WINDOW (gst_gl_window_gbm_egl_new (display));
#endif
#if GST_GL_HAVE_WINDOW_WINRT
if (!window && (!user_choice || g_strstr_len (user_choice, 5, "winrt")))
window = GST_GL_WINDOW (gst_gl_window_winrt_egl_new (display));
#endif

if (!window) {
/* subclass returned a NULL window */
Expand Down
32 changes: 31 additions & 1 deletion gst-libs/gst/gl/meson.build
Expand Up @@ -112,6 +112,7 @@ glconf_options = [
'GST_GL_HAVE_WINDOW_X11',
'GST_GL_HAVE_WINDOW_COCOA',
'GST_GL_HAVE_WINDOW_WIN32',
'GST_GL_HAVE_WINDOW_WINRT',
'GST_GL_HAVE_WINDOW_WAYLAND',
'GST_GL_HAVE_WINDOW_ANDROID',
'GST_GL_HAVE_WINDOW_DISPMANX',
Expand Down Expand Up @@ -232,6 +233,7 @@ if gl_winsys.contains('auto')
need_win_x11 = 'auto'
need_win_wayland = 'auto'
need_win_win32 = 'auto'
need_win_winrt = 'auto'
need_win_cocoa = 'auto'
need_win_eagl = 'auto'
need_win_dispmanx = 'auto'
Expand All @@ -242,6 +244,7 @@ else
need_win_x11 = 'no'
need_win_wayland = 'no'
need_win_win32 = 'no'
need_win_winrt = 'no'
need_win_cocoa = 'no'
need_win_eagl = 'no'
need_win_dispmanx = 'no'
Expand All @@ -255,6 +258,8 @@ else
need_win_wayland = 'yes'
elif winsys == 'win32'
need_win_win32 = 'yes'
elif winsys == 'winrt'
need_win_winrt = 'yes'
elif winsys == 'cocoa'
need_win_cocoa = 'yes'
elif winsys == 'eagl'
Expand Down Expand Up @@ -655,7 +660,6 @@ endif

if need_platform_wgl != 'no' and need_win_win32 != 'no'
gdi_dep = cc.find_library('gdi32', required : false)
# FIXME: Revert back to has_header once it gains prefix support
wglext_h = cc.has_header('GL/wglext.h',
prefix : '''#include <windows.h>
#include <GL/gl.h>''',
Expand All @@ -677,6 +681,32 @@ if need_platform_wgl != 'no' and need_win_win32 != 'no'
endif
endif

# WinRT ANGLE checks
if need_win_winrt != 'no' and host_system == 'windows'
if need_win_winrt == 'yes' and not enabled_gl_platforms.contains('egl')
error('Impossible situation requested: Cannot use WinRT ANGLE without EGL support')
endif

if egl_dep.found()
windows_graphics_h = cc.has_header('windows.graphics.h')
windows_app_dep = cc.find_library('WindowsApp', required: false)

if windows_graphics_h and windows_app_dep.found()
enabled_gl_winsys += 'winrt'
glconf.set10('GST_GL_HAVE_WINDOW_WINRT', 1)
gl_sources += [
'winrt/gstglwindow_winrt_egl.c'
]
elif need_win_winrt == 'yes'
error('WinRT is enabled, but headers/libraries were not found')
endif
elif need_win_winrt == 'yes'
error('WinRT ANGLE is enabled, but EGL was not found')
else
message('WinRT ANGLE disabled because EGL was not found')
endif
endif

if ['darwin', 'ios'].contains(host_system)
if not have_objc
error('No ObjC compiler found')
Expand Down
108 changes: 108 additions & 0 deletions gst-libs/gst/gl/winrt/gstglwindow_winrt_egl.c
@@ -0,0 +1,108 @@
/*
* GStreamer
* Copyright (C) 2019 Nirbheek Chauhan <nirbheek@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gst/gl/gstglcontext.h>
#include <gst/gl/egl/gstglcontext_egl.h>

#include "gstglwindow_winrt_egl.h"
#include "../gstglwindow_private.h"

#define GST_CAT_DEFAULT gst_gl_window_debug

#define GST_GL_WINDOW_WINRT_EGL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
GST_TYPE_GL_WINDOW_WINRT_EGL, GstGLWindowWinRTEGLPrivate))


G_DEFINE_TYPE (GstGLWindowWinRTEGL, gst_gl_window_winrt_egl,
GST_TYPE_GL_WINDOW);

static guintptr gst_gl_window_winrt_egl_get_display (GstGLWindow * window);
static guintptr gst_gl_window_winrt_egl_get_window_handle (GstGLWindow *
window);
static void gst_gl_window_winrt_egl_set_window_handle (GstGLWindow * window,
guintptr handle);

static void
gst_gl_window_winrt_egl_class_init (GstGLWindowWinRTEGLClass * klass)
{
GstGLWindowClass *window_class = (GstGLWindowClass *) klass;

window_class->get_display =
GST_DEBUG_FUNCPTR (gst_gl_window_winrt_egl_get_display);
window_class->get_window_handle =
GST_DEBUG_FUNCPTR (gst_gl_window_winrt_egl_get_window_handle);
window_class->set_window_handle =
GST_DEBUG_FUNCPTR (gst_gl_window_winrt_egl_set_window_handle);
}

static void
gst_gl_window_winrt_egl_init (GstGLWindowWinRTEGL * window_winrt)
{
}

static void
gst_gl_window_winrt_egl_set_window_handle (GstGLWindow * window,
guintptr handle)
{
GstGLWindowWinRTEGL *window_egl = GST_GL_WINDOW_WINRT_EGL (window);

GST_INFO_OBJECT (window, "Setting WinRT EGL window handle: %p", handle);

window_egl->window = (EGLNativeWindowType) handle;
}

static guintptr
gst_gl_window_winrt_egl_get_window_handle (GstGLWindow * window)
{
GstGLWindowWinRTEGL *window_egl = GST_GL_WINDOW_WINRT_EGL (window);

GST_INFO_OBJECT (window, "Getting WinRT EGL window handle");

return (guintptr) window_egl->window;
}

/* Must be called in the gl thread */
GstGLWindowWinRTEGL *
gst_gl_window_winrt_egl_new (GstGLDisplay * display)
{
GstGLWindowWinRTEGL *window_egl;

GST_INFO_OBJECT (display, "Trying to create WinRT EGL window");

if ((gst_gl_display_get_handle_type (display) & GST_GL_DISPLAY_TYPE_EGL) == 0)
/* we require an EGL display to create windows */
return NULL;

GST_INFO_OBJECT (display, "Creating WinRT EGL window");

window_egl = g_object_new (GST_TYPE_GL_WINDOW_WINRT_EGL, NULL);

return window_egl;
}

static guintptr
gst_gl_window_winrt_egl_get_display (GstGLWindow * window)
{
/* EGL_DEFAULT_DISPLAY */
return 0;
}

0 comments on commit 564ab30

Please sign in to comment.