WinRT: Got OpenGL ES 2 working with the latest version of ANGLE/WinRT.
SDL/WinRT did have support for OpenGL ES 2 via an older version of ANGLE/WinRT,
however its API changed a few months ago, and SDL/WinRT would crash when trying
to use it. It would also occasionally crash when using the older version.
This changeset should make SDL/WinRT work with the latest version, as
available via MS Open Tech's git repository of it at
https://github.com/msopentech/angle
Older versions of ANGLE/WinRT (from either https://github.com/stammen/angleproject
or https://bitbucket.org/DavidLudwig/angleproject) will need to be updated to
MS Open Tech's latest version.
1.1 --- a/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj Fri Mar 21 10:40:15 2014 -0400
1.2 +++ b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj Sat Mar 22 20:48:18 2014 -0400
1.3 @@ -324,7 +324,7 @@
1.4 <ClInclude Include="..\..\src\video\SDL_blit_auto.h" />
1.5 <ClInclude Include="..\..\src\video\SDL_blit_copy.h" />
1.6 <ClInclude Include="..\..\src\video\SDL_blit_slow.h" />
1.7 - <ClInclude Include="..\..\src\video\SDL_egl.h" />
1.8 + <ClInclude Include="..\..\src\video\SDL_egl_c.h" />
1.9 <ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
1.10 <ClInclude Include="..\..\src\video\SDL_rect_c.h" />
1.11 <ClInclude Include="..\..\src\video\SDL_RLEaccel_c.h" />
2.1 --- a/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj.filters Fri Mar 21 10:40:15 2014 -0400
2.2 +++ b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj.filters Sat Mar 22 20:48:18 2014 -0400
2.3 @@ -633,9 +633,6 @@
2.4 <ClInclude Include="..\..\src\video\winrt\SDL_winrtopengles.h">
2.5 <Filter>Source Files</Filter>
2.6 </ClInclude>
2.7 - <ClInclude Include="..\..\src\video\SDL_egl.h">
2.8 - <Filter>Source Files</Filter>
2.9 - </ClInclude>
2.10 <ClInclude Include="..\..\include\SDL_opengles2.h">
2.11 <Filter>Header Files</Filter>
2.12 </ClInclude>
2.13 @@ -666,6 +663,9 @@
2.14 <ClInclude Include="..\..\src\render\direct3d11\SDL_render_winrt.h">
2.15 <Filter>Source Files</Filter>
2.16 </ClInclude>
2.17 + <ClInclude Include="..\..\src\video\SDL_egl_c.h">
2.18 + <Filter>Source Files</Filter>
2.19 + </ClInclude>
2.20 </ItemGroup>
2.21 <ItemGroup>
2.22 <Filter Include="Header Files">
3.1 --- a/include/SDL_egl.h Fri Mar 21 10:40:15 2014 -0400
3.2 +++ b/include/SDL_egl.h Sat Mar 22 20:48:18 2014 -0400
3.3 @@ -394,8 +394,8 @@
3.4 #if __WINRT__
3.5 #include <Unknwn.h>
3.6 typedef IUnknown * EGLNativeWindowType;
3.7 -typedef int EGLNativeDisplayType;
3.8 -typedef HBITMAP EGLNativePixmapType;
3.9 +typedef IUnknown * EGLNativePixmapType;
3.10 +typedef IUnknown * EGLNativeDisplayType;
3.11 #else
3.12 typedef HDC EGLNativeDisplayType;
3.13 typedef HBITMAP EGLNativePixmapType;
4.1 --- a/src/video/SDL_egl.c Fri Mar 21 10:40:15 2014 -0400
4.2 +++ b/src/video/SDL_egl.c Sat Mar 22 20:48:18 2014 -0400
4.3 @@ -216,6 +216,7 @@
4.4 LOAD_FUNC(eglWaitGL);
4.5 LOAD_FUNC(eglBindAPI);
4.6
4.7 +#if !defined(__WINRT__)
4.8 _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
4.9 if (!_this->egl_data->egl_display) {
4.10 return SDL_SetError("Could not get EGL display");
4.11 @@ -224,6 +225,7 @@
4.12 if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
4.13 return SDL_SetError("Could not initialize EGL");
4.14 }
4.15 +#endif
4.16
4.17 _this->egl_data->dll_handle = dll_handle;
4.18 _this->egl_data->egl_dll_handle = egl_dll_handle;
5.1 --- a/src/video/winrt/SDL_winrtopengles.cpp Fri Mar 21 10:40:15 2014 -0400
5.2 +++ b/src/video/winrt/SDL_winrtopengles.cpp Sat Mar 22 20:48:18 2014 -0400
5.3 @@ -20,8 +20,6 @@
5.4 */
5.5 #include "../../SDL_internal.h"
5.6
5.7 -// TODO: WinRT, make this file compile via C code
5.8 -
5.9 #if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL
5.10
5.11 /* EGL implementation of SDL OpenGL support */
5.12 @@ -29,13 +27,77 @@
5.13 #include "SDL_winrtvideo_cpp.h"
5.14 extern "C" {
5.15 #include "SDL_winrtopengles.h"
5.16 +#include "SDL_loadso.h"
5.17 }
5.18
5.19 -#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((NativeDisplayType) -3)
5.20 +/* Windows includes */
5.21 +#include <wrl/client.h>
5.22 +using namespace Windows::UI::Core;
5.23 +
5.24 +/* ANGLE/WinRT constants */
5.25 +static const int ANGLE_D3D_FEATURE_LEVEL_ANY = 0;
5.26 +
5.27 +
5.28 +/*
5.29 + * SDL/EGL top-level implementation
5.30 + */
5.31
5.32 extern "C" int
5.33 -WINRT_GLES_LoadLibrary(_THIS, const char *path) {
5.34 - return SDL_EGL_LoadLibrary(_this, path, EGL_D3D11_ONLY_DISPLAY_ANGLE);
5.35 +WINRT_GLES_LoadLibrary(_THIS, const char *path)
5.36 +{
5.37 + SDL_VideoData *video_data = (SDL_VideoData *)_this->driverdata;
5.38 +
5.39 + if (SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY) != 0) {
5.40 + return -1;
5.41 + }
5.42 +
5.43 + /* Load ANGLE/WinRT-specific functions */
5.44 + CreateWinrtEglWindow_Function CreateWinrtEglWindow = (CreateWinrtEglWindow_Function) SDL_LoadFunction(_this->egl_data->egl_dll_handle, "CreateWinrtEglWindow");
5.45 + if (!CreateWinrtEglWindow) {
5.46 + return SDL_SetError("Could not retrieve ANGLE/WinRT function CreateWinrtEglWindow");
5.47 + }
5.48 +
5.49 + /* Create an ANGLE/WinRT EGL-window */
5.50 + /* TODO, WinRT: check for XAML usage before accessing the CoreWindow, as not doing so could lead to a crash */
5.51 + CoreWindow ^ native_win = CoreWindow::GetForCurrentThread();
5.52 + Microsoft::WRL::ComPtr<IUnknown> cpp_win = reinterpret_cast<IUnknown *>(native_win);
5.53 + HRESULT result = CreateWinrtEglWindow(cpp_win, ANGLE_D3D_FEATURE_LEVEL_ANY, &(video_data->winrtEglWindow));
5.54 + if (FAILED(result)) {
5.55 + return -1;
5.56 + }
5.57 +
5.58 + /* Call eglGetDisplay and eglInitialize as appropriate. On other
5.59 + * platforms, this would probably get done by SDL_EGL_LoadLibrary,
5.60 + * however ANGLE/WinRT's current implementation (as of Mar 22, 2014) of
5.61 + * eglGetDisplay requires that a C++ object be passed into it, so the
5.62 + * call will be made in this file, a C++ file, instead.
5.63 + */
5.64 + Microsoft::WRL::ComPtr<IUnknown> cpp_display = video_data->winrtEglWindow;
5.65 + _this->egl_data->egl_display = ((eglGetDisplay_Function)_this->egl_data->eglGetDisplay)(cpp_display);
5.66 + if (!_this->egl_data->egl_display) {
5.67 + return SDL_SetError("Could not get EGL display");
5.68 + }
5.69 +
5.70 + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
5.71 + return SDL_SetError("Could not initialize EGL");
5.72 + }
5.73 +
5.74 + return 0;
5.75 +}
5.76 +
5.77 +extern "C" void
5.78 +WINRT_GLES_UnloadLibrary(_THIS)
5.79 +{
5.80 + SDL_VideoData *video_data = (SDL_VideoData *)_this->driverdata;
5.81 +
5.82 + /* Release SDL's own COM reference to the ANGLE/WinRT IWinrtEglWindow */
5.83 + if (video_data->winrtEglWindow) {
5.84 + video_data->winrtEglWindow->Release();
5.85 + video_data->winrtEglWindow = nullptr;
5.86 + }
5.87 +
5.88 + /* Perform the bulk of the unloading */
5.89 + SDL_EGL_UnloadLibrary(_this);
5.90 }
5.91
5.92 extern "C" {
6.1 --- a/src/video/winrt/SDL_winrtopengles.h Fri Mar 21 10:40:15 2014 -0400
6.2 +++ b/src/video/winrt/SDL_winrtopengles.h Sat Mar 22 20:48:18 2014 -0400
6.3 @@ -31,16 +31,34 @@
6.4 /* OpenGLES functions */
6.5 #define WINRT_GLES_GetAttribute SDL_EGL_GetAttribute
6.6 #define WINRT_GLES_GetProcAddress SDL_EGL_GetProcAddress
6.7 -#define WINRT_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
6.8 #define WINRT_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
6.9 #define WINRT_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
6.10 #define WINRT_GLES_DeleteContext SDL_EGL_DeleteContext
6.11
6.12 extern int WINRT_GLES_LoadLibrary(_THIS, const char *path);
6.13 +extern void WINRT_GLES_UnloadLibrary(_THIS);
6.14 extern SDL_GLContext WINRT_GLES_CreateContext(_THIS, SDL_Window * window);
6.15 extern void WINRT_GLES_SwapWindow(_THIS, SDL_Window * window);
6.16 extern int WINRT_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
6.17
6.18 +
6.19 +#ifdef __cplusplus
6.20 +
6.21 +/* Typedefs for ANGLE/WinRT's C++-based native-display and native-window types,
6.22 + * which are used when calling eglGetDisplay and eglCreateWindowSurface.
6.23 + */
6.24 +typedef Microsoft::WRL::ComPtr<IUnknown> WINRT_EGLNativeWindowType;
6.25 +typedef WINRT_EGLNativeWindowType WINRT_EGLNativeDisplayType;
6.26 +
6.27 +/* Function pointer typedefs for ANGLE/WinRT's functions that require
6.28 + * parameter customization [by passing in C++ objects].
6.29 + */
6.30 +typedef EGLDisplay (EGLAPIENTRY *eglGetDisplay_Function)(WINRT_EGLNativeWindowType);
6.31 +typedef EGLSurface (EGLAPIENTRY *eglCreateWindowSurface_Function)(EGLDisplay, EGLConfig, WINRT_EGLNativeWindowType, const EGLint *);
6.32 +typedef HRESULT (EGLAPIENTRY *CreateWinrtEglWindow_Function)(Microsoft::WRL::ComPtr<IUnknown>, int, IUnknown ** result);
6.33 +
6.34 +#endif /* __cplusplus */
6.35 +
6.36 #endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */
6.37
6.38 #endif /* _SDL_winrtopengles_h */
7.1 --- a/src/video/winrt/SDL_winrtvideo.cpp Fri Mar 21 10:40:15 2014 -0400
7.2 +++ b/src/video/winrt/SDL_winrtvideo.cpp Sat Mar 22 20:48:18 2014 -0400
7.3 @@ -30,6 +30,7 @@
7.4
7.5 /* Windows includes */
7.6 #include <agile.h>
7.7 +#include <wrl/client.h>
7.8 using namespace Windows::UI::Core;
7.9
7.10
7.11 @@ -86,6 +87,15 @@
7.12 if (device == WINRT_GlobalSDLVideoDevice) {
7.13 WINRT_GlobalSDLVideoDevice = NULL;
7.14 }
7.15 +
7.16 + if (device->driverdata) {
7.17 + SDL_VideoData * video_data = (SDL_VideoData *)device->driverdata;
7.18 + if (video_data->winrtEglWindow) {
7.19 + video_data->winrtEglWindow->Release();
7.20 + }
7.21 + SDL_free(video_data);
7.22 + }
7.23 +
7.24 SDL_free(device);
7.25 }
7.26
7.27 @@ -93,6 +103,7 @@
7.28 WINRT_CreateDevice(int devindex)
7.29 {
7.30 SDL_VideoDevice *device;
7.31 + SDL_VideoData *data;
7.32
7.33 /* Initialize all variables that we clean on shutdown */
7.34 device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
7.35 @@ -104,6 +115,14 @@
7.36 return (0);
7.37 }
7.38
7.39 + data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
7.40 + if (!data) {
7.41 + SDL_OutOfMemory();
7.42 + return (0);
7.43 + }
7.44 + SDL_zerop(data);
7.45 + device->driverdata = data;
7.46 +
7.47 /* Set the function pointers */
7.48 device->VideoInit = WINRT_VideoInit;
7.49 device->VideoQuit = WINRT_VideoQuit;
7.50 @@ -301,29 +320,25 @@
7.51 data->egl_surface = EGL_NO_SURFACE;
7.52 } else {
7.53 /* OpenGL ES 2 was reuqested. Set up an EGL surface. */
7.54 + SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata;
7.55
7.56 - /* HACK: ANGLE/WinRT currently uses non-pointer, C++ objects to represent
7.57 - native windows. The object only contains a single pointer to a COM
7.58 - interface pointer, which on x86 appears to be castable to the object
7.59 - without apparant problems. On other platforms, notable ARM and x64,
7.60 - doing so will cause a crash. To avoid this crash, we'll bypass
7.61 - SDL's normal call to eglCreateWindowSurface, which is invoked from C
7.62 - code, and call it here, where an appropriate C++ object may be
7.63 - passed in.
7.64 + /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly,
7.65 + * rather than via SDL_EGL_CreateSurface, as ANGLE/WinRT requires
7.66 + * a C++ object, ComPtr<IUnknown>, to be passed into
7.67 + * eglCreateWindowSurface.
7.68 */
7.69 - typedef EGLSurface (*eglCreateWindowSurfaceFunction)(EGLDisplay dpy, EGLConfig config,
7.70 - Microsoft::WRL::ComPtr<IUnknown> win,
7.71 - const EGLint *attrib_list);
7.72 - eglCreateWindowSurfaceFunction WINRT_eglCreateWindowSurface =
7.73 - (eglCreateWindowSurfaceFunction) _this->egl_data->eglCreateWindowSurface;
7.74 + if (SDL_EGL_ChooseConfig(_this) != 0) {
7.75 + char buf[512];
7.76 + SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError());
7.77 + return SDL_SetError(buf);
7.78 + }
7.79
7.80 - Microsoft::WRL::ComPtr<IUnknown> nativeWindow = reinterpret_cast<IUnknown *>(data->coreWindow.Get());
7.81 - data->egl_surface = WINRT_eglCreateWindowSurface(
7.82 + Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow;
7.83 + data->egl_surface = ((eglCreateWindowSurface_Function)_this->egl_data->eglCreateWindowSurface)(
7.84 _this->egl_data->egl_display,
7.85 _this->egl_data->egl_config,
7.86 - nativeWindow, NULL);
7.87 + cpp_winrtEglWindow, NULL);
7.88 if (data->egl_surface == NULL) {
7.89 - // TODO, WinRT: see if eglCreateWindowSurface, or its callee(s), sets an error message. If so, attach it to the SDL error.
7.90 return SDL_SetError("eglCreateWindowSurface failed");
7.91 }
7.92 }
8.1 --- a/src/video/winrt/SDL_winrtvideo_cpp.h Fri Mar 21 10:40:15 2014 -0400
8.2 +++ b/src/video/winrt/SDL_winrtvideo_cpp.h Sat Mar 22 20:48:18 2014 -0400
8.3 @@ -34,6 +34,13 @@
8.4 #include "../SDL_egl_c.h"
8.5 }
8.6
8.7 +/* Private display data */
8.8 +typedef struct SDL_VideoData {
8.9 + /* An object created by ANGLE/WinRT (OpenGL ES 2 for WinRT) that gets
8.10 + * passed to eglGetDisplay and eglCreateWindowSurface:
8.11 + */
8.12 + IUnknown *winrtEglWindow;
8.13 +} SDL_VideoData;
8.14
8.15 /* The global, WinRT, SDL Window.
8.16 For now, SDL/WinRT only supports one window (due to platform limitations of