From 0a879d63bddc6d58bbeb7bf7d377f9d36b335a01 Mon Sep 17 00:00:00 2001 From: David Ludwig Date: Fri, 9 May 2014 20:16:21 -0400 Subject: [PATCH] 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 | 81 ++++++++++-------------- src/render/direct3d11/SDL_render_d3d11.c | 21 +++++- src/video/winrt/SDL_winrtvideo.cpp | 15 ++++- src/video/winrt/SDL_winrtvideo_cpp.h | 7 ++ 4 files changed, 72 insertions(+), 52 deletions(-) diff --git a/src/core/winrt/SDL_winrtapp_direct3d.cpp b/src/core/winrt/SDL_winrtapp_direct3d.cpp index 3a9f597f6..d17171b5c 100644 --- a/src/core/winrt/SDL_winrtapp_direct3d.cpp +++ b/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 diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index 1e2b09992..2f1164bee 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/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 @@ -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; diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp index 6c6fce026..0443b99b2 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/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. diff --git a/src/video/winrt/SDL_winrtvideo_cpp.h b/src/video/winrt/SDL_winrtvideo_cpp.h index a90f0437f..e327280dc 100644 --- a/src/video/winrt/SDL_winrtvideo_cpp.h +++ b/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 {