From 60871b4fdf1ec977498ec4baa1d33c0972ac434f Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 23 Sep 2020 15:40:06 +0200 Subject: [PATCH] rhi: vulkan: Fix mipmap generation for cubemaps Change-Id: Ia1aab06214be802aaabc97ffefa28947e11148e3 Reviewed-by: Andy Nichols --- src/gui/rhi/qrhi.cpp | 11 +- src/gui/rhi/qrhi_p.h | 2 +- src/gui/rhi/qrhi_p_p.h | 4 +- src/gui/rhi/qrhivulkan.cpp | 144 ++++++++++++++------------- tests/manual/rhi/cubemap/cubemap.cpp | 5 +- 5 files changed, 85 insertions(+), 81 deletions(-) diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 849519cb7a..17a1ca91e2 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -4963,19 +4963,20 @@ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, } /*! - Enqueues a mipmap generation operation for the specified \a layer of texture - \a tex. + Enqueues a mipmap generation operation for the specified texture \a tex. + + Both 2D and cube textures are supported. \note The texture must be created with QRhiTexture::MipMapped and QRhiTexture::UsedWithGenerateMips. */ -void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex, int layer) +void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex) { const int idx = d->activeTextureOpCount++; if (idx < d->textureOps.size()) - d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex, layer); + d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex); else - d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex, layer)); + d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex)); } /*! diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 1e86cbc04a..bdfaec9fdf 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -1413,7 +1413,7 @@ public: void uploadTexture(QRhiTexture *tex, const QImage &image); void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription()); void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result); - void generateMips(QRhiTexture *tex, int layer = 0); + void generateMips(QRhiTexture *tex); private: QRhiResourceUpdateBatch(QRhiImplementation *rhi); diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index 13f1c88f2d..0128fd2d4e 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -393,7 +393,6 @@ public: QRhiTextureCopyDescription desc; QRhiReadbackDescription rb; QRhiReadbackResult *result; - int layer; static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc) { @@ -424,12 +423,11 @@ public: return op; } - static TextureOp genMips(QRhiTexture *tex, int layer) + static TextureOp genMips(QRhiTexture *tex) { TextureOp op = {}; op.type = GenMips; op.dst = tex; - op.layer = layer; return op; } }; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 835db74804..1a0431e19d 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -3318,8 +3318,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) { QVkTexture *utexD = QRHI_RES(QVkTexture, u.dst); Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips)); - int w = utexD->m_pixelSize.width(); - int h = utexD->m_pixelSize.height(); + const bool isCube = utexD->m_flags.testFlag(QRhiTexture::CubeMap); VkImageLayout origLayout = utexD->usageState.layout; VkAccessFlags origAccess = utexD->usageState.access; @@ -3327,80 +3326,83 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat if (!origStage) origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - for (int level = 1; level < int(utexD->mipLevelCount); ++level) { - if (level == 1) { + for (int layer = 0; layer < (isCube ? 6 : 1); ++layer) { + int w = utexD->m_pixelSize.width(); + int h = utexD->m_pixelSize.height(); + for (int level = 1; level < int(utexD->mipLevelCount); ++level) { + if (level == 1) { + subresourceBarrier(cbD, utexD->image, + origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + origAccess, VK_ACCESS_TRANSFER_READ_BIT, + origStage, VK_PIPELINE_STAGE_TRANSFER_BIT, + layer, 1, + level - 1, 1); + } else { + subresourceBarrier(cbD, utexD->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + layer, 1, + level - 1, 1); + } + subresourceBarrier(cbD, utexD->image, - origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - origAccess, VK_ACCESS_TRANSFER_READ_BIT, + origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + origAccess, VK_ACCESS_TRANSFER_WRITE_BIT, origStage, VK_PIPELINE_STAGE_TRANSFER_BIT, - u.layer, 1, - level - 1, 1); - } else { - subresourceBarrier(cbD, utexD->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - u.layer, 1, - level - 1, 1); + layer, 1, + level, 1); + + VkImageBlit region; + memset(®ion, 0, sizeof(region)); + + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.srcSubresource.mipLevel = uint32_t(level) - 1; + region.srcSubresource.baseArrayLayer = uint32_t(layer); + region.srcSubresource.layerCount = 1; + + region.srcOffsets[1].x = qMax(1, w); + region.srcOffsets[1].y = qMax(1, h); + region.srcOffsets[1].z = 1; + + region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.dstSubresource.mipLevel = uint32_t(level); + region.dstSubresource.baseArrayLayer = uint32_t(layer); + region.dstSubresource.layerCount = 1; + + region.dstOffsets[1].x = qMax(1, w >> 1); + region.dstOffsets[1].y = qMax(1, h >> 1); + region.dstOffsets[1].z = 1; + + QVkCommandBuffer::Command cmd; + cmd.cmd = QVkCommandBuffer::Command::BlitImage; + cmd.args.blitImage.src = utexD->image; + cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + cmd.args.blitImage.dst = utexD->image; + cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + cmd.args.blitImage.filter = VK_FILTER_LINEAR; + cmd.args.blitImage.desc = region; + cbD->commands.append(cmd); + + w >>= 1; + h >>= 1; } - subresourceBarrier(cbD, utexD->image, - origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - origAccess, VK_ACCESS_TRANSFER_WRITE_BIT, - origStage, VK_PIPELINE_STAGE_TRANSFER_BIT, - u.layer, 1, - level, 1); - - VkImageBlit region; - memset(®ion, 0, sizeof(region)); - - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.srcSubresource.mipLevel = uint32_t(level) - 1; - region.srcSubresource.baseArrayLayer = uint32_t(u.layer); - region.srcSubresource.layerCount = 1; - - region.srcOffsets[1].x = qMax(1, w); - region.srcOffsets[1].y = qMax(1, h); - region.srcOffsets[1].z = 1; - - region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.dstSubresource.mipLevel = uint32_t(level); - region.dstSubresource.baseArrayLayer = uint32_t(u.layer); - region.dstSubresource.layerCount = 1; - - region.dstOffsets[1].x = qMax(1, w >> 1); - region.dstOffsets[1].y = qMax(1, h >> 1); - region.dstOffsets[1].z = 1; - - QVkCommandBuffer::Command cmd; - cmd.cmd = QVkCommandBuffer::Command::BlitImage; - cmd.args.blitImage.src = utexD->image; - cmd.args.blitImage.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - cmd.args.blitImage.dst = utexD->image; - cmd.args.blitImage.dstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - cmd.args.blitImage.filter = VK_FILTER_LINEAR; - cmd.args.blitImage.desc = region; - cbD->commands.append(cmd); - - w >>= 1; - h >>= 1; + if (utexD->mipLevelCount > 1) { + subresourceBarrier(cbD, utexD->image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout, + VK_ACCESS_TRANSFER_READ_BIT, origAccess, + VK_PIPELINE_STAGE_TRANSFER_BIT, origStage, + layer, 1, + 0, int(utexD->mipLevelCount) - 1); + subresourceBarrier(cbD, utexD->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout, + VK_ACCESS_TRANSFER_WRITE_BIT, origAccess, + VK_PIPELINE_STAGE_TRANSFER_BIT, origStage, + layer, 1, + int(utexD->mipLevelCount) - 1, 1); + } } - - if (utexD->mipLevelCount > 1) { - subresourceBarrier(cbD, utexD->image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout, - VK_ACCESS_TRANSFER_READ_BIT, origAccess, - VK_PIPELINE_STAGE_TRANSFER_BIT, origStage, - u.layer, 1, - 0, int(utexD->mipLevelCount) - 1); - subresourceBarrier(cbD, utexD->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout, - VK_ACCESS_TRANSFER_WRITE_BIT, origAccess, - VK_PIPELINE_STAGE_TRANSFER_BIT, origStage, - u.layer, 1, - int(utexD->mipLevelCount) - 1, 1); - } - utexD->lastActiveFrameSlot = currentFrameSlot; } } diff --git a/tests/manual/rhi/cubemap/cubemap.cpp b/tests/manual/rhi/cubemap/cubemap.cpp index 6004c39ea9..7949d2ecfc 100644 --- a/tests/manual/rhi/cubemap/cubemap.cpp +++ b/tests/manual/rhi/cubemap/cubemap.cpp @@ -73,7 +73,8 @@ void Window::customInit() d.releasePool << d.ubuf; const QSize cubeMapSize(512, 512); - d.tex = m_r->newTexture(QRhiTexture::RGBA8, cubeMapSize, 1, QRhiTexture::CubeMap); + d.tex = m_r->newTexture(QRhiTexture::RGBA8, cubeMapSize, 1, QRhiTexture::CubeMap + | QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips); // exercise mipmap generation as well d.releasePool << d.tex; d.tex->create(); @@ -93,6 +94,8 @@ void Window::customInit() }); d.initialUpdates->uploadTexture(d.tex, desc); + d.initialUpdates->generateMips(d.tex); + d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::Repeat, QRhiSampler::Repeat); d.releasePool << d.sampler;