rhi: Take mip size into account for render target size
Also extend autotesting, both for rendering into a given mip level and for rendering into a given cubemap face. Change-Id: Ida94b71150477ceb50a3b5616d8b7be13174558b Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
parent
4545eadd3e
commit
3ef7a760ff
@ -582,6 +582,13 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
|
|||||||
practice this will be reported as unsupported with OpenGL ES 2.0 and OpenGL
|
practice this will be reported as unsupported with OpenGL ES 2.0 and OpenGL
|
||||||
2.x contexts, because GLSL 100 es and versions before 130 do not support
|
2.x contexts, because GLSL 100 es and versions before 130 do not support
|
||||||
this function.
|
this function.
|
||||||
|
|
||||||
|
\value RenderToNonBaseMipLevel Indicates that specifying a mip level other
|
||||||
|
than 0 is supported when creating a QRhiTextureRenderTarget with a
|
||||||
|
QRhiTexture as its color attachment. When not supported, build() will fail
|
||||||
|
whenever the target mip level is not zero. In practice this feature will be
|
||||||
|
unsupported with OpenGL ES 2.0, while it will likely be supported everywhere
|
||||||
|
else.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1446,7 +1446,8 @@ public:
|
|||||||
TriangleFanTopology,
|
TriangleFanTopology,
|
||||||
ReadBackNonUniformBuffer,
|
ReadBackNonUniformBuffer,
|
||||||
ReadBackNonBaseMipLevel,
|
ReadBackNonBaseMipLevel,
|
||||||
TexelFetch
|
TexelFetch,
|
||||||
|
RenderToNonBaseMipLevel
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BeginFrameFlag {
|
enum BeginFrameFlag {
|
||||||
|
@ -470,6 +470,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return true;
|
return true;
|
||||||
case QRhi::TexelFetch:
|
case QRhi::TexelFetch:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::RenderToNonBaseMipLevel:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -3243,7 +3245,7 @@ bool QD3D11TextureRenderTarget::build()
|
|||||||
}
|
}
|
||||||
ownsRtv[attIndex] = true;
|
ownsRtv[attIndex] = true;
|
||||||
if (attIndex == 0) {
|
if (attIndex == 0) {
|
||||||
d.pixelSize = texD->pixelSize();
|
d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
|
||||||
d.sampleCount = int(texD->sampleDesc.Count);
|
d.sampleCount = int(texD->sampleDesc.Count);
|
||||||
}
|
}
|
||||||
} else if (rb) {
|
} else if (rb) {
|
||||||
|
@ -769,6 +769,8 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return caps.nonBaseLevelFramebufferTexture;
|
return caps.nonBaseLevelFramebufferTexture;
|
||||||
case QRhi::TexelFetch:
|
case QRhi::TexelFetch:
|
||||||
return caps.texelFetch;
|
return caps.texelFetch;
|
||||||
|
case QRhi::RenderToNonBaseMipLevel:
|
||||||
|
return caps.nonBaseLevelFramebufferTexture;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -3930,7 +3932,7 @@ bool QGles2TextureRenderTarget::build()
|
|||||||
rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()),
|
rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()),
|
||||||
texD->texture, colorAtt.level());
|
texD->texture, colorAtt.level());
|
||||||
if (attIndex == 0) {
|
if (attIndex == 0) {
|
||||||
d.pixelSize = texD->pixelSize();
|
d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
|
||||||
d.sampleCount = 1;
|
d.sampleCount = 1;
|
||||||
}
|
}
|
||||||
} else if (renderBuffer) {
|
} else if (renderBuffer) {
|
||||||
|
@ -564,6 +564,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return true;
|
return true;
|
||||||
case QRhi::TexelFetch:
|
case QRhi::TexelFetch:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::RenderToNonBaseMipLevel:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -2863,6 +2865,7 @@ QRhiRenderPassDescriptor *QMetalTextureRenderTarget::newCompatibleRenderPassDesc
|
|||||||
|
|
||||||
bool QMetalTextureRenderTarget::build()
|
bool QMetalTextureRenderTarget::build()
|
||||||
{
|
{
|
||||||
|
QRHI_RES_RHI(QRhiMetal);
|
||||||
const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments();
|
const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments();
|
||||||
Q_ASSERT(hasColorAttachments || m_desc.depthTexture());
|
Q_ASSERT(hasColorAttachments || m_desc.depthTexture());
|
||||||
Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
|
Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
|
||||||
@ -2879,7 +2882,7 @@ bool QMetalTextureRenderTarget::build()
|
|||||||
if (texD) {
|
if (texD) {
|
||||||
dst = texD->d->tex;
|
dst = texD->d->tex;
|
||||||
if (attIndex == 0) {
|
if (attIndex == 0) {
|
||||||
d->pixelSize = texD->pixelSize();
|
d->pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
|
||||||
d->sampleCount = texD->samples;
|
d->sampleCount = texD->samples;
|
||||||
}
|
}
|
||||||
} else if (rbD) {
|
} else if (rbD) {
|
||||||
|
@ -740,11 +740,13 @@ QRhiRenderPassDescriptor *QNullTextureRenderTarget::newCompatibleRenderPassDescr
|
|||||||
|
|
||||||
bool QNullTextureRenderTarget::build()
|
bool QNullTextureRenderTarget::build()
|
||||||
{
|
{
|
||||||
|
QRHI_RES_RHI(QRhiNull);
|
||||||
d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
|
d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
|
||||||
if (m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments()) {
|
if (m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments()) {
|
||||||
QRhiTexture *tex = m_desc.cbeginColorAttachments()->texture();
|
const QRhiColorAttachment *colorAtt = m_desc.cbeginColorAttachments();
|
||||||
QRhiRenderBuffer *rb = m_desc.cbeginColorAttachments()->renderBuffer();
|
QRhiTexture *tex = colorAtt->texture();
|
||||||
d.pixelSize = tex ? tex->pixelSize() : rb->pixelSize();
|
QRhiRenderBuffer *rb = colorAtt->renderBuffer();
|
||||||
|
d.pixelSize = tex ? rhiD->q->sizeForMipLevel(colorAtt->level(), tex->pixelSize()) : rb->pixelSize();
|
||||||
} else if (m_desc.depthStencilBuffer()) {
|
} else if (m_desc.depthStencilBuffer()) {
|
||||||
d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
|
d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
|
||||||
} else if (m_desc.depthTexture()) {
|
} else if (m_desc.depthTexture()) {
|
||||||
|
@ -4023,6 +4023,8 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return true;
|
return true;
|
||||||
case QRhi::TexelFetch:
|
case QRhi::TexelFetch:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::RenderToNonBaseMipLevel:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -5911,7 +5913,7 @@ bool QVkTextureRenderTarget::build()
|
|||||||
}
|
}
|
||||||
views.append(rtv[attIndex]);
|
views.append(rtv[attIndex]);
|
||||||
if (attIndex == 0) {
|
if (attIndex == 0) {
|
||||||
d.pixelSize = texD->pixelSize();
|
d.pixelSize = rhiD->q->sizeForMipLevel(it->level(), texD->pixelSize());
|
||||||
d.sampleCount = texD->samples;
|
d.sampleCount = texD->samples;
|
||||||
}
|
}
|
||||||
} else if (rbD) {
|
} else if (rbD) {
|
||||||
|
@ -89,6 +89,10 @@ private slots:
|
|||||||
void invalidPipeline();
|
void invalidPipeline();
|
||||||
void renderToTextureSimple_data();
|
void renderToTextureSimple_data();
|
||||||
void renderToTextureSimple();
|
void renderToTextureSimple();
|
||||||
|
void renderToTextureMip_data();
|
||||||
|
void renderToTextureMip();
|
||||||
|
void renderToTextureCubemapFace_data();
|
||||||
|
void renderToTextureCubemapFace();
|
||||||
void renderToTextureTexturedQuad_data();
|
void renderToTextureTexturedQuad_data();
|
||||||
void renderToTextureTexturedQuad();
|
void renderToTextureTexturedQuad();
|
||||||
void renderToTextureArrayOfTexturedQuad_data();
|
void renderToTextureArrayOfTexturedQuad_data();
|
||||||
@ -299,7 +303,8 @@ void tst_QRhi::create()
|
|||||||
QRhi::TriangleFanTopology,
|
QRhi::TriangleFanTopology,
|
||||||
QRhi::ReadBackNonUniformBuffer,
|
QRhi::ReadBackNonUniformBuffer,
|
||||||
QRhi::ReadBackNonBaseMipLevel,
|
QRhi::ReadBackNonBaseMipLevel,
|
||||||
QRhi::TexelFetch
|
QRhi::TexelFetch,
|
||||||
|
QRhi::RenderToNonBaseMipLevel
|
||||||
};
|
};
|
||||||
for (size_t i = 0; i <sizeof(features) / sizeof(QRhi::Feature); ++i)
|
for (size_t i = 0; i <sizeof(features) / sizeof(QRhi::Feature); ++i)
|
||||||
rhi->isFeatureSupported(features[i]);
|
rhi->isFeatureSupported(features[i]);
|
||||||
@ -1341,6 +1346,267 @@ void tst_QRhi::renderToTextureSimple()
|
|||||||
QVERIFY(redCount > blueCount);
|
QVERIFY(redCount > blueCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QRhi::renderToTextureMip_data()
|
||||||
|
{
|
||||||
|
rhiTestData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QRhi::renderToTextureMip()
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
|
||||||
|
if (!rhi->isFeatureSupported(QRhi::RenderToNonBaseMipLevel))
|
||||||
|
QSKIP("Rendering to non-base mip levels is not supported on this platform, skipping test");
|
||||||
|
|
||||||
|
const QSize baseLevelSize(1024, 1024);
|
||||||
|
const int LEVEL = 3; // render into mip #3 (128x128)
|
||||||
|
QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, baseLevelSize, 1,
|
||||||
|
QRhiTexture::RenderTarget
|
||||||
|
| QRhiTexture::UsedAsTransferSource
|
||||||
|
| QRhiTexture::MipMapped));
|
||||||
|
QVERIFY(texture->build());
|
||||||
|
|
||||||
|
QRhiColorAttachment colorAtt(texture.data());
|
||||||
|
colorAtt.setLevel(LEVEL);
|
||||||
|
QRhiTextureRenderTargetDescription rtDesc(colorAtt);
|
||||||
|
QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
|
||||||
|
QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
|
||||||
|
rt->setRenderPassDescriptor(rpDesc.data());
|
||||||
|
QVERIFY(rt->build());
|
||||||
|
|
||||||
|
QCOMPARE(rt->pixelSize(), rhi->sizeForMipLevel(LEVEL, baseLevelSize));
|
||||||
|
const QSize mipSize(baseLevelSize.width() >> LEVEL, baseLevelSize.height() >> LEVEL);
|
||||||
|
QCOMPARE(rt->pixelSize(), mipSize);
|
||||||
|
|
||||||
|
QRhiCommandBuffer *cb = nullptr;
|
||||||
|
QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
|
||||||
|
QVERIFY(cb);
|
||||||
|
|
||||||
|
QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
|
||||||
|
|
||||||
|
static const float vertices[] = {
|
||||||
|
-1.0f, -1.0f,
|
||||||
|
1.0f, -1.0f,
|
||||||
|
0.0f, 1.0f
|
||||||
|
};
|
||||||
|
QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)));
|
||||||
|
QVERIFY(vbuf->build());
|
||||||
|
updates->uploadStaticBuffer(vbuf.data(), vertices);
|
||||||
|
|
||||||
|
QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
|
||||||
|
QVERIFY(srb->build());
|
||||||
|
|
||||||
|
QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
|
||||||
|
QShader vs = loadShader(":/data/simple.vert.qsb");
|
||||||
|
QVERIFY(vs.isValid());
|
||||||
|
QShader fs = loadShader(":/data/simple.frag.qsb");
|
||||||
|
QVERIFY(fs.isValid());
|
||||||
|
pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
|
||||||
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
inputLayout.setBindings({ { 2 * sizeof(float) } });
|
||||||
|
inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
|
||||||
|
pipeline->setVertexInputLayout(inputLayout);
|
||||||
|
pipeline->setShaderResourceBindings(srb.data());
|
||||||
|
pipeline->setRenderPassDescriptor(rpDesc.data());
|
||||||
|
|
||||||
|
QVERIFY(pipeline->build());
|
||||||
|
|
||||||
|
cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, updates);
|
||||||
|
cb->setGraphicsPipeline(pipeline.data());
|
||||||
|
cb->setViewport({ 0, 0, float(rt->pixelSize().width()), float(rt->pixelSize().height()) });
|
||||||
|
QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0);
|
||||||
|
cb->setVertexInput(0, 1, &vbindings);
|
||||||
|
cb->draw(3);
|
||||||
|
|
||||||
|
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();
|
||||||
|
QRhiReadbackDescription readbackDescription(texture.data());
|
||||||
|
readbackDescription.setLevel(LEVEL);
|
||||||
|
readbackBatch->readBackTexture(readbackDescription, &readResult);
|
||||||
|
cb->endPass(readbackBatch);
|
||||||
|
|
||||||
|
rhi->endOffscreenFrame();
|
||||||
|
|
||||||
|
if (!rhi->isFeatureSupported(QRhi::ReadBackNonBaseMipLevel))
|
||||||
|
QSKIP("Reading back non-base mip levels is not supported on this platform, skipping readback");
|
||||||
|
|
||||||
|
QCOMPARE(result.size(), mipSize);
|
||||||
|
|
||||||
|
if (impl == QRhi::Null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int y = 100;
|
||||||
|
const quint32 *p = reinterpret_cast<const quint32 *>(result.constScanLine(y));
|
||||||
|
int x = result.width() - 1;
|
||||||
|
int redCount = 0;
|
||||||
|
int blueCount = 0;
|
||||||
|
const int maxFuzz = 1;
|
||||||
|
while (x-- >= 0) {
|
||||||
|
const QRgb c(*p++);
|
||||||
|
if (qRed(c) >= (255 - maxFuzz) && qGreen(c) == 0 && qBlue(c) == 0)
|
||||||
|
++redCount;
|
||||||
|
else if (qRed(c) == 0 && qGreen(c) == 0 && qBlue(c) >= (255 - maxFuzz))
|
||||||
|
++blueCount;
|
||||||
|
else
|
||||||
|
QFAIL("Encountered a pixel that is neither red or blue");
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(redCount + blueCount, mipSize.width());
|
||||||
|
|
||||||
|
if (rhi->isYUpInFramebuffer() == rhi->isYUpInNDC())
|
||||||
|
QVERIFY(redCount > blueCount); // 100, 28
|
||||||
|
else
|
||||||
|
QVERIFY(redCount < blueCount); // 28, 100
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QRhi::renderToTextureCubemapFace_data()
|
||||||
|
{
|
||||||
|
rhiTestData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QRhi::renderToTextureCubemapFace()
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
|
||||||
|
const QSize outputSize(512, 512); // width must be same as height
|
||||||
|
QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, outputSize, 1,
|
||||||
|
QRhiTexture::RenderTarget
|
||||||
|
| QRhiTexture::UsedAsTransferSource
|
||||||
|
| QRhiTexture::CubeMap)); // will be a cubemap, so 6 layers
|
||||||
|
QVERIFY(texture->build());
|
||||||
|
|
||||||
|
const int LAYER = 1; // render into the layer for face -X
|
||||||
|
const int BAD_LAYER = 2; // +Y
|
||||||
|
|
||||||
|
QRhiColorAttachment colorAtt(texture.data());
|
||||||
|
colorAtt.setLayer(LAYER);
|
||||||
|
QRhiTextureRenderTargetDescription rtDesc(colorAtt);
|
||||||
|
QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
|
||||||
|
QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
|
||||||
|
rt->setRenderPassDescriptor(rpDesc.data());
|
||||||
|
QVERIFY(rt->build());
|
||||||
|
|
||||||
|
QCOMPARE(rt->pixelSize(), texture->pixelSize());
|
||||||
|
QCOMPARE(rt->pixelSize(), outputSize);
|
||||||
|
|
||||||
|
QRhiCommandBuffer *cb = nullptr;
|
||||||
|
QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
|
||||||
|
QVERIFY(cb);
|
||||||
|
|
||||||
|
QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
|
||||||
|
|
||||||
|
static const float vertices[] = {
|
||||||
|
-1.0f, -1.0f,
|
||||||
|
1.0f, -1.0f,
|
||||||
|
0.0f, 1.0f
|
||||||
|
};
|
||||||
|
QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)));
|
||||||
|
QVERIFY(vbuf->build());
|
||||||
|
updates->uploadStaticBuffer(vbuf.data(), vertices);
|
||||||
|
|
||||||
|
QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
|
||||||
|
QVERIFY(srb->build());
|
||||||
|
|
||||||
|
QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
|
||||||
|
QShader vs = loadShader(":/data/simple.vert.qsb");
|
||||||
|
QVERIFY(vs.isValid());
|
||||||
|
QShader fs = loadShader(":/data/simple.frag.qsb");
|
||||||
|
QVERIFY(fs.isValid());
|
||||||
|
pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
|
||||||
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
inputLayout.setBindings({ { 2 * sizeof(float) } });
|
||||||
|
inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
|
||||||
|
pipeline->setVertexInputLayout(inputLayout);
|
||||||
|
pipeline->setShaderResourceBindings(srb.data());
|
||||||
|
pipeline->setRenderPassDescriptor(rpDesc.data());
|
||||||
|
|
||||||
|
QVERIFY(pipeline->build());
|
||||||
|
|
||||||
|
cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, updates);
|
||||||
|
cb->setGraphicsPipeline(pipeline.data());
|
||||||
|
cb->setViewport({ 0, 0, float(rt->pixelSize().width()), float(rt->pixelSize().height()) });
|
||||||
|
QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0);
|
||||||
|
cb->setVertexInput(0, 1, &vbindings);
|
||||||
|
cb->draw(3);
|
||||||
|
|
||||||
|
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();
|
||||||
|
QRhiReadbackDescription readbackDescription(texture.data());
|
||||||
|
readbackDescription.setLayer(LAYER);
|
||||||
|
readbackBatch->readBackTexture(readbackDescription, &readResult);
|
||||||
|
|
||||||
|
// also read back a layer we did not render into
|
||||||
|
QRhiReadbackResult readResult2;
|
||||||
|
QImage result2;
|
||||||
|
readResult2.completed = [&readResult2, &result2] {
|
||||||
|
result2 = QImage(reinterpret_cast<const uchar *>(readResult2.data.constData()),
|
||||||
|
readResult2.pixelSize.width(), readResult2.pixelSize.height(),
|
||||||
|
QImage::Format_RGBA8888_Premultiplied);
|
||||||
|
};
|
||||||
|
QRhiReadbackDescription readbackDescription2(texture.data());
|
||||||
|
readbackDescription2.setLayer(BAD_LAYER);
|
||||||
|
readbackBatch->readBackTexture(readbackDescription2, &readResult2);
|
||||||
|
|
||||||
|
cb->endPass(readbackBatch);
|
||||||
|
|
||||||
|
rhi->endOffscreenFrame();
|
||||||
|
|
||||||
|
QCOMPARE(result.size(), outputSize);
|
||||||
|
QCOMPARE(result2.size(), outputSize);
|
||||||
|
|
||||||
|
if (impl == QRhi::Null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// just want to ensure that we did not read the same thing back twice, i.e.
|
||||||
|
// that the 'layer' parameter was not ignored
|
||||||
|
QVERIFY(result != result2);
|
||||||
|
|
||||||
|
const int y = 100;
|
||||||
|
const quint32 *p = reinterpret_cast<const quint32 *>(result.constScanLine(y));
|
||||||
|
int x = result.width() - 1;
|
||||||
|
int redCount = 0;
|
||||||
|
int blueCount = 0;
|
||||||
|
const int maxFuzz = 1;
|
||||||
|
while (x-- >= 0) {
|
||||||
|
const QRgb c(*p++);
|
||||||
|
if (qRed(c) >= (255 - maxFuzz) && qGreen(c) == 0 && qBlue(c) == 0)
|
||||||
|
++redCount;
|
||||||
|
else if (qRed(c) == 0 && qGreen(c) == 0 && qBlue(c) >= (255 - maxFuzz))
|
||||||
|
++blueCount;
|
||||||
|
else
|
||||||
|
QFAIL("Encountered a pixel that is neither red or blue");
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(redCount + blueCount, outputSize.width());
|
||||||
|
|
||||||
|
if (rhi->isYUpInFramebuffer() == rhi->isYUpInNDC())
|
||||||
|
QVERIFY(redCount < blueCount); // 100, 412
|
||||||
|
else
|
||||||
|
QVERIFY(redCount > blueCount); // 412, 100
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QRhi::renderToTextureTexturedQuad_data()
|
void tst_QRhi::renderToTextureTexturedQuad_data()
|
||||||
{
|
{
|
||||||
rhiTestData();
|
rhiTestData();
|
||||||
|
Loading…
Reference in New Issue
Block a user