src/video/winrt/SDL_winrtvideo.cpp
author David Ludwig <dludwig@pobox.com>
Sun, 06 Dec 2015 17:06:40 -0500
changeset 9947 3b68fd2503df
parent 9931 0bb3dd1c95f2
child 9948 46ba1492b14b
permissions -rw-r--r--
WinRT: workaround for a possible bug in the Win10 Store's Certification Kit

DXGI fails to report any displays in at least one of the
"Windows App Certification Kit 10.0"'s tests for Store Apps. This was
causing SDL's video initialization code to fail, when the suspect test
("Direct3D Feature Test") was run, as DXGI was unable to report a
display-output at adapter-index 0, output-index 0.

The workaround that is applied here attempts to detect this case, then
use a hopefully-reasonable alternative means to calculate at least one
display output.
dludwig@8327
     1
/*
dludwig@8327
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
dludwig@8327
     4
dludwig@8327
     5
  This software is provided 'as-is', without any express or implied
dludwig@8327
     6
  warranty.  In no event will the authors be held liable for any damages
dludwig@8327
     7
  arising from the use of this software.
dludwig@8327
     8
dludwig@8327
     9
  Permission is granted to anyone to use this software for any purpose,
dludwig@8327
    10
  including commercial applications, and to alter it and redistribute it
dludwig@8327
    11
  freely, subject to the following restrictions:
dludwig@8327
    12
dludwig@8327
    13
  1. The origin of this software must not be misrepresented; you must not
dludwig@8327
    14
     claim that you wrote the original software. If you use this software
dludwig@8327
    15
     in a product, an acknowledgment in the product documentation would be
dludwig@8327
    16
     appreciated but is not required.
dludwig@8327
    17
  2. Altered source versions must be plainly marked as such, and must not be
dludwig@8327
    18
     misrepresented as being the original software.
dludwig@8327
    19
  3. This notice may not be removed or altered from any source distribution.
dludwig@8327
    20
*/
dludwig@8600
    21
#include "../../SDL_internal.h"
dludwig@8327
    22
dludwig@8327
    23
#if SDL_VIDEO_DRIVER_WINRT
dludwig@8327
    24
dludwig@8327
    25
/* WinRT SDL video driver implementation
dludwig@8327
    26
dludwig@8327
    27
   Initial work on this was done by David Ludwig (dludwig@pobox.com), and
dludwig@8327
    28
   was based off of SDL's "dummy" video driver.
dludwig@8327
    29
 */
dludwig@8327
    30
dludwig@8494
    31
/* Windows includes */
dludwig@8494
    32
#include <agile.h>
dludwig@9924
    33
#include <windows.graphics.display.h>
dludwig@9924
    34
#include <dxgi.h>
dludwig@9924
    35
#include <dxgi1_2.h>
dludwig@9924
    36
using namespace Windows::ApplicationModel::Core;
dludwig@9924
    37
using namespace Windows::Foundation;
dludwig@9925
    38
using namespace Windows::Graphics::Display;
dludwig@8494
    39
using namespace Windows::UI::Core;
dludwig@9924
    40
using namespace Windows::UI::ViewManagement;
dludwig@9924
    41
dludwig@9924
    42
dludwig@9924
    43
/* [re]declare Windows GUIDs locally, to limit the amount of external lib(s) SDL has to link to */
dludwig@9924
    44
