src/video/winrt/SDL_winrtvideo.cpp
author David Ludwig <dludwig@pobox.com>
Mon, 04 Nov 2013 19:54:29 -0500
changeset 8541 0041edb891f3
parent 8527 e3807733fad5
child 8551 666f05b079ea
permissions -rw-r--r--
WinRT: added experimental OpenGL ES 2.0 support

A port of the ANGLE library (OpenGL ES 2.0 for Direct3D) to WinRT, via https://github.com/stammen/angleproject, is used as a base.

To enable, clone 'angleproject' into the directory one above where SDL/WinRT is, open the file SDL/include/SDL_config_winrt.h, and uncomment the #defines that begin with 'SDL_VIDEO_OPENGL'. From there, apps can create an OpenGL capable SDL_Window via the flag, SDL_WINDOW_OPENGL, and an OpenGL ES 2 context via SDL_GL_CreateContext. The Direct3D 11.1 renderer cannot be used alongside SDL_WINDOW_OPENGL. Only Windows 8/8.1 is supported for now. Shaders may need to be precompiled, in some (all?) cases.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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_config.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 using namespace Windows::UI::Core;
    34 
    35 
    36 /* SDL includes */
    37 extern "C" {
    38 #include "SDL_video.h"
    39 #include "SDL_mouse.h"
    40 #include "../SDL_sysvideo.h"
    41 #include "../SDL_pixels_c.h"
    42 #include "../../events/SDL_events_c.h"
    43 #include "../../render/SDL_sysrender.h"
    44 #include "SDL_syswm.h"
    45 #include "SDL_winrtopengles.h"
    46 }
    47 
    48 #include "../../core/winrt/SDL_winrtapp_direct3d.h"
    49 #include "../../core/winrt/SDL_winrtapp_xaml.h"
    50 #include "SDL_winrtvideo_cpp.h"
    51 #include "SDL_winrtevents_c.h"
    52 #include "SDL_winrtmouse_c.h"
    53 #include "SDL_main.h"
    54 #include "SDL_system.h"
    55 
    56 
    57 /* Initialization/Query functions */
    58 static int WINRT_VideoInit(_THIS);
    59 static int WINRT_InitModes(_THIS);
    60 static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
    61 static void WINRT_VideoQuit(_THIS);
    62 
    63 
    64 /* Window functions */
    65 static int WINRT_CreateWindow(_THIS, SDL_Window * window);
    66 static void WINRT_DestroyWindow(_THIS, SDL_Window * window);
    67 static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
    68 
    69 
    70 /* SDL-internal globals: */
    71 SDL_Window * WINRT_GlobalSDLWindow = NULL;
    72 SDL_VideoDevice * WINRT_GlobalSDLVideoDevice = NULL;
    73 
    74 
    75 /* WinRT driver bootstrap functions */
    76 
    77 static int
    78 WINRT_Available(void)
    79 {
    80     return (1);
    81 }
    82 
    83 static void
    84 WINRT_DeleteDevice(SDL_VideoDevice * device)
    85 {
    86     if (device == WINRT_GlobalSDLVideoDevice) {
    87         WINRT_GlobalSDLVideoDevice = NULL;
    88     }
    89     SDL_free(device);
    90 }
    91 
    92 static SDL_VideoDevice *
    93 WINRT_CreateDevice(int devindex)
    94 {
    95     SDL_VideoDevice *device;
    96 
    97     /* Initialize all variables that we clean on shutdown */
    98     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
    99     if (!device) {
   100         SDL_OutOfMemory();
   101         if (device) {
   102             SDL_free(device);
   103         }
   104         return (0);
   105     }
   106 
   107     /* Set the function pointers */
   108     device->VideoInit = WINRT_VideoInit;
   109     device->VideoQuit = WINRT_VideoQuit;
   110     device->CreateWindow = WINRT_CreateWindow;
   111     device->DestroyWindow = WINRT_DestroyWindow;
   112     device->SetDisplayMode = WINRT_SetDisplayMode;
   113     device->PumpEvents = WINRT_PumpEvents;
   114     device->GetWindowWMInfo = WINRT_GetWindowWMInfo;
   115 #ifdef SDL_VIDEO_OPENGL_EGL
   116     device->GL_LoadLibrary = WINRT_GLES_LoadLibrary;
   117     device->GL_GetProcAddress = WINRT_GLES_GetProcAddress;
   118     device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary;
   119     device->GL_CreateContext = WINRT_GLES_CreateContext;
   120     device->GL_MakeCurrent = WINRT_GLES_MakeCurrent;
   121     device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval;
   122     device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval;
   123     device->GL_SwapWindow = WINRT_GLES_SwapWindow;
   124     device->GL_DeleteContext = WINRT_GLES_DeleteContext;
   125 #endif
   126     device->free = WINRT_DeleteDevice;
   127     WINRT_GlobalSDLVideoDevice = device;
   128 
   129     return device;
   130 }
   131 
   132 #define WINRTVID_DRIVER_NAME "winrt"
   133 VideoBootStrap WINRT_bootstrap = {
   134     WINRTVID_DRIVER_NAME, "SDL WinRT video driver",
   135     WINRT_Available, WINRT_CreateDevice
   136 };
   137 
   138 int
   139 WINRT_VideoInit(_THIS)
   140 {
   141     if (WINRT_InitModes(_this) < 0) {
   142         return -1;
   143     }
   144     WINRT_InitMouse(_this);
   145     WINRT_InitTouch(_this);
   146 
   147     return 0;
   148 }
   149 
   150 SDL_DisplayMode
   151 WINRT_CalcDisplayModeUsingNativeWindow()
   152 {
   153     using namespace Windows::Graphics::Display;
   154 
   155     // Create an empty, zeroed-out display mode:
   156     SDL_DisplayMode mode;
   157     SDL_zero(mode);
   158 
   159     // Go no further if a native window cannot be accessed.  This can happen,
   160     // for example, if this function is called from certain threads, such as
   161     // the SDL/XAML thread.
   162     if (!CoreWindow::GetForCurrentThread()) {
   163         return mode;
   164     }
   165 
   166     // Fill in most fields:
   167     mode.format = SDL_PIXELFORMAT_RGB888;
   168     mode.refresh_rate = 0;  // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps)
   169     mode.driverdata = (void *) DisplayProperties::CurrentOrientation;
   170 
   171     // Calculate the display size given the window size, taking into account
   172     // the current display's DPI:
   173     const float currentDPI = Windows::Graphics::Display::DisplayProperties::LogicalDpi; 
   174     const float dipsPerInch = 96.0f;
   175     mode.w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch);
   176     mode.h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch);
   177 
   178 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
   179     // On Windows Phone, the native window's size is always in portrait,
   180     // regardless of the device's orientation.  This is in contrast to
   181     // Windows 8/RT, which will resize the native window as the device's
   182     // orientation changes.  In order to compensate for this behavior,
   183     // on Windows Phone, the mode's width and height will be swapped when
   184     // the device is in a landscape (non-portrait) mode.
   185     switch (DisplayProperties::CurrentOrientation) {
   186         case DisplayOrientations::Landscape:
   187         case DisplayOrientations::LandscapeFlipped:
   188         {
   189             const int tmp = mode.h;
   190             mode.h = mode.w;
   191             mode.w = tmp;
   192             break;
   193         }
   194 
   195         default:
   196             break;
   197     }
   198 
   199     // Attach the mode to te
   200 #endif
   201 
   202     return mode;
   203 }
   204 
   205 int
   206 WINRT_InitModes(_THIS)
   207 {
   208     // Retrieve the display mode:
   209     SDL_DisplayMode mode = WINRT_CalcDisplayModeUsingNativeWindow();
   210     if (mode.w == 0 || mode.h == 0) {
   211         return SDL_SetError("Unable to calculate the WinRT window/display's size");
   212     }
   213 
   214     if (SDL_AddBasicVideoDisplay(&mode) < 0) {
   215         return -1;
   216     }
   217 
   218     SDL_AddDisplayMode(&_this->displays[0], &mode);
   219     return 0;
   220 }
   221 
   222 static int
   223 WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   224 {
   225     return 0;
   226 }
   227 
   228 void
   229 WINRT_VideoQuit(_THIS)
   230 {
   231     WINRT_QuitMouse(_this);
   232 }
   233 
   234 int
   235 WINRT_CreateWindow(_THIS, SDL_Window * window)
   236 {
   237     // Make sure that only one window gets created, at least until multimonitor
   238     // support is added.
   239     if (WINRT_GlobalSDLWindow != NULL) {
   240         SDL_SetError("WinRT only supports one window");
   241         return -1;
   242     }
   243 
   244     SDL_WindowData *data = new SDL_WindowData;
   245     if (!data) {
   246         SDL_OutOfMemory();
   247         return -1;
   248     }
   249     window->driverdata = data;
   250     data->sdlWindow = window;
   251 
   252     /* To note, when XAML support is enabled, access to the CoreWindow will not
   253        be possible, at least not via the SDL/XAML thread.  Attempts to access it
   254        from there will throw exceptions.  As such, the SDL_WindowData's
   255        'coreWindow' field will only be set (to a non-null value) if XAML isn't
   256        enabled.
   257     */
   258     if (!WINRT_XAMLWasEnabled) {
   259         data->coreWindow = CoreWindow::GetForCurrentThread();
   260     }
   261 
   262 #if SDL_VIDEO_OPENGL_EGL
   263     /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */
   264     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   265         /* OpenGL ES 2 wasn't requested.  Don't set up an EGL surface. */
   266         data->egl_surface = EGL_NO_SURFACE;
   267     } else {
   268         /* OpenGL ES 2 was reuqested.  Set up an EGL surface. */
   269         IUnknown * nativeWindow = reinterpret_cast<IUnknown *>(data->coreWindow.Get());
   270         data->egl_surface = SDL_EGL_CreateSurface(_this, nativeWindow);
   271         if (data->egl_surface == NULL) {
   272             // TODO, WinRT: see if SDL_EGL_CreateSurface, or its callee(s), sets an error message.  If so, attach it to the SDL error.
   273             return SDL_SetError("SDL_EGL_CreateSurface failed");
   274         }
   275     }
   276 #endif
   277 
   278     /* Make sure the window is considered to be positioned at {0,0},
   279        and is considered fullscreen, shown, and the like.
   280     */
   281     window->x = 0;
   282     window->y = 0;
   283     window->flags =
   284         SDL_WINDOW_FULLSCREEN |
   285         SDL_WINDOW_SHOWN |
   286         SDL_WINDOW_BORDERLESS |
   287         SDL_WINDOW_MAXIMIZED |
   288         SDL_WINDOW_INPUT_GRABBED;
   289 
   290 #if SDL_VIDEO_OPENGL_EGL
   291     if (data->egl_surface) {
   292         window->flags |= SDL_WINDOW_OPENGL;
   293     }
   294 #endif
   295 
   296     /* WinRT does not, as of this writing, appear to support app-adjustable
   297        window sizes.  Set the window size to whatever the native WinRT
   298        CoreWindow is set at.
   299 
   300        TODO, WinRT: if and when non-fullscreen XAML control support is added to SDL, consider making those resizable via SDL_Window's interfaces.
   301     */
   302     window->w = _this->displays[0].current_mode.w;
   303     window->h = _this->displays[0].current_mode.h;
   304  
   305     /* Make sure the WinRT app's IFramworkView can post events on
   306        behalf of SDL:
   307     */
   308     WINRT_GlobalSDLWindow = window;
   309 
   310     /* All done! */
   311     return 0;
   312 }
   313 
   314 void
   315 WINRT_DestroyWindow(_THIS, SDL_Window * window)
   316 {
   317     SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
   318 
   319     if (WINRT_GlobalSDLWindow == window) {
   320         WINRT_GlobalSDLWindow = NULL;
   321     }
   322 
   323     if (data) {
   324         // Delete the internal window data:
   325         delete data;
   326         data = NULL;
   327     }
   328 }
   329 
   330 SDL_bool
   331 WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   332 {
   333     SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
   334 
   335     if (info->version.major <= SDL_MAJOR_VERSION) {
   336         info->subsystem = SDL_SYSWM_WINRT;
   337         info->info.winrt.window = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
   338         return SDL_TRUE;
   339     } else {
   340         SDL_SetError("Application not compiled with SDL %d.%d\n",
   341                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   342         return SDL_FALSE;
   343     }
   344     return SDL_FALSE;
   345 }
   346 
   347 #endif /* SDL_VIDEO_DRIVER_WINRT */
   348 
   349 /* vi: set ts=4 sw=4 expandtab: */