summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2022-01-17 17:27:17 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2022-01-25 01:55:18 +0100
commit6d90ab18cd37f9d7b138333e2e27c10437e2764c (patch)
tree848312b874f3ca9cbea77dacf200540ce1fc9f5e
parentf804be32d25baf506fdfb99a3e43b797cf43e769 (diff)
rhi: d3d: Fix up non-vsynced presentation
Doing Present(0, 0) is not necessarily sufficient to get rid of blocking. It may very well start blocking after a few frames. This does not apply to a non-flip-discard swapchain (when running with QT_D3D_NO_FLIP=1), but for flip-discard we should also try using DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING and DXGI_PRESENT_ALLOW_TEARING in case a swap interval of 0 is wanted. Fixes: QTBUG-99949 Change-Id: I9cb13b139ba04e41b4f25b94bcd3d1e973496414 Reviewed-by: Andy Nichols <andy.nichols@qt.io> (cherry picked from commit 6dd09664b280df827788ab7d21c0e279b1f79c5a) Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r--src/gui/rhi/qrhid3d11.cpp71
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h5
2 files changed, 50 insertions, 26 deletions
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index a8fd9a686f..175015f7fe 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -199,19 +199,32 @@ bool QRhiD3D11::create(QRhi::Flags flags)
dxgiFactory = createDXGIFactory2();
if (dxgiFactory != nullptr) {
- hasDxgi2 = true;
supportsFlipDiscardSwapchain = !qEnvironmentVariableIntValue("QT_D3D_NO_FLIP");
} else {
dxgiFactory = createDXGIFactory1();
- hasDxgi2 = false;
supportsFlipDiscardSwapchain = false;
}
if (dxgiFactory == nullptr)
return false;
- qCDebug(QRHI_LOG_INFO, "DXGI 1.2 = %s, FLIP_DISCARD swapchain supported = %s",
- hasDxgi2 ? "true" : "false", supportsFlipDiscardSwapchain ? "true" : "false");
+ supportsAllowTearing = false;
+ if (supportsFlipDiscardSwapchain) {
+ // For a FLIP_DISCARD swapchain Present(0, 0) is not necessarily
+ // sufficient to get non-blocking behavior, try using ALLOW_TEARING
+ // when available.
+ IDXGIFactory5 *factory5 = nullptr;
+ if (SUCCEEDED(dxgiFactory->QueryInterface(IID_IDXGIFactory5, reinterpret_cast<void **>(&factory5)))) {
+ BOOL allowTearing = false;
+ if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing))))
+ supportsAllowTearing = allowTearing;
+ factory5->Release();
+ }
+ }
+
+ qCDebug(QRHI_LOG_INFO, "FLIP_DISCARD swapchain supported = %s, ALLOW_TEARING supported = %s",
+ supportsFlipDiscardSwapchain ? "true" : "false",
+ supportsAllowTearing ? "true" : "false");
if (!importedDeviceAndContext) {
IDXGIAdapter1 *adapter;
@@ -1145,7 +1158,9 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
if (!flags.testFlag(QRhi::SkipPresent)) {
- const UINT presentFlags = 0;
+ UINT presentFlags = 0;
+ if (swapChainD->swapInterval == 0 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
+ presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
qWarning("Device loss detected in Present()");
@@ -4489,26 +4504,35 @@ bool QD3D11SwapChain::createOrResize()
const DXGI_FORMAT srgbAdjustedFormat = m_flags.testFlag(sRGB) ?
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
- const UINT swapChainFlags = 0;
-
QRHI_RES_RHI(QRhiD3D11);
- bool useFlipDiscard = rhiD->hasDxgi2 && rhiD->supportsFlipDiscardSwapchain;
+ bool useFlipDiscard = rhiD->supportsFlipDiscardSwapchain;
+
+ // Take a shortcut for alpha: whatever the platform plugin does to enable
+ // transparency for our QWindow will be sufficient on the legacy (DISCARD)
+ // path. For FLIP_DISCARD we'd need to use DirectComposition (create a
+ // IDCompositionDevice/Target/Visual), avoid that for now. (this though
+ // means HDR and semi-transparent windows cannot be combined)
+ if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
+ useFlipDiscard = false;
+ if (window->requestedFormat().alphaBufferSize() <= 0)
+ qWarning("Swapchain says surface has alpha but the window has no alphaBufferSize set. "
+ "This may lead to problems.");
+ }
+
+ swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
+ swapChainFlags = 0;
+
+ // A non-flip swapchain can do Present(0) as expected without
+ // ALLOW_TEARING, and ALLOW_TEARING is not compatible with it at all so the
+ // flag must not be set then. Whereas for flip-discard we should use it, if
+ // supported, to get better results for 'unthrottled' presentation.
+ if (swapInterval == 0 && useFlipDiscard && rhiD->supportsAllowTearing)
+ swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
+
if (!swapChain) {
HWND hwnd = reinterpret_cast<HWND>(window->winId());
sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
- // Take a shortcut for alpha: our QWindow is OpenGLSurface so whatever
- // the platform plugin does to enable transparency for OpenGL window
- // will be sufficient for us too on the legacy (DISCARD) path. For
- // FLIP_DISCARD we'd need to use DirectComposition (create a
- // IDCompositionDevice/Target/Visual), avoid that for now.
- if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
- useFlipDiscard = false;
- if (window->requestedFormat().alphaBufferSize() <= 0)
- qWarning("Swapchain says surface has alpha but the window has no alphaBufferSize set. "
- "This may lead to problems.");
- }
-
HRESULT hr;
if (useFlipDiscard) {
// We use FLIP_DISCARD which implies a buffer count of 2 (as opposed to the
@@ -4538,9 +4562,9 @@ bool QD3D11SwapChain::createOrResize()
if (SUCCEEDED(hr))
swapChain = sc1;
} else {
- // Windows 7 for instance. Use DISCARD mode. Regardless, keep on
- // using our manual resolve for symmetry with the FLIP_DISCARD code
- // path when MSAA is requested.
+ // Fallback: use DISCARD mode. Regardless, keep on using our manual
+ // resolve for symmetry with the FLIP_DISCARD code path when MSAA
+ // is requested. This has no HDR support.
DXGI_SWAP_CHAIN_DESC desc;
memset(&desc, 0, sizeof(desc));
@@ -4636,7 +4660,6 @@ bool QD3D11SwapChain::createOrResize()
currentFrameSlot = 0;
frameCount = 0;
ds = m_depthStencil ? QRHI_RES(QD3D11RenderBuffer, m_depthStencil) : nullptr;
- swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
QD3D11ReferenceRenderTarget *rtD = QRHI_RES(QD3D11ReferenceRenderTarget, &rt);
rtD->d.rp = QRHI_RES(QD3D11RenderPassDescriptor, m_renderPassDesc);
diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h
index 70c7ad969b..7620fd9e89 100644
--- a/src/gui/rhi/qrhid3d11_p_p.h
+++ b/src/gui/rhi/qrhid3d11_p_p.h
@@ -57,7 +57,7 @@
#include <QWindow>
#include <d3d11_1.h>
-#include <dxgi1_3.h>
+#include <dxgi1_5.h>
QT_BEGIN_NAMESPACE
@@ -573,6 +573,7 @@ struct QD3D11SwapChain : public QRhiSwapChain
QD3D11CommandBuffer cb;
DXGI_FORMAT colorFormat;
IDXGISwapChain *swapChain = nullptr;
+ UINT swapChainFlags = 0;
static const int BUFFER_COUNT = 2;
ID3D11Texture2D *backBufferTex;
ID3D11RenderTargetView *backBufferRtv;
@@ -723,8 +724,8 @@ public:
LUID adapterLuid = {};
ID3DUserDefinedAnnotation *annotations = nullptr;
IDXGIFactory1 *dxgiFactory = nullptr;
- bool hasDxgi2 = false;
bool supportsFlipDiscardSwapchain = false;
+ bool supportsAllowTearing = false;
bool deviceLost = false;
QRhiD3D11NativeHandles nativeHandlesStruct;
QRhiDriverInfo driverInfoStruct;