WinRT: bug fixes for device orientation + Direct3D 11.1 rendering
authorDavid Ludwig <dludwig@pobox.com>
Sun, 17 Feb 2013 23:23:59 -0500
changeset 8433 3017f87e4479
parent 8432 929e53386278
child 8434 c49d0a46f516
WinRT: bug fixes for device orientation + Direct3D 11.1 rendering
src/render/direct3d11/SDL_render_d3d11.cpp
src/video/windowsrt/SDL_WinRTApp.cpp
src/video/windowsrt/SDL_WinRTApp.h
src/video/windowsrt/SDL_winrtvideo.cpp
--- a/src/render/direct3d11/SDL_render_d3d11.cpp	Sun Feb 17 11:09:07 2013 -0500
+++ b/src/render/direct3d11/SDL_render_d3d11.cpp	Sun Feb 17 23:23:59 2013 -0500
@@ -30,6 +30,8 @@
 #include "SDL_system.h"
 #include "SDL_syswm.h"
 #include "../SDL_sysrender.h"
+#include "SDL_log.h"
+#include "../../video/SDL_sysvideo.h"
 //#include "stdio.h"
 }
 
@@ -561,7 +563,7 @@
     // landscape-oriented width and height. If the window is in a portrait
     // orientation, the dimensions must be reversed.
     data->orientation = DisplayProperties::CurrentOrientation;
-    bool swapDimensions =
+    const bool swapDimensions =
         data->orientation == DisplayOrientations::Portrait ||
         data->orientation == DisplayOrientations::PortraitFlipped;
     data->renderTargetSize.x = swapDimensions ? windowHeight : windowWidth;
@@ -930,9 +932,9 @@
             break;
 
         case DisplayOrientations::Portrait:
-            data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 270-degree Z-rotation
-                0.0f, -1.0f, 0.0f, 0.0f,
-                1.0f, 0.0f, 0.0f, 0.0f,
+            data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 90-degree Z-rotation
+                0.0f, 1.0f, 0.0f, 0.0f,
+                -1.0f, 0.0f, 0.0f, 0.0f,
                 0.0f, 0.0f, 1.0f, 0.0f,
                 0.0f, 0.0f, 0.0f, 1.0f
                 );
@@ -948,9 +950,9 @@
             break;
 
         case DisplayOrientations::PortraitFlipped:
-            data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 90-degree Z-rotation
-                0.0f, 1.0f, 0.0f, 0.0f,
-                -1.0f, 0.0f, 0.0f, 0.0f,
+            data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 270-degree Z-rotation
+                0.0f, -1.0f, 0.0f, 0.0f,
+                1.0f, 0.0f, 0.0f, 0.0f,
                 0.0f, 0.0f, 1.0f, 0.0f,
                 0.0f, 0.0f, 0.0f, 1.0f
                 );
@@ -964,26 +966,58 @@
     //
     // Update the view matrix
     //
