Search code examples
pythonqtqt5qtquick2pyside2

QQuickFrameBufferObject causes crash in PySide2


I am trying to create a simple QQuickFrameBufferObject in order to render some custom opengl textures in Qt Quick. So I decided to test it with PySide2. Here is a simple implementation:

from PySide2.QtQuick import QQuickFramebufferObject
from PySide2.QtGui import QOpenGLFramebufferObjectFormat, QOpenGLFramebufferObject
from PySide2.QtCore import QSize, Qt

class FboRenderer(QQuickFramebufferObject.Renderer):
    def __init__(self, parent=None):
        super().__init__(parent)
        print("Creating renderer")

    def createFrameBufferObject(self, size):
        format = QOpenGLFramebufferObjectFormat()
        format.setAttachment(QOpenGLFramebufferObject.Depth)
        return QOpenGLFramebufferObject(size, format)

    def synchronize(self, item):
        print("Synchronizing")

    def render(self):
        print("Rendering")

class OpenGLCanvas(QQuickFramebufferObject):
    def __init__(self, parent=None):
        super().__init__(parent)

    def createRenderer(self):
        return FboRenderer()

Then to use this in QML I used:

    qmlRegisterType(OpenGLCanvas,"OpenGLCanvas", 1, 0, "OpenGLCanvas")
import QtQuick 2.12
import QtQuick.Window 2.12
import OpenGLCanvas 1.0

Window{
    id: win
    visible: true

    OpenGLCanvas{
        anchors.fill: parent
    }
}

Now the app runs and displays "Creating renderer" but then it crashes after a couple of seconds.


Solution

  • The problem is that FboRenderer() is a local variable that will be destroyed instantly, and therefore it will also destroy the C++ object causing a Segmentation fault since unreserved memory is accessed.

    On the other hand you have a typo in createFrameBufferObject since it must be createFramebufferObject, that also reveals an error similar to the initial error, for this the solution is similar.

    class FboRenderer(QQuickFramebufferObject.Renderer):
        def __init__(self):
            super().__init__()
            print("Creating renderer")
            self._fbos = []
    
        def createFramebufferObject(self, size):
            fmt = QOpenGLFramebufferObjectFormat()
            fmt.setAttachment(QOpenGLFramebufferObject.Depth)
            fbo = QOpenGLFramebufferObject(size, fmt)
            self._fbos.append(fbo)
            return fbo
    
        def synchronize(self, item):
            print("Synchronizing")
    
        def render(self):
            print("Rendering")
    
    
    class OpenGLCanvas(QQuickFramebufferObject):
        def __init__(self, parent=None):
            super().__init__(parent)
            self._renderer = None
    
        def createRenderer(self):
            if self._renderer is None:
                self.renderer = FboRenderer()
            return self.renderer