rhi: Autotest rendering a textured quad
Task-number: QTBUG-78971 Change-Id: I0e7e0f3c00f9509031f7b4a8a389e51c915f01c2 Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
This commit is contained in:
parent
8f44da1f55
commit
b2de7f8583
@ -397,6 +397,7 @@ void QRhiNull::simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::Textu
|
||||
QPainter painter(&texD->image[layer][level]);
|
||||
const QSize srcSize = subresDesc.sourceSize().isEmpty()
|
||||
? src.size() : subresDesc.sourceSize();
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
painter.drawImage(subresDesc.destinationTopLeft(), src,
|
||||
QRect(subresDesc.sourceTopLeft(), srcSize));
|
||||
} else if (!subresDesc.data().isEmpty()) {
|
||||
@ -435,6 +436,7 @@ void QRhiNull::simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::Texture
|
||||
const QPoint srcPos = u.desc.sourceTopLeft();
|
||||
|
||||
QPainter painter(&dstImage);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
painter.drawImage(QRect(dstPos, size), srcImage, QRect(srcPos, size));
|
||||
}
|
||||
|
||||
|
@ -42,3 +42,5 @@
|
||||
|
||||
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simple.vert.qsb simple.vert
|
||||
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simple.frag.qsb simple.frag
|
||||
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simpletextured.vert.qsb simpletextured.vert
|
||||
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simpletextured.frag.qsb simpletextured.frag
|
||||
|
BIN
tests/auto/gui/rhi/qrhi/data/qt256.png
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/qt256.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
Binary file not shown.
13
tests/auto/gui/rhi/qrhi/data/simpletextured.frag
Normal file
13
tests/auto/gui/rhi/qrhi/data/simpletextured.frag
Normal file
@ -0,0 +1,13 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec2 uv;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(binding = 0) uniform sampler2D tex;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 c = texture(tex, uv);
|
||||
c.rgb *= c.a;
|
||||
fragColor = c;
|
||||
}
|
BIN
tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb
Normal file
Binary file not shown.
14
tests/auto/gui/rhi/qrhi/data/simpletextured.vert
Normal file
14
tests/auto/gui/rhi/qrhi/data/simpletextured.vert
Normal file
@ -0,0 +1,14 @@
|
||||
#version 440
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
layout(location = 1) in vec2 texcoord;
|
||||
|
||||
layout(location = 0) out vec2 uv;
|
||||
|
||||
out gl_PerVertex { vec4 gl_Position; };
|
||||
|
||||
void main()
|
||||
{
|
||||
uv = texcoord;
|
||||
gl_Position = position;
|
||||
}
|
BIN
tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb
Normal file
Binary file not shown.
@ -85,6 +85,8 @@ private slots:
|
||||
void invalidPipeline();
|
||||
void renderToTextureSimple_data();
|
||||
void renderToTextureSimple();
|
||||
void renderToTextureTexturedQuad_data();
|
||||
void renderToTextureTexturedQuad();
|
||||
|
||||
private:
|
||||
struct {
|
||||
@ -818,6 +820,34 @@ void tst_QRhi::resourceUpdateBatchRGBATextureUpload()
|
||||
|
||||
QVERIFY(imageRGBAEquals(expectedImage, wrapperImage));
|
||||
}
|
||||
|
||||
// now a QImage from an actual file
|
||||
{
|
||||
QImage inputImage;
|
||||
inputImage.load(QLatin1String(":/data/qt256.png"));
|
||||
QVERIFY(!inputImage.isNull());
|
||||
inputImage = std::move(inputImage).convertToFormat(image.format());
|
||||
|
||||
QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size(),
|
||||
1, QRhiTexture::UsedAsTransferSource));
|
||||
QVERIFY(texture->build());
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
batch->uploadTexture(texture.data(), inputImage);
|
||||
|
||||
QRhiReadbackResult readResult;
|
||||
bool readCompleted = false;
|
||||
readResult.completed = [&readCompleted] { readCompleted = true; };
|
||||
batch->readBackTexture(texture.data(), &readResult);
|
||||
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(readCompleted);
|
||||
QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
|
||||
readResult.pixelSize.width(), readResult.pixelSize.height(),
|
||||
inputImage.format());
|
||||
|
||||
QVERIFY(imageRGBAEquals(inputImage, wrapperImage));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QRhi::resourceUpdateBatchRGBATextureCopy_data()
|
||||
@ -1201,5 +1231,134 @@ void tst_QRhi::renderToTextureSimple()
|
||||
QVERIFY(redCount > blueCount);
|
||||
}
|
||||
|
||||
void tst_QRhi::renderToTextureTexturedQuad_data()
|
||||
{
|
||||
rhiTestData();
|
||||
}
|
||||
|
||||
void tst_QRhi::renderToTextureTexturedQuad()
|
||||
{
|
||||
QFETCH(QRhi::Implementation, impl);
|
||||
QFETCH(QRhiInitParams *, initParams);
|
||||
|
||||
QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr));
|
||||
if (!rhi)
|
||||
QSKIP("QRhi could not be created, skipping testing rendering");
|
||||
|
||||
QImage inputImage;
|
||||
inputImage.load(QLatin1String(":/data/qt256.png"));
|
||||
QVERIFY(!inputImage.isNull());
|
||||
|
||||
QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size(), 1,
|
||||
QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
|
||||
QVERIFY(texture->build());
|
||||
|
||||
QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() }));
|
||||
QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
|
||||
rt->setRenderPassDescriptor(rpDesc.data());
|
||||
QVERIFY(rt->build());
|
||||
|
||||
QRhiCommandBuffer *cb = nullptr;
|
||||
QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
|
||||
QVERIFY(cb);
|
||||
|
||||
QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
|
||||
|
||||
static const float verticesUvs[] = {
|
||||
-1.0f, -1.0f, 0.0f, 0.0f,
|
||||
1.0f, -1.0f, 1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f
|
||||
};
|
||||
QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(verticesUvs)));
|
||||
QVERIFY(vbuf->build());
|
||||
updates->uploadStaticBuffer(vbuf.data(), verticesUvs);
|
||||
|
||||
QScopedPointer<QRhiTexture> inputTexture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size()));
|
||||
QVERIFY(inputTexture->build());
|
||||
updates->uploadTexture(inputTexture.data(), inputImage);
|
||||
|
||||
QScopedPointer<QRhiSampler> sampler(rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
|
||||
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
|
||||
QVERIFY(sampler->build());
|
||||
|
||||
QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
|
||||
srb->setBindings({
|
||||
QRhiShaderResourceBinding::sampledTexture(0, QRhiShaderResourceBinding::FragmentStage, inputTexture.data(), sampler.data())
|
||||
});
|
||||
QVERIFY(srb->build());
|
||||
|
||||
QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
|
||||
pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip);
|
||||
QShader vs = loadShader(":/data/simpletextured.vert.qsb");
|
||||
QVERIFY(vs.isValid());
|
||||
QShader fs = loadShader(":/data/simpletextured.frag.qsb");
|
||||
QVERIFY(fs.isValid());
|
||||
pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({ { 4 * sizeof(float) } });
|
||||
inputLayout.setAttributes({
|
||||
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
|
||||
{ 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) }
|
||||
});
|
||||
pipeline->setVertexInputLayout(inputLayout);
|
||||
pipeline->setShaderResourceBindings(srb.data());
|
||||
pipeline->setRenderPassDescriptor(rpDesc.data());
|
||||
|
||||
QVERIFY(pipeline->build());
|
||||
|
||||
cb->beginPass(rt.data(), Qt::black, { 1.0f, 0 }, updates);
|
||||
cb->setGraphicsPipeline(pipeline.data());
|
||||
cb->setShaderResources();
|
||||
cb->setViewport({ 0, 0, float(texture->pixelSize().width()), float(texture->pixelSize().height()) });
|
||||
QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0);
|
||||
cb->setVertexInput(0, 1, &vbindings);
|
||||
cb->draw(4);
|
||||
|
||||
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_Premultiplied);
|
||||
};
|
||||
QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch();
|
||||
readbackBatch->readBackTexture({ texture.data() }, &readResult);
|
||||
cb->endPass(readbackBatch);
|
||||
|
||||
rhi->endOffscreenFrame();
|
||||
|
||||
QVERIFY(!result.isNull());
|
||||
|
||||
if (impl == QRhi::Null)
|
||||
return;
|
||||
|
||||
// Flip with D3D and Metal because these have Y down in images. Vulkan does
|
||||
// not need this because there Y is down both in images and in NDC, which
|
||||
// just happens to give correct results with our OpenGL-targeted vertex and
|
||||
// UV data.
|
||||
if (rhi->isYUpInFramebuffer() != rhi->isYUpInNDC())
|
||||
result = std::move(result).mirrored();
|
||||
|
||||
// check a few points that are expected to match regardless of the implementation
|
||||
QRgb white = qRgba(255, 255, 255, 255);
|
||||
QCOMPARE(result.pixel(79, 77), white);
|
||||
QCOMPARE(result.pixel(124, 81), white);
|
||||
QCOMPARE(result.pixel(128, 149), white);
|
||||
QCOMPARE(result.pixel(120, 189), white);
|
||||
QCOMPARE(result.pixel(116, 185), white);
|
||||
|
||||
QRgb empty = qRgba(0, 0, 0, 0);
|
||||
QCOMPARE(result.pixel(11, 45), empty);
|
||||
QCOMPARE(result.pixel(246, 202), empty);
|
||||
QCOMPARE(result.pixel(130, 18), empty);
|
||||
QCOMPARE(result.pixel(4, 227), empty);
|
||||
|
||||
QVERIFY(qGreen(result.pixel(32, 52)) > 2 * qRed(result.pixel(32, 52)));
|
||||
QVERIFY(qGreen(result.pixel(32, 52)) > 2 * qBlue(result.pixel(32, 52)));
|
||||
QVERIFY(qGreen(result.pixel(214, 191)) > 2 * qRed(result.pixel(214, 191)));
|
||||
QVERIFY(qGreen(result.pixel(214, 191)) > 2 * qBlue(result.pixel(214, 191)));
|
||||
}
|
||||
|
||||
#include <tst_qrhi.moc>
|
||||
QTEST_MAIN(tst_QRhi)
|
||||
|
Loading…
x
Reference in New Issue
Block a user