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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
diff --git a/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj
index 9649279..d19b9d0 100644
--- a/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj
+++ b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj
@@ -324,7 +324,7 @@
<ClInclude Include="..\..\src\video\SDL_blit_auto.h" />
<ClInclude Include="..\..\src\video\SDL_blit_copy.h" />
<ClInclude Include="..\..\src\video\SDL_blit_slow.h" />
- <ClInclude Include="..\..\src\video\SDL_egl.h" />
+ <ClInclude Include="..\..\src\video\SDL_egl_c.h" />
<ClInclude Include="..\..\src\video\SDL_pixels_c.h" />
<ClInclude Include="..\..\src\video\SDL_rect_c.h" />
<ClInclude Include="..\..\src\video\SDL_RLEaccel_c.h" />
diff --git a/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj.filters b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj.filters
index 7cdc81d..b5050af 100644
--- a/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj.filters
+++ b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj.filters
@@ -633,9 +633,6 @@
<ClInclude Include="..\..\src\video\winrt\SDL_winrtopengles.h">
<Filter>Source Files</Filter>
</ClInclude>
- <ClInclude Include="..\..\src\video\SDL_egl.h">
- <Filter>Source Files</Filter>
- </ClInclude>
<ClInclude Include="..\..\include\SDL_opengles2.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -666,6 +663,9 @@
<ClInclude Include="..\..\src\render\direct3d11\SDL_render_winrt.h">
<Filter>Source Files</Filter>
</ClInclude>
+ <ClInclude Include="..\..\src\video\SDL_egl_c.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">
diff --git a/include/SDL_egl.h b/include/SDL_egl.h
index d312f04..a345818 100644
--- a/include/SDL_egl.h
+++ b/include/SDL_egl.h
@@ -394,8 +394,8 @@ typedef enum {
#if __WINRT__
#include <Unknwn.h>
typedef IUnknown * EGLNativeWindowType;
-typedef int EGLNativeDisplayType;
-typedef HBITMAP EGLNativePixmapType;
+typedef IUnknown * EGLNativePixmapType;
+typedef IUnknown * EGLNativeDisplayType;
#else
typedef HDC EGLNativeDisplayType;
typedef HBITMAP EGLNativePixmapType;
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index cfba200..e0efa64 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -216,6 +216,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
LOAD_FUNC(eglWaitGL);
LOAD_FUNC(eglBindAPI);
+#if !defined(__WINRT__)
_this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
if (!_this->egl_data->egl_display) {
return SDL_SetError("Could not get EGL display");
@@ -224,6 +225,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
return SDL_SetError("Could not initialize EGL");
}
+#endif
_this->egl_data->dll_handle = dll_handle;
_this->egl_data->egl_dll_handle = egl_dll_handle;
diff --git a/src/video/winrt/SDL_winrtopengles.cpp b/src/video/winrt/SDL_winrtopengles.cpp
index 6f3ddce..4a84174 100644
--- a/src/video/winrt/SDL_winrtopengles.cpp
+++ b/src/video/winrt/SDL_winrtopengles.cpp
@@ -20,8 +20,6 @@
*/
#include "../../SDL_internal.h"
-// TODO: WinRT, make this file compile via C code
-
#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL
/* EGL implementation of SDL OpenGL support */
@@ -29,13 +27,77 @@
#include "SDL_winrtvideo_cpp.h"
extern "C" {
#include "SDL_winrtopengles.h"
+#include "SDL_loadso.h"
}
-#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((NativeDisplayType) -3)
+/* Windows includes */
+#include <wrl/client.h>
+using namespace Windows::UI::Core;
+
+/* ANGLE/WinRT constants */
+static const int ANGLE_D3D_FEATURE_LEVEL_ANY = 0;
+
+
+/*
+ * SDL/EGL top-level implementation
+ */
extern "C" int
-WINRT_GLES_LoadLibrary(_THIS, const char *path) {
- return SDL_EGL_LoadLibrary(_this, path, EGL_D3D11_ONLY_DISPLAY_ANGLE);
+WINRT_GLES_LoadLibrary(_THIS, const char *path)
+{
+ SDL_VideoData *video_data = (SDL_VideoData *)_this->driverdata;
+
+ if (SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY) != 0) {
+ return -1;
+ }
+
+ /* 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");
+ }
+
+ /* 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");
+ }
+
+ return 0;
+}
+
+extern "C" void
+WINRT_GLES_UnloadLibrary(_THIS)
+{
+ SDL_VideoData *video_data = (SDL_VideoData *)_this->driverdata;
+
+ /* Release SDL's own COM reference to the ANGLE/WinRT IWinrtEglWindow */
+ if (video_data->winrtEglWindow) {
+ video_data->winrtEglWindow->Release();
+ video_data->winrtEglWindow = nullptr;
+ }
+
+ /* Perform the bulk of the unloading */
+ SDL_EGL_UnloadLibrary(_this);
}
extern "C" {
diff --git a/src/video/winrt/SDL_winrtopengles.h b/src/video/winrt/SDL_winrtopengles.h
index f051132..ae17391 100644
--- a/src/video/winrt/SDL_winrtopengles.h
+++ b/src/video/winrt/SDL_winrtopengles.h
@@ -31,16 +31,34 @@
/* OpenGLES functions */
#define WINRT_GLES_GetAttribute SDL_EGL_GetAttribute
#define WINRT_GLES_GetProcAddress SDL_EGL_GetProcAddress
-#define WINRT_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define WINRT_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
#define WINRT_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
#define WINRT_GLES_DeleteContext SDL_EGL_DeleteContext
extern int WINRT_GLES_LoadLibrary(_THIS, const char *path);
+extern void WINRT_GLES_UnloadLibrary(_THIS);
extern SDL_GLContext WINRT_GLES_CreateContext(_THIS, SDL_Window * window);
extern void WINRT_GLES_SwapWindow(_THIS, SDL_Window * window);
extern int WINRT_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
+
+#ifdef __cplusplus
+
+/* 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;
+
+/* Function pointer typedefs for ANGLE/WinRT's functions that require
+ * parameter customization [by passing in C++ objects].
+ */
+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);
+
+#endif /* __cplusplus */
+
#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 4a5301f..f54e985 100644
--- a/src/video/winrt/SDL_winrtvideo.cpp
+++ b/src/video/winrt/SDL_winrtvideo.cpp
@@ -30,6 +30,7 @@
/* Windows includes */
#include <agile.h>
+#include <wrl/client.h>
using namespace Windows::UI::Core;
@@ -86,6 +87,15 @@ WINRT_DeleteDevice(SDL_VideoDevice * device)
if (device == WINRT_GlobalSDLVideoDevice) {
WINRT_GlobalSDLVideoDevice = NULL;
}
+
+ if (device->driverdata) {
+ SDL_VideoData * video_data = (SDL_VideoData *)device->driverdata;
+ if (video_data->winrtEglWindow) {
+ video_data->winrtEglWindow->Release();
+ }
+ SDL_free(video_data);
+ }
+
SDL_free(device);
}
@@ -93,6 +103,7 @@ static SDL_VideoDevice *
WINRT_CreateDevice(int devindex)
{
SDL_VideoDevice *device;
+ SDL_VideoData *data;
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
@@ -104,6 +115,14 @@ WINRT_CreateDevice(int devindex)
return (0);
}
+ data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
+ if (!data) {
+ SDL_OutOfMemory();
+ return (0);
+ }
+ SDL_zerop(data);
+ device->driverdata = data;
+
/* Set the function pointers */
device->VideoInit = WINRT_VideoInit;
device->VideoQuit = WINRT_VideoQuit;
@@ -301,29 +320,25 @@ WINRT_CreateWindow(_THIS, SDL_Window * window)
data->egl_surface = EGL_NO_SURFACE;
} else {
/* OpenGL ES 2 was reuqested. Set up an EGL surface. */
+ SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata;
- /* HACK: ANGLE/WinRT currently uses non-pointer, C++ objects to represent
- native windows. The object only contains a single pointer to a COM
- interface pointer, which on x86 appears to be castable to the object
- without apparant problems. On other platforms, notable ARM and x64,
- doing so will cause a crash. To avoid this crash, we'll bypass
- SDL's normal call to eglCreateWindowSurface, which is invoked from C
- code, and call it here, where an appropriate C++ object may be
- passed in.
+ /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly,
+ * rather than via SDL_EGL_CreateSurface, as ANGLE/WinRT requires
+ * a C++ object, ComPtr<IUnknown>, to be passed into
+ * eglCreateWindowSurface.
*/
- typedef EGLSurface (*eglCreateWindowSurfaceFunction)(EGLDisplay dpy, EGLConfig config,
- Microsoft::WRL::ComPtr<IUnknown> win,
- const EGLint *attrib_list);
- eglCreateWindowSurfaceFunction WINRT_eglCreateWindowSurface =
- (eglCreateWindowSurfaceFunction) _this->egl_data->eglCreateWindowSurface;
-
- Microsoft::WRL::ComPtr<IUnknown> nativeWindow = reinterpret_cast<IUnknown *>(data->coreWindow.Get());
- data->egl_surface = WINRT_eglCreateWindowSurface(
+ if (SDL_EGL_ChooseConfig(_this) != 0) {
+ char buf[512];
+ SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError());
+ 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,
- nativeWindow, NULL);
+ cpp_winrtEglWindow, NULL);
if (data->egl_surface == NULL) {
- // TODO, WinRT: see if eglCreateWindowSurface, or its callee(s), sets an error message. If so, attach it to the SDL error.
return SDL_SetError("eglCreateWindowSurface failed");
}
}
diff --git a/src/video/winrt/SDL_winrtvideo_cpp.h b/src/video/winrt/SDL_winrtvideo_cpp.h
index b5f4451..119f5b8 100644
--- a/src/video/winrt/SDL_winrtvideo_cpp.h
+++ b/src/video/winrt/SDL_winrtvideo_cpp.h
@@ -34,6 +34,13 @@ extern "C" {
#include "../SDL_egl_c.h"
}
+/* Private display data */
+typedef struct SDL_VideoData {
+ /* An object created by ANGLE/WinRT (OpenGL ES 2 for WinRT) that gets
+ * passed to eglGetDisplay and eglCreateWindowSurface:
+ */
+ IUnknown *winrtEglWindow;
+} SDL_VideoData;
/* The global, WinRT, SDL Window.
For now, SDL/WinRT only supports one window (due to platform limitations of