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 921104c7e1220a65
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
     1.1 --- a/src/video/winrt/SDL_winrtopengles.cpp	Sat Nov 01 11:41:18 2014 -0400
     1.2 +++ b/src/video/winrt/SDL_winrtopengles.cpp	Sun Nov 02 08:47:05 2014 -0500
     1.3 @@ -36,7 +36,10 @@
     1.4  
     1.5  /* ANGLE/WinRT constants */
     1.6  static const int ANGLE_D3D_FEATURE_LEVEL_ANY = 0;
     1.7 -
     1.8 +#define EGL_PLATFORM_ANGLE_ANGLE                0x3201
     1.9 +#define EGL_PLATFORM_ANGLE_TYPE_ANGLE           0x3202
    1.10 +#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE   0x3203
    1.11 +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE     0x3205
    1.12  
    1.13  /*
    1.14   * SDL/EGL top-level implementation
    1.15 @@ -52,32 +55,56 @@
    1.16      }
    1.17  
    1.18      /* Load ANGLE/WinRT-specific functions */
    1.19 -    CreateWinrtEglWindow_Function CreateWinrtEglWindow = (CreateWinrtEglWindow_Function) SDL_LoadFunction(_this->egl_data->egl_dll_handle, "CreateWinrtEglWindow");
    1.20 -    if (!CreateWinrtEglWindow) {
    1.21 -        return SDL_SetError("Could not retrieve ANGLE/WinRT function CreateWinrtEglWindow");
    1.22 +    CreateWinrtEglWindow_Old_Function CreateWinrtEglWindow = (CreateWinrtEglWindow_Old_Function) SDL_LoadFunction(_this->egl_data->egl_dll_handle, "CreateWinrtEglWindow");
    1.23 +    if (CreateWinrtEglWindow) {
    1.24 +        /* 'CreateWinrtEglWindow' was found, which means that an an older
    1.25 +         * version of ANGLE/WinRT is being used.  Continue setting up EGL,
    1.26 +         * as appropriate to this version of ANGLE.
    1.27 +         */
    1.28 +
    1.29 +        /* Create an ANGLE/WinRT EGL-window */
    1.30 +        /* TODO, WinRT: check for XAML usage before accessing the CoreWindow, as not doing so could lead to a crash */
    1.31 +        CoreWindow ^ native_win = CoreWindow::GetForCurrentThread();
    1.32 +        Microsoft::WRL::ComPtr<IUnknown> cpp_win = reinterpret_cast<IUnknown *>(native_win);
    1.33 +        HRESULT result = CreateWinrtEglWindow(cpp_win, ANGLE_D3D_FEATURE_LEVEL_ANY, &(video_data->winrtEglWindow));
    1.34 +        if (FAILED(result)) {
    1.35 +            return -1;
    1.36 +        }
    1.37 +
    1.38 +        /* Call eglGetDisplay and eglInitialize as appropriate.  On other
    1.39 +         * platforms, this would probably get done by SDL_EGL_LoadLibrary,
    1.40 +         * however ANGLE/WinRT's current implementation (as of Mar 22, 2014) of
    1.41 +         * eglGetDisplay requires that a C++ object be passed into it, so the
    1.42 +         * call will be made in this file, a C++ file, instead.
    1.43 +         */
    1.44 +        Microsoft::WRL::ComPtr<IUnknown> cpp_display = video_data->winrtEglWindow;
    1.45 +        _this->egl_data->egl_display = ((eglGetDisplay_Old_Function)_this->egl_data->eglGetDisplay)(cpp_display);
    1.46 +        if (!_this->egl_data->egl_display) {
    1.47 +            return SDL_SetError("Could not get EGL display");
    1.48 +        }
    1.49 +    } else {
    1.50 +        const EGLint displayAttributes[] = {
    1.51 +            EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
    1.52 +            EGL_NONE,
    1.53 +        };
    1.54 +
    1.55 +        /* 'CreateWinrtEglWindow' was NOT found, which either means that a
    1.56 +         * newer version of ANGLE/WinRT is being used, or that we don't have
    1.57 +         * a valid copy of ANGLE.
    1.58 +         *
    1.59 +         * Try loading ANGLE as if it were the newer version.
    1.60 +         */
    1.61 +        eglGetPlatformDisplayEXT_Function eglGetPlatformDisplayEXT = (eglGetPlatformDisplayEXT_Function)_this->egl_data->eglGetProcAddress("eglGetPlatformDisplayEXT");
    1.62 +        if (!eglGetPlatformDisplayEXT) {
    1.63 +            return SDL_SetError("Could not retrieve ANGLE/WinRT display function(s)");
    1.64 +        }
    1.65 +
    1.66 +        _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes);
    1.67 +        if (!_this->egl_data->egl_display) {
    1.68 +            return SDL_SetError("Could not get EGL display");
    1.69 +        }
    1.70      }
    1.71  
    1.72 -    /* Create an ANGLE/WinRT EGL-window */
    1.73 -    /* TODO, WinRT: check for XAML usage before accessing the CoreWindow, as not doing so could lead to a crash */
    1.74 -    CoreWindow ^ native_win = CoreWindow::GetForCurrentThread();
    1.75 -    Microsoft::WRL::ComPtr<IUnknown> cpp_win = reinterpret_cast<IUnknown *>(native_win);
    1.76 -    HRESULT result = CreateWinrtEglWindow(cpp_win, ANGLE_D3D_FEATURE_LEVEL_ANY, &(video_data->winrtEglWindow));
    1.77 -    if (FAILED(result)) {
    1.78 -        return -1;
    1.79 -    }
    1.80 -
    1.81 -    /* Call eglGetDisplay and eglInitialize as appropriate.  On other
    1.82 -     * platforms, this would probably get done by SDL_EGL_LoadLibrary,
    1.83 -     * however ANGLE/WinRT's current implementation (as of Mar 22, 2014) of
    1.84 -     * eglGetDisplay requires that a C++ object be passed into it, so the
    1.85 -     * call will be made in this file, a C++ file, instead.
    1.86 -     */
    1.87 -    Microsoft::WRL::ComPtr<IUnknown> cpp_display = video_data->winrtEglWindow;
    1.88 -    _this->egl_data->egl_display = ((eglGetDisplay_Function)_this->egl_data->eglGetDisplay)(cpp_display);
    1.89 -    if (!_this->egl_data->egl_display) {
    1.90 -        return SDL_SetError("Could not get EGL display");
    1.91 -    }
    1.92 -    
    1.93      if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
    1.94          return SDL_SetError("Could not initialize EGL");
    1.95      }
     2.1 --- a/src/video/winrt/SDL_winrtopengles.h	Sat Nov 01 11:41:18 2014 -0400
     2.2 +++ b/src/video/winrt/SDL_winrtopengles.h	Sun Nov 02 08:47:05 2014 -0500
     2.3 @@ -47,18 +47,22 @@
     2.4  /* Typedefs for ANGLE/WinRT's C++-based native-display and native-window types,
     2.5   * which are used when calling eglGetDisplay and eglCreateWindowSurface.
     2.6   */
     2.7 -typedef Microsoft::WRL::ComPtr<IUnknown> WINRT_EGLNativeWindowType;
     2.8 -typedef WINRT_EGLNativeWindowType WINRT_EGLNativeDisplayType;
     2.9 +typedef Microsoft::WRL::ComPtr<IUnknown> WINRT_EGLNativeWindowType_Old;
    2.10  
    2.11 -/* Function pointer typedefs for ANGLE/WinRT's functions that require
    2.12 - * parameter customization [by passing in C++ objects].
    2.13 +/* Function pointer typedefs for 'old' ANGLE/WinRT's functions, which may
    2.14 + * require that C++ objects be passed in:
    2.15   */
    2.16 -typedef EGLDisplay (EGLAPIENTRY *eglGetDisplay_Function)(WINRT_EGLNativeWindowType);
    2.17 -typedef EGLSurface (EGLAPIENTRY *eglCreateWindowSurface_Function)(EGLDisplay, EGLConfig, WINRT_EGLNativeWindowType, const EGLint *);
    2.18 -typedef HRESULT (EGLAPIENTRY *CreateWinrtEglWindow_Function)(Microsoft::WRL::ComPtr<IUnknown>, int, IUnknown ** result);
    2.19 +typedef EGLDisplay (EGLAPIENTRY *eglGetDisplay_Old_Function)(WINRT_EGLNativeWindowType_Old);
    2.20 +typedef EGLSurface (EGLAPIENTRY *eglCreateWindowSurface_Old_Function)(EGLDisplay, EGLConfig, WINRT_EGLNativeWindowType_Old, const EGLint *);
    2.21 +typedef HRESULT (EGLAPIENTRY *CreateWinrtEglWindow_Old_Function)(Microsoft::WRL::ComPtr<IUnknown>, int, IUnknown ** result);
    2.22  
    2.23  #endif /* __cplusplus */
    2.24  
    2.25 +/* Function pointer typedefs for 'new' ANGLE/WinRT functions, which, unlike
    2.26 + * the old functions, do not require C++ support and work with plain C.
    2.27 + */
    2.28 +typedef EGLDisplay (EGLAPIENTRY *eglGetPlatformDisplayEXT_Function)(EGLenum, void *, const EGLint *);
    2.29 +
    2.30  #endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */
    2.31  
    2.32  #endif /* _SDL_winrtopengles_h */
     3.1 --- a/src/video/winrt/SDL_winrtvideo.cpp	Sat Nov 01 11:41:18 2014 -0400
     3.2 +++ b/src/video/winrt/SDL_winrtvideo.cpp	Sun Nov 02 08:47:05 2014 -0500
     3.3 @@ -328,13 +328,33 @@
     3.4              return SDL_SetError(buf);
     3.5          }
     3.6  
     3.7 -        Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow;
     3.8 -        data->egl_surface = ((eglCreateWindowSurface_Function)_this->egl_data->eglCreateWindowSurface)(
     3.9 -            _this->egl_data->egl_display,
    3.10 -            _this->egl_data->egl_config,
    3.11 -            cpp_winrtEglWindow, NULL);
    3.12 -        if (data->egl_surface == NULL) {
    3.13 -            return SDL_SetError("eglCreateWindowSurface failed");
    3.14 +        if (video_data->winrtEglWindow) {   /* ... is the 'old' version of ANGLE/WinRT being used? */
    3.15 +            /* Attempt to create a window surface using older versions of
    3.16 +             * ANGLE/WinRT:
    3.17 +             */
    3.18 +            Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow;
    3.19 +            data->egl_surface = ((eglCreateWindowSurface_Old_Function)_this->egl_data->eglCreateWindowSurface)(
    3.20 +                _this->egl_data->egl_display,
    3.21 +                _this->egl_data->egl_config,
    3.22 +                cpp_winrtEglWindow, NULL);
    3.23 +            if (data->egl_surface == NULL) {
    3.24 +                return SDL_SetError("eglCreateWindowSurface failed");
    3.25 +            }
    3.26 +        } else if (data->coreWindow.Get() != nullptr) {
    3.27 +            /* Attempt to create a window surface using newer versions of
    3.28 +             * ANGLE/WinRT:
    3.29 +             */
    3.30 +            IInspectable * coreWindowAsIInspectable = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
    3.31 +            data->egl_surface = _this->egl_data->eglCreateWindowSurface(
    3.32 +                _this->egl_data->egl_display,
    3.33 +                _this->egl_data->egl_config,
    3.34 +                coreWindowAsIInspectable,
    3.35 +                NULL);
    3.36 +            if (data->egl_surface == NULL) {
    3.37 +                return SDL_SetError("eglCreateWindowSurface failed");
    3.38 +            }
    3.39 +        } else {
    3.40 +            return SDL_SetError("No supported means to create an EGL window surface are available");
    3.41          }
    3.42      }
    3.43  #endif