static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48,{ 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
dludwig@8494
    45
dludwig@8494
    46
dludwig@8494
    47
/* SDL includes */
dludwig@8329
    48
extern "C" {
dludwig@8327
    49
#include "SDL_video.h"
dludwig@8327
    50
#include "SDL_mouse.h"
dludwig@8327
    51
#include "../SDL_sysvideo.h"
dludwig@8327
    52
#include "../SDL_pixels_c.h"
dludwig@8327
    53
#include "../../events/SDL_events_c.h"
dludwig@8400
    54
#include "../../render/SDL_sysrender.h"
dludwig@8411
    55
#include "SDL_syswm.h"
dludwig@8541
    56
#include "SDL_winrtopengles.h"
dludwig@9924
    57
#include "../../core/windows/SDL_windows.h"
dludwig@8329
    58
}
dludwig@8327
    59
dludwig@8522
    60
#include "../../core/winrt/SDL_winrtapp_direct3d.h"
dludwig@8522
    61
#include "../../core/winrt/SDL_winrtapp_xaml.h"
dludwig@8512
    62
#include "SDL_winrtvideo_cpp.h"
dludwig@8327
    63
#include "SDL_winrtevents_c.h"
dludwig@8516
    64
#include "SDL_winrtmouse_c.h"
dludwig@8505
    65
#include "SDL_main.h"
dludwig@8505
    66
#include "SDL_system.h"
dludwig@8755
    67
//#include "SDL_log.h"
dludwig@8327
    68
dludwig@8327
    69
dludwig@8327
    70
/* Initialization/Query functions */
dludwig@8327
    71
static int WINRT_VideoInit(_THIS);
dludwig@8374
    72
static int WINRT_InitModes(_THIS);
dludwig@8327
    73
static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
dludwig@8327
    74
static void WINRT_VideoQuit(_THIS);
dludwig@8327
    75
dludwig@8494
    76
dludwig@8333
    77
/* Window functions */
dludwig@8522
    78
static int WINRT_CreateWindow(_THIS, SDL_Window * window);
dludwig@9931
    79
static void WINRT_SetWindowSize(_THIS, SDL_Window * window);
dludwig@9931
    80
static void WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
dludwig@8333
    81
static void WINRT_DestroyWindow(_THIS, SDL_Window * window);
dludwig@8411
    82
static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
dludwig@8333
    83
dludwig@8494
    84
dludwig@8515
    85
/* SDL-internal globals: */
dludwig@8497
    86
SDL_Window * WINRT_GlobalSDLWindow = NULL;
dludwig@8498
    87
dludwig@8498
    88
dludwig@8327
    89
/* WinRT driver bootstrap functions */
dludwig@8327
    90
dludwig@8327
    91
static int
dludwig@8327
    92
WINRT_Available(void)
dludwig@8327
    93
{
dludwig@8328
    94
    return (1);
dludwig@8327
    95
}
dludwig@8327
    96
dludwig@8327
    97
static void
dludwig@8327
    98
WINRT_DeleteDevice(SDL_VideoDevice * device)
dludwig@8327
    99
{
dludwig@8663
   100
    if (device->driverdata) {
dludwig@8663
   101
        SDL_VideoData * video_data = (SDL_VideoData *)device->driverdata;
dludwig@8663
   102
        if (video_data->winrtEglWindow) {
dludwig@8663
   103
            video_data->winrtEglWindow->Release();
dludwig@8663
   104
        }
dludwig@8663
   105
        SDL_free(video_data);
dludwig@8663
   106
    }
dludwig@8663
   107
dludwig@8327
   108
    SDL_free(device);
dludwig@8327
   109
}
dludwig@8327
   110
dludwig@8327
   111
static SDL_VideoDevice *
dludwig@8327
   112
WINRT_CreateDevice(int devindex)
dludwig@8327
   113
{
dludwig@8327
   114
    SDL_VideoDevice *device;
dludwig@8663
   115
    SDL_VideoData *data;
dludwig@8327
   116
dludwig@8327
   117
    /* Initialize all variables that we clean on shutdown */
dludwig@8327
   118
    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
dludwig@8327
   119
    if (!device) {
dludwig@8327
   120
        SDL_OutOfMemory();
dludwig@8327
   121
        if (device) {
dludwig@8327
   122
            SDL_free(device);
dludwig@8327
   123
        }
dludwig@8327
   124
        return (0);
dludwig@8327
   125
    }
dludwig@8327
   126
dludwig@8663
   127
    data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
dludwig@8663
   128
    if (!data) {
dludwig@8663
   129
        SDL_OutOfMemory();
dludwig@8663
   130
        return (0);
dludwig@8663
   131
    }
dludwig@8663
   132
    SDL_zerop(data);
dludwig@8663
   133
    device->driverdata = data;
dludwig@8663
   134
dludwig@8327
   135
    /* Set the function pointers */
dludwig@8327
   136
    device->VideoInit = WINRT_VideoInit;
dludwig@8327
   137
    device->VideoQuit = WINRT_VideoQuit;
dludwig@8333
   138
    device->CreateWindow = WINRT_CreateWindow;
dludwig@9931
   139
    device->SetWindowSize = WINRT_SetWindowSize;
dludwig@9931
   140
    device->SetWindowFullscreen = WINRT_SetWindowFullscreen;
dludwig@8333
   141
    device->DestroyWindow = WINRT_DestroyWindow;
dludwig@8327
   142
    device->SetDisplayMode = WINRT_SetDisplayMode;
dludwig@8327
   143
    device->PumpEvents = WINRT_PumpEvents;
dludwig@8411
   144
    device->GetWindowWMInfo = WINRT_GetWindowWMInfo;
dludwig@8541
   145
#ifdef SDL_VIDEO_OPENGL_EGL
slouken@8582
   146
    device->GL_LoadLibrary = WINRT_GLES_LoadLibrary;
slouken@8582
   147
    device->GL_GetProcAddress = WINRT_GLES_GetProcAddress;
slouken@8582
   148
    device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary;
slouken@8582
   149
    device->GL_CreateContext = WINRT_GLES_CreateContext;
slouken@8582
   150
    device->GL_MakeCurrent = WINRT_GLES_MakeCurrent;
slouken@8582
   151
    device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval;
slouken@8582
   152
    device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval;
slouken@8582
   153
    device->GL_SwapWindow = WINRT_GLES_SwapWindow;
dludwig@8541
   154
    device->GL_DeleteContext = WINRT_GLES_DeleteContext;
dludwig@8541
   155
#endif
dludwig@8433
   156
    device->free = WINRT_DeleteDevice;
dludwig@8327
   157
dludwig@8327
   158
    return device;
dludwig@8327
   159
}
dludwig@8327
   160
dludwig@8494
   161
#define WINRTVID_DRIVER_NAME "winrt"
dludwig@8327
   162
VideoBootStrap WINRT_bootstrap = {
dludwig@8500
   163
    WINRTVID_DRIVER_NAME, "SDL WinRT video driver",
dludwig@8327
   164
    WINRT_Available, WINRT_CreateDevice
dludwig@8327
   165
};
dludwig@8327
   166
dludwig@8327
   167
int
dludwig@8327
   168
WINRT_VideoInit(_THIS)
dludwig@8327
   169
{
dludwig@8374
   170
    if (WINRT_InitModes(_this) < 0) {
dludwig@8374
   171
        return -1;
dludwig@8374
   172
    }
dludwig@8374
   173
    WINRT_InitMouse(_this);
dludwig@8515
   174
    WINRT_InitTouch(_this);
dludwig@8522
   175
dludwig@8374
   176
    return 0;
dludwig@8374
   177
}
dludwig@8374
   178
dludwig@9924
   179
extern "C"
dludwig@9924
   180
Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat);
dludwig@9924
   181
