From 0bcc254e4f050baa893a387a846273aa941c39c4 Mon Sep 17 00:00:00 2001 From: David Ludwig Date: Sun, 2 Nov 2014 08:47:05 -0500 Subject: [PATCH] WinRT: expanded OpenGL ES 2 support to enable recent updates to ANGLE/WinRT ANGLE for WinRT has at least two versions: - an older version, which supports Windows 8.0 and 8.1. This is currently the "winrt" branch in MSOpenTech's ANGLE repository (at https://github.com/msopentech/angle) - a newer version, which drops support for Windows 8.0, but is under more active development (via MSOpenTech's "future-dev" branch), and which was recently merged into the ANGLE project's official "master" branch (at https://chromium.googlesource.com/angle/angle) Both versions are setup using slightly different APIs. SDL/WinRT will now attempt to detect which version is being used, and configure it appropriately. --- src/video/winrt/SDL_winrtopengles.cpp | 77 ++++++++++++++++++--------- src/video/winrt/SDL_winrtopengles.h | 18 ++++--- src/video/winrt/SDL_winrtvideo.cpp | 34 +++++++++--- 3 files changed, 90 insertions(+), 39 deletions(-) diff --git a/src/video/winrt/SDL_winrtopengles.cpp b/src/video/winrt/SDL_winrtopengles.cpp index 4a84174d0c114..e3a955be1a60a 100644 --- a/src/video/winrt/SDL_winrtopengles.cpp +++ b/src/video/winrt/SDL_winrtopengles.cpp @@ -36,7 +36,10 @@ using namespace Windows::UI::Core; /* ANGLE/WinRT constants */ static const int ANGLE_D3D_FEATURE_LEVEL_ANY = 0; - +#define EGL_PLATFORM_ANGLE_ANGLE 0x3201 +#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202 +#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3203 +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3205 /* * SDL/EGL top-level implementation @@ -52,32 +55,56 @@ WINRT_GLES_LoadLibrary(_THIS, const char *path) } /* Load ANGLE/WinRT-specific functions */ - CreateWinrtEglWindow_Function CreateWinrtEglWindow = (CreateWinrtEglWindow_Function) SDL_LoadFunction(_this->egl_data->egl_dll_handle, "CreateWinrtEglWindow"); - if (!CreateWinrtEglWindow) { - return SDL_SetError("Could not retrieve ANGLE/WinRT function CreateWinrtEglWindow"); + CreateWinrtEglWindow_Old_Function CreateWinrtEglWindow = (CreateWinrtEglWindow_Old_Function) SDL_LoadFunction(_this->egl_data->egl_dll_handle, "CreateWinrtEglWindow"); + if (CreateWinrtEglWindow) { + /* 'CreateWinrtEglWindow' was found, which means that an an older + * version of ANGLE/WinRT is being used. Continue setting up EGL, + * as appropriate to this version of ANGLE. + */ + + /* Create an ANGLE/WinRT EGL-window */ + /* TODO, WinRT: check for XAML usage before accessing the CoreWindow, as not doing so could lead to a crash */ + CoreWindow ^ native_win = CoreWindow::GetForCurrentThread(); + Microsoft::WRL::ComPtr cpp_win = reinterpret_cast(native_win); + HRESULT result = CreateWinrtEglWindow(cpp_win, ANGLE_D3D_FEATURE_LEVEL_ANY, &(video_data->winrtEglWindow)); + if (FAILED(result)) { + return -1; + } + + /* Call eglGetDisplay and eglInitialize as appropriate. On other + * platforms, this would probably get done by SDL_EGL_LoadLibrary, + * however ANGLE/WinRT's current implementation (as of Mar 22, 2014) of + * eglGetDisplay requires that a C++ object be passed into it, so the + * call will be made in this file, a C++ file, instead. + */ + Microsoft::WRL::ComPtr cpp_display = video_data->winrtEglWindow; + _this->egl_data->egl_display = ((eglGetDisplay_Old_Function)_this->egl_data->eglGetDisplay)(cpp_display); + if (!_this->egl_data->egl_display) { + return SDL_SetError("Could not get EGL display"); + } + } else { + const EGLint displayAttributes[] = { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_NONE, + }; + + /* 'CreateWinrtEglWindow' was NOT found, which either means that a + * newer version of ANGLE/WinRT is being used, or that we don't have + * a valid copy of ANGLE. + * + * Try loading ANGLE as if it were the newer version. + */ + eglGetPlatformDisplayEXT_Function eglGetPlatformDisplayEXT = (eglGetPlatformDisplayEXT_Function)_this->egl_data->eglGetProcAddress("eglGetPlatformDisplayEXT"); + if (!eglGetPlatformDisplayEXT) { + return SDL_SetError("Could not retrieve ANGLE/WinRT display function(s)"); + } + + _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes); + if (!_this->egl_data->egl_display) { + return SDL_SetError("Could not get EGL display"); + } } - /* Create an ANGLE/WinRT EGL-window */ - /* TODO, WinRT: check for XAML usage before accessing the CoreWindow, as not doing so could lead to a crash */ - CoreWindow ^ native_win = CoreWindow::GetForCurrentThread(); - Microsoft::WRL::ComPtr cpp_win = reinterpret_cast(native_win); - HRESULT result = CreateWinrtEglWindow(cpp_win, ANGLE_D3D_FEATURE_LEVEL_ANY, &(video_data->winrtEglWindow)); - if (FAILED(result)) { - return -1; - } - - /* Call eglGetDisplay and eglInitialize as appropriate. On other - * platforms, this would probably get done by SDL_EGL_LoadLibrary, - * however ANGLE/WinRT's current implementation (as of Mar 22, 2014) of - * eglGetDisplay requires that a C++ object be passed into it, so the - * call will be made in this file, a C++ file, instead. - */ - Microsoft::WRL::ComPtr cpp_display = video_data->winrtEglWindow; - _this->egl_data->egl_display = ((eglGetDisplay_Function)_this->egl_data->eglGetDisplay)(cpp_display); - if (!_this->egl_data->egl_display) { - return SDL_SetError("Could not get EGL display"); - } - if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { return SDL_SetError("Could not initialize EGL"); } diff --git a/src/video/winrt/SDL_winrtopengles.h b/src/video/winrt/SDL_winrtopengles.h index ae17391712fb4..f090f9b262de4 100644 --- a/src/video/winrt/SDL_winrtopengles.h +++ b/src/video/winrt/SDL_winrtopengles.h @@ -47,18 +47,22 @@ extern int WINRT_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext cont /* Typedefs for ANGLE/WinRT's C++-based native-display and native-window types, * which are used when calling eglGetDisplay and eglCreateWindowSurface. */ -typedef Microsoft::WRL::ComPtr WINRT_EGLNativeWindowType; -typedef WINRT_EGLNativeWindowType WINRT_EGLNativeDisplayType; +typedef Microsoft::WRL::ComPtr WINRT_EGLNativeWindowType_Old; -/* Function pointer typedefs for ANGLE/WinRT's functions that require - * parameter customization [by passing in C++ objects]. +/* Function pointer typedefs for 'old' ANGLE/WinRT's functions, which may + * require that C++ objects be passed in: */ -typedef EGLDisplay (EGLAPIENTRY *eglGetDisplay_Function)(WINRT_EGLNativeWindowType); -typedef EGLSurface (EGLAPIENTRY *eglCreateWindowSurface_Function)(EGLDisplay, EGLConfig, WINRT_EGLNativeWindowType, const EGLint *); -typedef HRESULT (EGLAPIENTRY *CreateWinrtEglWindow_Function)(Microsoft::WRL::ComPtr, int, IUnknown ** result); +typedef EGLDisplay (EGLAPIENTRY *eglGetDisplay_Old_Function)(WINRT_EGLNativeWindowType_Old); +typedef EGLSurface (EGLAPIENTRY *eglCreateWindowSurface_Old_Function)(EGLDisplay, EGLConfig, WINRT_EGLNativeWindowType_Old, const EGLint *); +typedef HRESULT (EGLAPIENTRY *CreateWinrtEglWindow_Old_Function)(Microsoft::WRL::ComPtr, int, IUnknown ** result); #endif /* __cplusplus */ +/* Function pointer typedefs for 'new' ANGLE/WinRT functions, which, unlike + * the old functions, do not require C++ support and work with plain C. + */ +typedef EGLDisplay (EGLAPIENTRY *eglGetPlatformDisplayEXT_Function)(EGLenum, void *, const EGLint *); + #endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */ #endif /* _SDL_winrtopengles_h */ diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp index 6ec01609a76cd..b58c9e2359e78 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -328,13 +328,33 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) return SDL_SetError(buf); } - Microsoft::WRL::ComPtr cpp_winrtEglWindow = video_data->winrtEglWindow; - data->egl_surface = ((eglCreateWindowSurface_Function)_this->egl_data->eglCreateWindowSurface)( - _this->egl_data->egl_display, - _this->egl_data->egl_config, - cpp_winrtEglWindow, NULL); - if (data->egl_surface == NULL) { - return SDL_SetError("eglCreateWindowSurface failed"); + if (video_data->winrtEglWindow) { /* ... is the 'old' version of ANGLE/WinRT being used? */ + /* Attempt to create a window surface using older versions of + * ANGLE/WinRT: + */ + Microsoft::WRL::ComPtr cpp_winrtEglWindow = video_data->winrtEglWindow; + data->egl_surface = ((eglCreateWindowSurface_Old_Function)_this->egl_data->eglCreateWindowSurface)( + _this->egl_data->egl_display, + _this->egl_data->egl_config, + cpp_winrtEglWindow, NULL); + if (data->egl_surface == NULL) { + return SDL_SetError("eglCreateWindowSurface failed"); + } + } else if (data->coreWindow.Get() != nullptr) { + /* Attempt to create a window surface using newer versions of + * ANGLE/WinRT: + */ + IInspectable * coreWindowAsIInspectable = reinterpret_cast(data->coreWindow.Get()); + data->egl_surface = _this->egl_data->eglCreateWindowSurface( + _this->egl_data->egl_display, + _this->egl_data->egl_config, + coreWindowAsIInspectable, + NULL); + if (data->egl_surface == NULL) { + return SDL_SetError("eglCreateWindowSurface failed"); + } + } else { + return SDL_SetError("No supported means to create an EGL window surface are available"); } } #endif