-    float windowWidth = (float) renderer->viewport.w;
-    float windowHeight = (float) renderer->viewport.h;
-    XMStoreFloat4x4(&data->vertexShaderConstantsData.view,  // (4)
+    float viewportWidth = (float) renderer->viewport.w;
+    float viewportHeight = (float) renderer->viewport.h;
+    XMStoreFloat4x4(&data->vertexShaderConstantsData.view,
         XMMatrixMultiply(
-            XMMatrixScaling(2.0f / windowWidth, 2.0f / windowHeight, 1.0f),
+            XMMatrixScaling(2.0f / viewportWidth, 2.0f / viewportHeight, 1.0f),
             XMMatrixMultiply(
                 XMMatrixTranslation(-1, -1, 0),
                 XMMatrixRotationX(XM_PI)
                 )));
+
+    //
+    // Update the Direct3D viewport, which seems to be aligned to the
+    // swap buffer's coordinate space, which is always in landscape:
+    //
+    SDL_FRect orientationAlignedViewport;
+    const bool swapDimensions =
+        data->orientation == DisplayOrientations::Portrait ||
+        data->orientation == DisplayOrientations::PortraitFlipped;
+    if (swapDimensions) {
+        orientationAlignedViewport.x = (float) renderer->viewport.y;
+        orientationAlignedViewport.y = (float) renderer->viewport.x;
+        orientationAlignedViewport.w = (float) renderer->viewport.h;
+        orientationAlignedViewport.h = (float) renderer->viewport.w;
+    } else {
+        orientationAlignedViewport.x = (float) renderer->viewport.x;
+        orientationAlignedViewport.y = (float) renderer->viewport.y;
+        orientationAlignedViewport.w = (float) renderer->viewport.w;
+        orientationAlignedViewport.h = (float) renderer->viewport.h;
+    }
+    // WinRT, TODO: get custom viewports working with non-Landscape modes (Portrait, PortraitFlipped, and LandscapeFlipped)
 
     D3D11_VIEWPORT viewport;
     memset(&viewport, 0, sizeof(viewport));
-    viewport.TopLeftX = (float) renderer->viewport.x;
-    viewport.TopLeftY = (float) renderer->viewport.y;
-    viewport.Width = (float) renderer->viewport.w;
-    viewport.Height = (float) renderer->viewport.h;
+    viewport.TopLeftX = orientationAlignedViewport.x;
+    viewport.TopLeftY = orientationAlignedViewport.y;
+    viewport.Width = orientationAlignedViewport.w;
+    viewport.Height = orientationAlignedViewport.h;
     viewport.MinDepth = 0.0f;
     viewport.MaxDepth = 1.0f;
     data->d3dContext->RSSetViewports(1, &viewport);
 
+#if 0
+    SDL_Log("%s, oav={%.0f,%.0f,%.0f,%.0f}, rend={%.0f,%.0f}\n",
+        __FUNCTION__,
+        orientationAlignedViewport.x,
+        orientationAlignedViewport.y,
+        orientationAlignedViewport.w,
+        orientationAlignedViewport.h,
+        data->renderTargetSize.x,
+        data->renderTargetSize.y);
+#endif
+
     return 0;
 }
 
@@ -1116,9 +1150,33 @@
     b = (float)(renderer->b / 255.0f);
     a = (float)(renderer->a / 255.0f);
 
-    D3D11_RenderStartDrawOp(renderer);
+#if 0
+    // Set up a test pattern:
+    SDL_FRect rects[] = {
+        {-1.1f, 1.1f, 1.1f, -1.1f},
+        {-1.0f, 1.0f, 1.0f, -1.0f},     // red
+        {0.0f, 1.0f, 1.0f, -1.0f},      // green
+        {-1.0f, 0.0f, 1.0f, -1.0f},     // blue
+        {0.0f, 0.0f, 1.0f, -1.0f}       // white
+    };
+    count = sizeof(rects) / sizeof(SDL_FRect);
+#endif
 
     for (int i = 0; i < count; ++i) {
+        D3D11_RenderStartDrawOp(renderer);
+
+#if 0
+        // Set colors for the test pattern:
+        a = 1.0f;
+        switch (i) {
+            case 0: r = 1.0f; g = 1.0f; b = 0.0f; break;
+            case 1: r = 1.0f; g = 0.0f; b = 0.0f; break;
+            case 2: r = 0.0f; g = 1.0f; b = 0.0f; break;
+            case 3: r = 0.0f; g = 0.0f; b = 1.0f; break;
+            case 4: r = 1.0f; g = 1.0f; b = 1.0f; break;
+        }
+#endif
+
         VertexPositionColor vertices[] = {
             {XMFLOAT3(rects[i].x, rects[i].y, 0.0f),                           XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)},
             {XMFLOAT3(rects[i].x, rects[i].y + rects[i].h, 0.0f),              XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)},
--- a/src/video/windowsrt/SDL_WinRTApp.cpp	Sun Feb 17 11:09:07 2013 -0500
+++ b/src/video/windowsrt/SDL_WinRTApp.cpp	Sun Feb 17 23:23:59 2013 -0500
@@ -51,6 +51,7 @@
     m_windowClosed(false),
     m_windowVisible(true),
     m_sdlWindowData(NULL),
+    m_sdlVideoDevice(NULL),
     m_useRelativeMouseMode(false)
 {
 }