dludwig@9924
   182
static void
dludwig@9924
   183
WINRT_DXGIModeToSDLDisplayMode(const DXGI_MODE_DESC * dxgiMode, SDL_DisplayMode * sdlMode)
dludwig@8522
   184
{
dludwig@9924
   185
    SDL_zerop(sdlMode);
dludwig@9924
   186
    sdlMode->w = dxgiMode->Width;
dludwig@9924
   187
    sdlMode->h = dxgiMode->Height;
dludwig@9924
   188
    sdlMode->refresh_rate = dxgiMode->RefreshRate.Numerator / dxgiMode->RefreshRate.Denominator;
dludwig@9924
   189
    sdlMode->format = D3D11_DXGIFormatToSDLPixelFormat(dxgiMode->Format);
dludwig@9924
   190
}
dludwig@8578
   191
dludwig@9924
   192
static int
dludwig@9924
   193
WINRT_AddDisplaysForOutput (_THIS, IDXGIAdapter1 * dxgiAdapter1, int outputIndex)
dludwig@9924
   194
{
dludwig@9924
   195
    HRESULT hr;
dludwig@9924
   196
    IDXGIOutput * dxgiOutput = NULL;
dludwig@9924
   197
    DXGI_OUTPUT_DESC dxgiOutputDesc;
dludwig@9924
   198
    SDL_VideoDisplay display;
dludwig@9924
   199
    char * displayName = NULL;
dludwig@9924
   200
    UINT numModes;
dludwig@9924
   201
    DXGI_MODE_DESC * dxgiModes = NULL;
dludwig@9924
   202
    int functionResult = -1;        /* -1 for failure, 0 for success */
dludwig@9924
   203
    DXGI_MODE_DESC modeToMatch, closestMatch;
dludwig@8522
   204
dludwig@9924
   205
    SDL_zero(display);
dludwig@9924
   206
dludwig@9924
   207
    hr = dxgiAdapter1->EnumOutputs(outputIndex, &dxgiOutput);
dludwig@9924
   208
    if (FAILED(hr)) {
dludwig@9924
   209
        if (hr != DXGI_ERROR_NOT_FOUND) {
dludwig@9924
   210
            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIAdapter1::EnumOutputs failed", hr);
dludwig@9924
   211
        }
dludwig@9924
   212
        goto done;
dludwig@8522
   213
    }
dludwig@8522
   214
dludwig@9924
   215
    hr = dxgiOutput->GetDesc(&dxgiOutputDesc);
dludwig@9924
   216
    if (FAILED(hr)) {
dludwig@9924
   217
        WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDesc failed", hr);
dludwig@9924
   218
        goto done;
dludwig@8579
   219
    }
dludwig@8579
   220
dludwig@9924
   221
    SDL_zero(modeToMatch);
dludwig@9924
   222
    modeToMatch.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
dludwig@9924
   223
    modeToMatch.Width = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left);
dludwig@9924
   224
    modeToMatch.Height = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top);
dludwig@9924
   225
    hr = dxgiOutput->FindClosestMatchingMode(&modeToMatch, &closestMatch, NULL);
dludwig@9924
   226
    if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
dludwig@9924
   227
        /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE gets returned by IDXGIOutput::FindClosestMatchingMode
dludwig@9924
   228
           when running under the Windows Simulator, which uses Remote Desktop (formerly known as Terminal
dludwig@9924
   229
           Services) under the hood.  According to the MSDN docs for the similar function,
dludwig@9924
   230
           IDXGIOutput::GetDisplayModeList, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE is returned if and
dludwig@9924
   231
           when an app is run under a Terminal Services session, hence the assumption.
dludwig@9924
   232
dludwig@9924
   233
           In this case, just add an SDL display mode, with approximated values.
dludwig@9924
   234
        */
dludwig@9924
   235
        SDL_DisplayMode mode;
dludwig@9924
   236
        SDL_zero(mode);
dludwig@9924
   237
        display.name = "Windows Simulator / Terminal Services Display";
dludwig@9924
   238
        mode.w = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left);
dludwig@9924
   239
        mode.h = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top);
dludwig@9924
   240
        mode.format = DXGI_FORMAT_B8G8R8A8_UNORM;
dludwig@9924
   241
        mode.refresh_rate = 0;  /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */
dludwig@9924
   242
        display.desktop_mode = mode;
dludwig@9924
   243
        display.current_mode = mode;
dludwig@9924
   244
        if ( ! SDL_AddDisplayMode(&display, &mode)) {
dludwig@9924
   245
            goto done;
dludwig@9924
   246
        }
dludwig@9924
   247
    } else if (FAILED(hr)) {
dludwig@9924
   248
        WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::FindClosestMatchingMode failed", hr);
dludwig@9924
   249
        goto done;
dludwig@9924
   250
    } else {
dludwig@9924
   251
        displayName = WIN_StringToUTF8(dxgiOutputDesc.DeviceName);
dludwig@9924
   252
        display.name = displayName;
dludwig@9924
   253
        WINRT_DXGIModeToSDLDisplayMode(&closestMatch, &display.desktop_mode);
dludwig@9924
   254
        display.current_mode = display.desktop_mode;
dludwig@9924
   255
dludwig@9924
   256
        hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, NULL);
dludwig@9924
   257
        if (FAILED(hr)) {
dludwig@9924
   258
            if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
dludwig@9924
   259
                // TODO, WinRT: make sure display mode(s) are added when using Terminal Services / Windows Simulator
dludwig@9924
   260
            }
