summaryrefslogtreecommitdiffstats
path: root/tests/auto/gui
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2021-03-25 12:39:02 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2021-05-19 17:35:35 +0200
commit8827cd657d12a037deb3e6f4f76271ee0bbd0b13 (patch)
tree6acbccb6ceda0714740a813da14a6f1abd139672 /tests/auto/gui
parent2d9cc639a4a7a5e97979a6034364bd67dfa10c23 (diff)
rhi: gl: Add support for importing an existing renderbuffer object
Normally we only allow creating wrappers for texture objects. These can then be used with a QRhiTextureRenderTarget to allow rendering into an externally created texture. With OpenGL (ES), there are additional, special cases, especially on embedded. Consider EGLImages for example. An EGLImageKHR can be bound to a renderbuffer object (glEGLImageTargetRenderbufferStorageOES), which can then be associated with a framebuffer object to allow rendering into the external buffer represented by the EGLImage. To implement the same via QRhi one needs a way to create a wrapping QRhiRenderBuffer for the native OpenGL renderbuffer object. Here we add a createFrom() to QRhiRenderBuffer, while providing a dummy, default implementation. The only real implementation is in the OpenGL backend, which simply takes a renderbuffer id, without taking ownership. Task-number: QTBUG-92116 Change-Id: I4e68e665fb35a7d7803b7780db901c8bed5740e2 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'tests/auto/gui')
-rw-r--r--tests/auto/gui/rhi/qrhi/tst_qrhi.cpp140
1 files changed, 139 insertions, 1 deletions
diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
index 076106a589..18eebaae1e 100644
--- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
+++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
@@ -37,6 +37,7 @@
#if QT_CONFIG(opengl)
# include <QOpenGLContext>
+# include <QOpenGLFunctions>
# include <QtGui/private/qrhigles2_p.h>
# define TST_GL
#endif
@@ -70,6 +71,7 @@ private slots:
void cleanupTestCase();
void rhiTestData();
+ void rhiTestDataOpenGL();
void create_data();
void create();
void nativeHandles_data();
@@ -129,6 +131,10 @@ private slots:
void pipelineCache_data();
void pipelineCache();
+ void textureImportOpenGL_data();
+ void textureImportOpenGL();
+ void renderbufferImportOpenGL_data();
+ void renderbufferImportOpenGL();
private:
void setWindowType(QWindow *window, QRhi::Implementation impl);
@@ -214,6 +220,16 @@ void tst_QRhi::rhiTestData()
#endif
}
+void tst_QRhi::rhiTestDataOpenGL()
+{
+ QTest::addColumn<QRhi::Implementation>("impl");
+ QTest::addColumn<QRhiInitParams *>("initParams");
+
+#ifdef TST_GL
+ QTest::newRow("OpenGL") << QRhi::OpenGLES2 << static_cast<QRhiInitParams *>(&initParams.gl);
+#endif
+}
+
void tst_QRhi::create_data()
{
rhiTestData();
@@ -351,7 +367,8 @@ void tst_QRhi::create()
QRhi::ScreenSpaceDerivatives,
QRhi::ReadBackAnyTextureFormat,
QRhi::PipelineCacheDataLoadSave,
- QRhi::ImageDataStride
+ QRhi::ImageDataStride,
+ QRhi::RenderBufferImport
};
for (size_t i = 0; i <sizeof(features) / sizeof(QRhi::Feature); ++i)
rhi->isFeatureSupported(features[i]);
@@ -3689,5 +3706,126 @@ void tst_QRhi::pipelineCache()
}
}
+void tst_QRhi::textureImportOpenGL_data()
+{
+ rhiTestDataOpenGL();
+}
+
+void tst_QRhi::textureImportOpenGL()
+{
+ QFETCH(QRhi::Implementation, impl);
+ if (impl != QRhi::OpenGLES2)
+ QSKIP("Skipping OpenGL-dependent test");
+
+#ifdef TST_GL
+ QFETCH(QRhiInitParams *, initParams);
+
+ QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr));
+ if (!rhi)
+ QSKIP("QRhi could not be created, skipping testing native texture");
+
+ QVERIFY(rhi->makeThreadLocalNativeContextCurrent());
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QVERIFY(ctx);
+ QOpenGLFunctions *f = ctx->functions();
+
+ QImage image(320, 200, QImage::Format_RGBA8888_Premultiplied);
+ image.fill(Qt::red);
+
+ GLuint t = 0;
+ f->glGenTextures(1, &t);
+ f->glBindTexture(GL_TEXTURE_2D, t);
+ f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
+
+ QScopedPointer<QRhiTexture> tex(rhi->newTexture(QRhiTexture::RGBA8, image.size()));
+ QRhiTexture::NativeTexture nativeTex = { t, 0 };
+ QVERIFY(tex->createFrom(nativeTex));
+ QCOMPARE(tex->nativeTexture().object, nativeTex.object);
+
+ QRhiReadbackResult readResult;
+ bool readCompleted = false;
+ readResult.completed = [&readCompleted] { readCompleted = true; };
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ batch->readBackTexture(tex.data(), &readResult);
+ QVERIFY(submitResourceUpdates(rhi.data(), batch));
+ QVERIFY(readCompleted);
+ QCOMPARE(readResult.format, QRhiTexture::RGBA8);
+ QCOMPARE(readResult.pixelSize, image.size());
+ QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ image.format());
+ QVERIFY(imageRGBAEquals(image, wrapperImage));
+
+ f->glDeleteTextures(1, &t);
+#endif
+}
+
+void tst_QRhi::renderbufferImportOpenGL_data()
+{
+ rhiTestDataOpenGL();
+}
+
+void tst_QRhi::renderbufferImportOpenGL()
+{
+ QFETCH(QRhi::Implementation, impl);
+ if (impl != QRhi::OpenGLES2)
+ QSKIP("Skipping OpenGL-dependent test");
+
+#ifdef TST_GL
+ QFETCH(QRhiInitParams *, initParams);
+
+ QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr));
+ if (!rhi)
+ QSKIP("QRhi could not be created, skipping testing native texture");
+
+ QVERIFY(rhi->makeThreadLocalNativeContextCurrent());
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QVERIFY(ctx);
+ QOpenGLFunctions *f = ctx->functions();
+
+ const QSize size(320, 200);
+ GLuint b = 0;
+ f->glGenRenderbuffers(1, &b);
+ f->glBindRenderbuffer(GL_RENDERBUFFER, b);
+ // in a real world use case this would be some extension, e.g. glEGLImageTargetRenderbufferStorageOES instead
+ f->glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, size.width(), size.height());
+ f->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ QScopedPointer<QRhiRenderBuffer> rb(rhi->newRenderBuffer(QRhiRenderBuffer::Color, size));
+ QVERIFY(rb->createFrom({ b }));
+
+ QScopedPointer<QRhiRenderBuffer> depthStencil(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size));
+ QVERIFY(depthStencil->create());
+ QRhiColorAttachment att(rb.data());
+ QRhiTextureRenderTargetDescription rtDesc(att);
+ rtDesc.setDepthStencilBuffer(depthStencil.data());
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
+ QScopedPointer<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.data());
+ QVERIFY(rt->create());
+
+ QRhiCommandBuffer *cb = nullptr;
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+ cb->beginPass(rt.data(), Qt::red, { 1.0f, 0 }, nullptr, QRhiCommandBuffer::ExternalContent);
+ cb->beginExternal();
+ QByteArray tmpBuf;
+ tmpBuf.resize(size.width() * size.height() * 4);
+ f->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_BYTE, tmpBuf.data());
+ cb->endExternal();
+ cb->endPass();
+ rhi->endOffscreenFrame();
+
+ f->glDeleteRenderbuffers(1, &b);
+
+ QImage wrapperImage(reinterpret_cast<const uchar *>(tmpBuf.constData()),
+ size.width(), size.height(), QImage::Format_RGBA8888_Premultiplied);
+
+ QImage image(320, 200, QImage::Format_RGBA8888_Premultiplied);
+ image.fill(Qt::red);
+ QVERIFY(imageRGBAEquals(image, wrapperImage));
+#endif
+}
+
#include <tst_qrhi.moc>
QTEST_MAIN(tst_QRhi)