Browse Source

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.
David Ludwig 11 years ago
parent
commit
0a879d63bd

+ 35 - 46
src/core/winrt/SDL_winrtapp_direct3d.cpp

@@ -229,36 +229,30 @@ WINRT_ProcessWindowSizeChange()
     }
 
     if (WINRT_GlobalSDLWindow) {
-        // Send a window-resize event to the rest of SDL, and to apps:
-        SDL_SendWindowEvent(
-            WINRT_GlobalSDLWindow,
-            SDL_WINDOWEVENT_RESIZED,
-            newDisplayMode.w,
-            newDisplayMode.h);
-
+        // If the window size changed, send a resize event to SDL and its host app:
+        int window_w = 0;
+        int window_h = 0;
+        SDL_GetWindowSize(WINRT_GlobalSDLWindow, &window_w, &window_h);
+        if ((window_w != newDisplayMode.w) || (window_h != newDisplayMode.h)) {
+            SDL_SendWindowEvent(
+                WINRT_GlobalSDLWindow,
+                SDL_WINDOWEVENT_RESIZED,
+                newDisplayMode.w,
+                newDisplayMode.h);
+        } else {
 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
-        // HACK: On Windows Phone, make sure that orientation changes from
-        // Landscape to LandscapeFlipped, Portrait to PortraitFlipped,
-        // or vice-versa on either of those two, lead to the Direct3D renderer
-        // getting updated.
-        const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation;
-        const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation;
-
-        if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) ||
-            (oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) ||
-            (oldOrientation == DisplayOrientations::Portrait && newOrientation == DisplayOrientations::PortraitFlipped) ||
-            (oldOrientation == DisplayOrientations::PortraitFlipped && newOrientation == DisplayOrientations::Portrait))
-        {
-            // One of the reasons this event is getting sent out is because SDL
-            // will ignore requests to send out SDL_WINDOWEVENT_RESIZED events
-            // if and when the event size doesn't change (and the Direct3D 11.1
-            // renderer doesn't get the memo).
+            // HACK: Make sure that orientation changes
+            // lead to the Direct3D renderer's viewport getting updated:
             //
-            // Make sure that the display/window size really didn't change.  If
-            // it did, then a SDL_WINDOWEVENT_SIZE_CHANGED event got sent, and
-            // the Direct3D 11.1 renderer picked it up, presumably.
-            if (oldDisplayMode.w == newDisplayMode.w &&
-                oldDisplayMode.h == newDisplayMode.h)
+            // For some reason, this doesn't seem to need to be done on Windows 8.x,
+            // even when going from Landscape to LandscapeFlipped.  It only seems to
+            // be needed on Windows Phone, at least when I tested on my devices.
+            // I'm not currently sure why this is, but it seems to work fine. -- David L.
+            //
+            // 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
+            const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation;
+            const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation;
+            if (oldOrientation != newOrientation)
             {
                 SDL_SendWindowEvent(
                     WINRT_GlobalSDLWindow,
@@ -266,8 +260,8 @@ WINRT_ProcessWindowSizeChange()
                     newDisplayMode.w,
                     newDisplayMode.h);
             }
-        }
 #endif
+        }
     }
     
     // Finally, free the 'driverdata' field of the old 'desktop_mode'.
@@ -309,26 +303,21 @@ void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
     if (window) {
         SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n",
             __FUNCTION__,
-            (int)DisplayProperties::CurrentOrientation,
-            (int)DisplayProperties::NativeOrientation,
-            (int)DisplayProperties::AutoRotationPreferences,
+            WINRT_DISPLAY_PROPERTY(CurrentOrientation),
+            WINRT_DISPLAY_PROPERTY(NativeOrientation),
+            WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
             window->Bounds.Width,
             window->Bounds.Height);
     } else {
         SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
             __FUNCTION__,
-            (int)DisplayProperties::CurrentOrientation,
-            (int)DisplayProperties::NativeOrientation,
-            (int)DisplayProperties::AutoRotationPreferences);
+            WINRT_DISPLAY_PROPERTY(CurrentOrientation),
+            WINRT_DISPLAY_PROPERTY(NativeOrientation),
+            WINRT_DISPLAY_PROPERTY(AutoRotationPreferences));
     }
 #endif
 
-#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
-    // On Windows Phone, treat an orientation change as a change in window size.
-    // The native window's size doesn't seem to change, however SDL will simulate
-    // a window size change.
     WINRT_ProcessWindowSizeChange();
-#endif
 }
 
 void SDL_WinRTApp::SetWindow(CoreWindow^ window)
@@ -336,9 +325,9 @@ void SDL_WinRTApp::SetWindow(CoreWindow^ window)
 #if LOG_WINDOW_EVENTS==1
     SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n",
         __FUNCTION__,
-        (int)DisplayProperties::CurrentOrientation,
-        (int)DisplayProperties::NativeOrientation,
-        (int)DisplayProperties::AutoRotationPreferences,
+        WINRT_DISPLAY_PROPERTY(CurrentOrientation),
+        WINRT_DISPLAY_PROPERTY(NativeOrientation),
+        WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
         window->Bounds.Width,
         window->Bounds.Height);
 #endif
@@ -540,9 +529,9 @@ void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEven
     SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n",
         __FUNCTION__,
         args->Size.Width, args->Size.Height,
-        (int)DisplayProperties::CurrentOrientation,
-        (int)DisplayProperties::NativeOrientation,
-        (int)DisplayProperties::AutoRotationPreferences,
+        WINRT_DISPLAY_PROPERTY(CurrentOrientation),
+        WINRT_DISPLAY_PROPERTY(NativeOrientation),
+        WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
         (WINRT_GlobalSDLWindow ? "yes" : "no"));
 #endif
 

+ 18 - 3
src/render/direct3d11/SDL_render_d3d11.c

@@ -29,6 +29,7 @@
 #include "SDL_syswm.h"
 #include "../SDL_sysrender.h"
 #include "../SDL_d3dmath.h"
+/* #include "SDL_log.h" */
 
 #include <d3d11_1.h>
 
@@ -1390,6 +1391,7 @@ D3D11_CreateSwapChain(SDL_Renderer * renderer, int w, int h)
 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
     swapChainDesc.Scaling = DXGI_SCALING_STRETCH; /* On phone, only stretch and aspect-ratio stretch scaling are allowed. */
     swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; /* On phone, no swap effects are supported. */
