diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-05-28 19:23:49 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-06-03 17:05:44 +0200 |
commit | 64089b900fe245cc64c10ff47033dda60d4a5f86 (patch) | |
tree | 07f3f38f6ff40738969f8886b6ce707e39be8bf2 /src/gui | |
parent | 4652da536a5db3608e6026b27dfe808227b721f2 (diff) |
rhi: Enable reading back slices of 3D textures
Change-Id: I0c687677b7e86b7284130c775718b29aca2cca40
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/rhi/qrhi.cpp | 9 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11.cpp | 23 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 21 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2_p_p.h | 1 | ||||
-rw-r--r-- | src/gui/rhi/qrhimetal.mm | 10 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan.cpp | 10 |
6 files changed, 46 insertions, 28 deletions
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 58962b8e35..78c615451e 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2426,8 +2426,7 @@ bool QRhiRenderBuffer::createFrom(NativeRenderBuffer src) \value ThreeDimensional The texture is a 3D texture. Such textures should be created with the QRhi::newTexture() overload taking a depth in addition to width and height. A 3D texture can have mipmaps but cannot be - multisample. Reading back the contents of a 3D texture is not currently - supported. When rendering into a 3D texture, the layer specified in the + multisample. When rendering into a 3D texture, the layer specified in the render target's color attachment refers to a slice in range [0..depth-1]. The underlying graphics API may not support 3D textures at run time. Support is indicated by the QRhi::ThreeDimensionalTextures feature. @@ -5322,8 +5321,6 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, co \note Multisample textures cannot be read back. - \note 3D textures cannot be read back. - \note The readback returns raw byte data, in order to allow the applications to interpret it in any way they see fit. Be aware of the blending settings of rendering code: if the blending is set up to rely on premultiplied alpha, @@ -5342,6 +5339,10 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, co N is the \l{QRhi::resourceLimit()}{resource limit value} returned for QRhi::MaxAsyncReadbackFrames. + A single readback operation copies one mip level of one layer (cubemap face + or 3D slice) at a time. The level and layer are specified by the respective + fields in \a rb. + \sa readBackBuffer(), QRhi::resourceLimit() */ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result) diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 35118a4d81..6b4be76fef 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -1564,23 +1564,19 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate UINT subres = 0; QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.rb.texture()); QD3D11SwapChain *swapChainD = nullptr; + bool is3D = false; if (texD) { if (texD->sampleDesc.Count > 1) { qWarning("Multisample texture cannot be read back"); continue; } - // No support for reading back 3D, not because it is not - // possible technically, but we need to draw the line somewhere. - if (texD->m_flags.testFlag(QRhiTexture::ThreeDimensional)) { - qWarning("3D texture cannot be read back"); - continue; - } src = texD->textureResource(); dxgiFormat = texD->dxgiFormat; pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize); format = texD->m_format; - subres = D3D11CalcSubresource(UINT(u.rb.level()), UINT(u.rb.layer()), texD->mipLevelCount); + is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional); + subres = D3D11CalcSubresource(UINT(u.rb.level()), UINT(is3D ? 0 : u.rb.layer()), texD->mipLevelCount); } else { Q_ASSERT(contextState.currentSwapChain); swapChainD = QRHI_RES(QD3D11SwapChain, contextState.currentSwapChain); @@ -1635,7 +1631,18 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate cmd.args.copySubRes.dstZ = 0; cmd.args.copySubRes.src = src; cmd.args.copySubRes.srcSubRes = subres; - cmd.args.copySubRes.hasSrcBox = false; + if (is3D) { + D3D11_BOX srcBox; + memset(&srcBox, 0, sizeof(srcBox)); + srcBox.front = UINT(u.rb.layer()); + srcBox.right = desc.Width; // exclusive + srcBox.bottom = desc.Height; + srcBox.back = srcBox.front + 1; + cmd.args.copySubRes.hasSrcBox = true; + cmd.args.copySubRes.srcBox = srcBox; + } else { + cmd.args.copySubRes.hasSrcBox = false; + } readback.stagingTex = stagingTex; readback.byteSize = byteSize; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 5f8ef08e31..a703c4bc9a 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -2045,14 +2045,20 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate if (texD) trackedImageBarrier(cbD, texD, QGles2Texture::AccessRead); cmd.args.readPixels.texture = texD ? texD->texture : 0; + cmd.args.readPixels.slice3D = -1; if (texD) { const QSize readImageSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize); cmd.args.readPixels.w = readImageSize.width(); cmd.args.readPixels.h = readImageSize.height(); cmd.args.readPixels.format = texD->m_format; - const GLenum faceTargetBase = texD->m_flags.testFlag(QRhiTexture::CubeMap) - ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target; - cmd.args.readPixels.readTarget = faceTargetBase + uint(u.rb.layer()); + if (texD->m_flags.testFlag(QRhiTexture::ThreeDimensional)) { + cmd.args.readPixels.readTarget = texD->target; + cmd.args.readPixels.slice3D = u.rb.layer(); + } else { + const GLenum faceTargetBase = texD->m_flags.testFlag(QRhiTexture::CubeMap) + ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target; + cmd.args.readPixels.readTarget = faceTargetBase + uint(u.rb.layer()); + } cmd.args.readPixels.level = u.rb.level(); } } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) { @@ -2802,8 +2808,13 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) if (mipLevel == 0 || caps.nonBaseLevelFramebufferTexture) { f->glGenFramebuffers(1, &fbo); f->glBindFramebuffer(GL_FRAMEBUFFER, fbo); - f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - cmd.args.readPixels.readTarget, cmd.args.readPixels.texture, mipLevel); + if (cmd.args.readPixels.slice3D >= 0) { + f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + tex, mipLevel, cmd.args.readPixels.slice3D); + } else { + f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + cmd.args.readPixels.readTarget, tex, mipLevel); + } } } else { result->pixelSize = currentSwapChain->pixelSize; diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index b4179c0ce8..d5087b92ed 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -467,6 +467,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer QRhiTexture::Format format; GLenum readTarget; int level; + int slice3D; } readPixels; struct { GLenum target; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index b31d7cccaa..cf11f12ead 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -1854,15 +1854,13 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate QMetalSwapChain *swapChainD = nullptr; id<MTLTexture> src; QSize srcSize; + bool is3D = false; if (texD) { if (texD->samples > 1) { qWarning("Multisample texture cannot be read back"); continue; } - if (texD->m_flags.testFlag(QRhiTexture::ThreeDimensional)) { - qWarning("3D texture readback is not implemented"); - continue; - } + is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional); readback.pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize); readback.format = texD->m_format; src = texD->d->tex; @@ -1890,9 +1888,9 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate ensureBlit(); [blitEnc copyFromTexture: src - sourceSlice: NSUInteger(u.rb.layer()) + sourceSlice: NSUInteger(is3D ? 0 : u.rb.layer()) sourceLevel: NSUInteger(u.rb.level()) - sourceOrigin: MTLOriginMake(0, 0, 0) + sourceOrigin: MTLOriginMake(0, 0, is3D ? u.rb.layer() : 0) sourceSize: MTLSizeMake(NSUInteger(srcSize.width()), NSUInteger(srcSize.height()), 1) toBuffer: readback.buf destinationOffset: 0 diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index d5b6f5760d..64b979b8c7 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -3347,15 +3347,13 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat QVkTexture *texD = QRHI_RES(QVkTexture, u.rb.texture()); QVkSwapChain *swapChainD = nullptr; + bool is3D = false; if (texD) { if (texD->samples > VK_SAMPLE_COUNT_1_BIT) { qWarning("Multisample texture cannot be read back"); continue; } - if (texD->m_flags.testFlag(QRhiTexture::ThreeDimensional)) { - qWarning("3D texture cannot be read back"); - continue; - } + is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional); readback.pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize); readback.format = texD->m_format; texD->lastActiveFrameSlot = currentFrameSlot; @@ -3405,8 +3403,10 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat copyDesc.bufferOffset = 0; copyDesc.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level()); - copyDesc.imageSubresource.baseArrayLayer = uint32_t(u.rb.layer()); + copyDesc.imageSubresource.baseArrayLayer = is3D ? 0 : uint32_t(u.rb.layer()); copyDesc.imageSubresource.layerCount = 1; + if (is3D) + copyDesc.imageOffset.z = u.rb.layer(); copyDesc.imageExtent.width = uint32_t(readback.pixelSize.width()); copyDesc.imageExtent.height = uint32_t(readback.pixelSize.height()); copyDesc.imageExtent.depth = 1; |