From 1ae39cc72b7840b383aabbb5fd89fcfa3483d68c Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 12 Aug 2019 16:15:40 +0200 Subject: rhi: d3d11: Rework swapchain effect handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use FLIP_DISCARD swapchains only on Win10, stick with DISCARD otherwise. This may fix the swapchain creation problems on Windows 7. Add a QT_D3D_NO_FLIP env.var. to make it possible to disable using FLIP_DISCARD even on Win10. This is there for troubleshooting purposes. Finally, fix the backbuffer handling. What we originally ported from the D3D12 backend of Qt Quick is not quite how DXGI used to work with D3D11 and earlier. GetBuffer() can only be used to query index 0, and that's the backbuffer, the rest is managed internally. Follow this model. As an added bonus, disable Alt+Enter. Change-Id: Ie5c7a1e813864e7f873d55bc72cb22fc09213a05 Reviewed-by: Friedemann Kleint Reviewed-by: André de la Rocha Reviewed-by: Christian Strømme --- src/gui/rhi/qrhid3d11.cpp | 113 ++++++++++++++++++++++++++++---------------- src/gui/rhi/qrhid3d11_p_p.h | 5 +- 2 files changed, 75 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index c0b13f1cc8..ddcc5179d2 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -196,14 +196,22 @@ bool QRhiD3D11::create(QRhi::Flags flags) devFlags |= D3D11_CREATE_DEVICE_DEBUG; dxgiFactory = createDXGIFactory2(); - if (dxgiFactory != nullptr) + if (dxgiFactory != nullptr) { hasDxgi2 = true; - else + supportsFlipDiscardSwapchain = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10 + && !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"); + if (!importedDevice) { IDXGIAdapter1 *adapterToUse = nullptr; IDXGIAdapter1 *adapter; @@ -916,7 +924,7 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF swapChainD->cb.resetState(); swapChainD->rt.d.rtv[0] = swapChainD->sampleDesc.Count > 1 ? - swapChainD->msaaRtv[currentFrameSlot] : swapChainD->rtv[currentFrameSlot]; + swapChainD->msaaRtv[currentFrameSlot] : swapChainD->backBufferRtv; swapChainD->rt.d.dsv = swapChainD->ds ? swapChainD->ds->dsv : nullptr; QRHI_PROF_F(beginSwapChainFrame(swapChain)); @@ -945,7 +953,7 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame executeCommandBuffer(&swapChainD->cb); if (swapChainD->sampleDesc.Count > 1) { - context->ResolveSubresource(swapChainD->tex[currentFrameSlot], 0, + context->ResolveSubresource(swapChainD->backBufferTex, 0, swapChainD->msaaTex[currentFrameSlot], 0, swapChainD->colorFormat); } @@ -1329,14 +1337,14 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate // has to be supported. Insert a resolve. QD3D11CommandBuffer::Command rcmd; rcmd.cmd = QD3D11CommandBuffer::Command::ResolveSubRes; - rcmd.args.resolveSubRes.dst = swapChainD->tex[swapChainD->currentFrameSlot]; + rcmd.args.resolveSubRes.dst = swapChainD->backBufferTex; rcmd.args.resolveSubRes.dstSubRes = 0; rcmd.args.resolveSubRes.src = swapChainD->msaaTex[swapChainD->currentFrameSlot]; rcmd.args.resolveSubRes.srcSubRes = 0; rcmd.args.resolveSubRes.format = swapChainD->colorFormat; cbD->commands.append(rcmd); } - src = swapChainD->tex[swapChainD->currentFrameSlot]; + src = swapChainD->backBufferTex; dxgiFormat = swapChainD->colorFormat; pixelSize = swapChainD->pixelSize; format = colorTextureFormatFromDxgiFormat(dxgiFormat, nullptr); @@ -3528,9 +3536,9 @@ QD3D11SwapChain::QD3D11SwapChain(QRhiImplementation *rhi) rt(rhi), cb(rhi) { + backBufferTex = nullptr; + backBufferRtv = nullptr; for (int i = 0; i < BUFFER_COUNT; ++i) { - tex[i] = nullptr; - rtv[i] = nullptr; msaaTex[i] = nullptr; msaaRtv[i] = nullptr; timestampActive[i] = false; @@ -3547,15 +3555,15 @@ QD3D11SwapChain::~QD3D11SwapChain() void QD3D11SwapChain::releaseBuffers() { + if (backBufferRtv) { + backBufferRtv->Release(); + backBufferRtv = nullptr; + } + if (backBufferTex) { + backBufferTex->Release(); + backBufferTex = nullptr; + } for (int i = 0; i < BUFFER_COUNT; ++i) { - if (rtv[i]) { - rtv[i]->Release(); - rtv[i] = nullptr; - } - if (tex[i]) { - tex[i]->Release(); - tex[i] = nullptr; - } if (msaaRtv[i]) { msaaRtv[i]->Release(); msaaRtv[i] = nullptr; @@ -3681,18 +3689,19 @@ bool QD3D11SwapChain::buildOrResize() const UINT swapChainFlags = 0; QRHI_RES_RHI(QRhiD3D11); + const bool useFlipDiscard = rhiD->hasDxgi2 && rhiD->supportsFlipDiscardSwapchain; if (!swapChain) { HWND hwnd = reinterpret_cast(window->winId()); sampleDesc = rhiD->effectiveSampleCount(m_sampleCount); - // We use FLIP_DISCARD which implies a buffer count of 2 (as opposed to the - // old DISCARD with back buffer count == 1). This makes no difference for - // the rest of the stuff except that automatic MSAA is unsupported and - // needs to be implemented via a custom multisample render target and an - // explicit resolve. - HRESULT hr; - if (rhiD->hasDxgi2) { + if (useFlipDiscard) { + // We use FLIP_DISCARD which implies a buffer count of 2 (as opposed to the + // old DISCARD with back buffer count == 1). This makes no difference for + // the rest of the stuff except that automatic MSAA is unsupported and + // needs to be implemented via a custom multisample render target and an + // explicit resolve. + DXGI_SWAP_CHAIN_DESC1 desc; memset(&desc, 0, sizeof(desc)); desc.Width = pixelSize.width(); @@ -3715,7 +3724,10 @@ bool QD3D11SwapChain::buildOrResize() if (SUCCEEDED(hr)) swapChain = sc1; } else { - // Windows 7 + // 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. + DXGI_SWAP_CHAIN_DESC desc; memset(&desc, 0, sizeof(desc)); desc.BufferDesc.Width = pixelSize.width(); @@ -3725,10 +3737,10 @@ bool QD3D11SwapChain::buildOrResize() desc.BufferDesc.Format = colorFormat; desc.SampleDesc.Count = 1; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.BufferCount = BUFFER_COUNT; + desc.BufferCount = 1; desc.OutputWindow = hwnd; desc.Windowed = true; - desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; desc.Flags = swapChainFlags; hr = rhiD->dxgiFactory->CreateSwapChain(rhiD->dev, &desc, &swapChain); @@ -3737,30 +3749,49 @@ bool QD3D11SwapChain::buildOrResize() qWarning("Failed to create D3D11 swapchain: %s", qPrintable(comErrorMessage(hr))); return false; } + rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); } else { releaseBuffers(); - HRESULT hr = swapChain->ResizeBuffers(2, pixelSize.width(), pixelSize.height(), colorFormat, swapChainFlags); + const UINT count = useFlipDiscard ? BUFFER_COUNT : 1; + HRESULT hr = swapChain->ResizeBuffers(count, pixelSize.width(), pixelSize.height(), + colorFormat, swapChainFlags); if (FAILED(hr)) { qWarning("Failed to resize D3D11 swapchain: %s", qPrintable(comErrorMessage(hr))); return false; } } + // This looks odd (for FLIP_DISCARD, esp. compared with backends for Vulkan + // & co.) but the backbuffer is always at index 0, with magic underneath. + // Some explanation from + // https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-1-4-improvements + // + // "In Direct3D 11, applications could call GetBuffer( 0, … ) only once. + // Every call to Present implicitly changed the resource identity of the + // returned interface. Direct3D 12 no longer supports that implicit + // resource identity change, due to the CPU overhead required and the + // flexible resource descriptor design. As a result, the application must + // manually call GetBuffer for every each buffer created with the + // swapchain." + + // So just query index 0 once (per resize) and be done with it. + HRESULT hr = swapChain->GetBuffer(0, IID_ID3D11Texture2D, reinterpret_cast(&backBufferTex)); + if (FAILED(hr)) { + qWarning("Failed to query swapchain backbuffer: %s", qPrintable(comErrorMessage(hr))); + return false; + } + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + memset(&rtvDesc, 0, sizeof(rtvDesc)); + rtvDesc.Format = srgbAdjustedFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtv); + if (FAILED(hr)) { + qWarning("Failed to create rtv for swapchain backbuffer: %s", qPrintable(comErrorMessage(hr))); + return false; + } + + // Try to reduce stalls by having a dedicated MSAA texture per swapchain buffer. for (int i = 0; i < BUFFER_COUNT; ++i) { - HRESULT hr = swapChain->GetBuffer(0, IID_ID3D11Texture2D, reinterpret_cast(&tex[i])); - if (FAILED(hr)) { - qWarning("Failed to query swapchain buffer %d: %s", i, qPrintable(comErrorMessage(hr))); - return false; - } - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - memset(&rtvDesc, 0, sizeof(rtvDesc)); - rtvDesc.Format = srgbAdjustedFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - hr = rhiD->dev->CreateRenderTargetView(tex[i], &rtvDesc, &rtv[i]); - if (FAILED(hr)) { - qWarning("Failed to create rtv for swapchain buffer %d: %s", i, qPrintable(comErrorMessage(hr))); - return false; - } if (sampleDesc.Count > 1) { if (!newColorBuffer(pixelSize, srgbAdjustedFormat, sampleDesc, &msaaTex[i], &msaaRtv[i])) return false; diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 34c9ff70f8..3ceb055b27 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -523,8 +523,8 @@ struct QD3D11SwapChain : public QRhiSwapChain DXGI_FORMAT colorFormat; IDXGISwapChain *swapChain = nullptr; static const int BUFFER_COUNT = 2; - ID3D11Texture2D *tex[BUFFER_COUNT]; - ID3D11RenderTargetView *rtv[BUFFER_COUNT]; + ID3D11Texture2D *backBufferTex; + ID3D11RenderTargetView *backBufferRtv; ID3D11Texture2D *msaaTex[BUFFER_COUNT]; ID3D11RenderTargetView *msaaRtv[BUFFER_COUNT]; DXGI_SAMPLE_DESC sampleDesc; @@ -656,6 +656,7 @@ public: ID3DUserDefinedAnnotation *annotations = nullptr; IDXGIFactory1 *dxgiFactory = nullptr; bool hasDxgi2 = false; + bool supportsFlipDiscardSwapchain = false; QRhiD3D11NativeHandles nativeHandlesStruct; struct { -- cgit v1.2.3