0

I have a RenderWidget class inherited from QOpenGLWidget, which has the following two methods, among others:

RenderWidget : public QOpenGLWidget, protected QOpenGLFunctions_4_3_Core {
    // ...
public slots:
    void setSmthEnabled(bool enabled) {
        float val = (enabled == true) ? 1.0f : 0.0f;
        shader.setUniformValue("uniformUserInput", val);
    }

public:
    void paintGL() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // ...
        shader.setUniformValue("uniform1", value1);
        shader.setUniformValue("uniform2", value2);
        // ...
        mesh->draw();
    }
};

paintGL is being called 100 times/second, while setSmthEnabled is only called when a user toggles a checkbox in the UI, which happens occasionally. uniformUserInput uniform does not need to be set every frame, so I try to set it only in user input slot, but it does not work. The uniform preserves it's value, which was set on initialization.

I guess this happens because rendering is asynchronous, and uniform cannot be updated while the pipeline is busy. That's why I tried to call glFinish() before setting uniformUserInput in setSmthEnabled slot, but it didn't help. The only solution I found is to rewrite the class in the following manner:

RenderWidget : public QOpenGLWidget, protected QOpenGLFunctions_4_3_Core {
    // ...
private:
    float val = 1.0f;

public slots:
    void setSmthEnabled(bool enabled) {
        val = (enabled == true) ? 1.0f : 0.0f;
    }

public:
    void paintGL() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // ...
        shader.setUniformValue("uniform1", value1);
        shader.setUniformValue("uniform2", value2);
        // ...
        shader.setUniformValue("uniformUserInput", val);
        mesh->draw();
    }
};

Real-world code contains much more user-input uniforms, so I wouldn't like to update all of them each frame and keep redundant member variables for that purpose. How do I update uniforms on user input only?

shader.setUniformValue in the core above only calls QOpenGLShaderProgram::setUniformValue on a relevant QOpenGLShaderProgram object and returns.

Sergey
  • 7,985
  • 4
  • 48
  • 80

1 Answers1

2

so I try to set it only in user input slot, but it does not work

Which is to be expected. OpenGL is a statefull API and the state is encapsulated in a context. There may be any number of contexts used in a single program, which must be bound and can be unbound. for the sake of clarity in Qt's programming model the a OpenGL context is only bound in very specific circumstances, namely when inside initializeGL, paintGL and resizeGL. Also you can make a context current with QOpenGLContext::makeCurrent.

Only when a OpenGL context is bound current you can do things with it. Like setting uniform values.

I guess this happens because rendering is asynchronous, and uniform cannot be updated while the pipeline is busy.

That's not the reason. Also OpenGL is perfectly capable, in fact it is specified, that you can make any call at any time and everything gets queued up. You can even replace texture images (even through a PBO) even while the GPU is still using the texture object for rendering (the driver has to keep track of these changes and defer the execution until all affected resources are free to use).

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • I didn't know that the context is current in `paintGL`, but not other methods defined by me. So your answer helped, thanks! But what is the rationale behind making the context current only in the few methods? Is it done to manage several contexts in one application? Doesn't it slow down rendering significantly? – Sergey Sep 19 '16 at 04:35
  • @Sergey: Yes, this is about the possibility of having several contexts in an application. In its default mode of operation Qt creates a separate context for each window (with Qt5 and the new way of OpenGL integration you can do it in other ways, but it's not very straightforward). So if there are multiple OpenGL windows around contexts must be switched. In addition to that Qt5 may use OpenGL for rendering UI elements, too and your widget is actually ending up in an FBO managed by Qt. – datenwolf Sep 19 '16 at 06:56