PyQT5 OpenGL 4.1 Primary Profile - Invalid Frame Buffer Operation - Mac OS

This question may be related to another SO question .

I am running MacOS 10.11.2 El Capitan. Desiring the rich GUI features around my OpenGL applications, I decided to give PyQT5 a shot at creating an OpenGL context so that I can integrate OpenGL into QtWidget in a graphical application.

QT5 provides several API methods for QGlWidget , which I will summarize here:

  • initializeGL: called once before paintGL
  • paintGL: place to draw material in the active frame buffer

I can create a widget and initialize shaders, etc. But when it comes to framebuffer related operations, such as glClearan error appears:

File "errorchecker.pyx", line 53, in OpenGL_accelerate.errorchecker._ErrorChecker.glCheckError (src/errorchecker.c:1218)

OpenGL.error.GLError: GLError(
    err = 1286,
    description = 'invalid framebuffer operation',
    baseOperation = glClear,
    cArguments = (GL_COLOR_BUFFER_BIT,)
)

, . , API. , QT, framebuffer . , API . , , , paintGL NSKIP_PAINTGL=3 . , paintGL . , . , NSKIP_PAINTGL , sleep . , QT . , QT ? QOpenGLWidget , - :

0, .

, , . ( , QT paintGL , ). QT , :

- , , QGLControllerWidget, updateGL, try/catch, , GlError? QOpenGLWidget::defaultFramebufferObject() .

, QT - , .

- ? PyQT - , OpenGL API , ?

, Mac:

from PyQt5 import QtGui, QtCore, QtOpenGL, QtWidgets
from PyQt5.QtOpenGL import QGLWidget
from OpenGL.GL import *

from time import sleep

NSKIP_PAINTGL = 3

class QGLControllerWidget(QGLWidget):
    """
    basic test widget: a black screen which clears
    framebuffer on paintGL event so it should stay
    black on resize and so on.
    """
    def __init__(self, format = None):
        super(QGLControllerWidget, self).__init__(format, None)

        self._weird_pyqt5_framebuffer_hack = 0

        # replace paintGL by workaround
        self._weird_pyqt5_framebuffer_hack_original_paintGL = self.paintGL
        self.paintGL = self._weird_pyqt5_framebuffer_hack_paintGL

    def initializeGL(self): 
        pass

    def _weird_pyqt5_framebuffer_hack_paintGL(self):
        self._weird_pyqt5_framebuffer_hack += 1 
        if self._weird_pyqt5_framebuffer_hack < NSKIP_PAINTGL:
            return

        sleep(0.1)
        # restore original paintGL
        self.paintGL = self._weird_pyqt5_framebuffer_hack_original_paintGL
        self.updateGL()

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT)

if __name__ == '__main__':
    import sys

    class QTWithGLTest(QtWidgets.QMainWindow):
        def __init__(self, parent = None):
            super(QTWithGLTest, self).__init__(parent)

            # MacOS core profile 4.1
            qgl_format = QtOpenGL.QGLFormat()
            qgl_format.setVersion(4, 1)
            qgl_format.setProfile(QtOpenGL.QGLFormat.CoreProfile)
            qgl_format.setSampleBuffers(True)

            self.widget = QGLControllerWidget(qgl_format)
            self.setCentralWidget(self.widget)

            self.show()

    app = QtWidgets.QApplication(sys.argv)
    window = QTWithGLTest()
    window.show()
    app.exec_()

, ++, python.

+4
1

QGL* Qt5. , paintGL() . QOpenGLWidget QOpenGLWindow .

isValid() paintGL() , :

def paintGL(self):
    if not self.isValid():
        return

QOpenGLWidget, :

#!/usr/bin/env python

from PyQt5.QtGui import (
        QOpenGLBuffer,
        QOpenGLShader,
        QOpenGLShaderProgram,
        QOpenGLVersionProfile,
        QOpenGLVertexArrayObject,
        QSurfaceFormat,
    )
from PyQt5.QtWidgets import QApplication, QMainWindow, QOpenGLWidget


class QTWithGLTest(QMainWindow):
    """Main window."""

    def __init__(self, versionprofile=None, *args, **kwargs):
        """Initialize with an OpenGL Widget."""
        super(QTWithGLTest, self).__init__(*args, **kwargs)

        self.widget = QOpenGLControllerWidget(versionprofile=versionprofile)
        self.setCentralWidget(self.widget)
        self.show()


class QOpenGLControllerWidget(QOpenGLWidget):
    """Widget that sets up specific OpenGL version profile."""

    def __init__(self, versionprofile=None, *args, **kwargs):
        """Initialize OpenGL version profile."""
        super(QOpenGLControllerWidget, self).__init__(*args, **kwargs)

        self.versionprofile = versionprofile

    def initializeGL(self):
        """Apply OpenGL version profile and initialize OpenGL functions."""
        self.gl = self.context().versionFunctions(self.versionprofile)
        if not self.gl:
            raise RuntimeError("unable to apply OpenGL version profile")

        self.gl.initializeOpenGLFunctions()

        self.createShaders()
        self.createVBO()
        self.gl.glClearColor(0.0, 0.0, 0.0, 0.0)

    def paintGL(self):
        """Painting callback that uses the initialized OpenGL functions."""
        if not self.gl:
            return

        self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT)
        self.gl.glDrawArrays(self.gl.GL_TRIANGLES, 0, 3)

    def resizeGL(self, w, h):
        """Resize viewport to match widget dimensions."""
        self.gl.glViewport(0, 0, w, h)

    def createShaders(self):
        ...

    def createVBO(self):
        ...


if __name__ == '__main__':
    import sys

    fmt = QSurfaceFormat()
    fmt.setVersion(4, 1)
    fmt.setProfile(QSurfaceFormat.CoreProfile)
    fmt.setSamples(4)
    QSurfaceFormat.setDefaultFormat(fmt)

    vp = QOpenGLVersionProfile()
    vp.setVersion(4, 1)
    vp.setProfile(QSurfaceFormat.CoreProfile)

    app = QApplication(sys.argv)
    window = QTWithGLTest(versionprofile=vp)
    window.show()
    sys.exit(app.exec_())

, OpenGL, Qt, . OpenGL.GL, (Qt , GL). OpenGL.GL, , QOpenGLVersionProfile, versionprofile, versionFunctions, initializeOpenGLFunctions self.gl.

+2

All Articles