+    /* 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 */
 #else
     if (usingXAML) {
         swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
@@ -1484,6 +1486,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
      */
     SDL_GetWindowSize(renderer->window, &w, &h);
     data->rotation = D3D11_GetCurrentRotation();
+    /* SDL_Log("%s: windowSize={%d,%d}, orientation=%d\n", __FUNCTION__, w, h, (int)data->rotation); */
     if (D3D11_IsDisplayRotated90Degrees(data->rotation)) {
         int tmp = w;
         w = h;
@@ -1521,11 +1524,21 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
     }
     
 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
-    /* Set the proper rotation for the swap chain, and generate the
-     * 3D matrix transformation for rendering to the rotated swap chain.
+    /* Set the proper rotation for the swap chain.
      *
      * To note, the call for this, IDXGISwapChain1::SetRotation, is not necessary
-     * on Windows Phone, nor is it supported there.  It's only needed in Windows 8/RT.
+     * on Windows Phone 8.0, nor is it supported there.
+     *
+     * IDXGISwapChain1::SetRotation does seem to be available on Windows Phone 8.1,
+     * however I've yet to find a way to make it work.  It might have something to
+     * do with IDXGISwapChain::ResizeBuffers appearing to not being available on
+     * Windows Phone 8.1 (it wasn't on Windows Phone 8.0), but I'm not 100% sure of this.
+     * The call doesn't appear to be entirely necessary though, and is a performance-related
+     * call, at least according to the following page on MSDN:
+     * http://code.msdn.microsoft.com/windowsapps/DXGI-swap-chain-rotation-21d13d71
+     *   -- David L.
+     *
+     * TODO, WinRT: reexamine the docs for IDXGISwapChain1::SetRotation, see if might be available, usable, and prudent-to-call on WinPhone 8.1
      */
     if (data->swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) {
         result = IDXGISwapChain1_SetRotation(data->swapChain, data->rotation);
@@ -2144,6 +2157,7 @@ D3D11_UpdateViewport(SDL_Renderer * renderer)
          * SDL_CreateRenderer is calling it, and will call it again later
          * with a non-empty viewport.
          */
+        /* SDL_Log("%s, no viewport was set!\n", __FUNCTION__); */
         return 0;
     }
 
@@ -2223,6 +2237,7 @@ D3D11_UpdateViewport(SDL_Renderer * renderer)
     viewport.Height = orientationAlignedViewport.h;
     viewport.MinDepth = 0.0f;
     viewport.MaxDepth = 1.0f;
+    /* SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, viewport.TopLeftX, viewport.TopLeftY, viewport.Width, viewport.Height); */
     ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &viewport);
 
     return 0;

+ 12 - 3
src/video/winrt/SDL_winrtvideo.cpp

@@ -53,6 +53,7 @@ extern "C" {
 #include "SDL_winrtmouse_c.h"
 #include "SDL_main.h"
 #include "SDL_system.h"
+//#include "SDL_log.h"
 
 
 /* Initialization/Query functions */
@@ -174,6 +175,14 @@ WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode)
         return SDL_SetError("SDL/WinRT display modes cannot be calculated outside of the main thread, such as in SDL's XAML thread");
     }
 
+    //SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, DPI = %f\n",
+    //    __FUNCTION__,
+    //    CoreWindow::GetForCurrentThread()->Bounds.Width, CoreWindow::GetForCurrentThread()->Bounds.Height,
+    //    WINRT_DISPLAY_PROPERTY(CurrentOrientation),
+    //    WINRT_DISPLAY_PROPERTY(NativeOrientation),
+    //    WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
+    //    WINRT_DISPLAY_PROPERTY(LogicalDpi));
+
     // Calculate the display size given the window size, taking into account
     // the current display's DPI:
 #if NTDDI_VERSION > NTDDI_WIN8
@@ -208,10 +217,10 @@ WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode)
     driverdata->currentOrientation = DisplayProperties::CurrentOrientation;
 #endif
 
-#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
-    // On Windows Phone, the native window's size is always in portrait,
+#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8)
+    // On Windows Phone 8.0, the native window's size is always in portrait,
     // regardless of the device's orientation.  This is in contrast to
-    // Windows 8/RT, which will resize the native window as the device's
+    // Windows 8.x/RT and Windows Phone 8.1, which will resize the native window as the device's
     // orientation changes.  In order to compensate for this behavior,
     // on Windows Phone, the mode's width and height will be swapped when
     // the device is in a landscape (non-portrait) mode.

+ 7 - 0
src/video/winrt/SDL_winrtvideo_cpp.h

@@ -70,6 +70,13 @@ typedef struct
 
 #ifdef __cplusplus_winrt
 
+/* A convenience macro to get a WinRT display property */
+#if NTDDI_VERSION > NTDDI_WIN8
+#define WINRT_DISPLAY_PROPERTY(NAME) (Windows::Graphics::Display::DisplayInformation::GetForCurrentView()->NAME)
+#else
+#define WINRT_DISPLAY_PROPERTY(NAME) (Windows::Graphics::Display::DisplayProperties::NAME)
+#endif
+
 /* Internal window data */
 struct SDL_WindowData
 {