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. QOpenGLShaderProgram: how to update fragment shader on-the-fly?
Forum Update on Monday, May 27th 2025

QOpenGLShaderProgram: how to update fragment shader on-the-fly?

Scheduled Pinned Locked Moved Solved General and Desktop
14 Posts 3 Posters 4.9k Views
  • 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.
  • V Offline
    V Offline
    Violet Giraffe
    wrote on 20 Apr 2017, 20:44 last edited by Violet Giraffe
    #1

    I'm trying to create an OpenGL application where I can update fragment shader on the go. I've got a very simple application working and drawing as intended using a vertex shader and a fragment shader. Now, I've tried a number of ways to update the shader, and none work. Some ways have no effect, and some others cause a crash inside the Qt framebuffer-related code (not my own code).

    This is what I have right now - it has no effect. I'm recreating and re-binding the shader program object when I need to update the shader:

    void MainWidget::setFragmentShader(const QString& shaderSource)
    {
    	QMutexLocker locker(&m);
    
    	if (_program && _program->isLinked())
    	{
    		_program->release();
    		_program->removeAllShaders();
    	}
    
    	_program = std::make_unique<QOpenGLShaderProgram>();
    	_fragmentShader = std::make_unique<QOpenGLShader>(QOpenGLShader::Fragment);
    
    
    	if (!_fragmentShader->compileSourceCode(shaderSource))
    	{
    		qDebug() << "Error compiling fragment shader:";
    		qDebug() << _fragmentShader->log();
    		return;
    	}
    
    	if (!_program->addShader(_fragmentShader.get()))
    		qDebug() << "Failed to add fragment shader:\n" << _program->log();
    
    	// Compile vertex shader
    	if (!_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vshader))
    		qDebug() << "Failed to add vertex shader:\n" << _program->log();
    
    	if (!_program->link())
    		qDebug() << "Failed to link the program\n:" << _program->log();
    
    	if (!_program->bind())
    		qDebug() << "Failed to bind the program\n:" << _program->log();
    }
    

    MainWidget is QOpenGLWidget.

    If I don't recreate the program object the program usually crashes, but there are specific code sequences that also have no effect rather than cause a crash.

    If I need to re-initialize the whole rendering system, how can I do that without re-creating the widget?

    Full code here.

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 20 Apr 2017, 22:09 last edited by
      #2

      Hi,

      WARNING not tested
      Quick idea: shouldn't you remove the shader, build it again (or create a new one) and then add it again to the program ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      V 1 Reply Last reply 21 Apr 2017, 04:53
      0
      • S SGaist
        20 Apr 2017, 22:09

        Hi,

        WARNING not tested
        Quick idea: shouldn't you remove the shader, build it again (or create a new one) and then add it again to the program ?

        V Offline
        V Offline
        Violet Giraffe
        wrote on 21 Apr 2017, 04:53 last edited by
        #3

        @SGaist said in QOpenGLShaderProgram: how to update fragment shader on-the-fly?:

        Hi,

        WARNING not tested
        Quick idea: shouldn't you remove the shader, build it again (or create a new one) and then add it again to the program ?

        Hi,
        You mean without recreating the program object? Something like this?

        void MainWidget::setFragmentShader(const QString& shaderSource)
        {
        	QMutexLocker locker(&m);
        
        	if (_program)
        	{
        		_program->removeShader(_fragmentShader.get());
        	}
        	else
        	{
        		_program = std::make_unique<QOpenGLShaderProgram>();
        
        		// Compile vertex shader
        		if (!_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vshader))
        			qDebug() << "Failed to add vertex shader:\n" << _program->log();
        	}
        
        	_fragmentShader = std::make_unique<QOpenGLShader>(QOpenGLShader::Fragment);
        
        
        	if (!_fragmentShader->compileSourceCode(shaderSource))
        	{
        		qDebug() << "Error compiling fragment shader:";
        		qDebug() << _fragmentShader->log();
        		return;
        	}
        
        	if (!_program->addShader(_fragmentShader.get()))
        		qDebug() << "Failed to add fragment shader:\n" << _program->log();
        
        	if (!_program->link())
        		qDebug() << "Failed to link the program\n:" << _program->log();
        
        	if (!_program->bind())
        		qDebug() << "Failed to bind the program\n:" << _program->log();
        }
        

        This code crashes. The callstack is always the same:

        alt text

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SGaist
          Lifetime Qt Champion
          wrote on 21 Apr 2017, 06:57 last edited by
          #4

          Are you using the mutex to avoid this call being made while the widget is being repainted ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          V 1 Reply Last reply 21 Apr 2017, 06:58
          0
          • S SGaist
            21 Apr 2017, 06:57

            Are you using the mutex to avoid this call being made while the widget is being repainted ?

            V Offline
            V Offline
            Violet Giraffe
            wrote on 21 Apr 2017, 06:58 last edited by
            #5

            @SGaist
            Yes, but it doesn't matter on Windows because there's no separate OpenGL thread on this OS.

            1 Reply Last reply
            0
            • V Offline
              V Offline
              Violet Giraffe
              wrote on 29 Apr 2017, 21:13 last edited by
              #6

              Still can't get it working, any advice?
              The code that crashes on my home PC with AMD graphics adapter simply does nothing on a built-in Intel GPU, so the crash is probably just an AMD driver bug, but clearly that code is not the proper way to replace the shader on the fly.

              1 Reply Last reply
              0
              • S Offline
                S Offline
                SGaist
                Lifetime Qt Champion
                wrote on 29 Apr 2017, 21:25 last edited by
                #7

                Can you share a minimal sample so I can give it a spin on my machine ?

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                V 1 Reply Last reply 29 Apr 2017, 22:12
                0
                • S SGaist
                  29 Apr 2017, 21:25

                  Can you share a minimal sample so I can give it a spin on my machine ?

                  V Offline
                  V Offline
                  Violet Giraffe
                  wrote on 29 Apr 2017, 22:12 last edited by
                  #8
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • johngodJ Offline
                    johngodJ Offline
                    johngod
                    wrote on 30 Apr 2017, 05:52 last edited by
                    #9

                    I admit I havent check your code sample, but why dont you just creat 2 shader programs at the initialization and then change between the shader programs on the fly, i.e change the binding between them ? AFAIK this is the best pratice, changing bindings, and not compiling shader on the fly, performance wise this seems bad.

                    V 1 Reply Last reply 30 Apr 2017, 06:38
                    0
                    • johngodJ johngod
                      30 Apr 2017, 05:52

                      I admit I havent check your code sample, but why dont you just creat 2 shader programs at the initialization and then change between the shader programs on the fly, i.e change the binding between them ? AFAIK this is the best pratice, changing bindings, and not compiling shader on the fly, performance wise this seems bad.

                      V Offline
                      V Offline
                      Violet Giraffe
                      wrote on 30 Apr 2017, 06:38 last edited by Violet Giraffe
                      #10

                      @johngod said in QOpenGLShaderProgram: how to update fragment shader on-the-fly?:

                      change between the shader programs on the fly

                      That is exactly what I have not been able to achieve. But the shader code is dynamic, I can't pre-compile it because it's determined at runtime.

                      1 Reply Last reply
                      0
                      • johngodJ Offline
                        johngodJ Offline
                        johngod
                        wrote on 30 Apr 2017, 08:34 last edited by
                        #11

                        Hi

                        Just tested your sample program, it works for me if we force the program shader binding in paintGL:

                        QMatrix4x4 pmvMatrix;
                        pmvMatrix.ortho(rect());
                        
                        _program->bind(); //add this line
                        
                        _program->enableAttributeArray("vertexPosition");
                        LogGlError;
                        
                        V 1 Reply Last reply 30 Apr 2017, 08:57
                        1
                        • johngodJ johngod
                          30 Apr 2017, 08:34

                          Hi

                          Just tested your sample program, it works for me if we force the program shader binding in paintGL:

                          QMatrix4x4 pmvMatrix;
                          pmvMatrix.ortho(rect());
                          
                          _program->bind(); //add this line
                          
                          _program->enableAttributeArray("vertexPosition");
                          LogGlError;
                          
                          V Offline
                          V Offline
                          Violet Giraffe
                          wrote on 30 Apr 2017, 08:57 last edited by Violet Giraffe
                          #12

                          @johngod said in QOpenGLShaderProgram: how to update fragment shader on-the-fly?:

                          Hi

                          Just tested your sample program, it works for me if we force the program shader binding in paintGL:

                          Interesting, thanks a bunch!
                          What do you think is wrong with bind() in setFragmentShader() ? Why is it not enough / has no effect?
                          As a reminder, I'm currently testing on Windows where there's not even a separate OpenGL thread to which such peculiarities could otherwise be attributed.

                          1 Reply Last reply
                          0
                          • johngodJ Offline
                            johngodJ Offline
                            johngod
                            wrote on 30 Apr 2017, 17:41 last edited by
                            #13

                            Hi Violet Giraffe

                            OpenGL being such a tricky beast I usually play safe, if I need to use a program shader, bind it first,
                            same goes for buffers, need to use it, bind it first.

                            That being said, afaik when deleting or detaching a shader, that doenst happen right away, that only marks the shader
                            for deletion, that can happen later when its not being used by the program, so I think its safe for you to forget about
                            QMutexLocker, and not worrying about locking.
                            This would perhaps also explain why binding the program in setFragmentShader() doesnt work, because you're binding
                            the program that is not yet in the desired state.

                            Also for the sake of safety, I find a bit risky that you're not compiling the shaders and linking them to
                            the program explicitly in the initGL() function, I would definitly do that.

                            Also in setFragmentShader() I dont think is necessary to remove all shaders, since you're only updating the fragment
                            shader I think ist safe to only remove it, compile it with the new source code, and link the program.

                            Hope it helps, let me know how it goes :)

                            V 1 Reply Last reply 30 Apr 2017, 20:38
                            1
                            • johngodJ johngod
                              30 Apr 2017, 17:41

                              Hi Violet Giraffe

                              OpenGL being such a tricky beast I usually play safe, if I need to use a program shader, bind it first,
                              same goes for buffers, need to use it, bind it first.

                              That being said, afaik when deleting or detaching a shader, that doenst happen right away, that only marks the shader
                              for deletion, that can happen later when its not being used by the program, so I think its safe for you to forget about
                              QMutexLocker, and not worrying about locking.
                              This would perhaps also explain why binding the program in setFragmentShader() doesnt work, because you're binding
                              the program that is not yet in the desired state.

                              Also for the sake of safety, I find a bit risky that you're not compiling the shaders and linking them to
                              the program explicitly in the initGL() function, I would definitly do that.

                              Also in setFragmentShader() I dont think is necessary to remove all shaders, since you're only updating the fragment
                              shader I think ist safe to only remove it, compile it with the new source code, and link the program.

                              Hope it helps, let me know how it goes :)

                              V Offline
                              V Offline
                              Violet Giraffe
                              wrote on 30 Apr 2017, 20:38 last edited by
                              #14

                              @johngod said in QOpenGLShaderProgram: how to update fragment shader on-the-fly?:

                              I think its safe for you to forget about
                              QMutexLocker, and not worrying about locking.

                              Makes sense. I'm sure OpenGL itself handles it correctly and is thread-safe. The mutex is only for protecting the QOpenGLShaderProgram object itself.

                              Also for the sake of safety, I find a bit risky that you're not compiling the shaders and linking them to
                              the program explicitly in the initGL() function, I would definitly do that.

                              Also in setFragmentShader() I dont think is necessary to remove all shaders, since you're only updating the fragment
                              shader I think ist safe to only remove it, compile it with the new source code, and link the program.

                              Yep, those are the first things I did after applying your answer, and everything works as expected (thanks again!). I just needed a working program before I could start optimizing it.

                              1 Reply Last reply
                              0

                              • Login

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