jars121
jars121

Reputation: 1157

Converting QWidget to QOpenGLWidget

I have a PyQt5 application which runs perfectly on my development machine, but has severe performance issues on my target embedded device (Raspberry Pi 2). I ported my application from PySide (Qt4-based) to PyQt5 to enable the use of an eglfs-based build of Qt on the RPi2, in hopes of improving graphical performance (writing directly to the frame buffer with hardware acceleration support), but I haven't yet converted the raster engine-based QWidgets (and associated QPainter() classes) to hardware-accelerated equivalents.

Below is an excerpt of my working Qt4-based QWidget() paintEvent class, which draws a dynamic gauge needle on top of a static .png background:

class Qt4Widget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Qt4Widget, self).__init__(parent)
        self.Background = QtGui.QPixmap("Images/Background.png")

        #Other initialisation activity

    #The paintEvent is called from various Qt4Widget.update(self) calls
    def paintEvent(self, e):
        self.Painter = QtGui.QPainter(self)
        self.Painter.setRenderHint(self.Painter.Antialiasing)

        self.Rect = e.rect()
        self.MainRect = QtCore.QRect(self.Rect)
        self.MainSize = self.MainRect.size()
        self.MainPosition = self.MainRect.center()
        self.MainRect.moveCenter(QtCore.QPoint(self.MainPosition.x()-self.MainSize.width(), self.MainPosition.y()-self.MainSize.height()))

        self.MainRect.setSize(self.MainSize*0.85)
        self.MainRect.moveCenter(self.MainPosition)

        self.RefillRect = QtCore.QRect(self.MainRect)
        self.MainSize = self.RefillRect.size()
        self.MainPosition = self.RefillRect.center()
        self.RefillRect.moveCenter(QtCore.QPoint(self.MainPosition.x()-self.MainSize.width(), self.MainPosition.y()-self.MainSize.height()))

        self.RefillRect.setSize(self.MainSize*0.6)
        self.RefillRect.moveCenter(self.MainPosition)

        self.MainPainter.setPen(QtCore.Qt.NoPen)

        self.MainPainter.drawPixmap(self.Rect, self.Background)

        self.Painter.save()

        self.Gradient = QtGui.QConicalGradient(QtCore.QPointF(self.MainRect.center()), 273.0)
        self.Gradient.setColorAt(.8, QtCore.Qt.white)
        self.Gradient.setColorAt(.4, QtCore.Qt.white)
        self.Gradient.setColorAt(.2, QtCore.Qt.red)
        self.Painter.setBrush(self.Gradient)

        self.Painter.drawPie(self.MainRect, 225.0*16, self.Value*16)
        self.Painter.restore()

        self.Painter.setBrush(QtGui.QBrush(self.Background.scaled(self.Rect.size())))
        self.Painter.drawEllipse(self.RefillRect)

        self.Painter.end()

The application updates the gauge 60 times a second (60Hz display), which is accomplished easily on my development machine. However, when I ran cProfile over 10 seconds worth of execution (600 updates) on the RPi2, it took approximately 50 seconds to complete, with the paintEvent() being a primary bottleneck. I've changed the QT4Widget class to a QOpenGLWidget, but the gauge is not shown, and doesn't produce any errors.

e.g.

class Qt5Widget(QtWidgets.QOpenGLWidget):

Can I use the existing paintEvent QPainter.drawPie, QPainter.drawPixmap and QPainter.drawEllipse functions with QOpenGLWidget, or do I need to start again entirely in order to utilise hardware acceleration with QOpenGLWidget?

EDIT: The Qt5 c++ documentation states the following on the QPainter Class:

OpenGL 2.0 (ES) - This backend is the primary backend for hardware accelerated graphics. It can be run on desktop machines and embedded devices supporting the OpenGL 2.0 or OpenGL/ES 2.0 specification. This includes most graphics chips produced in the last couple of years. The engine can be enabled by using QPainter onto a QOpenGLWidget.

Given this definition, is my approach of maintaining the existing QPainter() functions on a QOpenGLWidget correct? If so, why is nothing displayed?

Upvotes: 2

Views: 1344

Answers (1)

jars121
jars121

Reputation: 1157

As per the QT5 documentation, the QPainter() class can be used on a QOpenGLWidget exactly as it's used on a raster-based QWidget. Therefore, changing all QWidget classes to QOpenGLWidget classes should enable hardware accelerated operation of the QPainter() class, which is what I've found in my instance.

Upvotes: 3

Related Questions