Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QRhi draw() effects current frame, not inflight as expected
Forum Updated to NodeBB v4.3 + New Features

QRhi draw() effects current frame, not inflight as expected

Scheduled Pinned Locked Moved Solved General and Desktop
4 Posts 2 Posters 93 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    drwho 0
    wrote last edited by
    #1

    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;
    		}
    	}
    }
    
    1 Reply Last reply
    0
    • D Offline
      D Offline
      drwho 0
      wrote last edited by
      #4

      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);
      
      1 Reply Last reply
      1
      • U Offline
        U Offline
        unknown968787
        wrote last edited by
        #2

        may i ask how big is the exe file of your application in release mode ? and how are you compiling it ?

        1 Reply Last reply
        0
        • D Offline
          D Offline
          drwho 0
          wrote last edited by
          #3

          On Debian 13

          /tk/Qt/6.10.1/bin/qmake simplerhiwidget.pro
          make
          

          looks like 48KB on linux
          ls -l simplerhiwidget
          -rwxrwxr-x 1 drwho drwho 48368 Nov 26 12:50 simplerhiwidget

          On MacOS 12

          ~/tk/Qt/6.8.3/bin/qmake simplerhiwidget.pro
          make
          

          looks like 81KB
          ls -l simplerhiwidget.app/Contents/MacOS
          -rwxr-xr-x 1 drwho staff 81312 26 Nov 09:44 simplerhiwidget

          6.8.3 is the newest Qt I could get to compile on MacOX 12 using XCode 13

          1 Reply Last reply
          0
          • D Offline
            D Offline
            drwho 0
            wrote last edited by
            #4

            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);
            
            1 Reply Last reply
            1
            • D drwho 0 has marked this topic as solved

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved