Commit cafd62bb authored by Laszlo Agocs's avatar Laszlo Agocs

vk: implement image copying

Color only, one subres at a time, transitions between transfer and
shader-read every time. For the common cases this is good enough,
to be explored later if it could be made smarter.
parent fe83848a
......@@ -83,7 +83,7 @@ int main(int argc, char **argv)
return 1;
}
QRhiTexture *tex = r->newTexture(QRhiTexture::RGBA8, QSize(1280, 720), QRhiTexture::RenderTarget | QRhiTexture::ReadBack);
QRhiTexture *tex = r->newTexture(QRhiTexture::RGBA8, QSize(1280, 720), QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
tex->build();
QRhiTextureRenderTarget *rt = r->newTextureRenderTarget({ tex });
QRhiRenderPassDescriptor *rp = rt->newCompatibleRenderPassDescriptor();
......
......@@ -96,7 +96,7 @@ int main(int argc, char **argv)
return 1;
}
QRhiTexture *tex = r->newTexture(QRhiTexture::RGBA8, QSize(1280, 720), QRhiTexture::RenderTarget | QRhiTexture::ReadBack);
QRhiTexture *tex = r->newTexture(QRhiTexture::RGBA8, QSize(1280, 720), QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
tex->build();
QRhiTextureRenderTarget *rt = r->newTextureRenderTarget({ tex });
QRhiRenderPassDescriptor *rp = rt->newCompatibleRenderPassDescriptor();
......
......@@ -106,7 +106,7 @@ int main(int argc, char **argv)
return 1;
}
QRhiTexture *tex = r->newTexture(QRhiTexture::RGBA8, QSize(1280, 720), QRhiTexture::RenderTarget | QRhiTexture::ReadBack);
QRhiTexture *tex = r->newTexture(QRhiTexture::RGBA8, QSize(1280, 720), QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
tex->build();
QRhiTextureRenderTarget *rt = r->newTextureRenderTarget({ tex });
QRhiRenderPassDescriptor *rp = rt->newCompatibleRenderPassDescriptor();
......
......@@ -77,7 +77,7 @@ void Window::customInit()
d.ubuf->build();
QImage baseImage(QLatin1String(":/qt256.png"));
d.tex = m_r->newTexture(QRhiTexture::RGBA8, baseImage.size());
d.tex = m_r->newTexture(QRhiTexture::RGBA8, baseImage.size(), QRhiTexture::UsedAsTransferSource);
d.tex->build();
// As an alternative to what some of the other examples do, prepare an
......@@ -232,9 +232,9 @@ void Window::customRender()
// Copy the left-half of tex to the right-half of newTex, while
// leaving the left-half of newTex blue. Keep a 20 pixel gap at
// the top.
desc.sourceTopLeft = QPointF(0, 20);
desc.pixelSize = QSizeF(sz.width() / 2.0f, sz.height() - 20);
desc.destinationTopLeft = QPointF(sz.width() / 2.0f, 20);
desc.sourceTopLeft = QPoint(0, 20);
desc.pixelSize = QSize(sz.width() / 2, sz.height() - 20);
desc.destinationTopLeft = QPoint(sz.width() / 2, 20);
u->copyTexture(d.newTex, d.tex, desc);
......
......@@ -288,15 +288,15 @@ Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription, Q_MOVABLE_TYPE);
struct Q_RHI_EXPORT QRhiTextureCopyDescription
{
QSizeF pixelSize; // empty = entire texture
QSize pixelSize; // empty = entire texture
int sourceLayer = 0;
int sourceLevel = 0;
QPointF sourceTopLeft;
QPoint sourceTopLeft;
int destinationLayer = 0;
int destinationLevel = 0;
QPointF destinationTopLeft;
QPoint destinationTopLeft;
};
Q_DECLARE_TYPEINFO(QRhiTextureCopyDescription, Q_MOVABLE_TYPE);
......@@ -411,7 +411,7 @@ public:
CubeMap = 1 << 2,
MipMapped = 1 << 3,
sRGB = 1 << 4,
ReadBack = 1 << 5
UsedAsTransferSource = 1 << 5
};
Q_DECLARE_FLAGS(Flags, Flag)
......
......@@ -776,7 +776,7 @@ void QRhiD3D11::commitResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
UINT dstSubRes = D3D11CalcSubresource(u.desc.destinationLevel, u.desc.destinationLayer, dstD->mipLevelCount);
const float dx = u.desc.destinationTopLeft.x();
const float dy = u.desc.destinationTopLeft.y();
const QSizeF size = u.desc.pixelSize.isEmpty() ? srcD->m_pixelSize : u.desc.pixelSize;
const QSize size = u.desc.pixelSize.isEmpty() ? srcD->m_pixelSize : u.desc.pixelSize;
D3D11_BOX srcBox;
srcBox.left = u.desc.sourceTopLeft.x();
srcBox.top = u.desc.sourceTopLeft.y();
......
......@@ -1500,6 +1500,7 @@ bool QRhiVulkan::readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &
copyDesc.imageExtent.depth = 1;
if (texD) {
Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedAsTransferSource));
// assume the image was written
imageBarrier(cb, texD,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
......@@ -2065,6 +2066,73 @@ void QRhiVulkan::commitResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
}
for (const QRhiResourceUpdateBatchPrivate::TextureCopy &u : ud->textureCopies) {
Q_ASSERT(u.src && u.dst);
QVkTexture *srcD = QRHI_RES(QVkTexture, u.src);
QVkTexture *dstD = QRHI_RES(QVkTexture, u.dst);
VkImageCopy region;
memset(&region, 0, sizeof(region));
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.srcSubresource.mipLevel = u.desc.sourceLevel;
region.srcSubresource.baseArrayLayer = u.desc.sourceLayer;
region.srcSubresource.layerCount = 1;
region.srcOffset.x = u.desc.sourceTopLeft.x();
region.srcOffset.y = u.desc.sourceTopLeft.y();
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.dstSubresource.mipLevel = u.desc.destinationLevel;
region.dstSubresource.baseArrayLayer = u.desc.destinationLayer;
region.dstSubresource.layerCount = 1;
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 = size.width();
region.extent.height = size.height();
region.extent.depth = 1;
if (srcD->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
Q_ASSERT(srcD->m_flags.testFlag(QRhiTexture::UsedAsTransferSource));
imageBarrier(cb, srcD,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
}
if (dstD->layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
if (dstD->layout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
imageBarrier(cb, dstD,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
0, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
} else {
imageBarrier(cb, dstD,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
}
}
df->vkCmdCopyImage(QRHI_RES(QVkCommandBuffer, cb)->cb,
srcD->image, srcD->layout,
dstD->image, dstD->layout,
1, &region);
imageBarrier(cb, srcD,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
imageBarrier(cb, dstD,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
}
for (const QRhiResourceUpdateBatchPrivate::TexturePrepare &u : ud->texturePrepares) {
if (u.flags.testFlag(QRhiResourceUpdateBatch::TextureRead)) {
QVkTexture *utexD = QRHI_RES(QVkTexture, u.tex);
......@@ -3087,7 +3155,7 @@ bool QVkTexture::build()
else
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
if (m_flags.testFlag(QRhiTexture::ReadBack))
if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo allocInfo;
......@@ -3294,6 +3362,7 @@ bool QVkTextureRenderTarget::build()
d.colorAttCount = m_desc.colorAttachments.count();
for (int i = 0; i < d.colorAttCount; ++i) {
QVkTexture *texD = QRHI_RES(QVkTexture, m_desc.colorAttachments[i].texture);
Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
VkImageView view = texD->imageView;
if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
const int face = m_desc.colorAttachments[i].layer;
......
vk, gl, mtl: texcopy
gl, mtl: texcopy
mtl: tex upload with pos
mtl: rhi without a window, offscreen frame
mtl: readback (tex, backbuffer)
......@@ -46,6 +46,7 @@ indirect draw?
vk: subpasses?
more tex: 3d, array?
vk compressed tex: could it consume a complete ktx without any memcpys?
multi mip/layer copy? (fewer barriers...)
multi-buffer (region) readback?
depth readback
copy image depth
......@@ -55,6 +56,7 @@ dxc for d3d as an alternative to fxc?
hlsl -> dxc -> spirv -> spirv-cross hmmm...
+++ done
vk: texcopy
move cb api into QRhiCommandBuffer
d3d: texcopy
copyimage (color, with rect?, no resolve or transforms here)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment