WinRT: expanded OpenGL ES 2 support to enable recent updates to ANGLE/WinRT
authorDavid Ludwig <dludwig@pobox.com>
Sun, 02 Nov 2014 08:47:05 -0500
changeset 9211 04c7e1220a65
parent 9210 1486f4f3c67c
child 9212 6b9794bae8ed
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
src/video/winrt/SDL_winrtopengles.h
src/video/winrt/SDL_winrtvideo.cpp
--- a/src/video/winrt/SDL_winrtopengles.cpp	Sat Nov 01 11:41:18 2014 -0400
+++ b/src/video/winrt/SDL_winrtopengles.cpp	Sun Nov 02 08:47:05 2014 -0500
@@ -36,7 +36,10 @@
 
 /* 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 @@
     }
 
     /* 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<IUnknown> cpp_win = reinterpret_cast<IUnknown *>(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<IUnknown> 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<IUnknown> cpp_win = reinterpret_cast<IUnknown *>(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<IUnknown> 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");
     }
--- a/src/video/winrt/SDL_winrtopengles.h	Sat Nov 01 11:41:18 2014 -0400
+++ b/src/video/winrt/SDL_winrtopengles.h	Sun Nov 02 08:47:05 2014 -0500
@@ -47,18 +47,22 @@
 /* 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<IUnknown> WINRT_EGLNativeWindowType;
-typedef WINRT_EGLNativeWindowType WINRT_EGLNativeDisplayType;
+typedef Microsoft::WRL::ComPtr<IUnknown> 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<IUnknown>, 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<IUnknown>, 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 */
--- a/src/video/winrt/SDL_winrtvideo.cpp	Sat Nov 01 11:41:18 2014 -0400
+++ b/src/video/winrt/SDL_winrtvideo.cpp	Sun Nov 02 08:47:05 2014 -0500
@@ -328,13 +328,33 @@
             return SDL_SetError(buf);
         }
 
-        Microsoft::WRL::ComPtr<IUnknown> 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<IUnknown> 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<IInspectable *>(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