dludwig@9924
   261
            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode list size] failed", hr);
dludwig@9924
   262
            goto done;
dludwig@9924
   263
        }
dludwig@9924
   264
dludwig@9924
   265
        dxgiModes = (DXGI_MODE_DESC *)SDL_calloc(numModes, sizeof(DXGI_MODE_DESC));
dludwig@9924
   266
        if ( ! dxgiModes) {
dludwig@9924
   267
            SDL_OutOfMemory();
dludwig@9924
   268
            goto done;
dludwig@9924
   269
        }
dludwig@9924
   270
dludwig@9924
   271
        hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, dxgiModes);
dludwig@9924
   272
        if (FAILED(hr)) {
dludwig@9924
   273
            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode contents] failed", hr);
dludwig@9924
   274
            goto done;
dludwig@9924
   275
        }
dludwig@9924
   276
dludwig@9924
   277
        for (UINT i = 0; i < numModes; ++i) {
dludwig@9924
   278
            SDL_DisplayMode sdlMode;
dludwig@9924
   279
            WINRT_DXGIModeToSDLDisplayMode(&dxgiModes[i], &sdlMode);
dludwig@9924
   280
            SDL_AddDisplayMode(&display, &sdlMode);
dludwig@9924
   281
        }
dludwig@8578
   282
    }
dludwig@8578
   283
dludwig@9924
   284
    if (SDL_AddVideoDisplay(&display) < 0) {
dludwig@9924
   285
        goto done;
dludwig@9924
   286
    }
dludwig@8522
   287
dludwig@9924
   288
    functionResult = 0;     /* 0 for Success! */
dludwig@9924
   289
done:
dludwig@9924
   290
    if (dxgiModes) {
dludwig@9924
   291
        SDL_free(dxgiModes);
dludwig@9924
   292
    }
dludwig@9924
   293
    if (dxgiOutput) {
dludwig@9924
   294
        dxgiOutput->Release();
dludwig@9924
   295
    }
dludwig@9924
   296
    if (displayName) {
dludwig@9924
   297
        SDL_free(displayName);
dludwig@9924
   298
    }
dludwig@9924
   299
    return functionResult;
dludwig@9924
   300
}
dludwig@9924
   301
dludwig@9924
   302
static int
dludwig@9924
   303
WINRT_AddDisplaysForAdapter (_THIS, IDXGIFactory2 * dxgiFactory2, int adapterIndex)
dludwig@9924
   304
{
dludwig@9924
   305
    HRESULT hr;
dludwig@9924
   306
    IDXGIAdapter1 * dxgiAdapter1;
dludwig@9924
   307
dludwig@9924
   308
    hr = dxgiFactory2->EnumAdapters1(adapterIndex, &dxgiAdapter1);
dludwig@9924
   309
    if (FAILED(hr)) {
dludwig@9924
   310
        if (hr != DXGI_ERROR_NOT_FOUND) {
dludwig@9924
   311
            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory1::EnumAdapters1() failed", hr);
dludwig@9924
   312
        }
dludwig@9924
   313
        return -1;
dludwig@9924
   314
    }
dludwig@9924
   315
dludwig@9924
   316
    for (int outputIndex = 0; ; ++outputIndex) {
dludwig@9924
   317
        if (WINRT_AddDisplaysForOutput(_this, dxgiAdapter1, outputIndex) < 0) {
dludwig@9947
   318
            /* HACK: The Windows App Certification Kit 10.0 can fail, when
dludwig@9947
   319
               running the Store Apps' test, "Direct3D Feature Test".  The
dludwig@9947
   320
               certification kit's error is:
dludwig@9947
   321
dludwig@9947
   322
               "Application App was not running at the end of the test. It likely crashed or was terminated for having become unresponsive."
dludwig@9947
   323
dludwig@9947
   324
               This was caused by SDL/WinRT's DXGI failing to report any
dludwig@9947
   325
               outputs.  Attempts to get the 1st display-output from the
dludwig@9947
   326
               1st display-adapter can fail, with IDXGIAdapter::EnumOutputs
dludwig@9947
   327
               returning DXGI_ERROR_NOT_FOUND.  This could be a bug in Windows,
dludwig@9947
   328
               the Windows App Certification Kit, or possibly in SDL/WinRT's
dludwig@9947
   329
               display detection code.  Either way, try to detect when this
dludwig@9947
   330
               happens, and use a hackish means to create a reasonable-as-possible
dludwig@9947
   331
               'display mode'.  -- DavidL
dludwig@9947
   332
            */
dludwig@9947
   333
#if SDL_WINRT_USE_APPLICATIONVIEW
dludwig@9947
   334
            if (adapterIndex == 0 && outputIndex == 0) {
dludwig@9947
   335
                SDL_VideoDisplay display;
dludwig@9947
   336
                SDL_DisplayMode mode;
dludwig@9947
   337
                ApplicationView ^ appView = ApplicationView::GetForCurrentView();
dludwig@9947
   338
                SDL_zero(display);
dludwig@9947
   339
                SDL_zero(mode);
dludwig@9947
   340
                display.name = "DXGI Display-detection Workaround";
dludwig@9947
   341
dludwig@9947
   342
                /* HACK: ApplicationView's VisibleBounds property, appeared, via testing, to
dludwig@9947
   343
                   give a better approximation of display-size, than did CoreWindow's
dludwig@9947
   344
                   Bounds property, insofar that ApplicationView::VisibleBounds seems like
dludwig@9947
   345
                   it will, at least some of the time, give the full display size (during the
dludwig@9947
   346
                   failing test), whereas CoreWindow will not.  -- DavidL
dludwig@9947
   347
                */
dludwig@9947
   348
                mode.w = WINRT_DIPS_TO_PHYSICAL_PIXELS(appView->VisibleBounds.Width);
dludwig@9947
   349
                mode.h = WINRT_DIPS_TO_PHYSICAL_PIXELS(appView->VisibleBounds.Height);
dludwig@9947
   350
dludwig@9947
   351
                mode.format = DXGI_FORMAT_B8G8R8A8_UNORM;
dludwig@9947
   352
                mode.refresh_rate = 0;  /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */
dludwig@9947
   353
                display.desktop_mode = mode;
dludwig@9947
   354
                display.current_mode = mode;
dludwig@9947
   355
                if ((SDL_AddDisplayMode(&display, &mode) < 0) ||
dludwig@9947
   356
                    (SDL_AddVideoDisplay(&display) < 0))
dludwig@9947
   357
                {
dludwig@9947
   358
                    return SDL_SetError("Failed to apply DXGI Display-detection workaround");
dludwig@9947
   359
                }
dludwig@9947
   360
            }
dludwig@9947
   361
#endif  // SDL_WINRT_USE_APPLICATIONVIEW
dludwig@9947
   362
dludwig@8522
   363
            break;
dludwig@8522
   364
        }
dludwig@9924
   365
    }
dludwig@8522
   366
dludwig@9924
   367
    dxgiAdapter1->Release();
dludwig@8578
   368
    return 0;
dludwig@8522
   369
}
dludwig@8503
   370
