QRhi draw() effects current frame, not inflight as expected
-
Hi, I'm still getting my feet wet with QRhi. When I update new vertex data (colour or position) when doing a rendering pass, my system has a delay of 3 frames....the change appears on screen after two more rendering passes. (two frames inflight) I understand this is buffering to avoid tearing. What is unclear to me is why the draw() call effects the next frame shown and not the frame being drawn in the rendering pass. In my application I have two pipelines and I want to conditionally draw the second pipeline. Because the call to draw() is not synced with the vertex data, I get flashes of old vertex data. I could create a queue of 3 to delay the state of the draw call as a work around, but it appears I'm doing something wrong here.
The issue also happens with just one pipeline as well using the example in qtbase/examples/widgets/rhi/simplerhiwidget with minimal modifications....
- disable continues drawing - use the the key d to trigger a rendering pass
- change the vertex buffer (m_vbuf) type from Immutable to Dynamic
- add a line in the rendering pass to upload the colour change
- key t toggles a flag that enables / disables call to draw() in the rendering pass
- key c changes triangle colour Red --> Green --> Blue --> back to Red
Steps to reproduce.....
- Open then press C, D, D, D -> triangle will turn green.
- Then press C, T, D -> triangle disappears. Expected green triangle.
- Then press T, D -> green triangle appears
- Then press D -> blue triangle appears. Expected blank as draw() was not called for this rendering pass.
Is this the expected functionality or am I doing something wrong?
static float vertexData[] = { 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, }; static QShader getShader(const QString &name) { QFile f(name); return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader(); } void ExampleRhiWidget::initialize(QRhiCommandBuffer *cb) { if (m_rhi != rhi()) { m_pipeline.reset(); m_rhi = rhi(); } if (!m_pipeline) { m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, sizeof(vertexData))); // changed to Dynamic m_vbuf->create(); m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64)); m_ubuf->create(); m_srb.reset(m_rhi->newShaderResourceBindings()); m_srb->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, m_ubuf.get()), }); m_srb->create(); m_pipeline.reset(m_rhi->newGraphicsPipeline()); m_pipeline->setShaderStages({ { QRhiShaderStage::Vertex, getShader(QLatin1String(":/shader_assets/color.vert.qsb")) }, { QRhiShaderStage::Fragment, getShader(QLatin1String(":/shader_assets/color.frag.qsb")) } }); QRhiVertexInputLayout inputLayout; inputLayout.setBindings({ { 5 * sizeof(float) } }); inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } }); m_pipeline->setVertexInputLayout(inputLayout); m_pipeline->setShaderResourceBindings(m_srb.get()); m_pipeline->setRenderPassDescriptor(renderTarget()->renderPassDescriptor()); m_pipeline->create(); //QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch(); //resourceUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData); //cb->resourceUpdate(resourceUpdates); } const QSize outputSize = renderTarget()->pixelSize(); m_viewProjection = m_rhi->clipSpaceCorrMatrix(); m_viewProjection.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f); m_viewProjection.translate(0, 0, -4); } void ExampleRhiWidget::render(QRhiCommandBuffer *cb) { QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch(); //m_rotation += 1.0f; QMatrix4x4 modelViewProjection = m_viewProjection; modelViewProjection.rotate(m_rotation, 0, 1, 0); resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 0, 64, modelViewProjection.constData()); const QColor clearColor = QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f); cb->beginPass(renderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates); cb->setGraphicsPipeline(m_pipeline.get()); const QSize outputSize = renderTarget()->pixelSize(); cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height())); cb->setShaderResources(); resourceUpdates->updateDynamicBuffer(m_vbuf.get(), 0, sizeof(vertexData), vertexData); // this line added to get colour changes const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0); cb->setVertexInput(0, 1, &vbufBinding); if (drawEnabled) cb->draw(3); cb->endPass(); } void ExampleRhiWidget::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_D) { qDebug() << "Draw enabled=" << drawEnabled << color; update(); } else if (e->key() == Qt::Key_T) { if (drawEnabled) drawEnabled = false; else drawEnabled = true; } else if (e->key() == Qt::Key_C) { if (color == Qt::red) { color = Qt::green; vertexData[3] = vertexData[8] = vertexData[13] = 1.0f; vertexData[2] = vertexData[4] = vertexData[7] = vertexData[9] = vertexData[12] = vertexData[14] = 0.0f; } else if (color == Qt::green) { color = Qt::blue; vertexData[4] = vertexData[9] = vertexData[14] = 1.0f; vertexData[2] = vertexData[3] = vertexData[7] = vertexData[8] = vertexData[12] = vertexData[13] = 0.0f; } else if (color == Qt::blue) { color = Qt::red; vertexData[2] = vertexData[7] = vertexData[12] = 1.0f; vertexData[3] = vertexData[4] = vertexData[8] = vertexData[9] = vertexData[13] = vertexData[14] = 0.0f; } } } -
I figured out the issue. Buffer upload must be done before beginPass() is called.... in render function, this line
resourceUpdates->updateDynamicBuffer(m_vbuf.get(), 0, sizeof(vertexData), vertexData);needs to be before this line
cb->beginPass(renderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates); -
may i ask how big is the exe file of your application in release mode ? and how are you compiling it ?
-
On Debian 13
/tk/Qt/6.10.1/bin/qmake simplerhiwidget.pro makelooks like 48KB on linux
ls -l simplerhiwidget
-rwxrwxr-x 1 drwho drwho 48368 Nov 26 12:50 simplerhiwidgetOn MacOS 12
~/tk/Qt/6.8.3/bin/qmake simplerhiwidget.pro makelooks like 81KB
ls -l simplerhiwidget.app/Contents/MacOS
-rwxr-xr-x 1 drwho staff 81312 26 Nov 09:44 simplerhiwidget6.8.3 is the newest Qt I could get to compile on MacOX 12 using XCode 13
-
I figured out the issue. Buffer upload must be done before beginPass() is called.... in render function, this line
resourceUpdates->updateDynamicBuffer(m_vbuf.get(), 0, sizeof(vertexData), vertexData);needs to be before this line
cb->beginPass(renderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates); -
D drwho 0 has marked this topic as solved