Qt: Work around flip model swap chains being limited to vsync when parented
Fixes fast forward not working on some systems.
This commit is contained in:
parent
1f40d5f77d
commit
0a004361fc
|
@ -231,7 +231,7 @@ bool D3D11DisplayWidget::createDeviceContext(QThread* worker_thread, bool debug_
|
||||||
m_allow_tearing_supported = (allow_tearing_supported == TRUE);
|
m_allow_tearing_supported = (allow_tearing_supported == TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!createSwapChain(reinterpret_cast<HWND>(winId())))
|
if (!createSwapChain())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!QtDisplayWidget::createDeviceContext(worker_thread, debug_device))
|
if (!QtDisplayWidget::createDeviceContext(worker_thread, debug_device))
|
||||||
|
@ -263,9 +263,16 @@ void D3D11DisplayWidget::destroyDeviceContext()
|
||||||
m_device.Reset();
|
m_device.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D11DisplayWidget::createSwapChain(HWND hwnd)
|
bool D3D11DisplayWidget::shouldUseFlipModelSwapChain() const
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
// For some reason DXGI gets stuck waiting for some kernel object when the Qt window has a parent (render-to-main) on
|
||||||
|
// some computers, unless the window is completely occluded. The legacy swap chain mode does not have this problem.
|
||||||
|
return parent() == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D11DisplayWidget::createSwapChain()
|
||||||
|
{
|
||||||
|
m_using_flip_model_swap_chain = shouldUseFlipModelSwapChain();
|
||||||
|
|
||||||
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {};
|
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {};
|
||||||
swap_chain_desc.BufferDesc.Width = m_window_width;
|
swap_chain_desc.BufferDesc.Width = m_window_width;
|
||||||
|
@ -274,20 +281,22 @@ bool D3D11DisplayWidget::createSwapChain(HWND hwnd)
|
||||||
swap_chain_desc.SampleDesc.Count = 1;
|
swap_chain_desc.SampleDesc.Count = 1;
|
||||||
swap_chain_desc.BufferCount = 3;
|
swap_chain_desc.BufferCount = 3;
|
||||||
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||||
swap_chain_desc.OutputWindow = hwnd;
|
swap_chain_desc.OutputWindow = reinterpret_cast<HWND>(winId());
|
||||||
swap_chain_desc.Windowed = TRUE;
|
swap_chain_desc.Windowed = TRUE;
|
||||||
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
swap_chain_desc.SwapEffect = m_using_flip_model_swap_chain ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
|
||||||
|
|
||||||
if (m_allow_tearing_supported)
|
m_using_allow_tearing = (m_allow_tearing_supported && m_using_flip_model_swap_chain);
|
||||||
|
if (m_using_allow_tearing)
|
||||||
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||||
|
|
||||||
hr = m_dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf());
|
HRESULT hr = m_dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf());
|
||||||
if (FAILED(hr))
|
if (FAILED(hr) && m_using_flip_model_swap_chain)
|
||||||
{
|
{
|
||||||
Log_WarningPrintf("Failed to create a flip-discard swap chain, trying discard.");
|
Log_WarningPrintf("Failed to create a flip-discard swap chain, trying discard.");
|
||||||
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||||
swap_chain_desc.Flags = 0;
|
swap_chain_desc.Flags = 0;
|
||||||
m_allow_tearing_supported = false;
|
m_using_flip_model_swap_chain = false;
|
||||||
|
m_using_allow_tearing = false;
|
||||||
|
|
||||||
hr = m_dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf());
|
hr = m_dxgi_factory->CreateSwapChain(m_device.Get(), &swap_chain_desc, m_swap_chain.GetAddressOf());
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
|
@ -297,13 +306,22 @@ bool D3D11DisplayWidget::createSwapChain(HWND hwnd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = m_dxgi_factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
|
hr = m_dxgi_factory->MakeWindowAssociation(swap_chain_desc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
Log_WarningPrintf("MakeWindowAssociation() to disable ALT+ENTER failed");
|
Log_WarningPrintf("MakeWindowAssociation() to disable ALT+ENTER failed");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void D3D11DisplayWidget::recreateSwapChain()
|
||||||
|
{
|
||||||
|
m_swap_chain_rtv.Reset();
|
||||||
|
m_swap_chain.Reset();
|
||||||
|
|
||||||
|
if (!createSwapChain() || !createSwapChainRTV())
|
||||||
|
Panic("Failed to recreate swap chain");
|
||||||
|
}
|
||||||
|
|
||||||
void D3D11DisplayWidget::windowResized(s32 new_window_width, s32 new_window_height)
|
void D3D11DisplayWidget::windowResized(s32 new_window_width, s32 new_window_height)
|
||||||
{
|
{
|
||||||
QtDisplayWidget::windowResized(new_window_width, new_window_height);
|
QtDisplayWidget::windowResized(new_window_width, new_window_height);
|
||||||
|
@ -312,10 +330,16 @@ void D3D11DisplayWidget::windowResized(s32 new_window_width, s32 new_window_heig
|
||||||
if (!m_swap_chain)
|
if (!m_swap_chain)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (m_using_flip_model_swap_chain != shouldUseFlipModelSwapChain())
|
||||||
|
{
|
||||||
|
recreateSwapChain();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_swap_chain_rtv.Reset();
|
m_swap_chain_rtv.Reset();
|
||||||
|
|
||||||
HRESULT hr = m_swap_chain->ResizeBuffers(0, new_window_width, new_window_height, DXGI_FORMAT_UNKNOWN,
|
HRESULT hr = m_swap_chain->ResizeBuffers(0, new_window_width, new_window_height, DXGI_FORMAT_UNKNOWN,
|
||||||
m_allow_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
|
m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
Log_ErrorPrintf("ResizeBuffers() failed: 0x%08X", hr);
|
Log_ErrorPrintf("ResizeBuffers() failed: 0x%08X", hr);
|
||||||
|
|
||||||
|
@ -439,7 +463,7 @@ void D3D11DisplayWidget::Render()
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
|
||||||
if (!m_vsync && m_allow_tearing_supported)
|
if (!m_vsync && m_using_allow_tearing)
|
||||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||||
else
|
else
|
||||||
m_swap_chain->Present(BoolToUInt32(m_vsync), 0);
|
m_swap_chain->Present(BoolToUInt32(m_vsync), 0);
|
||||||
|
|
|
@ -55,8 +55,10 @@ private:
|
||||||
bool createDeviceResources() override;
|
bool createDeviceResources() override;
|
||||||
void destroyDeviceResources() override;
|
void destroyDeviceResources() override;
|
||||||
|
|
||||||
bool createSwapChain(HWND hwnd);
|
bool shouldUseFlipModelSwapChain() const;
|
||||||
|
bool createSwapChain();
|
||||||
bool createSwapChainRTV();
|
bool createSwapChainRTV();
|
||||||
|
void recreateSwapChain();
|
||||||
|
|
||||||
void renderDisplay();
|
void renderDisplay();
|
||||||
|
|
||||||
|
@ -80,5 +82,7 @@ private:
|
||||||
D3D11::AutoStagingTexture m_readback_staging_texture;
|
D3D11::AutoStagingTexture m_readback_staging_texture;
|
||||||
|
|
||||||
bool m_allow_tearing_supported = false;
|
bool m_allow_tearing_supported = false;
|
||||||
|
bool m_using_flip_model_swap_chain = false;
|
||||||
|
bool m_using_allow_tearing = false;
|
||||||
bool m_vsync = false;
|
bool m_vsync = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -153,6 +153,7 @@ void MainWindow::updateDisplayWindow(bool fullscreen, bool render_to_main)
|
||||||
m_display_widget->setCursor(QCursor());
|
m_display_widget->setCursor(QCursor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_display_widget->windowResizedEvent(m_display_widget->scaledWindowWidth(), m_display_widget->scaledWindowHeight());
|
||||||
m_display_widget->setFocus();
|
m_display_widget->setFocus();
|
||||||
|
|
||||||
QSignalBlocker blocker(m_ui.actionFullscreen);
|
QSignalBlocker blocker(m_ui.actionFullscreen);
|
||||||
|
|
|
@ -51,7 +51,7 @@ void QtDisplayWidget::destroyDeviceContext()
|
||||||
destroyDeviceResources();
|
destroyDeviceResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal QtDisplayWidget::getDevicePixelRatioFromScreen() const
|
qreal QtDisplayWidget::devicePixelRatioFromScreen() const
|
||||||
{
|
{
|
||||||
QScreen* screen_for_ratio;
|
QScreen* screen_for_ratio;
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
@ -65,14 +65,14 @@ qreal QtDisplayWidget::getDevicePixelRatioFromScreen() const
|
||||||
return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast<qreal>(1);
|
return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast<qreal>(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int QtDisplayWidget::getScaledWindowWidth() const
|
int QtDisplayWidget::scaledWindowWidth() const
|
||||||
{
|
{
|
||||||
return static_cast<int>(std::ceil(static_cast<qreal>(width()) * getDevicePixelRatioFromScreen()));
|
return static_cast<int>(std::ceil(static_cast<qreal>(width()) * devicePixelRatioFromScreen()));
|
||||||
}
|
}
|
||||||
|
|
||||||
int QtDisplayWidget::getScaledWindowHeight() const
|
int QtDisplayWidget::scaledWindowHeight() const
|
||||||
{
|
{
|
||||||
return static_cast<int>(std::ceil(static_cast<qreal>(height()) * getDevicePixelRatioFromScreen()));
|
return static_cast<int>(std::ceil(static_cast<qreal>(height()) * devicePixelRatioFromScreen()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QtDisplayWidget::createImGuiContext()
|
bool QtDisplayWidget::createImGuiContext()
|
||||||
|
@ -81,10 +81,10 @@ bool QtDisplayWidget::createImGuiContext()
|
||||||
|
|
||||||
auto& io = ImGui::GetIO();
|
auto& io = ImGui::GetIO();
|
||||||
io.IniFilename = nullptr;
|
io.IniFilename = nullptr;
|
||||||
io.DisplaySize.x = static_cast<float>(getScaledWindowWidth());
|
io.DisplaySize.x = static_cast<float>(scaledWindowWidth());
|
||||||
io.DisplaySize.y = static_cast<float>(getScaledWindowHeight());
|
io.DisplaySize.y = static_cast<float>(scaledWindowHeight());
|
||||||
|
|
||||||
const float framebuffer_scale = static_cast<float>(getDevicePixelRatioFromScreen());
|
const float framebuffer_scale = static_cast<float>(devicePixelRatioFromScreen());
|
||||||
io.DisplayFramebufferScale.x = framebuffer_scale;
|
io.DisplayFramebufferScale.x = framebuffer_scale;
|
||||||
io.DisplayFramebufferScale.y = framebuffer_scale;
|
io.DisplayFramebufferScale.y = framebuffer_scale;
|
||||||
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
||||||
|
@ -141,7 +141,7 @@ bool QtDisplayWidget::event(QEvent* event)
|
||||||
{
|
{
|
||||||
QWidget::event(event);
|
QWidget::event(event);
|
||||||
|
|
||||||
emit windowResizedEvent(getScaledWindowWidth(), getScaledWindowHeight());
|
emit windowResizedEvent(scaledWindowWidth(), scaledWindowHeight());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,15 @@ public:
|
||||||
|
|
||||||
virtual QPaintEngine* paintEngine() const override;
|
virtual QPaintEngine* paintEngine() const override;
|
||||||
|
|
||||||
|
int scaledWindowWidth() const;
|
||||||
|
int scaledWindowHeight() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void windowResizedEvent(int width, int height);
|
void windowResizedEvent(int width, int height);
|
||||||
void windowRestoredEvent();
|
void windowRestoredEvent();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
qreal getDevicePixelRatioFromScreen() const;
|
qreal devicePixelRatioFromScreen() const;
|
||||||
int getScaledWindowWidth() const;
|
|
||||||
int getScaledWindowHeight() const;
|
|
||||||
|
|
||||||
virtual bool createImGuiContext();
|
virtual bool createImGuiContext();
|
||||||
virtual void destroyImGuiContext();
|
virtual void destroyImGuiContext();
|
||||||
|
|
Loading…
Reference in New Issue