SDL_winrtvideo.cpp (13213B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_VIDEO_DRIVER_WINRT 24 25/* WinRT SDL video driver implementation 26 27 Initial work on this was done by David Ludwig (dludwig@pobox.com), and 28 was based off of SDL's "dummy" video driver. 29 */ 30 31/* Windows includes */ 32#include <agile.h> 33#include <wrl/client.h> 34using namespace Windows::UI::Core; 35 36 37/* SDL includes */ 38extern "C" { 39#include "SDL_video.h" 40#include "SDL_mouse.h" 41#include "../SDL_sysvideo.h" 42#include "../SDL_pixels_c.h" 43#include "../../events/SDL_events_c.h" 44#include "../../render/SDL_sysrender.h" 45#include "SDL_syswm.h" 46#include "SDL_winrtopengles.h" 47} 48 49#include "../../core/winrt/SDL_winrtapp_direct3d.h" 50#include "../../core/winrt/SDL_winrtapp_xaml.h" 51#include "SDL_winrtvideo_cpp.h" 52#include "SDL_winrtevents_c.h" 53#include "SDL_winrtmouse_c.h" 54#include "SDL_main.h" 55#include "SDL_system.h" 56//#include "SDL_log.h" 57 58 59/* Initialization/Query functions */ 60static int WINRT_VideoInit(_THIS); 61static int WINRT_InitModes(_THIS); 62static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); 63static void WINRT_VideoQuit(_THIS); 64 65 66/* Window functions */ 67static int WINRT_CreateWindow(_THIS, SDL_Window * window); 68static void WINRT_DestroyWindow(_THIS, SDL_Window * window); 69static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info); 70 71 72/* SDL-internal globals: */ 73SDL_Window * WINRT_GlobalSDLWindow = NULL; 74 75 76/* WinRT driver bootstrap functions */ 77 78static int 79WINRT_Available(void) 80{ 81 return (1); 82} 83 84static void 85WINRT_DeleteDevice(SDL_VideoDevice * device) 86{ 87 if (device->driverdata) { 88 SDL_VideoData * video_data = (SDL_VideoData *)device->driverdata; 89 if (video_data->winrtEglWindow) { 90 video_data->winrtEglWindow->Release(); 91 } 92 SDL_free(video_data); 93 } 94 95 SDL_free(device); 96} 97 98static SDL_VideoDevice * 99WINRT_CreateDevice(int devindex) 100{ 101 SDL_VideoDevice *device; 102 SDL_VideoData *data; 103 104 /* Initialize all variables that we clean on shutdown */ 105 device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); 106 if (!device) { 107 SDL_OutOfMemory(); 108 if (device) { 109 SDL_free(device); 110 } 111 return (0); 112 } 113 114 data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); 115 if (!data) { 116 SDL_OutOfMemory(); 117 return (0); 118 } 119 SDL_zerop(data); 120 device->driverdata = data; 121 122 /* Set the function pointers */ 123 device->VideoInit = WINRT_VideoInit; 124 device->VideoQuit = WINRT_VideoQuit; 125 device->CreateWindow = WINRT_CreateWindow; 126 device->DestroyWindow = WINRT_DestroyWindow; 127 device->SetDisplayMode = WINRT_SetDisplayMode; 128 device->PumpEvents = WINRT_PumpEvents; 129 device->GetWindowWMInfo = WINRT_GetWindowWMInfo; 130#ifdef SDL_VIDEO_OPENGL_EGL 131 device->GL_LoadLibrary = WINRT_GLES_LoadLibrary; 132 device->GL_GetProcAddress = WINRT_GLES_GetProcAddress; 133 device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary; 134 device->GL_CreateContext = WINRT_GLES_CreateContext; 135 device->GL_MakeCurrent = WINRT_GLES_MakeCurrent; 136 device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval; 137 device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval; 138 device->GL_SwapWindow = WINRT_GLES_SwapWindow; 139 device->GL_DeleteContext = WINRT_GLES_DeleteContext; 140#endif 141 device->free = WINRT_DeleteDevice; 142 143 return device; 144} 145 146#define WINRTVID_DRIVER_NAME "winrt" 147VideoBootStrap WINRT_bootstrap = { 148 WINRTVID_DRIVER_NAME, "SDL WinRT video driver", 149 WINRT_Available, WINRT_CreateDevice 150}; 151 152int 153WINRT_VideoInit(_THIS) 154{ 155 if (WINRT_InitModes(_this) < 0) { 156 return -1; 157 } 158 WINRT_InitMouse(_this); 159 WINRT_InitTouch(_this); 160 161 return 0; 162} 163 164int 165WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode) 166{ 167 SDL_DisplayModeData * driverdata; 168 169 using namespace Windows::Graphics::Display; 170 171 // Go no further if a native window cannot be accessed. This can happen, 172 // for example, if this function is called from certain threads, such as 173 // the SDL/XAML thread. 174 if (!CoreWindow::GetForCurrentThread()) { 175 return SDL_SetError("SDL/WinRT display modes cannot be calculated outside of the main thread, such as in SDL's XAML thread"); 176 } 177 178 //SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, DPI = %f\n", 179 // __FUNCTION__, 180 // CoreWindow::GetForCurrentThread()->Bounds.Width, CoreWindow::GetForCurrentThread()->Bounds.Height, 181 // WINRT_DISPLAY_PROPERTY(CurrentOrientation), 182 // WINRT_DISPLAY_PROPERTY(NativeOrientation), 183 // WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), 184 // WINRT_DISPLAY_PROPERTY(LogicalDpi)); 185 186 // Calculate the display size given the window size, taking into account 187 // the current display's DPI: 188 const float currentDPI = WINRT_DISPLAY_PROPERTY(LogicalDpi); 189 const float dipsPerInch = 96.0f; 190 const int w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch); 191 const int h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch); 192 if (w == 0 || w == h) { 193 return SDL_SetError("Unable to calculate the WinRT window/display's size"); 194 } 195 196 // Create a driverdata field: 197 driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata)); 198 if (!driverdata) { 199 return SDL_OutOfMemory(); 200 } 201 SDL_zerop(driverdata); 202 203 // Fill in most fields: 204 SDL_zerop(mode); 205 mode->format = SDL_PIXELFORMAT_RGB888; 206 mode->refresh_rate = 0; // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps) 207 mode->w = w; 208 mode->h = h; 209 mode->driverdata = driverdata; 210 driverdata->currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation); 211 212#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8) 213 // On Windows Phone 8.0, the native window's size is always in portrait, 214 // regardless of the device's orientation. This is in contrast to 215 // Windows 8.x/RT and Windows Phone 8.1, which will resize the native window as the device's 216 // orientation changes. In order to compensate for this behavior, 217 // on Windows Phone, the mode's width and height will be swapped when 218 // the device is in a landscape (non-portrait) mode. 219 switch (driverdata->currentOrientation) { 220 case DisplayOrientations::Landscape: 221 case DisplayOrientations::LandscapeFlipped: 222 { 223 const int tmp = mode->h; 224 mode->h = mode->w; 225 mode->w = tmp; 226 break; 227 } 228 229 default: 230 break; 231 } 232#endif 233 234 return 0; 235} 236 237int 238WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src) 239{ 240 SDL_DisplayModeData * driverdata; 241 driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata)); 242 if (!driverdata) { 243 return SDL_OutOfMemory(); 244 } 245 SDL_memcpy(driverdata, src->driverdata, sizeof(SDL_DisplayModeData)); 246 SDL_memcpy(dest, src, sizeof(SDL_DisplayMode)); 247 dest->driverdata = driverdata; 248 return 0; 249} 250 251int 252WINRT_InitModes(_THIS) 253{ 254 // Retrieve the display mode: 255 SDL_DisplayMode mode, desktop_mode; 256 if (WINRT_CalcDisplayModeUsingNativeWindow(&mode) != 0) { 257 return -1; // If WINRT_CalcDisplayModeUsingNativeWindow fails, it'll already have set the SDL error 258 } 259 260 if (WINRT_DuplicateDisplayMode(&desktop_mode, &mode) != 0) { 261 return -1; 262 } 263 if (SDL_AddBasicVideoDisplay(&desktop_mode) < 0) { 264 return -1; 265 } 266 267 SDL_AddDisplayMode(&_this->displays[0], &mode); 268 return 0; 269} 270 271static int 272WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) 273{ 274 return 0; 275} 276 277void 278WINRT_VideoQuit(_THIS) 279{ 280 WINRT_QuitMouse(_this); 281} 282 283int 284WINRT_CreateWindow(_THIS, SDL_Window * window) 285{ 286 // Make sure that only one window gets created, at least until multimonitor 287 // support is added. 288 if (WINRT_GlobalSDLWindow != NULL) { 289 SDL_SetError("WinRT only supports one window"); 290 return -1; 291 } 292 293 SDL_WindowData *data = new SDL_WindowData; 294 if (!data) { 295 SDL_OutOfMemory(); 296 return -1; 297 } 298 window->driverdata = data; 299 data->sdlWindow = window; 300 301 /* To note, when XAML support is enabled, access to the CoreWindow will not 302 be possible, at least not via the SDL/XAML thread. Attempts to access it 303 from there will throw exceptions. As such, the SDL_WindowData's 304 'coreWindow' field will only be set (to a non-null value) if XAML isn't 305 enabled. 306 */ 307 if (!WINRT_XAMLWasEnabled) { 308 data->coreWindow = CoreWindow::GetForCurrentThread(); 309 } 310 311#if SDL_VIDEO_OPENGL_EGL 312 /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */ 313 if (!(window->flags & SDL_WINDOW_OPENGL)) { 314 /* OpenGL ES 2 wasn't requested. Don't set up an EGL surface. */ 315 data->egl_surface = EGL_NO_SURFACE; 316 } else { 317 /* OpenGL ES 2 was reuqested. Set up an EGL surface. */ 318 SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata; 319 320 /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly, 321 * rather than via SDL_EGL_CreateSurface, as ANGLE/WinRT requires 322 * a C++ object, ComPtr<IUnknown>, to be passed into 323 * eglCreateWindowSurface. 324 */ 325 if (SDL_EGL_ChooseConfig(_this) != 0) { 326 char buf[512]; 327 SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError()); 328 return SDL_SetError(buf); 329 } 330 331 Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow; 332 data->egl_surface = ((eglCreateWindowSurface_Function)_this->egl_data->eglCreateWindowSurface)( 333 _this->egl_data->egl_display, 334 _this->egl_data->egl_config, 335 cpp_winrtEglWindow, NULL); 336 if (data->egl_surface == NULL) { 337 return SDL_SetError("eglCreateWindowSurface failed"); 338 } 339 } 340#endif 341 342 /* Make sure the window is considered to be positioned at {0,0}, 343 and is considered fullscreen, shown, and the like. 344 */ 345 window->x = 0; 346 window->y = 0; 347 window->flags = 348 SDL_WINDOW_FULLSCREEN | 349 SDL_WINDOW_SHOWN | 350 SDL_WINDOW_BORDERLESS | 351 SDL_WINDOW_MAXIMIZED | 352 SDL_WINDOW_INPUT_GRABBED; 353 354#if SDL_VIDEO_OPENGL_EGL 355 if (data->egl_surface) { 356 window->flags |= SDL_WINDOW_OPENGL; 357 } 358#endif 359 360 /* WinRT does not, as of this writing, appear to support app-adjustable 361 window sizes. Set the window size to whatever the native WinRT 362 CoreWindow is set at. 363 364 TODO, WinRT: if and when non-fullscreen XAML control support is added to SDL, consider making those resizable via SDL_Window's interfaces. 365 */ 366 window->w = _this->displays[0].current_mode.w; 367 window->h = _this->displays[0].current_mode.h; 368 369 /* For now, treat WinRT apps as if they always have focus. 370 TODO, WinRT: try tracking keyboard and mouse focus state with respect to snapped apps 371 */ 372 SDL_SetMouseFocus(window); 373 SDL_SetKeyboardFocus(window); 374 375 /* Make sure the WinRT app's IFramworkView can post events on 376 behalf of SDL: 377 */ 378 WINRT_GlobalSDLWindow = window; 379 380 /* All done! */ 381 return 0; 382} 383 384void 385WINRT_DestroyWindow(_THIS, SDL_Window * window) 386{ 387 SDL_WindowData * data = (SDL_WindowData *) window->driverdata; 388 389 if (WINRT_GlobalSDLWindow == window) { 390 WINRT_GlobalSDLWindow = NULL; 391 } 392 393 if (data) { 394 // Delete the internal window data: 395 delete data; 396 data = NULL; 397 } 398} 399 400SDL_bool 401WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) 402{ 403 SDL_WindowData * data = (SDL_WindowData *) window->driverdata; 404 405 if (info->version.major <= SDL_MAJOR_VERSION) { 406 info->subsystem = SDL_SYSWM_WINRT; 407 info->info.winrt.window = reinterpret_cast<IInspectable *>(data->coreWindow.Get()); 408 return SDL_TRUE; 409 } else { 410 SDL_SetError("Application not compiled with SDL %d.%d\n", 411 SDL_MAJOR_VERSION, SDL_MINOR_VERSION); 412 return SDL_FALSE; 413 } 414 return SDL_FALSE; 415} 416 417#endif /* SDL_VIDEO_DRIVER_WINRT */ 418 419/* vi: set ts=4 sw=4 expandtab: */