dludwig@8505
   371
int
dludwig@8374
   372
WINRT_InitModes(_THIS)
dludwig@8374
   373
{
dludwig@9924
   374
    /* HACK: Initialize a single display, for whatever screen the app's
dludwig@9924
   375
         CoreApplicationView is on.
dludwig@9924
   376
       TODO, WinRT: Try initializing multiple displays, one for each monitor.
dludwig@9924
   377
         Appropriate WinRT APIs for this seem elusive, though.  -- DavidL
dludwig@9924
   378
    */
dludwig@8522
   379
dludwig@9924
   380
    HRESULT hr;
dludwig@9924
   381
    IDXGIFactory2 * dxgiFactory2 = NULL;
dludwig@9924
   382
dludwig@9924
   383
    hr = CreateDXGIFactory1(IID_IDXGIFactory2, (void **)&dxgiFactory2);
dludwig@9924
   384
    if (FAILED(hr)) {
dludwig@9924
   385
        WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr);
dludwig@8522
   386
        return -1;
dludwig@8374
   387
    }
dludwig@8374
   388
dludwig@9924
   389
    int adapterIndex = 0;
dludwig@9924
   390
    for (int adapterIndex = 0; ; ++adapterIndex) {
dludwig@9924
   391
        if (WINRT_AddDisplaysForAdapter(_this, dxgiFactory2, adapterIndex) < 0) {
dludwig@9924
   392
            break;
dludwig@9924
   393
        }
dludwig@9924
   394
    }
dludwig@9924
   395
dludwig@8327
   396
    return 0;
dludwig@8327
   397
}
dludwig@8327
   398
dludwig@8327
   399
static int
dludwig@8327
   400
WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
dludwig@8327
   401
{
dludwig@8327
   402
    return 0;
dludwig@8327
   403
}
dludwig@8327
   404
dludwig@8327
   405
void
dludwig@8327
   406
WINRT_VideoQuit(_THIS)
dludwig@8327
   407
{
dludwig@8374
   408
    WINRT_QuitMouse(_this);
dludwig@8327
   409
}
dludwig@8327
   410
dludwig@9926
   411
static const Uint32 WINRT_DetectableFlags =
dludwig@9926
   412
    SDL_WINDOW_MAXIMIZED |
dludwig@9926
   413
    SDL_WINDOW_FULLSCREEN_DESKTOP |
dludwig@9926
   414
    SDL_WINDOW_SHOWN |
dludwig@9926
   415
    SDL_WINDOW_HIDDEN |
dludwig@9926
   416
    SDL_WINDOW_MOUSE_FOCUS;
dludwig@9926
   417
dludwig@9924
   418
extern "C" Uint32
dludwig@9924
   419
