Sfoglia il codice sorgente

Fix D3D11 window not switching to correct monitor

PredatorMF 6 anni fa
parent
commit
501f3a5c9a
1 ha cambiato i file con 56 aggiunte e 11 eliminazioni
  1. 56 11
      Source/Urho3D/Graphics/Direct3D11/D3D11Graphics.cpp

+ 56 - 11
Source/Urho3D/Graphics/Direct3D11/D3D11Graphics.cpp

@@ -313,8 +313,9 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool borderless,
         fullscreen = false;
 
     // If nothing changes, do not reset the device
-    if (width == width_ && height == height_ && fullscreen == fullscreen_ && borderless == borderless_ && resizable == resizable_ &&
-        vsync == vsync_ && tripleBuffer == tripleBuffer_ && multiSample == multiSample_)
+    if (width == width_ && height == height_ && fullscreen == fullscreen_ && borderless == borderless_ &&
+        resizable == resizable_ && vsync == vsync_ && tripleBuffer == tripleBuffer_ && multiSample == multiSample_ &&
+        monitor == monitor_ && refreshRate == refreshRate_)
         return true;
 
     SDL_SetHint(SDL_HINT_ORIENTATIONS, orientations_.CString());
@@ -337,6 +338,8 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool borderless,
             for (unsigned i = 0; i < resolutions.Size(); ++i)
             {
                 unsigned error = (unsigned)(Abs(resolutions[i].x_ - width) + Abs(resolutions[i].y_ - height));
+                if (refreshRate != 0)
+                    error += (unsigned)Abs(resolutions[i].z_ - refreshRate);
                 if (error < bestError)
                 {
                     best = i;
@@ -377,7 +380,8 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool borderless,
 
 #ifdef URHO3D_LOGGING
     String msg;
-    msg.AppendWithFormat("Set screen mode %dx%d %s monitor %d", width_, height_, (fullscreen_ ? "fullscreen" : "windowed"), monitor_);
+    msg.AppendWithFormat("Set screen mode %dx%d rate %d Hz %s monitor %d", width_, height_, refreshRate_,
+        (fullscreen_ ? "fullscreen" : "windowed"), monitor_);
     if (borderless_)
         msg.Append(" borderless");
     if (resizable_)
@@ -2088,11 +2092,13 @@ void Graphics::AdjustWindow(int& newWidth, int& newHeight, bool& newFullscreen,
             SDL_SetWindowSize(window_, newWidth, newHeight);
         }
 
+        // Turn off window fullscreen mode so it gets repositioned to the correct monitor
+        SDL_SetWindowFullscreen(window_, SDL_FALSE);
         // Hack fix: on SDL 2.0.4 a fullscreen->windowed transition results in a maximized window when the D3D device is reset, so hide before
-        SDL_HideWindow(window_);
+        if (!newFullscreen) SDL_HideWindow(window_);
         SDL_SetWindowFullscreen(window_, newFullscreen ? SDL_WINDOW_FULLSCREEN : 0);
         SDL_SetWindowBordered(window_, newBorderless ? SDL_FALSE : SDL_TRUE);
-        SDL_ShowWindow(window_);
+        if (!newFullscreen) SDL_ShowWindow(window_);
     }
     else
     {
@@ -2145,6 +2151,49 @@ bool Graphics::CreateDevice(int width, int height, int multiSample)
         impl_->swapChain_ = nullptr;
     }
 
+    IDXGIDevice* dxgiDevice = nullptr;
+    impl_->device_->QueryInterface(IID_IDXGIDevice, (void**)&dxgiDevice);
+    IDXGIAdapter* dxgiAdapter = nullptr;
+    dxgiDevice->GetParent(IID_IDXGIAdapter, (void**)&dxgiAdapter);
+    IDXGIFactory* dxgiFactory = nullptr;
+    dxgiAdapter->GetParent(IID_IDXGIFactory, (void**)&dxgiFactory);
+
+    DXGI_RATIONAL refreshRateRational = {};
+    IDXGIOutput* dxgiOutput = nullptr;
+    UINT numModes = 0;
+    dxgiAdapter->EnumOutputs(monitor_, &dxgiOutput);
+    dxgiOutput->GetDisplayModeList(sRGB_ ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, 0);
+
+    // find the best matching refresh rate with the specified resolution
+    if (numModes > 0)
+    {
+        DXGI_MODE_DESC* modes = new DXGI_MODE_DESC[numModes];
+        dxgiOutput->GetDisplayModeList(sRGB_ ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, modes);
+        unsigned bestMatchingRateIndex = -1;
+        unsigned bestError = M_MAX_UNSIGNED;
+        for (unsigned i = 0; i < numModes; ++i)
+        {
+            if (width != modes[i].Width || height != modes[i].Height)
+                continue;
+
+            float rate = (float)modes[i].RefreshRate.Numerator / modes[i].RefreshRate.Denominator;
+            unsigned error = (unsigned)(Abs(rate - refreshRate_));
+            if (error < bestError)
+            {
+                bestMatchingRateIndex = i;
+                bestError = error;
+            }
+        }
+        if (bestMatchingRateIndex != -1)
+        {
+            refreshRateRational.Numerator = modes[bestMatchingRateIndex].RefreshRate.Numerator;
+            refreshRateRational.Denominator = modes[bestMatchingRateIndex].RefreshRate.Denominator;
+        }
+        delete[] modes;
+    }
+
+    dxgiOutput->Release();
+
     DXGI_SWAP_CHAIN_DESC swapChainDesc;
     memset(&swapChainDesc, 0, sizeof swapChainDesc);
     swapChainDesc.BufferCount = 1;
@@ -2152,18 +2201,14 @@ bool Graphics::CreateDevice(int width, int height, int multiSample)
     swapChainDesc.BufferDesc.Height = (UINT)height;
     swapChainDesc.BufferDesc.Format = sRGB_ ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
     swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+    swapChainDesc.BufferDesc.RefreshRate.Numerator = refreshRateRational.Numerator;
+    swapChainDesc.BufferDesc.RefreshRate.Denominator = refreshRateRational.Denominator;
     swapChainDesc.OutputWindow = GetWindowHandle(window_);
     swapChainDesc.SampleDesc.Count = (UINT)multiSample;
     swapChainDesc.SampleDesc.Quality = impl_->GetMultiSampleQuality(swapChainDesc.BufferDesc.Format, multiSample);
     swapChainDesc.Windowed = TRUE;
     swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
 
-    IDXGIDevice* dxgiDevice = nullptr;
-    impl_->device_->QueryInterface(IID_IDXGIDevice, (void**)&dxgiDevice);
-    IDXGIAdapter* dxgiAdapter = nullptr;
-    dxgiDevice->GetParent(IID_IDXGIAdapter, (void**)&dxgiAdapter);
-    IDXGIFactory* dxgiFactory = nullptr;
-    dxgiAdapter->GetParent(IID_IDXGIFactory, (void**)&dxgiFactory);
     HRESULT hr = dxgiFactory->CreateSwapChain(impl_->device_, &swapChainDesc, &impl_->swapChain_);
     // After creating the swap chain, disable automatic Alt-Enter fullscreen/windowed switching
     // (the application will switch manually if it wants to)