Add stereo support for DirectX12 and Vulkan backends
Change-Id: Id12723d6c392e25935ccb265c58af91aff968984 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
parent
91dcc76fc1
commit
1eb15adee3
@ -7228,10 +7228,9 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
|
|||||||
is backed by two color buffers, one for each eye, instead of just one.
|
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
|
When stereoscopic rendering is not supported, the return value will be
|
||||||
the default target. For the time being the only backends and 3D API where traditional
|
the default target. It is supported by all hardware backends except for Metal, in
|
||||||
stereoscopic rendering is supported are OpenGL (excluding OpenGL ES) and Direct3D 11, in
|
|
||||||
combination with \l QSurfaceFormat::StereoBuffers, assuming it is supported
|
combination with \l QSurfaceFormat::StereoBuffers, assuming it is supported
|
||||||
by the graphics and display driver stack at run time. All other backends
|
by the graphics and display driver stack at run time. Metal and Null backends
|
||||||
are going to return the default render target from this overload.
|
are going to return the default render target from this overload.
|
||||||
|
|
||||||
\note the value must not be cached and reused between frames
|
\note the value must not be cached and reused between frames
|
||||||
|
@ -1497,6 +1497,16 @@ QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
|
|||||||
swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
|
swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
|
||||||
: D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
|
: D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
|
||||||
|
|
||||||
|
if (swapChainD->stereo) {
|
||||||
|
swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
|
||||||
|
? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
|
||||||
|
: swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
|
||||||
|
|
||||||
|
swapChainD->rtWrapperRight.d.dsv =
|
||||||
|
swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Time to release things that are marked for currentFrameSlot since due to
|
// Time to release things that are marked for currentFrameSlot since due to
|
||||||
// the wait above we know that the previous commands on the GPU for this
|
// the wait above we know that the previous commands on the GPU for this
|
||||||
// slot must have finished already.
|
// slot must have finished already.
|
||||||
@ -5970,6 +5980,7 @@ int QD3D12SwapChainRenderTarget::sampleCount() const
|
|||||||
QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
|
QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
|
||||||
: QRhiSwapChain(rhi),
|
: QRhiSwapChain(rhi),
|
||||||
rtWrapper(rhi, this),
|
rtWrapper(rhi, this),
|
||||||
|
rtWrapperRight(rhi, this),
|
||||||
cbWrapper(rhi)
|
cbWrapper(rhi)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -6026,6 +6037,8 @@ void QD3D12SwapChain::releaseBuffers()
|
|||||||
for (UINT i = 0; i < BUFFER_COUNT; ++i) {
|
for (UINT i = 0; i < BUFFER_COUNT; ++i) {
|
||||||
rhiD->resourcePool.remove(colorBuffers[i]);
|
rhiD->resourcePool.remove(colorBuffers[i]);
|
||||||
rhiD->rtvPool.release(rtvs[i], 1);
|
rhiD->rtvPool.release(rtvs[i], 1);
|
||||||
|
if (stereo)
|
||||||
|
rhiD->rtvPool.release(rtvsRight[i], 1);
|
||||||
if (!msaaBuffers[i].isNull())
|
if (!msaaBuffers[i].isNull())
|
||||||
rhiD->resourcePool.remove(msaaBuffers[i]);
|
rhiD->resourcePool.remove(msaaBuffers[i]);
|
||||||
if (msaaRtvs[i].isValid())
|
if (msaaRtvs[i].isValid())
|
||||||
@ -6060,6 +6073,11 @@ QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
|
|||||||
return &rtWrapper;
|
return &rtWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
|
||||||
|
{
|
||||||
|
return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
|
||||||
|
}
|
||||||
|
|
||||||
QSize QD3D12SwapChain::surfacePixelSize()
|
QSize QD3D12SwapChain::surfacePixelSize()
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_window);
|
Q_ASSERT(m_window);
|
||||||
@ -6191,6 +6209,7 @@ bool QD3D12SwapChain::createOrResize()
|
|||||||
HWND hwnd = reinterpret_cast<HWND>(window->winId());
|
HWND hwnd = reinterpret_cast<HWND>(window->winId());
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
QRHI_RES_RHI(QRhiD3D12);
|
QRHI_RES_RHI(QRhiD3D12);
|
||||||
|
stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
|
||||||
|
|
||||||
if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
|
if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
|
||||||
if (rhiD->ensureDirectCompositionDevice()) {
|
if (rhiD->ensureDirectCompositionDevice()) {
|
||||||
@ -6233,6 +6252,7 @@ bool QD3D12SwapChain::createOrResize()
|
|||||||
desc.Flags = swapChainFlags;
|
desc.Flags = swapChainFlags;
|
||||||
desc.Scaling = DXGI_SCALING_NONE;
|
desc.Scaling = DXGI_SCALING_NONE;
|
||||||
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||||
|
desc.Stereo = stereo;
|
||||||
|
|
||||||
if (dcompVisual) {
|
if (dcompVisual) {
|
||||||
// With DirectComposition setting AlphaMode to STRAIGHT fails the
|
// With DirectComposition setting AlphaMode to STRAIGHT fails the
|
||||||
@ -6342,6 +6362,16 @@ bool QD3D12SwapChain::createOrResize()
|
|||||||
rtvDesc.Format = srgbAdjustedColorFormat;
|
rtvDesc.Format = srgbAdjustedColorFormat;
|
||||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||||
rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
|
rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
|
||||||
|
|
||||||
|
if (stereo) {
|
||||||
|
rtvsRight[i] = rhiD->rtvPool.allocate(1);
|
||||||
|
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
||||||
|
rtvDesc.Format = srgbAdjustedColorFormat;
|
||||||
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||||
|
rtvDesc.Texture2DArray.ArraySize = 1;
|
||||||
|
rtvDesc.Texture2DArray.FirstArraySlice = 1;
|
||||||
|
rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
|
if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
|
||||||
@ -6414,6 +6444,15 @@ bool QD3D12SwapChain::createOrResize()
|
|||||||
rtD->d.colorAttCount = 1;
|
rtD->d.colorAttCount = 1;
|
||||||
rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
|
rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
|
||||||
|
|
||||||
|
rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
|
||||||
|
QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
|
||||||
|
rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
|
||||||
|
rtDr->d.pixelSize = pixelSize;
|
||||||
|
rtDr->d.dpr = float(window->devicePixelRatio());
|
||||||
|
rtDr->d.sampleCount = int(sampleDesc.Count);
|
||||||
|
rtDr->d.colorAttCount = 1;
|
||||||
|
rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
|
||||||
|
|
||||||
if (needsRegistration) {
|
if (needsRegistration) {
|
||||||
rhiD->swapchains.insert(this);
|
rhiD->swapchains.insert(this);
|
||||||
rhiD->registerResource(this);
|
rhiD->registerResource(this);
|
||||||
|
@ -972,6 +972,7 @@ struct QD3D12SwapChain : public QRhiSwapChain
|
|||||||
|
|
||||||
QRhiCommandBuffer *currentFrameCommandBuffer() override;
|
QRhiCommandBuffer *currentFrameCommandBuffer() override;
|
||||||
QRhiRenderTarget *currentFrameRenderTarget() override;
|
QRhiRenderTarget *currentFrameRenderTarget() override;
|
||||||
|
QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
|
||||||
|
|
||||||
QSize surfacePixelSize() override;
|
QSize surfacePixelSize() override;
|
||||||
bool isFormatSupported(Format f) override;
|
bool isFormatSupported(Format f) override;
|
||||||
@ -991,6 +992,7 @@ struct QD3D12SwapChain : public QRhiSwapChain
|
|||||||
QSize pixelSize;
|
QSize pixelSize;
|
||||||
UINT swapInterval = 1;
|
UINT swapInterval = 1;
|
||||||
UINT swapChainFlags = 0;
|
UINT swapChainFlags = 0;
|
||||||
|
BOOL stereo = false;
|
||||||
DXGI_FORMAT colorFormat;
|
DXGI_FORMAT colorFormat;
|
||||||
DXGI_FORMAT srgbAdjustedColorFormat;
|
DXGI_FORMAT srgbAdjustedColorFormat;
|
||||||
DXGI_COLOR_SPACE_TYPE hdrColorSpace;
|
DXGI_COLOR_SPACE_TYPE hdrColorSpace;
|
||||||
@ -999,12 +1001,14 @@ struct QD3D12SwapChain : public QRhiSwapChain
|
|||||||
static const UINT BUFFER_COUNT = 3;
|
static const UINT BUFFER_COUNT = 3;
|
||||||
QD3D12ObjectHandle colorBuffers[BUFFER_COUNT];
|
QD3D12ObjectHandle colorBuffers[BUFFER_COUNT];
|
||||||
QD3D12Descriptor rtvs[BUFFER_COUNT];
|
QD3D12Descriptor rtvs[BUFFER_COUNT];
|
||||||
|
QD3D12Descriptor rtvsRight[BUFFER_COUNT];
|
||||||
DXGI_SAMPLE_DESC sampleDesc;
|
DXGI_SAMPLE_DESC sampleDesc;
|
||||||
QD3D12ObjectHandle msaaBuffers[BUFFER_COUNT];
|
QD3D12ObjectHandle msaaBuffers[BUFFER_COUNT];
|
||||||
QD3D12Descriptor msaaRtvs[BUFFER_COUNT];
|
QD3D12Descriptor msaaRtvs[BUFFER_COUNT];
|
||||||
QD3D12RenderBuffer *ds = nullptr;
|
QD3D12RenderBuffer *ds = nullptr;
|
||||||
UINT currentBackBufferIndex = 0;
|
UINT currentBackBufferIndex = 0;
|
||||||
QD3D12SwapChainRenderTarget rtWrapper;
|
QD3D12SwapChainRenderTarget rtWrapper;
|
||||||
|
QD3D12SwapChainRenderTarget rtWrapperRight;
|
||||||
QD3D12CommandBuffer cbWrapper;
|
QD3D12CommandBuffer cbWrapper;
|
||||||
|
|
||||||
struct FrameResources {
|
struct FrameResources {
|
||||||
|
@ -1592,9 +1592,16 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
|
|||||||
if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
|
if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
|
||||||
usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
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;
|
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
|
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;
|
presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||||
else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
|
else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
|
||||||
presentMode = 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.imageFormat = swapChainD->colorFormat;
|
||||||
swapChainInfo.imageColorSpace = swapChainD->colorSpace;
|
swapChainInfo.imageColorSpace = swapChainD->colorSpace;
|
||||||
swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
|
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.imageUsage = usage;
|
||||||
swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
swapChainInfo.preTransform = preTransform;
|
swapChainInfo.preTransform = preTransform;
|
||||||
@ -1680,7 +1687,9 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
|
|||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
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) {
|
for (int i = 0; i < swapChainD->bufferCount; ++i) {
|
||||||
QVkSwapChain::ImageResources &image(swapChainD->imageRes[i]);
|
QVkSwapChain::ImageResources &image(swapChainD->imageRes[i]);
|
||||||
image.image = swapChainImages[i];
|
image.image = swapChainImages[i];
|
||||||
@ -1708,6 +1717,36 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
|
|||||||
|
|
||||||
image.lastUse = QVkSwapChain::ImageResources::ScImageUseNone;
|
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;
|
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]);
|
QVkSwapChain::ImageResources &image(swapChainD->imageRes[i]);
|
||||||
if (image.fb) {
|
if (image.fb) {
|
||||||
df->vkDestroyFramebuffer(dev, image.fb, nullptr);
|
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]);
|
QVkSwapChain::ImageResources &image(swapChainD->imageRes[swapChainD->currentImageIndex]);
|
||||||
swapChainD->rtWrapper.d.fb = image.fb;
|
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);
|
prepareNewFrame(&swapChainD->cbWrapper);
|
||||||
|
|
||||||
// Read the timestamps for the previous frame for this slot.
|
// Read the timestamps for the previous frame for this slot.
|
||||||
@ -7443,6 +7488,7 @@ const QRhiNativeHandles *QVkCommandBuffer::nativeHandles()
|
|||||||
QVkSwapChain::QVkSwapChain(QRhiImplementation *rhi)
|
QVkSwapChain::QVkSwapChain(QRhiImplementation *rhi)
|
||||||
: QRhiSwapChain(rhi),
|
: QRhiSwapChain(rhi),
|
||||||
rtWrapper(rhi, this),
|
rtWrapper(rhi, this),
|
||||||
|
rtWrapperRight(rhi, this),
|
||||||
cbWrapper(rhi)
|
cbWrapper(rhi)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -7485,6 +7531,11 @@ QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget()
|
|||||||
return &rtWrapper;
|
return &rtWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
|
||||||
|
{
|
||||||
|
return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
|
||||||
|
}
|
||||||
|
|
||||||
QSize QVkSwapChain::surfacePixelSize()
|
QSize QVkSwapChain::surfacePixelSize()
|
||||||
{
|
{
|
||||||
if (!ensureSurface())
|
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;
|
frameCount = 0;
|
||||||
|
|
||||||
if (needsRegistration)
|
if (needsRegistration)
|
||||||
|
@ -572,6 +572,7 @@ struct QVkSwapChain : public QRhiSwapChain
|
|||||||
|
|
||||||
QRhiCommandBuffer *currentFrameCommandBuffer() override;
|
QRhiCommandBuffer *currentFrameCommandBuffer() override;
|
||||||
QRhiRenderTarget *currentFrameRenderTarget() override;
|
QRhiRenderTarget *currentFrameRenderTarget() override;
|
||||||
|
QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
|
||||||
|
|
||||||
QSize surfacePixelSize() override;
|
QSize surfacePixelSize() override;
|
||||||
bool isFormatSupported(Format f) override;
|
bool isFormatSupported(Format f) override;
|
||||||
@ -586,6 +587,7 @@ struct QVkSwapChain : public QRhiSwapChain
|
|||||||
QWindow *window = nullptr;
|
QWindow *window = nullptr;
|
||||||
QSize pixelSize;
|
QSize pixelSize;
|
||||||
bool supportsReadback = false;
|
bool supportsReadback = false;
|
||||||
|
bool stereo = false;
|
||||||
VkSwapchainKHR sc = VK_NULL_HANDLE;
|
VkSwapchainKHR sc = VK_NULL_HANDLE;
|
||||||
int bufferCount = 0;
|
int bufferCount = 0;
|
||||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
@ -597,6 +599,7 @@ struct QVkSwapChain : public QRhiSwapChain
|
|||||||
QVarLengthArray<VkPresentModeKHR, 8> supportedPresentationModes;
|
QVarLengthArray<VkPresentModeKHR, 8> supportedPresentationModes;
|
||||||
VkDeviceMemory msaaImageMem = VK_NULL_HANDLE;
|
VkDeviceMemory msaaImageMem = VK_NULL_HANDLE;
|
||||||
QVkSwapChainRenderTarget rtWrapper;
|
QVkSwapChainRenderTarget rtWrapper;
|
||||||
|
QVkSwapChainRenderTarget rtWrapperRight;
|
||||||
QVkCommandBuffer cbWrapper;
|
QVkCommandBuffer cbWrapper;
|
||||||
|
|
||||||
struct ImageResources {
|
struct ImageResources {
|
||||||
|
@ -22,7 +22,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
QSurfaceFormat::setDefaultFormat(fmt);
|
QSurfaceFormat::setDefaultFormat(fmt);
|
||||||
|
|
||||||
Window w;
|
Window w{QRhi::Vulkan};
|
||||||
w.resize(1280, 720);
|
w.resize(1280, 720);
|
||||||
w.setTitle(QCoreApplication::applicationName());
|
w.setTitle(QCoreApplication::applicationName());
|
||||||
w.show();
|
w.show();
|
||||||
|
@ -8,9 +8,25 @@
|
|||||||
#include <rhi/qshader.h>
|
#include <rhi/qshader.h>
|
||||||
#include "../shared/cube.h"
|
#include "../shared/cube.h"
|
||||||
|
|
||||||
Window::Window()
|
Window::Window(QRhi::Implementation graphicsApi)
|
||||||
|
:m_graphicsApi(graphicsApi)
|
||||||
{
|
{
|
||||||
setSurfaceType(OpenGLSurface);
|
switch (graphicsApi) {
|
||||||
|
default:
|
||||||
|
case QRhi::OpenGLES2:
|
||||||
|
setSurfaceType(OpenGLSurface);
|
||||||
|
break;
|
||||||
|
case QRhi::Vulkan:
|
||||||
|
instance.setLayers({ "VK_LAYER_KHRONOS_validation" });
|
||||||
|
instance.create();
|
||||||
|
setVulkanInstance(&instance);
|
||||||
|
setSurfaceType(VulkanSurface);
|
||||||
|
break;
|
||||||
|
case QRhi::D3D11:
|
||||||
|
case QRhi::D3D12:
|
||||||
|
setSurfaceType(Direct3DSurface);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::exposeEvent(QExposeEvent *)
|
void Window::exposeEvent(QExposeEvent *)
|
||||||
@ -57,11 +73,42 @@ void Window::init()
|
|||||||
{
|
{
|
||||||
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers;
|
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers;
|
||||||
|
|
||||||
m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
|
switch (m_graphicsApi) {
|
||||||
QRhiGles2InitParams params;
|
case QRhi::Vulkan:
|
||||||
params.fallbackSurface = m_fallbackSurface.get();
|
{
|
||||||
params.window = this;
|
QRhiVulkanInitParams params;
|
||||||
m_rhi.reset(QRhi::create(QRhi::OpenGLES2, ¶ms, rhiFlags));
|
params.window = this;
|
||||||
|
params.inst = vulkanInstance();
|
||||||
|
m_rhi.reset(QRhi::create(QRhi::Vulkan, ¶ms, rhiFlags));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QRhi::Null:
|
||||||
|
case QRhi::Metal:
|
||||||
|
case QRhi::OpenGLES2:
|
||||||
|
{
|
||||||
|
m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
|
||||||
|
QRhiGles2InitParams params;
|
||||||
|
params.fallbackSurface = m_fallbackSurface.get();
|
||||||
|
params.window = this;
|
||||||
|
m_rhi.reset(QRhi::create(QRhi::OpenGLES2, ¶ms, rhiFlags));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QRhi::D3D11:
|
||||||
|
{
|
||||||
|
QRhiD3D11InitParams params;
|
||||||
|
m_rhi.reset(QRhi::create(QRhi::D3D11, ¶ms, rhiFlags));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QRhi::D3D12:
|
||||||
|
{
|
||||||
|
QRhiD3D12InitParams params;
|
||||||
|
params.enableDebugLayer = true;
|
||||||
|
m_rhi.reset(QRhi::create(QRhi::D3D12, ¶ms, rhiFlags));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
m_sc.reset(m_rhi->newSwapChain());
|
m_sc.reset(m_rhi->newSwapChain());
|
||||||
m_ds.reset(m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
m_ds.reset(m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
|
||||||
|
@ -11,17 +11,19 @@
|
|||||||
class Window : public QWindow
|
class Window : public QWindow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Window();
|
Window(QRhi::Implementation graphicsApi);
|
||||||
|
|
||||||
void releaseSwapChain();
|
void releaseSwapChain();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
QVulkanInstance instance;
|
||||||
std::unique_ptr<QOffscreenSurface> m_fallbackSurface;
|
std::unique_ptr<QOffscreenSurface> m_fallbackSurface;
|
||||||
std::unique_ptr<QRhi> m_rhi;
|
std::unique_ptr<QRhi> m_rhi;
|
||||||
std::unique_ptr<QRhiSwapChain> m_sc;
|
std::unique_ptr<QRhiSwapChain> m_sc;
|
||||||
std::unique_ptr<QRhiRenderBuffer> m_ds;
|
std::unique_ptr<QRhiRenderBuffer> m_ds;
|
||||||
std::unique_ptr<QRhiRenderPassDescriptor> m_rp;
|
std::unique_ptr<QRhiRenderPassDescriptor> m_rp;
|
||||||
|
|
||||||
|
QRhi::Implementation m_graphicsApi;
|
||||||
bool m_hasSwapChain = false;
|
bool m_hasSwapChain = false;
|
||||||
QMatrix4x4 m_proj;
|
QMatrix4x4 m_proj;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user