diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-03-25 12:39:02 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-05-19 17:35:35 +0200 |
commit | 8827cd657d12a037deb3e6f4f76271ee0bbd0b13 (patch) | |
tree | 6acbccb6ceda0714740a813da14a6f1abd139672 /tests/auto/gui | |
parent | 2d9cc639a4a7a5e97979a6034364bd67dfa10c23 (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.cpp | 140 |
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) |