summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2021-05-28 19:23:49 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2021-06-03 17:05:44 +0200
commit64089b900fe245cc64c10ff47033dda60d4a5f86 (patch)
tree07f3f38f6ff40738969f8886b6ce707e39be8bf2 /src/gui
parent4652da536a5db3608e6026b27dfe808227b721f2 (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.cpp9
-rw-r--r--src/gui/rhi/qrhid3d11.cpp23
-rw-r--r--src/gui/rhi/qrhigles2.cpp21
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h1
-rw-r--r--src/gui/rhi/qrhimetal.mm10
-rw-r--r--src/gui/rhi/qrhivulkan.cpp10
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;