From 340f0cff2cfdc6af149913c04ccf3a2494791af1 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 5 Mar 2017 01:39:26 +0100 Subject: [PATCH] Prepare for supporting manual screen rotation --- UI/NativeApp.cpp | 4 ++ ext/native/base/display.cpp | 5 +- ext/native/base/display.h | 16 ++++- ext/native/thin3d/thin3d.h | 4 +- ext/native/thin3d/thin3d_d3d11.cpp | 107 +++++++++++++++++++++++------ 5 files changed, 111 insertions(+), 25 deletions(-) diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index a50cf53626..8f0e84068d 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -764,6 +764,10 @@ void NativeRender(GraphicsContext *graphicsContext) { break; } + if (g_display_rotation != DisplayRotation::ROTATE_0) { + ortho = ortho * g_display_rot_matrix; + } + ui_draw2d.SetDrawMatrix(ortho); ui_draw2d_front.SetDrawMatrix(ortho); diff --git a/ext/native/base/display.cpp b/ext/native/base/display.cpp index b072e1d547..be74b3eaec 100644 --- a/ext/native/base/display.cpp +++ b/ext/native/base/display.cpp @@ -9,4 +9,7 @@ int pixel_yres; int g_dpi = 1; // will be overwritten float g_dpi_scale = 1.0f; float pixel_in_dps = 1.0f; -float display_hz = 60.0f; \ No newline at end of file +float display_hz = 60.0f; + +DisplayRotation g_display_rotation; +Matrix4x4 g_display_rot_matrix; diff --git a/ext/native/base/display.h b/ext/native/base/display.h index 43d3b31d0c..0ce257fa2f 100644 --- a/ext/native/base/display.h +++ b/ext/native/base/display.h @@ -1,5 +1,7 @@ #pragma once +#include "math/lin/matrix4x4.h" + // This is meant to be a framework for handling DPI scaling etc. // For now, it just consists of these ugly globals. @@ -11,4 +13,16 @@ extern int pixel_yres; extern int g_dpi; extern float g_dpi_scale; extern float pixel_in_dps; -extern float display_hz; \ No newline at end of file +extern float display_hz; + +// On some platforms (currently only Windows UWP) we need to manually rotate +// our rendered output to match the display. Use these to do so. +enum class DisplayRotation { + ROTATE_0 = 0, + ROTATE_90, + ROTATE_180, + ROTATE_270, +}; + +extern DisplayRotation g_display_rotation; +extern Matrix4x4 g_display_rot_matrix; \ No newline at end of file diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 3795731b30..ca6e16a6c7 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -21,7 +21,7 @@ class Matrix4x4; #endif #define WIN32_LEAN_AND_MEAN #include - +#include struct IDirect3DDevice9; struct IDirect3D9; struct IDirect3DDevice9Ex; @@ -664,7 +664,7 @@ extern const UniformBufferDesc UBPresetDesc; #ifdef _WIN32 DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx); -DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, HWND hWnd); +DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd); #endif DrawContext *T3DCreateVulkanContext(VulkanContext *context); diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index f9d1be49cc..5b98dda6d1 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -6,6 +6,7 @@ #else #include "thin3d/d3d11_loader.h" #endif +#include "base/display.h" #include "math/dataconv.h" #include "util/text/utf8.h" @@ -28,7 +29,7 @@ class D3D11RasterState; class D3D11DrawContext : public DrawContext { public: - D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, HWND hWnd); + D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd); ~D3D11DrawContext(); const DeviceCaps &GetDeviceCaps() const override { @@ -127,7 +128,12 @@ public: void HandleEvent(Event ev, int width, int height, void *param) override; private: + struct FRect { + float x, y, w, h; + }; + void ApplyCurrentState(); + void RotateRectToDisplay(FRect &rect); HWND hWnd_; ID3D11Device *device_; @@ -142,6 +148,11 @@ private: ID3D11RenderTargetView *curRenderTargetView_ = nullptr; ID3D11DepthStencilView *curDepthStencilView_ = nullptr; + // Needed to rotate stencil/viewport rectangles properly + int bbWidth_ = 0; + int bbHeight_ = 0; + int curRTWidth_ = 0; + int curRTHeight_ = 0; D3D11Pipeline *curPipeline_ = nullptr; DeviceCaps caps_{}; @@ -167,14 +178,16 @@ private: bool stencilRefDirty_; // System info + D3D_FEATURE_LEVEL featureLevel_; std::string adapterDesc_; }; -D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, HWND hWnd) +D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd) : device_(device), context_(deviceContext1), device1_(device1), context1_(deviceContext1), + featureLevel_(featureLevel), hWnd_(hWnd) { caps_.dualSourceBlend = true; caps_.depthRangeMinusOneToOne = false; @@ -214,10 +227,14 @@ void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param) bbDepthStencilView_ = nullptr; bbDepthStencilTex_->Release(); bbDepthStencilTex_ = nullptr; + curRTWidth_ = 0; + curRTHeight_ = 0; break; } case Event::GOT_BACKBUFFER: { bbRenderTargetView_ = (ID3D11RenderTargetView *)param; + bbWidth_ = width; + bbHeight_ = height; // Create matching depth stencil texture. This is not really needed for PPSSPP though, // and probably not for most other renderers either as you're usually rendering to other render targets and @@ -247,6 +264,39 @@ void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param) curRenderTargetView_ = bbRenderTargetView_; curDepthStencilView_ = bbDepthStencilView_; + curRTWidth_ = width; + curRTHeight_ = height; + break; + } + } +} + +void D3D11DrawContext::RotateRectToDisplay(FRect &rect) { + if (g_display_rotation == DisplayRotation::ROTATE_0) + return; + if (curRenderTargetView_ != bbRenderTargetView_) + return; // Only the backbuffer is actually rotated wrong! + switch (g_display_rotation) { + case DisplayRotation::ROTATE_180: + rect.x = curRTWidth_ - rect.w - rect.x; + rect.y = curRTHeight_ - rect.h - rect.y; + break; + case DisplayRotation::ROTATE_90: { + // Note that curRTWidth_ and curRTHeight_ are "swapped"! + float origX = rect.x; + float origY = rect.y; + float rtw = curRTHeight_; + float rth = curRTWidth_; + rect.x = rth - rect.h - origY; + rect.y = origX; + std::swap(rect.w, rect.h); + break; + } + case DisplayRotation::ROTATE_270: { + float origX = rect.x; + float origY = rect.y; + // TODO + std::swap(rect.w, rect.h); break; } } @@ -255,10 +305,12 @@ void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param) void D3D11DrawContext::SetViewports(int count, Viewport *viewports) { D3D11_VIEWPORT vp[4]; for (int i = 0; i < count; i++) { - vp[i].TopLeftX = viewports[i].TopLeftX; - vp[i].TopLeftY = viewports[i].TopLeftY; - vp[i].Width = viewports[i].Width; - vp[i].Height = viewports[i].Height; + FRect rc{ viewports[i].TopLeftX , viewports[i].TopLeftY, viewports[i].Width, viewports[i].Height }; + RotateRectToDisplay(rc); + vp[i].TopLeftX = rc.x; + vp[i].TopLeftY = rc.y; + vp[i].Width = rc.w; + vp[i].Height = rc.h; vp[i].MinDepth = viewports[i].MinDepth; vp[i].MaxDepth = viewports[i].MaxDepth; } @@ -266,11 +318,14 @@ void D3D11DrawContext::SetViewports(int count, Viewport *viewports) { } void D3D11DrawContext::SetScissorRect(int left, int top, int width, int height) { + FRect frc{ (float)left, (float)top, (float)width, (float)height }; + RotateRectToDisplay(frc); + D3D11_RECT rc{}; - rc.left = left; - rc.top = top; - rc.right = left + width; - rc.bottom = top + height; + rc.left = (INT)frc.x; + rc.top = (INT)frc.y; + rc.right = (INT)(frc.x + frc.w); + rc.bottom = (INT)(frc.y + frc.h); context_->RSSetScissorRects(1, &rc); } @@ -663,21 +718,27 @@ ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLang return nullptr; } + const char *vertexModel = "vs_4_0"; + const char *fragmentModel = "ps_4_0"; + const char *geometryModel = "gs_4_0"; + if (featureLevel_ <= D3D_FEATURE_LEVEL_9_3) { + vertexModel = "vs_4_0_level_9_1"; + fragmentModel = "ps_4_0_level_9_1"; + geometryModel = nullptr; + } + std::string compiled; std::string errors; if (language == ShaderLanguage::HLSL_D3D11) { const char *target = nullptr; switch (stage) { -#if PPSSPP_PLATFORM(UWP) && PPSSPP_ARCH(ARM) - case ShaderStage::FRAGMENT: target = "ps_4_0_level_9_1"; break; - case ShaderStage::VERTEX: target = "vs_4_0_level_9_1"; break; + case ShaderStage::FRAGMENT: target = fragmentModel; break; + case ShaderStage::VERTEX: target = vertexModel; break; + case ShaderStage::GEOMETRY: + if (!geometryModel) + return nullptr; + target = geometryModel; break; -#else - case ShaderStage::FRAGMENT: target = "ps_4_0"; break; - case ShaderStage::GEOMETRY: target = "gs_4_0"; break; - case ShaderStage::VERTEX: target = "vs_4_0"; break; - break; -#endif case ShaderStage::COMPUTE: case ShaderStage::CONTROL: case ShaderStage::EVALUATION: @@ -1160,6 +1221,8 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo) { context_->OMSetRenderTargets(1, &fb->colorRTView, fb->depthStencilRTView); curRenderTargetView_ = fb->colorRTView; curDepthStencilView_ = fb->depthStencilRTView; + curRTWidth_ = fb->width; + curRTHeight_ = fb->height; } // color must be 0, for now. @@ -1176,6 +1239,8 @@ void D3D11DrawContext::BindBackbufferAsRenderTarget() { context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_); curRenderTargetView_ = bbRenderTargetView_; curDepthStencilView_ = bbDepthStencilView_; + curRTWidth_ = bbWidth_; + curRTHeight_ = bbHeight_; } uintptr_t D3D11DrawContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) { @@ -1199,8 +1264,8 @@ void D3D11DrawContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h *h = fb->height; } -DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, HWND hWnd) { - return new D3D11DrawContext(device, context, device1, context1, hWnd); +DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd) { + return new D3D11DrawContext(device, context, device1, context1, featureLevel, hWnd); } } // namespace Draw \ No newline at end of file