From 931668955157fad787fd2a29b9b6b0d5f1d1ee9d Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Fri, 21 Jul 2023 22:03:21 +0200 Subject: [PATCH] Add stereo support for Dx11 RHI Change-Id: I10ef8f80b4b4bcb91fc99ab4ab77f2ac031dbd33 Reviewed-by: Laszlo Agocs --- src/gui/rhi/qrhi.cpp | 4 ++-- src/gui/rhi/qrhid3d11.cpp | 40 ++++++++++++++++++++++++++++++++++++--- src/gui/rhi/qrhid3d11_p.h | 3 +++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 67265ebf46..88ba952592 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -7221,8 +7221,8 @@ QRhiResource::Type QRhiSwapChain::resourceType() const is backed by two color buffers, one for each eye, instead of just one. When stereoscopic rendering is not supported, the return value will be - the default target. For the time being the only backend and 3D API where traditional - stereoscopic rendering is supported is OpenGL (excluding OpenGL ES), in + the default target. For the time being the only backends and 3D API where traditional + stereoscopic rendering is supported are OpenGL (excluding OpenGL ES) and Direct3D 11, in combination with \l QSurfaceFormat::StereoBuffers, assuming it is supported by the graphics and display driver stack at run time. All other backends are going to return the default render target from this overload. diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 8e6dd24dc5..30ea2a5b7e 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -4781,9 +4781,7 @@ bool QD3D11Timestamps::tryQueryTimestamps(int idx, ID3D11DeviceContext *context, } QD3D11SwapChain::QD3D11SwapChain(QRhiImplementation *rhi) - : QRhiSwapChain(rhi), - rt(rhi, this), - cb(rhi) + : QRhiSwapChain(rhi), rt(rhi, this), rtRight(rhi, this), cb(rhi) { backBufferTex = nullptr; backBufferRtv = nullptr; @@ -4804,6 +4802,10 @@ void QD3D11SwapChain::releaseBuffers() backBufferRtv->Release(); backBufferRtv = nullptr; } + if (backBufferRtvRight) { + backBufferRtvRight->Release(); + backBufferRtvRight = nullptr; + } if (backBufferTex) { backBufferTex->Release(); backBufferTex = nullptr; @@ -4857,6 +4859,11 @@ QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget() return &rt; } +QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer) +{ + return targetBuffer == StereoTargetBuffer::LeftBuffer? &rt: &rtRight; +} + QSize QD3D11SwapChain::surfacePixelSize() { Q_ASSERT(m_window); @@ -4965,6 +4972,7 @@ bool QD3D11SwapChain::createOrResize() // resize the buffers then. const bool needsRegistration = !window || window != m_window; + const bool stereo = m_window->format().stereo(); // except if the window actually changes if (window && window != m_window) @@ -5064,6 +5072,7 @@ bool QD3D11SwapChain::createOrResize() desc.Flags = swapChainFlags; desc.Scaling = DXGI_SCALING_NONE; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + desc.Stereo = stereo; if (dcompVisual) { // With DirectComposition setting AlphaMode to STRAIGHT fails the @@ -5179,6 +5188,19 @@ bool QD3D11SwapChain::createOrResize() return false; } + if (stereo) { + // Create a second render target view for the right eye + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.FirstArraySlice = 1; + rtvDesc.Texture2DArray.ArraySize = 1; + hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtvRight); + if (FAILED(hr)) { + qWarning("Failed to create rtv for swapchain backbuffer (right eye): %s", + qPrintable(QSystemError::windowsComString(hr))); + return false; + } + } + // Try to reduce stalls by having a dedicated MSAA texture per swapchain buffer. for (int i = 0; i < BUFFER_COUNT; ++i) { if (sampleDesc.Count > 1) { @@ -5217,6 +5239,18 @@ bool QD3D11SwapChain::createOrResize() rtD->d.colorAttCount = 1; rtD->d.dsAttCount = m_depthStencil ? 1 : 0; + if (stereo) { + rtD = QRHI_RES(QD3D11SwapChainRenderTarget, &rtRight); + rtD->d.rp = QRHI_RES(QD3D11RenderPassDescriptor, m_renderPassDesc); + rtD->d.pixelSize = pixelSize; + rtD->d.dpr = float(window->devicePixelRatio()); + rtD->d.sampleCount = int(sampleDesc.Count); + rtD->d.colorAttCount = 1; + rtD->d.dsAttCount = m_depthStencil ? 1 : 0; + rtD->d.rtv[0] = backBufferRtvRight; + rtD->d.dsv = ds ? ds->dsv : nullptr; + } + if (rhiD->rhiFlags.testFlag(QRhi::EnableTimestamps)) { timestamps.prepare(BUFFER_COUNT, rhiD); // timestamp queries are optional so we can go on even if they failed diff --git a/src/gui/rhi/qrhid3d11_p.h b/src/gui/rhi/qrhid3d11_p.h index 0120df3690..b5684e05e2 100644 --- a/src/gui/rhi/qrhid3d11_p.h +++ b/src/gui/rhi/qrhid3d11_p.h @@ -579,6 +579,7 @@ struct QD3D11SwapChain : public QRhiSwapChain QRhiCommandBuffer *currentFrameCommandBuffer() override; QRhiRenderTarget *currentFrameRenderTarget() override; + QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override; QSize surfacePixelSize() override; bool isFormatSupported(Format f) override; @@ -594,6 +595,7 @@ struct QD3D11SwapChain : public QRhiSwapChain QWindow *window = nullptr; QSize pixelSize; QD3D11SwapChainRenderTarget rt; + QD3D11SwapChainRenderTarget rtRight; QD3D11CommandBuffer cb; DXGI_FORMAT colorFormat; DXGI_FORMAT srgbAdjustedColorFormat; @@ -601,6 +603,7 @@ struct QD3D11SwapChain : public QRhiSwapChain UINT swapChainFlags = 0; ID3D11Texture2D *backBufferTex; ID3D11RenderTargetView *backBufferRtv; + ID3D11RenderTargetView *backBufferRtvRight = nullptr; static const int BUFFER_COUNT = QD3D11_SWAPCHAIN_BUFFER_COUNT; ID3D11Texture2D *msaaTex[BUFFER_COUNT]; ID3D11RenderTargetView *msaaRtv[BUFFER_COUNT];