@@ -146,11 +147,35 @@
 
 void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
 {
-    SDL_SendWindowEvent(
-        m_sdlWindowData->sdlWindow,
-        SDL_WINDOWEVENT_RESIZED,
-        (int) ceil(args->Size.Width),
-        (int) ceil(args->Size.Height));
+#if 0
+    SDL_Log("%s, {%f,%f}\n", __FUNCTION__, args->Size.Width, args->Size.Height);
+#endif
+
+    if (m_sdlWindowData) {
+        // Make the new window size be the one true fullscreen mode.
+        // This change was done, in part, to allow the Direct3D 11.1 renderer
+        // to receive window-resize events as a device rotates.
+        // Before, rotating a device from landscape, to portrait, and then
+        // back to landscape would cause the Direct3D 11.1 swap buffer to
+        // not get resized appropriately.  SDL would, on the rotation from
+        // landscape to portrait, re-resize the SDL window to it's initial
+        // size (landscape).  On the subsequent rotation, SDL would drop the
+        // window-resize event as it appeared the SDL window didn't change
+        // size, and the Direct3D 11.1 renderer wouldn't resize its swap
+        // chain.
+        //
+        // TODO, WinRT: consider dropping old display modes after the fullscreen window changes size (from rotations, etc.)
+        m_sdlWindowData->sdlWindow->fullscreen_mode = SDL_WinRTGlobalApp->GetMainDisplayMode();
+        SDL_AddDisplayMode(&m_sdlVideoDevice->displays[0], &m_sdlWindowData->sdlWindow->fullscreen_mode);
+
+        const int windowWidth = (int) ceil(args->Size.Width);
+        const int windowHeight = (int) ceil(args->Size.Height);
+        SDL_SendWindowEvent(
+            m_sdlWindowData->sdlWindow,
+            SDL_WINDOWEVENT_RESIZED,
+            windowWidth,
+            windowHeight);
+    }
 }
 
 void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
@@ -739,11 +764,16 @@
     m_useRelativeMouseMode = enable;
 }
 
-void SDL_WinRTApp::SetSDLWindowData(const SDL_WindowData* windowData)
+void SDL_WinRTApp::SetSDLWindowData(const SDL_WindowData * windowData)
 {
     m_sdlWindowData = windowData;
 }
 
+void SDL_WinRTApp::SetSDLVideoDevice(const SDL_VideoDevice * videoDevice)
+{
+    m_sdlVideoDevice = videoDevice;
+}
+
 IFrameworkView^ Direct3DApplicationSource::CreateView()
 {
     // TODO, WinRT: see if this function (CreateView) can ever get called
--- a/src/video/windowsrt/SDL_WinRTApp.h	Sun Feb 17 11:09:07 2013 -0500
+++ b/src/video/windowsrt/SDL_WinRTApp.h	Sun Feb 17 23:23:59 2013 -0500
@@ -26,6 +26,7 @@
     bool HasSDLWindowData() const;
     void SetRelativeMouseMode(bool enable);
     void SetSDLWindowData(const SDL_WindowData * windowData);
+    void SetSDLVideoDevice(const SDL_VideoDevice * videoDevice);
     Windows::Foundation::Point TransformCursor(Windows::Foundation::Point rawPosition);
 
 protected:
@@ -49,6 +50,7 @@
     bool m_windowClosed;
     bool m_windowVisible;
     const SDL_WindowData* m_sdlWindowData;
+    const SDL_VideoDevice* m_sdlVideoDevice;
     bool m_useRelativeMouseMode;
 };
 
--- a/src/video/windowsrt/SDL_winrtvideo.cpp	Sun Feb 17 11:09:07 2013 -0500
+++ b/src/video/windowsrt/SDL_winrtvideo.cpp	Sun Feb 17 23:23:59 2013 -0500
@@ -74,6 +74,7 @@
 static void
 WINRT_DeleteDevice(SDL_VideoDevice * device)
 {
+    SDL_WinRTGlobalApp->SetSDLVideoDevice(NULL);
     SDL_free(device);
 }
 
@@ -103,8 +104,9 @@
     //device->UpdateWindowFramebuffer = SDL_WINRT_UpdateWindowFramebuffer;
     //device->DestroyWindowFramebuffer = SDL_WINRT_DestroyWindowFramebuffer;
     device->GetWindowWMInfo = WINRT_GetWindowWMInfo;
+    device->free = WINRT_DeleteDevice;
 
-    device->free = WINRT_DeleteDevice;
+    SDL_WinRTGlobalApp->SetSDLVideoDevice(device);
 
     return device;
 }