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.
This commit is contained in:
David Ludwig 2014-05-09 20:16:21 -04:00
parent 33f81a0da5
commit 0a879d63bd
4 changed files with 72 additions and 52 deletions

View File

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

View File

@ -29,6 +29,7 @@
#include "SDL_syswm.h" #include "SDL_syswm.h"
#include "../SDL_sysrender.h" #include "../SDL_sysrender.h"
#include "../SDL_d3dmath.h" #include "../SDL_d3dmath.h"
/* #include "SDL_log.h" */
#include <d3d11_1.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 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
swapChainDesc.Scaling = DXGI_SCALING_STRETCH; /* On phone, only stretch and aspect-ratio stretch scaling are allowed. */ 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. */ 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 #else
if (usingXAML) { if (usingXAML) {
swapChainDesc.Scaling = DXGI_SCALING_STRETCH; swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
@ -1484,6 +1486,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
*/ */
SDL_GetWindowSize(renderer->window, &w, &h); SDL_GetWindowSize(renderer->window, &w, &h);
data->rotation = D3D11_GetCurrentRotation(); data->rotation = D3D11_GetCurrentRotation();
/* SDL_Log("%s: windowSize={%d,%d}, orientation=%d\n", __FUNCTION__, w, h, (int)data->rotation); */
if (D3D11_IsDisplayRotated90Degrees(data->rotation)) { if (D3D11_IsDisplayRotated90Degrees(data->rotation)) {
int tmp = w; int tmp = w;
w = h; w = h;
@ -1521,11 +1524,21 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
} }
#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
/* Set the proper rotation for the swap chain, and generate the /* Set the proper rotation for the swap chain.
* 3D matrix transformation for rendering to the rotated swap chain.
* *
* To note, the call for this, IDXGISwapChain1::SetRotation, is not necessary * 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) { if (data->swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) {
result = IDXGISwapChain1_SetRotation(data->swapChain, data->rotation); 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 * SDL_CreateRenderer is calling it, and will call it again later
* with a non-empty viewport. * with a non-empty viewport.
*/ */
/* SDL_Log("%s, no viewport was set!\n", __FUNCTION__); */
return 0; return 0;
} }
@ -2223,6 +2237,7 @@ D3D11_UpdateViewport(SDL_Renderer * renderer)
viewport.Height = orientationAlignedViewport.h; viewport.Height = orientationAlignedViewport.h;
viewport.MinDepth = 0.0f; viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.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); ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &viewport);
return 0; return 0;

View File

@ -53,6 +53,7 @@ extern "C" {
#include "SDL_winrtmouse_c.h" #include "SDL_winrtmouse_c.h"
#include "SDL_main.h" #include "SDL_main.h"
#include "SDL_system.h" #include "SDL_system.h"
//#include "SDL_log.h"
/* Initialization/Query functions */ /* 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"); 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 // Calculate the display size given the window size, taking into account
// the current display's DPI: // the current display's DPI:
#if NTDDI_VERSION > NTDDI_WIN8 #if NTDDI_VERSION > NTDDI_WIN8
@ -208,10 +217,10 @@ WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode)
driverdata->currentOrientation = DisplayProperties::CurrentOrientation; driverdata->currentOrientation = DisplayProperties::CurrentOrientation;
#endif #endif
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP #if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8)
// On Windows Phone, the native window's size is always in portrait, // 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 // 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, // orientation changes. In order to compensate for this behavior,
// on Windows Phone, the mode's width and height will be swapped when // on Windows Phone, the mode's width and height will be swapped when
// the device is in a landscape (non-portrait) mode. // the device is in a landscape (non-portrait) mode.

View File

@ -70,6 +70,13 @@ typedef struct
#ifdef __cplusplus_winrt #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 */ /* Internal window data */
struct SDL_WindowData struct SDL_WindowData
{ {