From 59604405c98cc8d55e924573859dd64d94d5d877 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 7 Oct 2019 10:12:48 +0200 Subject: rhi: Fix non-base level copy and readback wrt source size When the source size is not explicitly specified, we take the entire subresource. However, just using the texture's size is wrong: when the source level in a copy or readback is not 0, the size for the corresponding mip level has to be used instead. This fixes occasional crashes with Metal in the autotest. Change-Id: I99f689feef93ec86dffdc9e82d6bfdaf5c1eb041 Reviewed-by: Paul Olav Tvete --- src/gui/rhi/qrhid3d11.cpp | 9 +++++---- src/gui/rhi/qrhigles2.cpp | 7 ++++--- src/gui/rhi/qrhimetal.mm | 10 +++++----- src/gui/rhi/qrhivulkan.cpp | 10 +++++----- 4 files changed, 19 insertions(+), 17 deletions(-) (limited to 'src/gui/rhi') diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 57ebb2909f..717f3e6d6c 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -1416,15 +1416,16 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate UINT srcSubRes = D3D11CalcSubresource(UINT(u.desc.sourceLevel()), UINT(u.desc.sourceLayer()), srcD->mipLevelCount); UINT dstSubRes = D3D11CalcSubresource(UINT(u.desc.destinationLevel()), UINT(u.desc.destinationLayer()), dstD->mipLevelCount); const QPoint dp = u.desc.destinationTopLeft(); - const QSize size = u.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.desc.pixelSize(); + const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize); + const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize(); const QPoint sp = u.desc.sourceTopLeft(); D3D11_BOX srcBox; srcBox.left = UINT(sp.x()); srcBox.top = UINT(sp.y()); srcBox.front = 0; // back, right, bottom are exclusive - srcBox.right = srcBox.left + UINT(size.width()); - srcBox.bottom = srcBox.top + UINT(size.height()); + srcBox.right = srcBox.left + UINT(copySize.width()); + srcBox.bottom = srcBox.top + UINT(copySize.height()); srcBox.back = 1; QD3D11CommandBuffer::Command cmd; cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes; @@ -1457,7 +1458,7 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate } src = texD->tex; dxgiFormat = texD->dxgiFormat; - pixelSize = u.rb.level() > 0 ? q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize) : texD->m_pixelSize; + 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); } else { diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 4163ab1e79..e355979626 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -1506,7 +1506,8 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate trackedImageBarrier(cbD, srcD, QGles2Texture::AccessRead); trackedImageBarrier(cbD, dstD, QGles2Texture::AccessUpdate); - const QSize size = u.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.desc.pixelSize(); + const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize); + const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize(); // do not translate coordinates, even if sp is bottom-left from gl's pov const QPoint sp = u.desc.sourceTopLeft(); const QPoint dp = u.desc.destinationTopLeft(); @@ -1532,8 +1533,8 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate cmd.args.copyTex.dstX = dp.x(); cmd.args.copyTex.dstY = dp.y(); - cmd.args.copyTex.w = size.width(); - cmd.args.copyTex.h = size.height(); + cmd.args.copyTex.w = copySize.width(); + cmd.args.copyTex.h = copySize.height(); cbD->commands.append(cmd); } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) { diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index ef5ab696d7..5f14d917b8 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -1628,7 +1628,8 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate QMetalTexture *srcD = QRHI_RES(QMetalTexture, u.src); QMetalTexture *dstD = QRHI_RES(QMetalTexture, u.dst); const QPoint dp = u.desc.destinationTopLeft(); - const QSize size = u.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.desc.pixelSize(); + const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize); + const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize(); const QPoint sp = u.desc.sourceTopLeft(); ensureBlit(); @@ -1636,7 +1637,7 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate sourceSlice: NSUInteger(u.desc.sourceLayer()) sourceLevel: NSUInteger(u.desc.sourceLevel()) sourceOrigin: MTLOriginMake(NSUInteger(sp.x()), NSUInteger(sp.y()), 0) - sourceSize: MTLSizeMake(NSUInteger(size.width()), NSUInteger(size.height()), 1) + sourceSize: MTLSizeMake(NSUInteger(copySize.width()), NSUInteger(copySize.height()), 1) toTexture: dstD->d->tex destinationSlice: NSUInteger(u.desc.destinationLayer()) destinationLevel: NSUInteger(u.desc.destinationLevel()) @@ -1658,11 +1659,10 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate qWarning("Multisample texture cannot be read back"); continue; } - readback.pixelSize = u.rb.level() > 0 ? q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize) - : texD->m_pixelSize; + readback.pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize); readback.format = texD->m_format; src = texD->d->tex; - srcSize = texD->m_pixelSize; + srcSize = readback.pixelSize; texD->lastActiveFrameSlot = currentFrameSlot; } else { Q_ASSERT(currentSwapChain); diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index fca2125f10..103fea627a 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -2913,9 +2913,10 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat region.dstOffset.x = u.desc.destinationTopLeft().x(); region.dstOffset.y = u.desc.destinationTopLeft().y(); - const QSize size = u.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.desc.pixelSize(); - region.extent.width = uint32_t(size.width()); - region.extent.height = uint32_t(size.height()); + const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize); + const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize(); + region.extent.width = uint32_t(copySize.width()); + region.extent.height = uint32_t(copySize.height()); region.extent.depth = 1; trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, @@ -2946,8 +2947,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat qWarning("Multisample texture cannot be read back"); continue; } - readback.pixelSize = u.rb.level() > 0 ? q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize) - : texD->m_pixelSize; + readback.pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize); readback.format = texD->m_format; texD->lastActiveFrameSlot = currentFrameSlot; } else { -- cgit v1.2.3