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. Why QSurfaceFormat is a cause of OpenGL error with the 1282 code (invalid operation) after glReadPixels call?
QtWS25 Last Chance

Why QSurfaceFormat is a cause of OpenGL error with the 1282 code (invalid operation) after glReadPixels call?

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 2 Posters 1.3k 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.
  • 8 Offline
    8 Offline
    8Observer8
    wrote on 23 Dec 2023, 14:06 last edited by 8Observer8
    #1

    Hi,

    I use OpenGL 2. The default OpenGL version in QSurfaceFormat is 2.0. Why QSurfaceFormat is a cause of OpenGL error with the 1282 code (invalid operation) after glReadPixels call?

    main.cpp

    #ifdef _WIN32
    #include <windows.h>
    extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
    extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
    #endif
    
    #include <QtGui/QOpenGLFunctions>
    #include <QtGui/QSurfaceFormat>
    #include <QtOpenGLWidgets/QOpenGLWidget>
    #include <QtWidgets/QApplication>
    #include <QtWidgets/QVBoxLayout>
    #include <QtWidgets/QWidget>
    
    class OpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions
    {
    public:
        OpenGLWidget()
        {
            // Set format
            QSurfaceFormat surfaceFormat;
            surfaceFormat.setSamples(4);
            setFormat(surfaceFormat);
        }
    
    private:
        void initializeGL() override
        {
            initializeOpenGLFunctions();
            glClearColor(0, 1.f, 0.f, 1.f);
        }
    
        void paintGL() override
        {
            glClear(GL_COLOR_BUFFER_BIT);
            qDebug() << glGetError();
            GLubyte pixels[3];
            glReadPixels(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixels);
            qDebug() << glGetError();
            qDebug() << pixels[0] << pixels[1] << pixels[2];
        }
    };
    
    class MainWindow : public QWidget
    {
    public:
        MainWindow()
        {
            resize(350, 350);
            QVBoxLayout *layout = new QVBoxLayout();
            OpenGLWidget *openGLWidget = new OpenGLWidget();
            layout->addWidget(openGLWidget);
            setLayout(layout);
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
        QApplication app(argc, argv);
        MainWindow w;
        w.show();
        return app.exec();
    }
    

    pro-file:

    QT += core gui openglwidgets widgets
    
    win32: LIBS += -lopengl32
    
    CONFIG += c++17
    
    SOURCES += \
        main.cpp
    
    TARGET = app
    

    c78f5644-5238-49bd-a3ee-1a5f166968f1-image.png

    Console output:

    0
    1282
    2 0 0
    

    There is no errors When I comment a section of code with QSurfaceFormat:

        OpenGLWidget()
        {
            // Set format
            // QSurfaceFormat surfaceFormat;
            // surfaceFormat.setSamples(4);
            // setFormat(surfaceFormat);
        }
    

    Console output:

    0
    0
    0 255 0
    
    C 1 Reply Last reply 23 Dec 2023, 15:11
    0
    • 8 8Observer8
      23 Dec 2023, 14:06

      Hi,

      I use OpenGL 2. The default OpenGL version in QSurfaceFormat is 2.0. Why QSurfaceFormat is a cause of OpenGL error with the 1282 code (invalid operation) after glReadPixels call?

      main.cpp

      #ifdef _WIN32
      #include <windows.h>
      extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
      extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
      #endif
      
      #include <QtGui/QOpenGLFunctions>
      #include <QtGui/QSurfaceFormat>
      #include <QtOpenGLWidgets/QOpenGLWidget>
      #include <QtWidgets/QApplication>
      #include <QtWidgets/QVBoxLayout>
      #include <QtWidgets/QWidget>
      
      class OpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions
      {
      public:
          OpenGLWidget()
          {
              // Set format
              QSurfaceFormat surfaceFormat;
              surfaceFormat.setSamples(4);
              setFormat(surfaceFormat);
          }
      
      private:
          void initializeGL() override
          {
              initializeOpenGLFunctions();
              glClearColor(0, 1.f, 0.f, 1.f);
          }
      
          void paintGL() override
          {
              glClear(GL_COLOR_BUFFER_BIT);
              qDebug() << glGetError();
              GLubyte pixels[3];
              glReadPixels(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixels);
              qDebug() << glGetError();
              qDebug() << pixels[0] << pixels[1] << pixels[2];
          }
      };
      
      class MainWindow : public QWidget
      {
      public:
          MainWindow()
          {
              resize(350, 350);
              QVBoxLayout *layout = new QVBoxLayout();
              OpenGLWidget *openGLWidget = new OpenGLWidget();
              layout->addWidget(openGLWidget);
              setLayout(layout);
          }
      };
      
      int main(int argc, char *argv[])
      {
          QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
          QApplication app(argc, argv);
          MainWindow w;
          w.show();
          return app.exec();
      }
      

      pro-file:

      QT += core gui openglwidgets widgets
      
      win32: LIBS += -lopengl32
      
      CONFIG += c++17
      
      SOURCES += \
          main.cpp
      
      TARGET = app
      

      c78f5644-5238-49bd-a3ee-1a5f166968f1-image.png

      Console output:

      0
      1282
      2 0 0
      

      There is no errors When I comment a section of code with QSurfaceFormat:

          OpenGLWidget()
          {
              // Set format
              // QSurfaceFormat surfaceFormat;
              // surfaceFormat.setSamples(4);
              // setFormat(surfaceFormat);
          }
      

      Console output:

      0
      0
      0 255 0
      
      C Offline
      C Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on 23 Dec 2023, 15:11 last edited by
      #2

      As specified glReadPixels will produce GL_INVALID_OPERATION if GL_SAMPLE_BUFFERS is greater than zero. In other words you can't read from a multisampled framebuffer directly (surfaceFormat.setSamples(4)).

      To get that value you have to manually blit to a normal buffer first and read from it. This will make the GPU do the multisampling and store the resulting value, which you can then read. OpenGL 2.0 doesn't have glBlitFramebuffer, but you can use the EXT_framebuffer_blit extension that will give you the same functionality.

      8 1 Reply Last reply 24 Dec 2023, 06:38
      2
      • 8 8Observer8 has marked this topic as solved on 23 Dec 2023, 16:47
      • C Chris Kawa
        23 Dec 2023, 15:11

        As specified glReadPixels will produce GL_INVALID_OPERATION if GL_SAMPLE_BUFFERS is greater than zero. In other words you can't read from a multisampled framebuffer directly (surfaceFormat.setSamples(4)).

        To get that value you have to manually blit to a normal buffer first and read from it. This will make the GPU do the multisampling and store the resulting value, which you can then read. OpenGL 2.0 doesn't have glBlitFramebuffer, but you can use the EXT_framebuffer_blit extension that will give you the same functionality.

        8 Offline
        8 Offline
        8Observer8
        wrote on 24 Dec 2023, 06:38 last edited by
        #3

        @Chris-Kawa thank a lot! I didn't know that I need to move pixels from the multisampled FBO to a normal FBO before using glReadPixels. For example, in WebGL 1.0 I don't need it because canvas.getContext() has an attribute antialias that enabled by default:

        const gl = canvas.getContext("webgl");
        

        I can set antialias obviously:

        const gl = canvas.getContext("webgl", { antialias: true });
        

        index.html

        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="utf-8">
            <title>Example</title>
        </head>
        <body>
            <canvas id="renderCanvas" width="100" height="100"></canvas>
        
            <script>
                const canvas = document.getElementById("renderCanvas");
                const gl = canvas.getContext("webgl", { antialias: true });
                gl.clearColor(0, 1, 0, 1);
                gl.clear(gl.COLOR_BUFFER_BIT);
                const pixels = new Uint8Array(4);
                gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
                console.log(pixels[0], pixels[1], pixels[2]);
            </script>
        </body>
        </html>
        

        533085f3-c744-4df7-ada6-f8799f77e0f8-image.png
        Console output: 0 255 0

        But I understand now that the Qt surfaceFormat.setSamples(4) is different.

        1 Reply Last reply
        0
        • 8 Offline
          8 Offline
          8Observer8
          wrote on 24 Dec 2023, 06:49 last edited by 8Observer8
          #4

          But I don't know how to call glBlitFrameBuffer directly (without QOpenGLFramebufferObject::blitFramebuffer) I didn't use OpenGL extensions before.

          I found an example here: https://stackoverflow.com/questions/765434/glreadpixels-from-fbo-fails-with-multisampling in this answer:

          I don't think you can read from a multisampled FBO with glReadPixels(). You need to blit from the multisampled FBO to a normal FBO, bind the normal FBO, and then read the pixels from the normal FBO.

          Something like this:

          // Bind the multisampled FBO for reading
          glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, my_multisample_fbo);
          // Bind the normal FBO for drawing
          glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, my_fbo);
          // Blit the multisampled FBO to the normal FBO
          glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
          //Bind the normal FBO for reading
          glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, my_fbo);
          // Read the pixels!
          glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
          

          I think he uses EXT even with glBindFramebufferEXT and with GL_DRAW_FRAMEBUFFER_EXT because he uses it with OpenGL 1.5. But OpenGL 2.0 has glBindFramebuffer() and GL_DRAW_FRAMEBUFFER

          Now I need to call glBlitFramebuffer. It is undefined now. I found an example here how to call an extension: https://www.opengl-tutorial.org/intermediate-tutorials/tutorial-12-opengl-extensions/

          int NumberOfExtensions;
          glGetIntegerv(GL_NUM_EXTENSIONS, &NumberOfExtensions);
          for(i=0; i<NumberOfExtensions; i++) {
            const GLubyte *ccc=glGetStringi(GL_EXTENSIONS, i);
            if ( strcmp(ccc, (const GLubyte *)"GL_ARB_debug_output") == 0 ){
              // The extension is supported by our hardware and driver
              // Try to get the "glDebugMessageCallbackARB" function :
              glDebugMessageCallbackARB  = (PFNGLDEBUGMESSAGECALLBACKARBPROC) wglGetProcAddress("glDebugMessageCallbackARB");
            }
          }
          

          The problem is that glGetStringi is not declared in this scope:

                  int numberOfExtensions;
                  glGetIntegerv(GL_NUM_EXTENSIONS, &numberOfExtensions);
                  for(int i = 0; i < numberOfExtensions; i++)
                  {
                      const GLubyte *ccc = glGetStringi(GL_EXTENSIONS, i);
                  }
          
          C 1 Reply Last reply 24 Dec 2023, 11:09
          0
          • 8 Offline
            8 Offline
            8Observer8
            wrote on 24 Dec 2023, 11:01 last edited by 8Observer8
            #5

            Another problem is here:

            glDebugMessageCallbackARB  = (PFNGLDEBUGMESSAGECALLBACKARBPROC) wglGetProcAddress("glDebugMessageCallbackARB");
            

            PFNGLDEBUGMESSAGECALLBACKARBPROC is WinAPI thing. I cannot use it because I want to build for Android too. I need to use Qt loader of function pointers but I didn't find how.

            1 Reply Last reply
            0
            • 8 8Observer8
              24 Dec 2023, 06:49

              But I don't know how to call glBlitFrameBuffer directly (without QOpenGLFramebufferObject::blitFramebuffer) I didn't use OpenGL extensions before.

              I found an example here: https://stackoverflow.com/questions/765434/glreadpixels-from-fbo-fails-with-multisampling in this answer:

              I don't think you can read from a multisampled FBO with glReadPixels(). You need to blit from the multisampled FBO to a normal FBO, bind the normal FBO, and then read the pixels from the normal FBO.

              Something like this:

              // Bind the multisampled FBO for reading
              glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, my_multisample_fbo);
              // Bind the normal FBO for drawing
              glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, my_fbo);
              // Blit the multisampled FBO to the normal FBO
              glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
              //Bind the normal FBO for reading
              glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, my_fbo);
              // Read the pixels!
              glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
              

              I think he uses EXT even with glBindFramebufferEXT and with GL_DRAW_FRAMEBUFFER_EXT because he uses it with OpenGL 1.5. But OpenGL 2.0 has glBindFramebuffer() and GL_DRAW_FRAMEBUFFER

              Now I need to call glBlitFramebuffer. It is undefined now. I found an example here how to call an extension: https://www.opengl-tutorial.org/intermediate-tutorials/tutorial-12-opengl-extensions/

              int NumberOfExtensions;
              glGetIntegerv(GL_NUM_EXTENSIONS, &NumberOfExtensions);
              for(i=0; i<NumberOfExtensions; i++) {
                const GLubyte *ccc=glGetStringi(GL_EXTENSIONS, i);
                if ( strcmp(ccc, (const GLubyte *)"GL_ARB_debug_output") == 0 ){
                  // The extension is supported by our hardware and driver
                  // Try to get the "glDebugMessageCallbackARB" function :
                  glDebugMessageCallbackARB  = (PFNGLDEBUGMESSAGECALLBACKARBPROC) wglGetProcAddress("glDebugMessageCallbackARB");
                }
              }
              

              The problem is that glGetStringi is not declared in this scope:

                      int numberOfExtensions;
                      glGetIntegerv(GL_NUM_EXTENSIONS, &numberOfExtensions);
                      for(int i = 0; i < numberOfExtensions; i++)
                      {
                          const GLubyte *ccc = glGetStringi(GL_EXTENSIONS, i);
                      }
              
              C Offline
              C Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on 24 Dec 2023, 11:09 last edited by Chris Kawa
              #6

              @8Observer8 said:

              But I understand now that the Qt surfaceFormat.setSamples(4) is different.

              It has nothing to do with Qt. Open GL 2.0 and WebGL are two different specs, and, although similar, they do differ in many places. The antialias context attribute in WebGL is optional and entirely implementation defined i.e. it could be implemented as multisampling, supersampling or a postprocess like FXAA. The readPixels function in WebGL does not have the same restrictions as the one in OpenGL 2.0.

              I didn't use OpenGL extensions before.

              You probably did. you just don't know it because Qt gives you nice wrappers around them. Same here. You don't need to deal with the extension interface directly. Qt provides functions that wrap that functionality:

              hasOpenGLFramebufferBlit - to check if the extension is present
              blitFramebuffer (any of the 4 overloads) - to blit a framebuffer

              or you can avoid creating your own buffer entirely and use toImage which takes care of all the low level buffer creation and blits using that extension.

              If you prefer to use the low level API directly you also don't have to resolve the extension's functions pointers directly. Qt does this for you and provides a platform independent wrapper. See QOpenGLExtraFunctions::glBlitFramebuffer.

              1 Reply Last reply
              2
              • 8 Offline
                8 Offline
                8Observer8
                wrote on 25 Dec 2023, 19:28 last edited by 8Observer8
                #7

                I have this exception:

                9f66b73c-2393-4ba0-87c0-66e0544c5ca8-image.png

                When I try to use glGetStringi from QOpenGLExtraFunctions:

                        QOpenGLExtraFunctions extraFunc;
                        int numberOfExtensions;
                        glGetIntegerv(GL_NUM_EXTENSIONS, &numberOfExtensions);
                        for(int i = 0; i < numberOfExtensions; i++)
                        {
                            const GLubyte *ccc = extraFunc.glGetStringi(GL_EXTENSIONS, i);
                        }
                

                I called initializeOpenGLFunctions() before it:

                    void initializeGL() override
                    {
                        initializeOpenGLFunctions();
                        glClearColor(0, 1.f, 0.f, 1.f);
                        qDebug() << glGetError();
                        GLubyte pixels[3];
                        glReadPixels(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixels);
                        qDebug() << glGetError();
                        qDebug() << pixels[0] << pixels[1] << pixels[2];
                
                        // qDebug() << QOpenGLFramebufferObject::hasOpenGLFramebufferObjects();
                
                        int myMultisampleFBO;
                        glBindFramebuffer(GL_READ_FRAMEBUFFER, myMultisampleFBO);
                        int myFBO;
                        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, myFBO);
                
                        QOpenGLExtraFunctions extraFunc;
                        int numberOfExtensions;
                        glGetIntegerv(GL_NUM_EXTENSIONS, &numberOfExtensions);
                        for(int i = 0; i < numberOfExtensions; i++)
                        {
                            const GLubyte *ccc = extraFunc.glGetStringi(GL_EXTENSIONS, i);
                        }
                        // glBlitFramebuffer(0, 0, width(), height(), 0, 0, width(), height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
                        // // qDebug() << glGetString(GL_EXTENSIONS);
                        // qDebug() << my_multisample_fbo;
                    }
                

                And I set 3.1 version of OpenGL for an experiment:

                        QSurfaceFormat surfaceFormat;
                        surfaceFormat.setMajorVersion(3);
                        surfaceFormat.setMinorVersion(1);
                        surfaceFormat.setSamples(4);
                        setFormat(surfaceFormat);
                

                Because the documentation says that QOpenGLExtraFunctions for OpenGL ES 3.0, 3.1 and 3.2 API

                C 1 Reply Last reply 25 Dec 2023, 19:47
                0
                • 8 8Observer8
                  25 Dec 2023, 19:28

                  I have this exception:

                  9f66b73c-2393-4ba0-87c0-66e0544c5ca8-image.png

                  When I try to use glGetStringi from QOpenGLExtraFunctions:

                          QOpenGLExtraFunctions extraFunc;
                          int numberOfExtensions;
                          glGetIntegerv(GL_NUM_EXTENSIONS, &numberOfExtensions);
                          for(int i = 0; i < numberOfExtensions; i++)
                          {
                              const GLubyte *ccc = extraFunc.glGetStringi(GL_EXTENSIONS, i);
                          }
                  

                  I called initializeOpenGLFunctions() before it:

                      void initializeGL() override
                      {
                          initializeOpenGLFunctions();
                          glClearColor(0, 1.f, 0.f, 1.f);
                          qDebug() << glGetError();
                          GLubyte pixels[3];
                          glReadPixels(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixels);
                          qDebug() << glGetError();
                          qDebug() << pixels[0] << pixels[1] << pixels[2];
                  
                          // qDebug() << QOpenGLFramebufferObject::hasOpenGLFramebufferObjects();
                  
                          int myMultisampleFBO;
                          glBindFramebuffer(GL_READ_FRAMEBUFFER, myMultisampleFBO);
                          int myFBO;
                          glBindFramebuffer(GL_DRAW_FRAMEBUFFER, myFBO);
                  
                          QOpenGLExtraFunctions extraFunc;
                          int numberOfExtensions;
                          glGetIntegerv(GL_NUM_EXTENSIONS, &numberOfExtensions);
                          for(int i = 0; i < numberOfExtensions; i++)
                          {
                              const GLubyte *ccc = extraFunc.glGetStringi(GL_EXTENSIONS, i);
                          }
                          // glBlitFramebuffer(0, 0, width(), height(), 0, 0, width(), height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
                          // // qDebug() << glGetString(GL_EXTENSIONS);
                          // qDebug() << my_multisample_fbo;
                      }
                  

                  And I set 3.1 version of OpenGL for an experiment:

                          QSurfaceFormat surfaceFormat;
                          surfaceFormat.setMajorVersion(3);
                          surfaceFormat.setMinorVersion(1);
                          surfaceFormat.setSamples(4);
                          setFormat(surfaceFormat);
                  

                  Because the documentation says that QOpenGLExtraFunctions for OpenGL ES 3.0, 3.1 and 3.2 API

                  C Offline
                  C Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 25 Dec 2023, 19:47 last edited by Chris Kawa
                  #8

                  @8Observer8 You are calling initializeOpenGLFunctions and glGetStringi on two completely different instances. Your extraFunc variable does not have the function pointers resolved.

                  There are multiple ways to get the extra functions:

                  Way 1. Subclass QOpenGLExtraFunctions:

                  class OpenGLWidget : public QOpenGLWidget, private QOpenGLExtraFunctions
                  

                  initialize:

                  void initializeGL() override
                  {
                      initializeOpenGLFunctions();
                  }
                  

                  and then you can simply use it:

                  void paintGL() override
                  {
                     glGetStringi(GL_EXTENSIONS, 42);
                     ...
                  

                  Way 2. Make a separate variable for your functions and initialize it. Keep in mind this is slow, so you should be doing it only once and store the variable. Don't do it every time in the paint event for example.

                  QOpenGLExtraFunctions extraFunc;
                  extraFunc.initializeOpenGLFunctions();
                  extraFunc.glGetStringi(GL_EXTENSIONS, 42);
                  

                  Way 3. Get the function pointers from your context:

                  context()->extraFunctions()->glGetStringi(GL_EXTENSIONS, 42);
                  

                  In any case you don't need the low level API to get the list of extensions. Again, Qt provides wrappers. In this case you can get the set of supported extensions via QOpenGLContext::extensions() function.
                  There's also QOpenGLContext::hasExtension() to check for support of any single extension.

                  Another issue is that this will absolutely not work:

                  int myMultisampleFBO;
                  glBindFramebuffer(GL_READ_FRAMEBUFFER, myMultisampleFBO);
                  

                  Bind does not create a buffer. It just binds an existing buffer to the read or write slot. myMultisampleFBO is not an existing buffer id. It's an uninitialized variable. This is undefined behavior. You need to create a buffer and get its id to pass it to glBindFramebuffer.

                  1 Reply Last reply
                  2
                  • 8 Offline
                    8 Offline
                    8Observer8
                    wrote on 25 Dec 2023, 22:39 last edited by 8Observer8
                    #9

                    I have 1282 error in the glBlitFramebuffer function. What is wrong?

                        void initializeGL() override
                        {
                            initializeOpenGLFunctions();
                            glClearColor(0, 1.f, 0.f, 1.f);
                    
                            GLuint myMultisampleFBO;
                            glGenFramebuffers(1, &myMultisampleFBO);
                            glBindFramebuffer(GL_READ_FRAMEBUFFER, myMultisampleFBO);
                    
                            GLuint myFBO;
                            glGenFramebuffers(1, &myFBO);
                            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, myFBO);
                    
                            glBlitFramebuffer(0, 0, width(), height(), 0, 0, width(), height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
                            qDebug() << glGetError();
                    

                    I tried to translate this example: https://stackoverflow.com/questions/765434/glreadpixels-from-fbo-fails-with-multisampling

                    // Bind the multisampled FBO for reading
                    glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, my_multisample_fbo);
                    // Bind the normal FBO for drawing
                    glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, my_fbo);
                    // Blit the multisampled FBO to the normal FBO
                    glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
                    //Bind the normal FBO for reading
                    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, my_fbo);
                    // Read the pixels!
                    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
                    

                    I inherited from QOpenGLExtraFuntions:

                    class OpenGLWidget : public QOpenGLWidget, private QOpenGLExtraFunctions
                    {
                    public:
                        OpenGLWidget()
                        {
                            resize(200, 200);
                            // Set format
                            QSurfaceFormat surfaceFormat;
                            surfaceFormat.setMajorVersion(3);
                            surfaceFormat.setMinorVersion(1);
                            surfaceFormat.setSamples(4);
                            setFormat(surfaceFormat);
                        }
                    
                    C 1 Reply Last reply 26 Dec 2023, 00:16
                    0
                    • 8 8Observer8
                      25 Dec 2023, 22:39

                      I have 1282 error in the glBlitFramebuffer function. What is wrong?

                          void initializeGL() override
                          {
                              initializeOpenGLFunctions();
                              glClearColor(0, 1.f, 0.f, 1.f);
                      
                              GLuint myMultisampleFBO;
                              glGenFramebuffers(1, &myMultisampleFBO);
                              glBindFramebuffer(GL_READ_FRAMEBUFFER, myMultisampleFBO);
                      
                              GLuint myFBO;
                              glGenFramebuffers(1, &myFBO);
                              glBindFramebuffer(GL_DRAW_FRAMEBUFFER, myFBO);
                      
                              glBlitFramebuffer(0, 0, width(), height(), 0, 0, width(), height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
                              qDebug() << glGetError();
                      

                      I tried to translate this example: https://stackoverflow.com/questions/765434/glreadpixels-from-fbo-fails-with-multisampling

                      // Bind the multisampled FBO for reading
                      glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, my_multisample_fbo);
                      // Bind the normal FBO for drawing
                      glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, my_fbo);
                      // Blit the multisampled FBO to the normal FBO
                      glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
                      //Bind the normal FBO for reading
                      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, my_fbo);
                      // Read the pixels!
                      glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
                      

                      I inherited from QOpenGLExtraFuntions:

                      class OpenGLWidget : public QOpenGLWidget, private QOpenGLExtraFunctions
                      {
                      public:
                          OpenGLWidget()
                          {
                              resize(200, 200);
                              // Set format
                              QSurfaceFormat surfaceFormat;
                              surfaceFormat.setMajorVersion(3);
                              surfaceFormat.setMinorVersion(1);
                              surfaceFormat.setSamples(4);
                              setFormat(surfaceFormat);
                          }
                      
                      C Offline
                      C Offline
                      Chris Kawa
                      Lifetime Qt Champion
                      wrote on 26 Dec 2023, 00:16 last edited by Chris Kawa
                      #10

                      @8Observer8 There are multiple issues in your code.

                      If you can use OpenGL 3.1 then you don't need extensions. Framebuffer object is part of the 3.1 spec. But keep in mind that merely setting the format to the specific version in the constructor doesn't guarantee you a context with that version. It's just a request and graphics driver is free to give you any other version if what you asked for exactly is not available. You have to check in initializeGL what you actually got by inspecting context()->format().

                      If you're going to read something from a framebuffer in initializeGL you need to first write there something, e.g. call glClear before you start reading anything. Better yet don't do that in initializeGL but where it belongs i.e. in paintGL.

                      This still won't work:

                      GLuint myMultisampleFBO;
                      glGenFramebuffers(1, &myMultisampleFBO);
                      glBindFramebuffer(GL_READ_FRAMEBUFFER, myMultisampleFBO);
                      

                      This does create a buffer object, but the buffer has no color attachments i.e. there's nothing to draw to. You need to attach a texture to it to be able to draw to it.

                      I tried to translate this example

                      That example doesn't apply here one to one. It shows how to blit between two buffers, but you need to understand what is your source and destination. In your code you're creating two buffers and then reading from one to the other. What's the point? There's nothing in them so nothing to read or write to. You want to read from the default framebuffer Qt has created for your window, not some random thing you create.

                      You need to manage the read and write slots i.e. restore them to their original values, otherwise any drawing you do later will not go to the widget but to your buffer.

                      Buffer objects in OpenGL have attachments. You can have depth, stencil and several color attachments for a buffer. To write to a buffer you need at least one color attachment, a 2D texture in your case. Setting that all up manually is a lot of work you can avoid. Qt again provides easy wrapper in form of QOpenGLFramebufferObject. The default constructor sets up a non-MSAA framebuffer with a single 2D texture color attachment. Exactly what you need here.

                      Here's a bare bones example. Context and error checks are omitted for brevity, but you definitely need to do the checks.

                      class OpenGLWidget: public QOpenGLWidget, public QOpenGLExtraFunctions
                      {
                      private:
                          std::unique_ptr<QOpenGLFramebufferObject> fbo;
                      
                      public:
                          OpenGLWidget()
                          {
                              QSurfaceFormat surfaceFormat;
                              surfaceFormat.setSamples(4);
                              setFormat(surfaceFormat);
                          }
                      
                          void initializeGL() override
                          {
                              initializeOpenGLFunctions();
                              glClearColor(0.f, 1.f, 0.f, 1.f);
                      
                              // Create a non-MSAA buffer with a single 1x1 color texture attachment
                              fbo.reset(new QOpenGLFramebufferObject(1,1));
                          }
                      
                          void paintGL() override
                          {
                              // Clear the default framebuffer
                              glClear(GL_COLOR_BUFFER_BIT);
                      
                              // Set draw buffer to be fbo. Read buffer is already the default one
                              glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle());
                      
                              // Blit from the default MSAA buffer to non-MSAA fbo
                              glBlitFramebuffer(0,0,fbo->width(), fbo->height(), 0,0, fbo->width(), fbo->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
                      
                              // Set the draw buffer back to default
                              glBindFramebuffer(GL_DRAW_FRAMEBUFFER, context()->defaultFramebufferObject());
                      
                              // Set read buffer.
                              glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle());
                      
                              // Read the pixel
                              GLubyte pixel[4];
                              glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
                      
                              // Set read buffer back to default
                              glBindFramebuffer(GL_READ_FRAMEBUFFER, context()->defaultFramebufferObject());
                          }
                      };
                      
                      8 2 Replies Last reply 28 Dec 2023, 00:51
                      2
                      • C Chris Kawa
                        26 Dec 2023, 00:16

                        @8Observer8 There are multiple issues in your code.

                        If you can use OpenGL 3.1 then you don't need extensions. Framebuffer object is part of the 3.1 spec. But keep in mind that merely setting the format to the specific version in the constructor doesn't guarantee you a context with that version. It's just a request and graphics driver is free to give you any other version if what you asked for exactly is not available. You have to check in initializeGL what you actually got by inspecting context()->format().

                        If you're going to read something from a framebuffer in initializeGL you need to first write there something, e.g. call glClear before you start reading anything. Better yet don't do that in initializeGL but where it belongs i.e. in paintGL.

                        This still won't work:

                        GLuint myMultisampleFBO;
                        glGenFramebuffers(1, &myMultisampleFBO);
                        glBindFramebuffer(GL_READ_FRAMEBUFFER, myMultisampleFBO);
                        

                        This does create a buffer object, but the buffer has no color attachments i.e. there's nothing to draw to. You need to attach a texture to it to be able to draw to it.

                        I tried to translate this example

                        That example doesn't apply here one to one. It shows how to blit between two buffers, but you need to understand what is your source and destination. In your code you're creating two buffers and then reading from one to the other. What's the point? There's nothing in them so nothing to read or write to. You want to read from the default framebuffer Qt has created for your window, not some random thing you create.

                        You need to manage the read and write slots i.e. restore them to their original values, otherwise any drawing you do later will not go to the widget but to your buffer.

                        Buffer objects in OpenGL have attachments. You can have depth, stencil and several color attachments for a buffer. To write to a buffer you need at least one color attachment, a 2D texture in your case. Setting that all up manually is a lot of work you can avoid. Qt again provides easy wrapper in form of QOpenGLFramebufferObject. The default constructor sets up a non-MSAA framebuffer with a single 2D texture color attachment. Exactly what you need here.

                        Here's a bare bones example. Context and error checks are omitted for brevity, but you definitely need to do the checks.

                        class OpenGLWidget: public QOpenGLWidget, public QOpenGLExtraFunctions
                        {
                        private:
                            std::unique_ptr<QOpenGLFramebufferObject> fbo;
                        
                        public:
                            OpenGLWidget()
                            {
                                QSurfaceFormat surfaceFormat;
                                surfaceFormat.setSamples(4);
                                setFormat(surfaceFormat);
                            }
                        
                            void initializeGL() override
                            {
                                initializeOpenGLFunctions();
                                glClearColor(0.f, 1.f, 0.f, 1.f);
                        
                                // Create a non-MSAA buffer with a single 1x1 color texture attachment
                                fbo.reset(new QOpenGLFramebufferObject(1,1));
                            }
                        
                            void paintGL() override
                            {
                                // Clear the default framebuffer
                                glClear(GL_COLOR_BUFFER_BIT);
                        
                                // Set draw buffer to be fbo. Read buffer is already the default one
                                glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle());
                        
                                // Blit from the default MSAA buffer to non-MSAA fbo
                                glBlitFramebuffer(0,0,fbo->width(), fbo->height(), 0,0, fbo->width(), fbo->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
                        
                                // Set the draw buffer back to default
                                glBindFramebuffer(GL_DRAW_FRAMEBUFFER, context()->defaultFramebufferObject());
                        
                                // Set read buffer.
                                glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle());
                        
                                // Read the pixel
                                GLubyte pixel[4];
                                glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
                        
                                // Set read buffer back to default
                                glBindFramebuffer(GL_READ_FRAMEBUFFER, context()->defaultFramebufferObject());
                            }
                        };
                        
                        8 Offline
                        8 Offline
                        8Observer8
                        wrote on 28 Dec 2023, 00:51 last edited by 8Observer8
                        #11
                        This post is deleted!
                        1 Reply Last reply
                        0
                        • 8 8Observer8 referenced this topic on 28 Dec 2023, 11:34
                        • 8 Offline
                          8 Offline
                          8Observer8
                          wrote on 28 Dec 2023, 11:36 last edited by 8Observer8
                          #12

                          I tried to build for Android but I have errors. I created a new topic: Qt 6.6.1 Buid Error: error: use of undeclared identifier 'GL_DRAW_FRAMEBUFFER'

                          1 Reply Last reply
                          0
                          • C Chris Kawa
                            26 Dec 2023, 00:16

                            @8Observer8 There are multiple issues in your code.

                            If you can use OpenGL 3.1 then you don't need extensions. Framebuffer object is part of the 3.1 spec. But keep in mind that merely setting the format to the specific version in the constructor doesn't guarantee you a context with that version. It's just a request and graphics driver is free to give you any other version if what you asked for exactly is not available. You have to check in initializeGL what you actually got by inspecting context()->format().

                            If you're going to read something from a framebuffer in initializeGL you need to first write there something, e.g. call glClear before you start reading anything. Better yet don't do that in initializeGL but where it belongs i.e. in paintGL.

                            This still won't work:

                            GLuint myMultisampleFBO;
                            glGenFramebuffers(1, &myMultisampleFBO);
                            glBindFramebuffer(GL_READ_FRAMEBUFFER, myMultisampleFBO);
                            

                            This does create a buffer object, but the buffer has no color attachments i.e. there's nothing to draw to. You need to attach a texture to it to be able to draw to it.

                            I tried to translate this example

                            That example doesn't apply here one to one. It shows how to blit between two buffers, but you need to understand what is your source and destination. In your code you're creating two buffers and then reading from one to the other. What's the point? There's nothing in them so nothing to read or write to. You want to read from the default framebuffer Qt has created for your window, not some random thing you create.

                            You need to manage the read and write slots i.e. restore them to their original values, otherwise any drawing you do later will not go to the widget but to your buffer.

                            Buffer objects in OpenGL have attachments. You can have depth, stencil and several color attachments for a buffer. To write to a buffer you need at least one color attachment, a 2D texture in your case. Setting that all up manually is a lot of work you can avoid. Qt again provides easy wrapper in form of QOpenGLFramebufferObject. The default constructor sets up a non-MSAA framebuffer with a single 2D texture color attachment. Exactly what you need here.

                            Here's a bare bones example. Context and error checks are omitted for brevity, but you definitely need to do the checks.

                            class OpenGLWidget: public QOpenGLWidget, public QOpenGLExtraFunctions
                            {
                            private:
                                std::unique_ptr<QOpenGLFramebufferObject> fbo;
                            
                            public:
                                OpenGLWidget()
                                {
                                    QSurfaceFormat surfaceFormat;
                                    surfaceFormat.setSamples(4);
                                    setFormat(surfaceFormat);
                                }
                            
                                void initializeGL() override
                                {
                                    initializeOpenGLFunctions();
                                    glClearColor(0.f, 1.f, 0.f, 1.f);
                            
                                    // Create a non-MSAA buffer with a single 1x1 color texture attachment
                                    fbo.reset(new QOpenGLFramebufferObject(1,1));
                                }
                            
                                void paintGL() override
                                {
                                    // Clear the default framebuffer
                                    glClear(GL_COLOR_BUFFER_BIT);
                            
                                    // Set draw buffer to be fbo. Read buffer is already the default one
                                    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle());
                            
                                    // Blit from the default MSAA buffer to non-MSAA fbo
                                    glBlitFramebuffer(0,0,fbo->width(), fbo->height(), 0,0, fbo->width(), fbo->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
                            
                                    // Set the draw buffer back to default
                                    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, context()->defaultFramebufferObject());
                            
                                    // Set read buffer.
                                    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle());
                            
                                    // Read the pixel
                                    GLubyte pixel[4];
                                    glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
                            
                                    // Set read buffer back to default
                                    glBindFramebuffer(GL_READ_FRAMEBUFFER, context()->defaultFramebufferObject());
                                }
                            };
                            
                            8 Offline
                            8 Offline
                            8Observer8
                            wrote on 29 Dec 2023, 01:40 last edited by 8Observer8
                            #13

                            @Chris-Kawa please, help me with building for Android

                            1 Reply Last reply
                            0

                            5/13

                            24 Dec 2023, 11:01

                            topic:navigator.unread, 8
                            • Login

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