diff options
author | Tom Cooksey <thomas.cooksey@nokia.com> | 2009-09-02 11:45:45 (GMT) |
---|---|---|
committer | Tom Cooksey <thomas.cooksey@nokia.com> | 2009-09-02 12:03:36 (GMT) |
commit | 5871ed63be9dae9543fa0b715d593365bd1d2a7c (patch) | |
tree | 6516a3008f1abd9159c81ba955c02c3a2e5c65de | |
parent | fa048c81e4b9bfd1ab05940a59735d7a536669f0 (diff) | |
download | Qt-5871ed63be9dae9543fa0b715d593365bd1d2a7c.zip Qt-5871ed63be9dae9543fa0b715d593365bd1d2a7c.tar.gz Qt-5871ed63be9dae9543fa0b715d593365bd1d2a7c.tar.bz2 |
Add autotests for FBO stacking and interleaved painting
Reviewed-By: Samuel
-rw-r--r-- | tests/auto/qgl/tst_qgl.cpp | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp index f979174..d87a29c 100644 --- a/tests/auto/qgl/tst_qgl.cpp +++ b/tests/auto/qgl/tst_qgl.cpp @@ -73,9 +73,11 @@ private slots: void partialGLWidgetUpdates(); void glWidgetRendering(); void glFBORendering(); + void multipleFBOInterleavedRendering(); void glFBOUseInGLWidget(); void glPBufferRendering(); void glWidgetReparent(); + void stackedFBOs(); void colormap(); }; @@ -770,6 +772,113 @@ void tst_QGL::glFBORendering() QCOMPARE(fb.pixel(192, 64), QColor(Qt::green).rgb()); } + +// Tests multiple QPainters active on different FBOs at the same time, with +// interleaving painting. Performance-wise, this is sub-optimal, but it still +// has to work flawlessly +void tst_QGL::multipleFBOInterleavedRendering() +{ + if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) + QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle); + + QGLWidget glw; + glw.makeCurrent(); + + // No multisample with combined depth/stencil attachment: + QGLFramebufferObjectFormat fboFormat(0, QGLFramebufferObject::CombinedDepthStencil); + + QGLFramebufferObject *fbo1 = new QGLFramebufferObject(256, 128, fboFormat); + QGLFramebufferObject *fbo2 = new QGLFramebufferObject(256, 128, fboFormat); + QGLFramebufferObject *fbo3 = new QGLFramebufferObject(256, 128, fboFormat); + + QPainter fbo1Painter; + QPainter fbo2Painter; + QPainter fbo3Painter; + + QVERIFY(fbo1Painter.begin(fbo1)); + QVERIFY(fbo2Painter.begin(fbo2)); + QVERIFY(fbo3Painter.begin(fbo3)); + + QPainterPath intersectingPath; + intersectingPath.moveTo(0, 0); + intersectingPath.lineTo(100, 0); + intersectingPath.lineTo(0, 100); + intersectingPath.lineTo(100, 100); + intersectingPath.closeSubpath(); + + QPainterPath trianglePath; + trianglePath.moveTo(50, 0); + trianglePath.lineTo(100, 100); + trianglePath.lineTo(0, 100); + trianglePath.closeSubpath(); + + fbo1Painter.fillRect(0, 0, fbo1->width(), fbo1->height(), Qt::red); // Background + fbo2Painter.fillRect(0, 0, fbo2->width(), fbo2->height(), Qt::green); // Background + fbo3Painter.fillRect(0, 0, fbo3->width(), fbo3->height(), Qt::blue); // Background + + fbo1Painter.translate(14, 14); + fbo2Painter.translate(14, 14); + fbo3Painter.translate(14, 14); + + fbo1Painter.fillPath(intersectingPath, Qt::blue); // Test stencil buffer works + fbo2Painter.fillPath(intersectingPath, Qt::red); // Test stencil buffer works + fbo3Painter.fillPath(intersectingPath, Qt::green); // Test stencil buffer works + + fbo1Painter.translate(128, 0); + fbo2Painter.translate(128, 0); + fbo3Painter.translate(128, 0); + + fbo1Painter.setClipPath(trianglePath); + fbo2Painter.setClipPath(trianglePath); + fbo3Painter.setClipPath(trianglePath); + + fbo1Painter.setTransform(QTransform()); // reset xform + fbo2Painter.setTransform(QTransform()); // reset xform + fbo3Painter.setTransform(QTransform()); // reset xform + + fbo1Painter.fillRect(0, 0, fbo1->width(), fbo1->height(), Qt::green); + fbo2Painter.fillRect(0, 0, fbo2->width(), fbo2->height(), Qt::blue); + fbo3Painter.fillRect(0, 0, fbo3->width(), fbo3->height(), Qt::red); + + fbo1Painter.end(); + fbo2Painter.end(); + fbo3Painter.end(); + + QImage fb1 = fbo1->toImage().convertToFormat(QImage::Format_RGB32); + QImage fb2 = fbo2->toImage().convertToFormat(QImage::Format_RGB32); + QImage fb3 = fbo3->toImage().convertToFormat(QImage::Format_RGB32); + delete fbo1; + delete fbo2; + delete fbo3; + + // As we're doing more than trivial painting, we can't just compare to + // an image rendered with raster. Instead, we sample at well-defined + // test-points: + QCOMPARE(fb1.pixel(39, 64), QColor(Qt::red).rgb()); + QCOMPARE(fb1.pixel(89, 64), QColor(Qt::red).rgb()); + QCOMPARE(fb1.pixel(64, 39), QColor(Qt::blue).rgb()); + QCOMPARE(fb1.pixel(64, 89), QColor(Qt::blue).rgb()); + QCOMPARE(fb1.pixel(167, 39), QColor(Qt::red).rgb()); + QCOMPARE(fb1.pixel(217, 39), QColor(Qt::red).rgb()); + QCOMPARE(fb1.pixel(192, 64), QColor(Qt::green).rgb()); + + QCOMPARE(fb2.pixel(39, 64), QColor(Qt::green).rgb()); + QCOMPARE(fb2.pixel(89, 64), QColor(Qt::green).rgb()); + QCOMPARE(fb2.pixel(64, 39), QColor(Qt::red).rgb()); + QCOMPARE(fb2.pixel(64, 89), QColor(Qt::red).rgb()); + QCOMPARE(fb2.pixel(167, 39), QColor(Qt::green).rgb()); + QCOMPARE(fb2.pixel(217, 39), QColor(Qt::green).rgb()); + QCOMPARE(fb2.pixel(192, 64), QColor(Qt::blue).rgb()); + + QCOMPARE(fb3.pixel(39, 64), QColor(Qt::blue).rgb()); + QCOMPARE(fb3.pixel(89, 64), QColor(Qt::blue).rgb()); + QCOMPARE(fb3.pixel(64, 39), QColor(Qt::green).rgb()); + QCOMPARE(fb3.pixel(64, 89), QColor(Qt::green).rgb()); + QCOMPARE(fb3.pixel(167, 39), QColor(Qt::blue).rgb()); + QCOMPARE(fb3.pixel(217, 39), QColor(Qt::blue).rgb()); + QCOMPARE(fb3.pixel(192, 64), QColor(Qt::red).rgb()); +} + class FBOUseInGLWidget : public QGLWidget { public: @@ -890,6 +999,108 @@ void tst_QGL::glWidgetReparent() delete widget; } +// When using multiple FBOs at the same time, unbinding one FBO should re-bind the +// previous. I.e. It should be possible to have a stack of FBOs where pop'ing there +// top re-binds the one underneeth. +void tst_QGL::stackedFBOs() +{ + if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) + QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle); + + QGLWidget glw; + glw.show(); + +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&glw); +#endif + QTest::qWait(200); + + glw.makeCurrent(); + + // No multisample with combined depth/stencil attachment: + QGLFramebufferObjectFormat fboFormat(0, QGLFramebufferObject::CombinedDepthStencil); + + // Don't complicate things by using NPOT: + QGLFramebufferObject *fbo1 = new QGLFramebufferObject(128, 128, fboFormat); + QGLFramebufferObject *fbo2 = new QGLFramebufferObject(128, 128, fboFormat); + QGLFramebufferObject *fbo3 = new QGLFramebufferObject(128, 128, fboFormat); + + glClearColor(1.0, 0.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + fbo1->bind(); + glClearColor(1.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + fbo2->bind(); + glClearColor(0.0, 1.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + fbo3->bind(); + glClearColor(0.0, 0.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glScissor(32, 32, 64, 64); + glEnable(GL_SCISSOR_TEST); + glClearColor(0.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + fbo3->release(); + + // Scissor rect & test should be left untouched by the fbo release... + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + fbo2->release(); + + glClearColor(1.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + fbo1->release(); + + glClearColor(1.0, 1.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + glw.swapBuffers(); + + QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32); + QImage fb1 = fbo1->toImage().convertToFormat(QImage::Format_RGB32); + QImage fb2 = fbo2->toImage().convertToFormat(QImage::Format_RGB32); + QImage fb3 = fbo3->toImage().convertToFormat(QImage::Format_RGB32); + + delete fbo1; + delete fbo2; + delete fbo3; + + QImage widgetReference(widgetFB.size(), widgetFB.format()); + QImage fb1Reference(fb1.size(), fb1.format()); + QImage fb2Reference(fb2.size(), fb2.format()); + QImage fb3Reference(fb3.size(), fb3.format()); + + QPainter widgetReferencePainter(&widgetReference); + QPainter fb1ReferencePainter(&fb1Reference); + QPainter fb2ReferencePainter(&fb2Reference); + QPainter fb3ReferencePainter(&fb3Reference); + + widgetReferencePainter.fillRect(0, 0, widgetReference.width(), widgetReference.height(), Qt::magenta); + fb1ReferencePainter.fillRect(0, 0, fb1Reference.width(), fb1Reference.height(), Qt::red); + fb2ReferencePainter.fillRect(0, 0, fb2Reference.width(), fb2Reference.height(), Qt::green); + fb3ReferencePainter.fillRect(0, 0, fb3Reference.width(), fb3Reference.height(), Qt::blue); + + // Flip y-coords to match GL for the widget (which can be any size) + widgetReferencePainter.fillRect(32, glw.height() - 96, 64, 64, Qt::yellow); + fb1ReferencePainter.fillRect(32, 32, 64, 64, Qt::white); + fb2ReferencePainter.fillRect(32, 32, 64, 64, Qt::black); + fb3ReferencePainter.fillRect(32, 32, 64, 64, Qt::cyan); + + widgetReferencePainter.end(); + fb1ReferencePainter.end(); + fb2ReferencePainter.end(); + fb3ReferencePainter.end(); + + QCOMPARE(widgetFB, widgetReference); + QCOMPARE(fb1, fb1Reference); + QCOMPARE(fb2, fb2Reference); + QCOMPARE(fb3, fb3Reference); +} + + class ColormapExtended : public QGLColormap { public: |