4

My Qt3DWindow flickers at redraw and it feels as if double buffering is not working properly - is there something I need to do?

I've tried setting the global surface format parameters setSwapBehavior(QSurfaceFormat::DoubleBuffer) but it does not seem to help. I'm using the default QForwardRenderer which is described as rendering into the backbuffer but I don't seem to be able to control when the buffer swaps

void SimulationWindow::initialiseScene()
{
    this->defaultFrameGraph()->setClearColor(m_backgroundColour);
    Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
    this->setRootEntity(rootEntity);       
    Qt3DRender::QRenderSettings *renderSettings = this->renderSettings();        
    renderSettings->setRenderPolicy(Qt3DRender::QRenderSettings::OnDemand);
}

This is the only customisation I do to the standard Qt3DWindow. Using QRenderSettings::Always makes no difference. My feeling is that there is a setting accessible either through QFrameGraphNode or through QForwardRenderer that ought to fix things, or perhaps there is a way of directly controlling when the back buffer swaps. It certainly does not only happen when I call requestUpdate() which is what I would expect. Or perhaps I need to use something other than QForwardRenderer to get more control.

Edit: I've discovered a things called Qt3DRender::QNoDraw which looks hopeful. The suggestion in the documentation is that it is attached to the QClearBuffers that is part of QForwardRenderer but not publicly accessible.

Bill Sellers
  • 436
  • 3
  • 9
  • What Qt version are you using on what platform? – vre Apr 08 '19 at 08:40
  • This is Qt 5.12.2 on Windows. I can try the Mac version to see if that helps... – Bill Sellers Apr 08 '19 at 09:14
  • 1
    No, don't need to. I was asking, because I had those effects when using 5.10 and when I switched to 5.12 they disappeared. – vre Apr 08 '19 at 09:19
  • Do you observe the same with Qt 5.12.0 and 5.12.1? – Megidd Apr 08 '19 at 14:25
  • Yes, I've just tried 5.12.0 and 5.12.1, and I've also tried it on a Mac with 5.12.2 and I get the same effect. It looks like my scene is being updated as I create the entities exactly like I'd expect with no double buffering. You don't see it if the scene is simple because the entity creation is too quick, but with a complicated scene not all the entities appear at once as I'd expect if I was just swapping a back buffer. – Bill Sellers Apr 08 '19 at 15:35
  • I suspect the forward render will just not do what I want. It updates entities in background as they are created and has no mechanism for delaying the update. Probably Qt will create more renderer options or they will add an option to make it behave more like some of us would expect. I think the work around at is for me to keep 2 copies of my scene and switch between them. Not optimal but the current renderer just runs as a separate thread and updates objects when they change. Probably it is possible to intercept the entity update messages but without example code to do that it is hard. – Bill Sellers Apr 10 '19 at 22:23

1 Answers1

5

OK, I'm pretty sure I've found out exactly what the problem is. I've created a test program based on the basicshapes-cpp example where one of the shapes overlaps the others and gets deleted and redrawn straight away every 0.5 second. This should all happen in the back buffer and should not be seen but in fact it causes occasional flickering.

Extra code in main.cpp

view->renderSettings()->setRenderPolicy(Qt3DRender::QRenderSettings::OnDemand);
modifier->setView(view);
QTimer *timer = new QTimer(widget);
QObject::connect(timer, SIGNAL(timeout()), modifier, SLOT(timer()));
timer->start(500);

Extra code in scenemodifier.cpp

void SceneModifier::timer()
{
    if (!m_torusEntity) return;
    delete m_torusEntity;

    // Torus shape data
    m_torus = new Qt3DExtras::QTorusMesh();
    m_torus->setRadius(1.0f);
    m_torus->setMinorRadius(0.4f);
    m_torus->setRings(100);
    m_torus->setSlices(20);

    // TorusMesh Transform
    Qt3DCore::QTransform *torusTransform = new Qt3DCore::QTransform();
    torusTransform->setScale(m_torusScale);
    torusTransform->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(0.0f, 1.0f, 0.0f), 25.0f));
    torusTransform->setTranslation(QVector3D(5.0f, 4.0f, 0.0f));

    Qt3DExtras::QPhongMaterial *torusMaterial = new Qt3DExtras::QPhongMaterial();
    torusMaterial->setDiffuse(QColor(QRgb(0xbeb32b)));

    // Torus
    m_torusEntity = new Qt3DCore::QEntity(m_rootEntity);
    m_torusEntity->addComponent(m_torus);
    m_torusEntity->addComponent(torusMaterial);
    m_torusEntity->addComponent(torusTransform);

    m_view->requestUpdate();

}

Extra code in scenemodifier.h

public slots:
    void timer();
    float m_torusScale = 4.0;
    Qt3DExtras::Qt3DWindow *m_view;
    void setView(Qt3DExtras::Qt3DWindow *view);

And there it is. It doesn't flicker all the time but every so often it gets the redraw out of sync with the buffer swap and you get flicker. In my app the drawing is much more complex and slower and the flickering is much worse.

enter image description here

Bill Sellers
  • 436
  • 3
  • 9