WINRT_DetectWindowFlags(SDL_Window * window)
dludwig@9924
   420
{
dludwig@9924
   421
    Uint32 latestFlags = 0;
dludwig@9924
   422
    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
dludwig@9924
   423
    bool is_fullscreen = false;
dludwig@9924
   424
dludwig@9924
   425
#if SDL_WINRT_USE_APPLICATIONVIEW
dludwig@9924
   426
    if (data->appView) {
dludwig@9924
   427
        is_fullscreen = data->appView->IsFullScreen;
dludwig@9924
   428
    }
dludwig@9927
   429
#elif (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION == NTDDI_WIN8)
dludwig@9924
   430
    is_fullscreen = true;
dludwig@9924
   431
#endif
dludwig@9924
   432
dludwig@9924
   433
    if (data->coreWindow.Get()) {
dludwig@9924
   434
        if (is_fullscreen) {
dludwig@9924
   435
            SDL_VideoDisplay * display = SDL_GetDisplayForWindow(window);
dludwig@9925
   436
            int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
dludwig@9925
   437
            int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
dludwig@9925
   438
dludwig@9925
   439
#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8)
dludwig@9925
   440
            // On all WinRT platforms, except for WinPhone 8.0, rotate the
dludwig@9925
   441
            // window size.  This is needed to properly calculate
dludwig@9925
   442
            // fullscreen vs. maximized.
dludwig@9925
   443
            const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
dludwig@9925
   444
            switch (currentOrientation) {
dludwig@9925
   445
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
dludwig@9925
   446
                case DisplayOrientations::Landscape:
dludwig@9925
   447
                case DisplayOrientations::LandscapeFlipped:
dludwig@9925
   448
#else
dludwig@9925
   449
                case DisplayOrientations::Portrait:
dludwig@9925
   450
                case DisplayOrientations::PortraitFlipped:
dludwig@9925
   451
#endif
dludwig@9925
   452
                {
dludwig@9925
   453
                    int tmp = w;
dludwig@9925
   454
                    w = h;
dludwig@9925
   455
                    h = tmp;
dludwig@9925
   456
                } break;
dludwig@9925
   457
            }
dludwig@9925
   458
#endif
dludwig@9925
   459
dludwig@9925
   460
            if (display->desktop_mode.w != w || display->desktop_mode.h != h) {
dludwig@9924
   461
                latestFlags |= SDL_WINDOW_MAXIMIZED;
dludwig@9924
   462
            } else {
dludwig@9924
   463
                latestFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
dludwig@9924
   464
            }
dludwig@9924
   465
        }
dludwig@9924
   466
dludwig@9924
   467
        if (data->coreWindow->Visible) {
dludwig@9924
   468
            latestFlags |= SDL_WINDOW_SHOWN;
dludwig@9924
   469
        } else {
dludwig@9924
   470
            latestFlags |= SDL_WINDOW_HIDDEN;
dludwig@9924
   471
        }
dludwig@9924
   472
dludwig@9924
   473
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION < NTDDI_WINBLUE)
dludwig@9924
   474
        // data->coreWindow->PointerPosition is not supported on WinPhone 8.0
dludwig@9924
   475
        latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
dludwig@9924
   476
#else
dludwig@9924
   477
        if (data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) {
dludwig@9924
   478
            latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
dludwig@9924
   479
        }
dludwig@9924
   480
#endif
dludwig@9924
   481
    }
dludwig@9924
   482
dludwig@9924
   483
    return latestFlags;
dludwig@9924
   484
}
dludwig@9924
   485
dludwig@9924
   486
void
dludwig@9924
   487
WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask)
dludwig@9924
   488
{
dludwig@9926
   489
    mask &= WINRT_DetectableFlags;
dludwig@9924
   490
    if (window) {
dludwig@9924
   491
        Uint32 apply = WINRT_DetectWindowFlags(window);
dludwig@9924
   492
        if ((apply & mask) & SDL_WINDOW_FULLSCREEN) {
dludwig@9924
   493
            window->last_fullscreen_flags = window->flags;  // seems necessary to programmatically un-fullscreen, via SDL APIs
dludwig@9924
   494
        }
dludwig@9924
   495
        window->flags = (window->flags & ~mask) | (apply & mask);
dludwig@9924
   496
    }
dludwig@9924
   497
}
dludwig@9924
   498
dludwig@8522
   499
int
dludwig@8522
   500
WINRT_CreateWindow(_THIS, SDL_Window * window)
dludwig@8522
   501
{
dludwig@8522
   502
    // Make sure that only one window gets created, at least until multimonitor
dludwig@8522
   503
    // support is added.
dludwig@8522
   504
    if (WINRT_GlobalSDLWindow != NULL) {
dludwig@8522
   505
        SDL_SetError("WinRT only supports one window");
dludwig@8522
   506
        return -1;
dludwig@8522
   507
    }
dludwig@8522
   508
dludwig@9924
   509
    SDL_WindowData *data = new SDL_WindowData;  /* use 'new' here as SDL_WindowData may use WinRT/C++ types */
dludwig@8522
   510
    if (!data) {
dludwig@8522
   511
        SDL_OutOfMemory();
dludwig@8522
   512
        return -1;
dludwig@8522
   513
    }
dludwig@8522
   514
    window->driverdata = data;
dludwig@8522
   515
    data->sdlWindow = window;
dludwig@8522
   516
dludwig@8522
   517
    /* To note, when XAML support is enabled, access to the CoreWindow will not
dludwig@8522
   518
       be possible, at least not via the SDL/XAML thread.  Attempts to access it
dludwig@8522
   519
       from there will throw exceptions.  As such, the SDL_WindowData's
dludwig@8522
   520
       'coreWindow' field will only be set (to a non-null value) if XAML isn't
dludwig@8522
   521
       enabled.
dludwig@8522
   522
    */
dludwig@8522
   523
    if (!WINRT_XAMLWasEnabled) {
dludwig@8522
   524
        data->coreWindow = CoreWindow::GetForCurrentThread();
dludwig@9924
   525
#if SDL_WINRT_USE_APPLICATIONVIEW
dludwig@9924
   526
        data->appView = ApplicationView::GetForCurrentView();
dludwig@9924
   527
#endif
dludwig@8522
   528
    }
dludwig@8522
   529
dludwig@9931
   530
    /* Make note of the requested window flags, before they start getting changed. */
dludwig@9931
   531
    const Uint32 requestedFlags = window->flags;
dludwig@9931
   532
dludwig@8541
   533
#if SDL_VIDEO_OPENGL_EGL
dludwig@8541
   534
    /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */
dludwig@8541
   535
    if (!(window->flags & SDL_WINDOW_OPENGL)) {
dludwig@8541
   536
        /* OpenGL ES 2 wasn't requested.  Don't set up an EGL surface. */
dludwig@8541
   537
        data->egl_surface = EGL_NO_SURFACE;
dludwig@8541
   538
    } else {
dludwig@8541
   539
        /* OpenGL ES 2 was reuqested.  Set up an EGL surface. */
dludwig@8663
   540
        SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata;
dludwig@8572
   541
dludwig@8663
   542
        /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly,
dludwig@9212
   543
         * rather than via SDL_EGL_CreateSurface, as older versions of
dludwig@9212
   544
         * ANGLE/WinRT may require that a C++ object, ComPtr<IUnknown>,
dludwig@9212
   545
         * be passed into eglCreateWindowSurface.
dludwig@8572
   546
         */
dludwig@8663
   547
        if (SDL_EGL_ChooseConfig(_this) != 0) {
dludwig@8663
   548
            char buf[512];
dludwig@8663
   549
            SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError());
philipp@9557
   550
            return SDL_SetError("%s", buf);
dludwig@8663
   551
        }
dludwig@8572
   552
dludwig@9211
   553
        if (video_data->winrtEglWindow) {   /* ... is the 'old' version of ANGLE/WinRT being used? */
dludwig@9211
   554
            /* Attempt to create a window surface using older versions of
dludwig@9211
   555
             * ANGLE/WinRT:
dludwig@9211
   556
             */
dludwig@9211
   557
            Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow;
dludwig@9211
   558
            data->egl_surface = ((eglCreateWindowSurface_Old_Function)_this->egl_data->eglCreateWindowSurface)(
dludwig@9211
   559
                _this->egl_data->egl_display,
dludwig@9211
   560
                _this->egl_data->egl_config,
dludwig@9211
   561
                cpp_winrtEglWindow, NULL);
dludwig@9211
   562
            if (data->egl_surface == NULL) {
dludwig@9211
   563
                return SDL_SetError("eglCreateWindowSurface failed");
dludwig@9211
   564
            }
dludwig@9211
   565
        } else if (data->coreWindow.Get() != nullptr) {
dludwig@9211
   566
            /* Attempt to create a window surface using newer versions of
dludwig@9211
   567
             * ANGLE/WinRT:
dludwig@9211
   568
             */
dludwig@9211
   569
            IInspectable * coreWindowAsIInspectable = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
dludwig@9211
   570
            data->egl_surface = _this->egl_data->eglCreateWindowSurface(
dludwig@9211
   571
                _this->egl_data->egl_display,
dludwig@9211
   572
                _this->egl_data->egl_config,
dludwig@9211
   573
                coreWindowAsIInspectable,
dludwig@9211
   574
                NULL);
dludwig@9211
   575
            if (data->egl_surface == NULL) {
dludwig@9211
   576
                return SDL_SetError("eglCreateWindowSurface failed");
dludwig@9211
   577
            }
dludwig@9211
   578
        } else {
dludwig@9211
   579
            return SDL_SetError("No supported means to create an EGL window surface are available");
dludwig@8541
   580
        }
dludwig@8541
   581
    }
dludwig@8541
   582
#endif
dludwig@8541
   583
dludwig@9924
   584
    /* Determine as many flags dynamically, as possible. */
dludwig@8522
   585
    window->flags =
dludwig@9928
   586
        SDL_WINDOW_BORDERLESS |
dludwig@9928
   587
        SDL_WINDOW_RESIZABLE;
dludwig@8522
   588
dludwig@8541
   589
#if SDL_VIDEO_OPENGL_EGL
dludwig@8541
   590
    if (data->egl_surface) {
dludwig@8541
   591
        window->flags |= SDL_WINDOW_OPENGL;
dludwig@8541
   592
    }
dludwig@8541
   593
#endif
dludwig@8541
   594
dludwig@9924
   595
    if (WINRT_XAMLWasEnabled) {
dludwig@9924
   596
        /* TODO, WinRT: set SDL_Window size, maybe position too, from XAML control */
dludwig@9924
   597
        window->x = 0;
dludwig@9924
   598
        window->y = 0;
dludwig@9924
   599
        window->flags |= SDL_WINDOW_SHOWN;
dludwig@9924
   600
        SDL_SetMouseFocus(NULL);        // TODO: detect this
dludwig@9924
   601
        SDL_SetKeyboardFocus(NULL);     // TODO: detect this
dludwig@9924
   602
    } else {
dludwig@9931
   603
        /* WinRT 8.x apps seem to live in an environment where the OS controls the
dludwig@9924
   604
           app's window size, with some apps being fullscreen, depending on
dludwig@9924
   605
           user choice of various things.  For now, just adapt the SDL_Window to
dludwig@9924
   606
           whatever Windows set-up as the native-window's geometry.
dludwig@9924
   607
        */
dludwig@9924
   608
        window->x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left);
dludwig@9924
   609
        window->y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top);
dludwig@9931
   610
#if NTDDI_VERSION < NTDDI_WIN10
dludwig@9931
   611
        /* On WinRT 8.x / pre-Win10, just use the size we were given. */
dludwig@9924
   612
        window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
dludwig@9924
   613
        window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
dludwig@9931
   614
#else
dludwig@9931
   615
        /* On Windows 10, we occasionally get control over window size.  For windowed
dludwig@9931
   616
           mode apps, try this.
dludwig@9931
   617
        */
dludwig@9931
   618
        bool didSetSize = false;
dludwig@9931
   619
        if (!(requestedFlags & SDL_WINDOW_FULLSCREEN)) {
dludwig@9931
   620
            const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w),
dludwig@9931
   621
                                                 WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h));
dludwig@9931
   622
            didSetSize = data->appView->TryResizeView(size);
