diff options
author | Ilya Doroshenko <ilya.doroshenko@kdab.com> | 2023-08-13 19:11:29 +0200 |
---|---|---|
committer | Ilya Doroshenko <ilya.doroshenko@kdab.com> | 2023-09-05 10:28:42 +0000 |
commit | 1eb15adee372bf4cf87ec6608b7027358d7df910 (patch) | |
tree | 902b0e60f47afdeb7385d8556e45ce4f8b539bbd /src/gui/rhi/qrhivulkan.cpp | |
parent | 91dcc76fc13d2ebbac9aa326f8c6d453a93a05bb (diff) |
Add stereo support for DirectX12 and Vulkan backends
Change-Id: Id12723d6c392e25935ccb265c58af91aff968984
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/gui/rhi/qrhivulkan.cpp')
-rw-r--r-- | src/gui/rhi/qrhivulkan.cpp | 108 |
1 files changed, 104 insertions, 4 deletions
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 98592dbf49..8f7f4ab81d 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -1592,9 +1592,16 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain) if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource)) usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + const bool stereo = bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo()) + && surfaceCaps.maxImageArrayLayers > 1; + swapChainD->stereo = stereo; + VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) { - if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR)) + // Stereo has a weird bug, when using VK_PRESENT_MODE_MAILBOX_KHR, + // black screen is shown, but there is no validation error. + // Detected on Windows, with NVidia RTX A series (at least 4000 and 6000) driver 535.98 + if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo) presentMode = VK_PRESENT_MODE_MAILBOX_KHR; else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR)) presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; @@ -1618,7 +1625,7 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain) swapChainInfo.imageFormat = swapChainD->colorFormat; swapChainInfo.imageColorSpace = swapChainD->colorSpace; swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) }; - swapChainInfo.imageArrayLayers = 1; + swapChainInfo.imageArrayLayers = stereo ? 2u : 1u; swapChainInfo.imageUsage = usage; swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapChainInfo.preTransform = preTransform; @@ -1680,7 +1687,9 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain) fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - swapChainD->imageRes.resize(swapChainD->bufferCount); + // Double up for stereo + swapChainD->imageRes.resize(swapChainD->bufferCount * (stereo ? 2u : 1u)); + for (int i = 0; i < swapChainD->bufferCount; ++i) { QVkSwapChain::ImageResources &image(swapChainD->imageRes[i]); image.image = swapChainImages[i]; @@ -1708,6 +1717,36 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain) image.lastUse = QVkSwapChain::ImageResources::ScImageUseNone; } + if (stereo) { + for (int i = 0; i < swapChainD->bufferCount; ++i) { + QVkSwapChain::ImageResources &image(swapChainD->imageRes[i + swapChainD->bufferCount]); + image.image = swapChainImages[i]; + if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) { + image.msaaImage = msaaImages[i]; + image.msaaImageView = msaaViews[i]; + } + + VkImageViewCreateInfo imgViewInfo = {}; + imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imgViewInfo.image = swapChainImages[i]; + imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imgViewInfo.format = swapChainD->colorFormat; + imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A; + imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imgViewInfo.subresourceRange.baseArrayLayer = 1; + imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1; + err = df->vkCreateImageView(dev, &imgViewInfo, nullptr, &image.imageView); + if (err != VK_SUCCESS) { + qWarning("Failed to create swapchain image view %d: %d", i, err); + return false; + } + + image.lastUse = QVkSwapChain::ImageResources::ScImageUseNone; + } + } swapChainD->currentImageIndex = 0; @@ -1775,7 +1814,7 @@ void QRhiVulkan::releaseSwapChainResources(QRhiSwapChain *swapChain) } } - for (int i = 0; i < swapChainD->bufferCount; ++i) { + for (int i = 0; i < swapChainD->bufferCount * (swapChainD->stereo ? 2 : 1); ++i) { QVkSwapChain::ImageResources &image(swapChainD->imageRes[i]); if (image.fb) { df->vkDestroyFramebuffer(dev, image.fb, nullptr); @@ -1907,6 +1946,12 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin QVkSwapChain::ImageResources &image(swapChainD->imageRes[swapChainD->currentImageIndex]); swapChainD->rtWrapper.d.fb = image.fb; + if (swapChainD->stereo) { + QVkSwapChain::ImageResources &image( + swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD->bufferCount]); + swapChainD->rtWrapperRight.d.fb = image.fb; + } + prepareNewFrame(&swapChainD->cbWrapper); // Read the timestamps for the previous frame for this slot. @@ -7443,6 +7488,7 @@ const QRhiNativeHandles *QVkCommandBuffer::nativeHandles() QVkSwapChain::QVkSwapChain(QRhiImplementation *rhi) : QRhiSwapChain(rhi), rtWrapper(rhi, this), + rtWrapperRight(rhi, this), cbWrapper(rhi) { } @@ -7485,6 +7531,11 @@ QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget() return &rtWrapper; } +QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer) +{ + return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight; +} + QSize QVkSwapChain::surfacePixelSize() { if (!ensureSurface()) @@ -7735,6 +7786,55 @@ bool QVkSwapChain::createOrResize() } } + if (stereo) { + rtWrapperRight.setRenderPassDescriptor( + m_renderPassDesc); // for the public getter in QRhiRenderTarget + rtWrapperRight.d.rp = QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc); + Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp); + + rtWrapperRight.d.pixelSize = pixelSize; + rtWrapperRight.d.dpr = float(window->devicePixelRatio()); + rtWrapperRight.d.sampleCount = samples; + rtWrapperRight.d.colorAttCount = 1; + if (m_depthStencil) { + rtWrapperRight.d.dsAttCount = 1; + ds = QRHI_RES(QVkRenderBuffer, m_depthStencil); + } else { + rtWrapperRight.d.dsAttCount = 0; + ds = nullptr; + } + if (samples > VK_SAMPLE_COUNT_1_BIT) + rtWrapperRight.d.resolveAttCount = 1; + else + rtWrapperRight.d.resolveAttCount = 0; + + for (int i = 0; i < bufferCount; ++i) { + QVkSwapChain::ImageResources &image(imageRes[i + bufferCount]); + VkImageView views[3] = { + // color, ds, resolve + samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView, + ds ? ds->imageView : VK_NULL_HANDLE, + samples > VK_SAMPLE_COUNT_1_BIT ? image.imageView : VK_NULL_HANDLE + }; + + VkFramebufferCreateInfo fbInfo = {}; + fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fbInfo.renderPass = rtWrapperRight.d.rp->rp; + fbInfo.attachmentCount = uint32_t(rtWrapperRight.d.colorAttCount + rtWrapperRight.d.dsAttCount + + rtWrapperRight.d.resolveAttCount); + fbInfo.pAttachments = views; + fbInfo.width = uint32_t(pixelSize.width()); + fbInfo.height = uint32_t(pixelSize.height()); + fbInfo.layers = 1; + + VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo, nullptr, &image.fb); + if (err != VK_SUCCESS) { + qWarning("Failed to create framebuffer: %d", err); + return false; + } + } + } + frameCount = 0; if (needsRegistration) |