Graphics caching for fast render: `QPixMap`, `QPainterPath`, `QBackingStore` or OpenGL?
In trying to squeeze performance for #109 I stumbled upon many resources for toying with avoidance of graphics re-drawing/rendering and have now a slew of place to get started if we decide to dig further on this optimization front in the Qt types and apis.
This also pertains to ongoing work discussed in #109 which has since moved to rendering OHLC bars using QPainterPath much like pyqtgraph's internal usage for line plots which are very performant even for moderately sized data sets.
As some preface please note the following:
-
pyqtgraphuses the Graphics View framework internally for which it overrides and extends many types, in particular theGraphicsItemandQGraphicsWidgettypes which serve as the base for almost everything drawn to screen - a primer on modern usage/discussion of
QGraphicsView(make sure to read follow up comments) - knowledge of the
QPainterapi is a must - take a cursory view of the 2d drawing options in
Qtand the 2d painting example - a SO answer of hop tips on speeding up graphics view stuff in
Qt
QPainterPath (what we're using)
-
pyqtgraphuses this internally with a fancy binary-format array generation routine,pg.functions.arrayToQPath(), which streams to the path magically and is quite fast - we've adopted this as the implementation for our internal
BarsItemsgraphics and it seems to be scaling well (at least way better then any other easily testable platform) with renders of 15-20k bars with ~ 3 - 10ms latency depending on how far zoomed out the view is. - we've
numba-ized the binary format array generation which can likely be extended ifarrayToQPath()can be split up into it'snumpyonly andQtonly parts. - appends are supported out of the box using
.addPath()(which we're also using) which avoids having to regenerate path segments previously drawn to screen - use of
QPictureandQPainter.drawPicture()seems to slow this down oddly - the painter paths example is likely relevant reading for newcomers to this api
QBackingStore (what we should probably look into for further speedups)
-
QBackingStoreapi docs - requires use of
QWindowand the raster surface none of which has been tested inside thepyqtgraphecosystem - detailed usage is in the raster window example
- not entirely sure if it's relevant but here is some code inside
pyqtgraphthat offers aQObjectbased canvas api.
OpenGL options in Qt (the distant goals of 3d UX)
- Qt opengl primer
- integration notes
-
pyqtgraphhas internal support for the old API which needs to be updated and tested withQtGui.QOpenGLWidgetin the graphics scene code here (which I've tested but haven't had a GPU rich machine to see if it's better yet) - the OpenGL Window examplge
- the goto resource on learning OpenGL
QPixMap for painting images to screen (likely not what we want at all)
-
api docs for creation and passing to
QPainter.drawPixmap()and redraws withQPainter.play() - originally looked into this due to discussion on forums regarding ways to speed up
QPicturedraws:- ironically, in practice
QPicture.play()seems to be slowing everything down - forum discussion on using pixmaps to do fast drawing for a music app
-
SO question regarding
QPainter"keeping" previous drawings to avoid re-draws -
SO answer on using
QPainterPathoverQLineF(this is actually the eventual solution we came to for bars drawing) -
SO question on how to use the
QPixMapapi - a slew of example code on using the pixmap api
-
SO question on how to update a
QPixmapinside aQGraphicsScene - a tutorial on
QPainterand bitmap graphics -
example C++ code on how to use a
QPixmapfor rendering a magnifying glass thinger
- ironically, in practice
- further resources:
- SO question on merging pictures and images
Oh boy.. and now we have vulkan contenders from the vispy authors..
So I guess on the GL front we have some other stuff to look at.
Some more graphics view hot tips: