Fixed rendering-alignment issues on WinPhone 8.1, when the device was rotated
authorDavid Ludwig <dludwig@pobox.com>
Fri, 09 May 2014 20:16:21 -0400
changeset 8755f2fc45874b9c
parent 8754 162dc8eaa609
child 8756 d35c6e6ccbb4
Fixed rendering-alignment issues on WinPhone 8.1, when the device was rotated

If a Windows Phone 8.1 device was rotated to anything but Portrait mode,
the Direct3D 11 renderer's output wouldn't get aligned correctly with the
screen.
src/core/winrt/SDL_winrtapp_direct3d.cpp
src/render/direct3d11/SDL_render_d3d11.c
src/video/winrt/SDL_winrtvideo.cpp
src/video/winrt/SDL_winrtvideo_cpp.h
     1.1 --- a/src/core/winrt/SDL_winrtapp_direct3d.cpp	Tue May 06 20:31:10 2014 -0400
     1.2 +++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp	Fri May 09 20:16:21 2014 -0400
     1.3 @@ -229,36 +229,30 @@
     1.4      }
     1.5  
     1.6      if (WINRT_GlobalSDLWindow) {
     1.7 -        // Send a window-resize event to the rest of SDL, and to apps:
     1.8 -        SDL_SendWindowEvent(
     1.9 -            WINRT_GlobalSDLWindow,
    1.10 -            SDL_WINDOWEVENT_RESIZED,
    1.11 -            newDisplayMode.w,
    1.12 -            newDisplayMode.h);
    1.13 -
    1.14 +        // If the window size changed, send a resize event to SDL and its host app:
    1.15 +        int window_w = 0;
    1.16 +        int window_h = 0;
    1.17 +        SDL_GetWindowSize(WINRT_GlobalSDLWindow, &window_w, &window_h);
    1.18 +        if ((window_w != newDisplayMode.w) || (window_h != newDisplayMode.h)) {
    1.19 +            SDL_SendWindowEvent(
    1.20 +                WINRT_GlobalSDLWindow,
    1.21 +                SDL_WINDOWEVENT_RESIZED,
    1.22 +                newDisplayMode.w,
    1.23 +                newDisplayMode.h);
    1.24 +        } else {
    1.25  #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
    1.26 -        // HACK: On Windows Phone, make sure that orientation changes from
    1.27 -        // Landscape to LandscapeFlipped, Portrait to PortraitFlipped,
    1.28 -        // or vice-versa on either of those two, lead to the Direct3D renderer
    1.29 -        // getting updated.
    1.30 -        const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation;
    1.31 -        const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation;
    1.32 -
    1.33 -        if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) ||
    1.34 -            (oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) ||
    1.35 -            (oldOrientation == DisplayOrientations::Portrait && newOrientation == DisplayOrientations::PortraitFlipped) ||
    1.36 -            (oldOrientation == DisplayOrientations::PortraitFlipped && newOrientation == DisplayOrientations::Portrait))
    1.37 -        {
    1.38 -            // One of the reasons this event is getting sent out is because SDL
    1.39 -            // will ignore requests to send out SDL_WINDOWEVENT_RESIZED events
    1.40 -            // if and when the event size doesn't change (and the Direct3D 11.1
    1.41 -            // renderer doesn't get the memo).
    1.42 +            // HACK: Make sure that orientation changes
    1.43 +            // lead to the Direct3D renderer's viewport getting updated:
    1.44              //
    1.45 -            // Make sure that the display/window size really didn't change.  If
    1.46 -            // it did, then a SDL_WINDOWEVENT_SIZE_CHANGED event got sent, and
    1.47 -            // the Direct3D 11.1 renderer picked it up, presumably.
    1.48 -            if (oldDisplayMode.w == newDisplayMode.w &&
    1.49 -                oldDisplayMode.h == newDisplayMode.h)
    1.50 +            // For some reason, this doesn't seem to need to be done on Windows 8.x,
    1.51 +            // even when going from Landscape to LandscapeFlipped.  It only seems to
    1.52 +            // be needed on Windows Phone, at least when I tested on my devices.
    1.53 +            // I'm not currently sure why this is, but it seems to work fine. -- David L.
    1.54 +            //
    1.55 +            // TODO, WinRT: do more extensive research into why orientation changes on Win 8.x don't need D3D changes, or if they might, in some cases
    1.56 +            const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation;
    1.57 +            const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation;
    1.58 +            if (oldOrientation != newOrientation)
    1.59              {
    1.60                  SDL_SendWindowEvent(
    1.61                      WINRT_GlobalSDLWindow,
    1.62 @@ -266,8 +260,8 @@
    1.63                      newDisplayMode.w,
    1.64                      newDisplayMode.h);
    1.65              }
    1.66 +#endif
    1.67          }
    1.68 -#endif
    1.69      }
    1.70      
    1.71      // Finally, free the 'driverdata' field of the old 'desktop_mode'.
    1.72 @@ -309,26 +303,21 @@
    1.73      if (window) {
    1.74          SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n",
    1.75              __FUNCTION__,
    1.76 -            (int)DisplayProperties::CurrentOrientation,
    1.77 -            (int)DisplayProperties::NativeOrientation,
    1.78 -            (int)DisplayProperties::AutoRotationPreferences,
    1.79 +            WINRT_DISPLAY_PROPERTY(CurrentOrientation),
    1.80 +            WINRT_DISPLAY_PROPERTY(NativeOrientation),
    1.81 +            WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
    1.82              window->Bounds.Width,
    1.83              window->Bounds.Height);
    1.84      } else {
    1.85          SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
    1.86              __FUNCTION__,
    1.87 -            (int)DisplayProperties::CurrentOrientation,
    1.88 -            (int)DisplayProperties::NativeOrientation,
    1.89 -            (int)DisplayProperties::AutoRotationPreferences);
    1.90 +            WINRT_DISPLAY_PROPERTY(CurrentOrientation),
    1.91 +            WINRT_DISPLAY_PROPERTY(NativeOrientation),
    1.92 +            WINRT_DISPLAY_PROPERTY(AutoRotationPreferences));
    1.93      }
    1.94  #endif
    1.95  
    1.96 -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
    1.97 -    // On Windows Phone, treat an orientation change as a change in window size.
    1.98 -    // The native window's size doesn't seem to change, however SDL will simulate
    1.99 -    // a window size change.
   1.100      WINRT_ProcessWindowSizeChange();
   1.101 -#endif
   1.102  }
   1.103  
   1.104  void SDL_WinRTApp::SetWindow(CoreWindow^ window)
   1.105 @@ -336,9 +325,9 @@
   1.106  #if LOG_WINDOW_EVENTS==1
   1.107      SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n",
   1.108          __FUNCTION__,
   1.109 -        (int)DisplayProperties::CurrentOrientation,
   1.110 -        (int)DisplayProperties::NativeOrientation,
   1.111 -        (int)DisplayProperties::AutoRotationPreferences,
   1.112 +        WINRT_DISPLAY_PROPERTY(CurrentOrientation),
   1.113 +        WINRT_DISPLAY_PROPERTY(NativeOrientation),
   1.114 +        WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
   1.115          window->Bounds.Width,
   1.116          window->Bounds.Height);
   1.117  #endif
   1.118 @@ -540,9 +529,9 @@
   1.119      SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n",
   1.120          __FUNCTION__,
   1.121          args->Size.Width, args->Size.Height,
   1.122 -        (int)DisplayProperties::CurrentOrientation,
   1.123 -        (int)DisplayProperties::NativeOrientation,
   1.124 -        (int)DisplayProperties::AutoRotationPreferences,
   1.125 +        WINRT_DISPLAY_PROPERTY(CurrentOrientation),
   1.126 +        WINRT_DISPLAY_PROPERTY(NativeOrientation),
   1.127 +        WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
   1.128          (WINRT_GlobalSDLWindow ? "yes" : "no"));
   1.129  #endif
   1.130  
     2.1 --- a/src/render/direct3d11/SDL_render_d3d11.c	Tue May 06 20:31:10 2014 -0400
     2.2 +++ b/src/render/direct3d11/SDL_render_d3d11.c	Fri May 09 20:16:21 2014 -0400
     2.3 @@ -29,6 +29,7 @@
     2.4  #include "SDL_syswm.h"
     2.5  #include "../SDL_sysrender.h"
     2.6  #include "../SDL_d3dmath.h"
     2.7 +/* #include "SDL_log.h" */
     2.8  
     2.9  #include <d3d11_1.h>
    2.10  
    2.11 @@ -1390,6 +1391,7 @@
    2.12  #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
    2.13      swapChainDesc.Scaling = DXGI_SCALING_STRETCH; /* On phone, only stretch and aspect-ratio stretch scaling are allowed. */
    2.14      swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; /* On phone, no swap effects are supported. */
    2.15 +    /* TODO, WinRT: see if Win 8.x DXGI_SWAP_CHAIN_DESC1 settings are available on Windows Phone 8.1, and if there's any advantage to having them on */
    2.16  #else
    2.17      if (usingXAML) {
    2.18          swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
    2.19 @@ -1484,6 +1486,7 @@
    2.20       */
    2.21      SDL_GetWindowSize(renderer->window, &w, &h);
    2.22      data->rotation = D3D11_GetCurrentRotation();
    2.23 +    /* SDL_Log("%s: windowSize={%d,%d}, orientation=%d\n", __FUNCTION__, w, h, (int)data->rotation); */
    2.24      if (D3D11_IsDisplayRotated90Degrees(data->rotation)) {
    2.25          int tmp = w;
    2.26          w = h;
    2.27 @@ -1521,11 +1524,21 @@
    2.28      }
    2.29      
    2.30  #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
    2.31 -    /* Set the proper rotation for the swap chain, and generate the
    2.32 -     * 3D matrix transformation for rendering to the rotated swap chain.
    2.33 +    /* Set the proper rotation for the swap chain.
    2.34       *
    2.35       * To note, the call for this, IDXGISwapChain1::SetRotation, is not necessary
    2.36 -     * on Windows Phone, nor is it supported there.  It's only needed in Windows 8/RT.
    2.37 +     * on Windows Phone 8.0, nor is it supported there.
    2.38 +     *
    2.39 +     * IDXGISwapChain1::SetRotation does seem to be available on Windows Phone 8.1,
    2.40 +     * however I've yet to find a way to make it work.  It might have something to
    2.41 +     * do with IDXGISwapChain::ResizeBuffers appearing to not being available on
    2.42 +     * Windows Phone 8.1 (it wasn't on Windows Phone 8.0), but I'm not 100% sure of this.
    2.43 +     * The call doesn't appear to be entirely necessary though, and is a performance-related
    2.44 +     * call, at least according to the following page on MSDN:
    2.45 +     * http://code.msdn.microsoft.com/windowsapps/DXGI-swap-chain-rotation-21d13d71
    2.46 +     *   -- David L.
    2.47 +     *
    2.48 +     * TODO, WinRT: reexamine the docs for IDXGISwapChain1::SetRotation, see if might be available, usable, and prudent-to-call on WinPhone 8.1
    2.49       */
    2.50      if (data->swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) {
    2.51          result = IDXGISwapChain1_SetRotation(data->swapChain, data->rotation);
    2.52 @@ -2144,6 +2157,7 @@
    2.53           * SDL_CreateRenderer is calling it, and will call it again later
    2.54           * with a non-empty viewport.
    2.55           */
    2.56 +        /* SDL_Log("%s, no viewport was set!\n", __FUNCTION__); */
    2.57          return 0;
    2.58      }
    2.59  
    2.60 @@ -2223,6 +2237,7 @@
    2.61      viewport.Height = orientationAlignedViewport.h;
    2.62      viewport.MinDepth = 0.0f;
    2.63      viewport.MaxDepth = 1.0f;
    2.64 +    /* SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, viewport.TopLeftX, viewport.TopLeftY, viewport.Width, viewport.Height); */
    2.65      ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &viewport);
    2.66  
    2.67      return 0;
     3.1 --- a/src/video/winrt/SDL_winrtvideo.cpp	Tue May 06 20:31:10 2014 -0400
     3.2 +++ b/src/video/winrt/SDL_winrtvideo.cpp	Fri May 09 20:16:21 2014 -0400
     3.3 @@ -53,6 +53,7 @@
     3.4  #include "SDL_winrtmouse_c.h"
     3.5  #include "SDL_main.h"
     3.6  #include "SDL_system.h"
     3.7 +//#include "SDL_log.h"
     3.8  
     3.9  
    3.10  /* Initialization/Query functions */
    3.11 @@ -174,6 +175,14 @@
    3.12          return SDL_SetError("SDL/WinRT display modes cannot be calculated outside of the main thread, such as in SDL's XAML thread");
    3.13      }
    3.14  
    3.15 +    //SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, DPI = %f\n",
    3.16 +    //    __FUNCTION__,
    3.17 +    //    CoreWindow::GetForCurrentThread()->Bounds.Width, CoreWindow::GetForCurrentThread()->Bounds.Height,
    3.18 +    //    WINRT_DISPLAY_PROPERTY(CurrentOrientation),
    3.19 +    //    WINRT_DISPLAY_PROPERTY(NativeOrientation),
    3.20 +    //    WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
    3.21 +    //    WINRT_DISPLAY_PROPERTY(LogicalDpi));
    3.22 +
    3.23      // Calculate the display size given the window size, taking into account
    3.24      // the current display's DPI:
    3.25  #if NTDDI_VERSION > NTDDI_WIN8
    3.26 @@ -208,10 +217,10 @@
    3.27      driverdata->currentOrientation = DisplayProperties::CurrentOrientation;
    3.28  #endif
    3.29  
    3.30 -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
    3.31 -    // On Windows Phone, the native window's size is always in portrait,
    3.32 +#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8)
    3.33 +    // On Windows Phone 8.0, the native window's size is always in portrait,
    3.34      // regardless of the device's orientation.  This is in contrast to
    3.35 -    // Windows 8/RT, which will resize the native window as the device's
    3.36 +    // Windows 8.x/RT and Windows Phone 8.1, which will resize the native window as the device's
    3.37      // orientation changes.  In order to compensate for this behavior,
    3.38      // on Windows Phone, the mode's width and height will be swapped when
    3.39      // the device is in a landscape (non-portrait) mode.
     4.1 --- a/src/video/winrt/SDL_winrtvideo_cpp.h	Tue May 06 20:31:10 2014 -0400
     4.2 +++ b/src/video/winrt/SDL_winrtvideo_cpp.h	Fri May 09 20:16:21 2014 -0400
     4.3 @@ -70,6 +70,13 @@
     4.4  
     4.5  #ifdef __cplusplus_winrt
     4.6  
     4.7 +/* A convenience macro to get a WinRT display property */
     4.8 +#if NTDDI_VERSION > NTDDI_WIN8
     4.9 +#define WINRT_DISPLAY_PROPERTY(NAME) (Windows::Graphics::Display::DisplayInformation::GetForCurrentView()->NAME)
    4.10 +#else
    4.11 +#define WINRT_DISPLAY_PROPERTY(NAME) (Windows::Graphics::Display::DisplayProperties::NAME)
    4.12 +#endif
    4.13 +
    4.14  /* Internal window data */
    4.15  struct SDL_WindowData
    4.16  {