dludwig@9931
   623
        }
dludwig@9931
   624
        if (!didSetSize) {
dludwig@9931
   625
            /* We either weren't able to set the window size, or a request for
dludwig@9931
   626
               fullscreen was made.  Get window-size info from the OS.
dludwig@9931
   627
            */
dludwig@9931
   628
            window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
dludwig@9931
   629
            window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
dludwig@9931
   630
        }
dludwig@9931
   631
#endif
dludwig@8522
   632
dludwig@9924
   633
        WINRT_UpdateWindowFlags(
dludwig@9924
   634
            window,
dludwig@9924
   635
            0xffffffff      /* Update any window flag(s) that WINRT_UpdateWindow can handle */
dludwig@9924
   636
        );
dludwig@8551
   637
dludwig@9924
   638
        /* Try detecting if the window is active */
dludwig@9924
   639
        bool isWindowActive = true;     /* Presume the window is active, unless we've been told otherwise */
dludwig@9924
   640
        if (data->coreWindow->CustomProperties->HasKey("SDLHelperWindowActivationState")) {
dludwig@9924
   641
            CoreWindowActivationState activationState = \
dludwig@9924
   642
                safe_cast<CoreWindowActivationState>(data->coreWindow->CustomProperties->Lookup("SDLHelperWindowActivationState"));
dludwig@9924
   643
            isWindowActive = (activationState != CoreWindowActivationState::Deactivated);
dludwig@9924
   644
        }
dludwig@9924
   645
        if (isWindowActive) {
dludwig@9924
   646
            SDL_SetKeyboardFocus(window);
dludwig@9924
   647
        }
dludwig@9924
   648
    }
dludwig@8522
   649
 
dludwig@8522
   650
    /* Make sure the WinRT app's IFramworkView can post events on
dludwig@8522
   651
       behalf of SDL:
dludwig@8522
   652
    */
dludwig@8522
   653
    WINRT_GlobalSDLWindow = window;
dludwig@8522
   654
dludwig@8522
   655
    /* All done! */
dludwig@8522
   656
    return 0;
dludwig@8522
   657
}
dludwig@8522
   658
dludwig@8333
   659
void
dludwig@9931
   660
WINRT_SetWindowSize(_THIS, SDL_Window * window)
dludwig@9931
   661
{
dludwig@9931
   662
#if NTDDI_VERSION >= NTDDI_WIN10
dludwig@9931
   663
    SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
dludwig@9931
   664
    const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w),
dludwig@9931
   665
                                         WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h));
dludwig@9931
   666
    data->appView->TryResizeView(size); // TODO, WinRT: return failure (to caller?) from TryResizeView()
dludwig@9931
   667
#endif
dludwig@9931
   668
}
dludwig@9931
   669
dludwig@9931
   670
void
dludwig@9931
   671
WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
dludwig@9931
   672
{
dludwig@9931
   673
#if NTDDI_VERSION >= NTDDI_WIN10
dludwig@9931
   674
    SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
dludwig@9931
   675
    if (fullscreen) {
dludwig@9931
   676
        if (!data->appView->IsFullScreenMode) {
dludwig@9931
   677
            data->appView->TryEnterFullScreenMode();    // TODO, WinRT: return failure (to caller?) from TryEnterFullScreenMode()
dludwig@9931
   678
        }
dludwig@9931
   679
    } else {
dludwig@9931
   680
        if (data->appView->IsFullScreenMode) {
dludwig@9931
   681
            data->appView->ExitFullScreenMode();
dludwig@9931
   682
        }
dludwig@9931
   683
    }
dludwig@9931
   684
#endif
dludwig@9931
   685
}
dludwig@9931
   686
dludwig@9931
   687
dludwig@9931
   688
void
dludwig@8333
   689
WINRT_DestroyWindow(_THIS, SDL_Window * window)
dludwig@8333
   690
{
dludwig@8411
   691
    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
dludwig@8411
   692
dludwig@8497
   693
    if (WINRT_GlobalSDLWindow == window) {
dludwig@8497
   694
        WINRT_GlobalSDLWindow = NULL;
dludwig@8424
   695
    }
dludwig@8424
   696
dludwig@8411
   697
    if (data) {
dludwig@8411
   698
        // Delete the internal window data:
dludwig@8411
   699
        delete data;
dludwig@8411
   700
        data = NULL;
dludwig@9214
   701
        window->driverdata = NULL;
dludwig@8411
   702
    }
dludwig@8333
   703
}
dludwig@8333
   704
dludwig@8522
   705
SDL_bool
dludwig@8522
   706
WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
dludwig@8522
   707
{
dludwig@8522
   708
    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
dludwig@8522
   709
dludwig@8522
   710
    if (info->version.major <= SDL_MAJOR_VERSION) {
dludwig@8522
   711
        info->subsystem = SDL_SYSWM_WINRT;
dludwig@8527
   712
        info->info.winrt.window = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
dludwig@8522
   713
        return SDL_TRUE;
dludwig@8522
   714
    } else {
dludwig@8522
   715
        SDL_SetError("Application not compiled with SDL %d.%d\n",
dludwig@8522
   716
                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
dludwig@8522
   717
        return SDL_FALSE;
dludwig@8522
   718
    }
dludwig@8522
   719
    return SDL_FALSE;
dludwig@8411
   720
}
dludwig@8333
   721
dludwig@8327
   722
#endif /* SDL_VIDEO_DRIVER_WINRT */
dludwig@8327
   723
dludwig@8327
   724
/* vi: set ts=4 sw=4 expandtab: */