summaryrefslogtreecommitdiffstats
path: root/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
diff options
context:
space:
mode:
authorBen Fletcher <ben.fletcher@me.com>2022-10-30 12:19:38 -0700
committerBen Fletcher <ben.fletcher@me.com>2022-11-15 11:36:18 -0800
commit85a1663eb15cd85f91fe1f6dd924588d9cc7c2a8 (patch)
treed04ee874657d709c9815b561acf1074d8e9f22a5 /tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
parenta47c7a98264c85e9ff0bc3e5a42b9554dd20576e (diff)
RHI: Add support for 1D textures
Support for 1D textures on Vulkan, OpenGL, Metal, and D3D. Change-Id: Ie74ec103da9cfcbf83fa78588cf8cfc1bd6e104f Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'tests/auto/gui/rhi/qrhi/tst_qrhi.cpp')
-rw-r--r--tests/auto/gui/rhi/qrhi/tst_qrhi.cpp510
1 files changed, 510 insertions, 0 deletions
diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
index f92b26a300..cf67708bca 100644
--- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
+++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
@@ -128,6 +128,8 @@ private slots:
void renderbufferImportOpenGL();
void threeDimTexture_data();
void threeDimTexture();
+ void oneDimTexture_data();
+ void oneDimTexture();
void leakedResourceDestroy_data();
void leakedResourceDestroy();
@@ -4677,6 +4679,514 @@ void tst_QRhi::threeDimTexture()
QVERIFY(imageRGBAEquals(result, referenceImage));
}
}
+void tst_QRhi::oneDimTexture_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::oneDimTexture()
+{
+ QFETCH(QRhi::Implementation, impl);
+ QFETCH(QRhiInitParams *, initParams);
+
+ QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams));
+ if (!rhi)
+ QSKIP("QRhi could not be created, skipping testing 1D textures");
+
+ if (!rhi->isFeatureSupported(QRhi::OneDimensionalTextures))
+ QSKIP("Skipping testing 1D textures because they are reported as unsupported");
+
+ const int WIDTH = 512;
+ const int LAYERS = 128;
+
+ {
+ QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, WIDTH, 0, 0));
+ QVERIFY(texture->create());
+
+ QVERIFY(texture->flags().testFlag(QRhiTexture::Flag::OneDimensional));
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ QImage img(WIDTH, 1, QImage::Format_RGBA8888);
+ img.fill(QColor::fromRgb(255, 0, 0));
+
+ QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(texture.data(), upload);
+
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ }
+
+ {
+ QScopedPointer<QRhiTexture> texture(
+ rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0)));
+ QVERIFY(texture->create());
+
+ QVERIFY(texture->flags().testFlag(QRhiTexture::Flag::OneDimensional));
+ QVERIFY(texture->flags().testFlag(QRhiTexture::Flag::TextureArray));
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ for (int i = 0; i < LAYERS; ++i) {
+ QImage img(WIDTH, 1, QImage::Format_RGBA8888);
+ img.fill(QColor::fromRgb(i * 2, 0, 0));
+ QRhiTextureUploadEntry layerUpload(i, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(texture.data(), layerUpload);
+ }
+
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ }
+
+ // Copy from 2D texture to 1D texture
+ {
+ const int WIDTH = 256;
+ const int HEIGHT = 256;
+
+ QScopedPointer<QRhiTexture> srcTexture(rhi->newTexture(
+ QRhiTexture::RGBA8, WIDTH, HEIGHT, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
+ QVERIFY(srcTexture->create());
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ QImage img(WIDTH, HEIGHT, QImage::Format_RGBA8888);
+ for (int x = 0; x < WIDTH; ++x) {
+ for (int y = 0; y < HEIGHT; ++y) {
+ img.setPixelColor(x, y, QColor::fromRgb(x, y, 0));
+ }
+ }
+ QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(srcTexture.data(), upload);
+
+ QScopedPointer<QRhiTexture> dstTexture(rhi->newTexture(
+ QRhiTexture::RGBA8, WIDTH, 0, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
+ QVERIFY(dstTexture->create());
+
+ QRhiTextureCopyDescription copy;
+ copy.setPixelSize(QSize(WIDTH / 2, 1));
+ copy.setDestinationTopLeft(QPoint(WIDTH / 2, 0));
+ copy.setSourceTopLeft(QPoint(33, 67));
+ batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
+
+ copy.setDestinationTopLeft(QPoint(0, 0));
+ copy.setSourceTopLeft(QPoint(99, 12));
+ batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
+
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readResult, &result] {
+ result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ };
+
+ QRhiReadbackDescription readbackDescription(dstTexture.data());
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ QImage referenceImage(WIDTH, 1, result.format());
+ for (int i = 0; i < WIDTH / 2; ++i) {
+ referenceImage.setPixelColor(i, 0, img.pixelColor(99 + i, 12));
+ referenceImage.setPixelColor(WIDTH / 2 + i, 0, img.pixelColor(33 + i, 67));
+ }
+
+ QVERIFY(imageRGBAEquals(result, referenceImage));
+ }
+
+ // Copy from 2D texture to 1D texture array
+ {
+ const int WIDTH = 256;
+ const int HEIGHT = 256;
+ const int LAYERS = 64;
+
+ QScopedPointer<QRhiTexture> srcTexture(rhi->newTexture(
+ QRhiTexture::RGBA8, WIDTH, HEIGHT, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
+ QVERIFY(srcTexture->create());
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ QImage img(WIDTH, HEIGHT, QImage::Format_RGBA8888);
+ for (int x = 0; x < WIDTH; ++x) {
+ for (int y = 0; y < HEIGHT; ++y) {
+ img.setPixelColor(x, y, QColor::fromRgb(x, y, 0));
+ }
+ }
+ QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(srcTexture.data(), upload);
+
+ QScopedPointer<QRhiTexture> dstTexture(
+ rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
+ QRhiTexture::Flag::UsedAsTransferSource));
+ QVERIFY(dstTexture->create());
+
+ QRhiTextureCopyDescription copy;
+ copy.setPixelSize(QSize(WIDTH / 2, 1));
+ copy.setDestinationTopLeft(QPoint(WIDTH / 2, 0));
+ copy.setSourceTopLeft(QPoint(33, 67));
+ copy.setDestinationLayer(12);
+ batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
+
+ copy.setDestinationTopLeft(QPoint(0, 0));
+ copy.setSourceTopLeft(QPoint(99, 12));
+ batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
+
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readResult, &result] {
+ result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ };
+
+ QRhiReadbackDescription readbackDescription(dstTexture.data());
+ readbackDescription.setLayer(12);
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ QImage referenceImage(WIDTH, 1, result.format());
+ for (int i = 0; i < WIDTH / 2; ++i) {
+ referenceImage.setPixelColor(i, 0, img.pixelColor(99 + i, 12));
+ referenceImage.setPixelColor(WIDTH / 2 + i, 0, img.pixelColor(33 + i, 67));
+ }
+
+ QVERIFY(imageRGBAEquals(result, referenceImage));
+ }
+
+ // Copy from 1D texture array to 1D texture
+ {
+ const int WIDTH = 256;
+ const int LAYERS = 256;
+
+ QScopedPointer<QRhiTexture> srcTexture(
+ rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
+ QRhiTexture::Flag::UsedAsTransferSource));
+ QVERIFY(srcTexture->create());
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ for (int y = 0; y < LAYERS; ++y) {
+ QImage img(WIDTH, 1, QImage::Format_RGBA8888);
+ for (int x = 0; x < WIDTH; ++x) {
+ img.setPixelColor(x, 0, QColor::fromRgb(x, y, 0));
+ }
+ QRhiTextureUploadEntry upload(y, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(srcTexture.data(), upload);
+ }
+
+ QScopedPointer<QRhiTexture> dstTexture(rhi->newTexture(
+ QRhiTexture::RGBA8, WIDTH, 0, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
+ QVERIFY(dstTexture->create());
+
+ QRhiTextureCopyDescription copy;
+ copy.setPixelSize(QSize(WIDTH / 2, 1));
+ copy.setDestinationTopLeft(QPoint(WIDTH / 2, 0));
+ copy.setSourceLayer(67);
+ copy.setSourceTopLeft(QPoint(33, 0));
+ batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
+
+ copy.setDestinationTopLeft(QPoint(0, 0));
+ copy.setSourceLayer(12);
+ copy.setSourceTopLeft(QPoint(99, 0));
+ batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
+
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readResult, &result] {
+ result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ };
+
+ QRhiReadbackDescription readbackDescription(dstTexture.data());
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ QImage referenceImage(WIDTH, 1, result.format());
+ for (int i = 0; i < WIDTH / 2; ++i) {
+ referenceImage.setPixelColor(i, 0, QColor::fromRgb(99 + i, 12, 0));
+ referenceImage.setPixelColor(WIDTH / 2 + i, 0, QColor::fromRgb(33 + i, 67, 0));
+ }
+
+ QVERIFY(imageRGBAEquals(result, referenceImage));
+ }
+
+ // Copy from 1D texture to 1D texture array
+ {
+ const int WIDTH = 256;
+ const int LAYERS = 256;
+
+ QScopedPointer<QRhiTexture> srcTexture(rhi->newTexture(
+ QRhiTexture::RGBA8, WIDTH, 0, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
+ QVERIFY(srcTexture->create());
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ QImage img(WIDTH, 1, QImage::Format_RGBA8888);
+ for (int x = 0; x < WIDTH; ++x) {
+ img.setPixelColor(x, 0, QColor::fromRgb(x, 0, 0));
+ }
+ QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(srcTexture.data(), upload);
+
+ QScopedPointer<QRhiTexture> dstTexture(
+ rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
+ QRhiTexture::Flag::UsedAsTransferSource));
+ QVERIFY(dstTexture->create());
+
+ QRhiTextureCopyDescription copy;
+ copy.setPixelSize(QSize(WIDTH / 2, 1));
+ copy.setDestinationTopLeft(QPoint(WIDTH / 2, 0));
+ copy.setDestinationLayer(67);
+ copy.setSourceTopLeft(QPoint(33, 0));
+ batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
+
+ copy.setDestinationTopLeft(QPoint(0, 0));
+ copy.setSourceTopLeft(QPoint(99, 0));
+ batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
+
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readResult, &result] {
+ result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ };
+
+ QRhiReadbackDescription readbackDescription(dstTexture.data());
+ readbackDescription.setLayer(67);
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ QImage referenceImage(WIDTH, 1, result.format());
+ for (int i = 0; i < WIDTH / 2; ++i) {
+ referenceImage.setPixelColor(i, 0, QColor::fromRgb(99 + i, 0, 0));
+ referenceImage.setPixelColor(WIDTH / 2 + i, 0, QColor::fromRgb(33 + i, 0, 0));
+ }
+
+ QVERIFY(imageRGBAEquals(result, referenceImage));
+ }
+
+ // mipmaps and 1D render target
+ if (!rhi->isFeatureSupported(QRhi::OneDimensionalTextureMipmaps))
+ QSKIP("Skipping testing 1D texture mipmaps and 1D render target because they are reported "
+ "as unsupported");
+
+ {
+ QScopedPointer<QRhiTexture> texture(
+ rhi->newTexture(QRhiTexture::RGBA8, WIDTH, 0, 0, 1,
+ QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
+ QVERIFY(texture->create());
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ QImage img(WIDTH, 1, QImage::Format_RGBA8888);
+ img.fill(QColor::fromRgb(128, 0, 0));
+ QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(texture.data(), upload);
+
+ batch->generateMips(texture.data());
+
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+
+ // read back level 1 (256x1, #800000ff)
+ batch = rhi->nextResourceUpdateBatch();
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readResult, &result] {
+ result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ };
+ QRhiReadbackDescription readbackDescription(texture.data());
+ readbackDescription.setLevel(1);
+ readbackDescription.setLayer(0);
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ QImage referenceImage(WIDTH / 2, 1, result.format());
+ referenceImage.fill(QColor::fromRgb(128, 0, 0));
+
+ QVERIFY(imageRGBAEquals(result, referenceImage, 2));
+ }
+
+ {
+ QScopedPointer<QRhiTexture> texture(
+ rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
+ QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
+ QVERIFY(texture->create());
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ for (int i = 0; i < LAYERS; ++i) {
+ QImage img(WIDTH, 1, QImage::Format_RGBA8888);
+ img.fill(QColor::fromRgb(i * 2, 0, 0));
+ QRhiTextureUploadEntry sliceUpload(i, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(texture.data(), sliceUpload);
+ }
+
+ batch->generateMips(texture.data());
+
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+
+ // read back slice 63 of level 1 (256x1, #7E0000FF)
+ batch = rhi->nextResourceUpdateBatch();
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readResult, &result] {
+ result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ };
+ QRhiReadbackDescription readbackDescription(texture.data());
+ readbackDescription.setLevel(1);
+ readbackDescription.setLayer(63);
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ QImage referenceImage(WIDTH / 2, 1, result.format());
+ referenceImage.fill(QColor::fromRgb(126, 0, 0));
+
+ // Now restrict the test a bit. The Null QRhi backend has broken support for
+ // mipmap generation of 1D texture arrays.
+ if (impl != QRhi::Null)
+ QVERIFY(imageRGBAEquals(result, referenceImage, 2));
+ }
+
+ // 1D texture render target
+ // NB with Vulkan we require Vulkan 1.1 for this to work.
+ // Metal does not allow 1D texture render targets
+ {
+ QScopedPointer<QRhiTexture> texture(
+ rhi->newTexture(QRhiTexture::RGBA8, WIDTH, 0, 0, 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
+ QVERIFY(texture->create());
+
+ QRhiColorAttachment att(texture.data());
+ QRhiTextureRenderTargetDescription rtDesc(att);
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
+ QScopedPointer<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.data());
+ QVERIFY(rt->create());
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ QImage img(WIDTH, 1, QImage::Format_RGBA8888);
+ img.fill(QColor::fromRgb(128, 0, 0));
+ QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(texture.data(), upload);
+
+ QRhiCommandBuffer *cb = nullptr;
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+ cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, batch);
+ // texture is now blue
+ cb->endPass();
+ rhi->endOffscreenFrame();
+
+ // read back texture (blue)
+ batch = rhi->nextResourceUpdateBatch();
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readResult, &result] {
+ result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ };
+ QRhiReadbackDescription readbackDescription(texture.data());
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ QImage referenceImage(WIDTH, 1, result.format());
+ referenceImage.fill(QColor::fromRgbF(0.0f, 0.0f, 1.0f));
+ // the Null backend does not render so skip the verification for that
+ if (impl != QRhi::Null)
+ QVERIFY(imageRGBAEquals(result, referenceImage));
+ }
+
+ // 1D array texture render target (one slice)
+ // NB with Vulkan we require Vulkan 1.1 for this to work.
+ // Metal does not allow 1D texture render targets
+ {
+ const int SLICE = 23;
+ QScopedPointer<QRhiTexture> texture(rhi->newTextureArray(
+ QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
+ QVERIFY(texture->create());
+
+ QRhiColorAttachment att(texture.data());
+ att.setLayer(SLICE);
+ QRhiTextureRenderTargetDescription rtDesc(att);
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
+ QScopedPointer<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.data());
+ QVERIFY(rt->create());
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QVERIFY(batch);
+
+ for (int i = 0; i < LAYERS; ++i) {
+ QImage img(WIDTH, 1, QImage::Format_RGBA8888);
+ img.fill(QColor::fromRgb(i * 2, 0, 0));
+ QRhiTextureUploadEntry sliceUpload(i, 0, QRhiTextureSubresourceUploadDescription(img));
+ batch->uploadTexture(texture.data(), sliceUpload);
+ }
+
+ QRhiCommandBuffer *cb = nullptr;
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+ cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, batch);
+ // slice 23 is now blue
+ cb->endPass();
+ rhi->endOffscreenFrame();
+
+ // read back slice 23 (blue)
+ batch = rhi->nextResourceUpdateBatch();
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readResult, &result] {
+ result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888);
+ };
+ QRhiReadbackDescription readbackDescription(texture.data());
+ readbackDescription.setLayer(23);
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ QImage referenceImage(WIDTH, 1, result.format());
+ referenceImage.fill(QColor::fromRgbF(0.0f, 0.0f, 1.0f));
+ // the Null backend does not render so skip the verification for that
+ if (impl != QRhi::Null)
+ QVERIFY(imageRGBAEquals(result, referenceImage));
+
+ // read back slice 0 (black)
+ batch = rhi->nextResourceUpdateBatch();
+ result = QImage();
+ readbackDescription.setLayer(0);
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ referenceImage.fill(QColor::fromRgbF(0.0f, 0.0f, 0.0f));
+ QVERIFY(imageRGBAEquals(result, referenceImage));
+
+ // read back slice 127 (almost red)
+ batch = rhi->nextResourceUpdateBatch();
+ result = QImage();
+ readbackDescription.setLayer(127);
+ batch->readBackTexture(readbackDescription, &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(!result.isNull());
+ referenceImage.fill(QColor::fromRgb(254, 0, 0));
+ QVERIFY(imageRGBAEquals(result, referenceImage));
+ }
+}
void tst_QRhi::leakedResourceDestroy_data()
{