问题
- In my application, I paint a street map using
QPainter
on awidget
- made by
QPainterPaths
that contain precalculated paths to be drawn - the
widget
is currently aQWidget
, not aQGLWidget
, but this might change.
- made by
- I'm trying to move the painting off-screen and split it into chunked jobs
- I want to paint each chunk onto a
QImage
and finally draw all images onto thewidget
QPainterPaths
are already chunked, so this is not the problem- problem is, that drawing on
QImages
is about 5 times slower than drawing onQWidget
- I want to paint each chunk onto a
- Some benchmark testing I've done
- time values are rounded averages over multiple runs
- test chunk contains 100
QPainterPaths
that have about 150 linear line segments each - the roughly 15k paths are drawn with
QPainter::Antialiasing
render hint,QPen
uses round cap and round join
- Remember that my source are
QPainterPaths
(and line width + color; some drawn, some filled)- I don't need all the other types of drawing
QPainter
supports - Can
QPainterPaths
be converted to something else which can be drawn on aOpenGL buffer
, this would be a good solution. - I'm not familiar with
OpenGL
off-screen rendering and I know that there are different types of OpenGL buffers, of which most of them aren't for 2D image rendering but for vertex data.
- I don't need all the other types of drawing
Paint Device for chunk | Rendering the chunk itself | Painting chunk on QWidget
-----------------------+----------------------------+--------------------------
QImage | 2000 ms | < 10 ms
QPixmap (*) | 250 ms | < 10 ms
QGLFramebufferObj. (*) | 50 ms | < 10 ms
QPicture | 50 ms | 400 ms
-----------------------+----------------------------+--------------------------
none (directly on a QWidget in paintEvent) | 400 ms
----------------------------------------------------+--------------------------
(*) These 2 lines have been added afterwards and are solutions to the problem!
It would be nice if you can tell me a non-OpenGL-based solution, too, as I want to compile my application in two versions: OpenGL
and non-OpenGL
version.
Also, I want the solution to be able to render in a non-GUI thread.
Is there a good way to efficiently draw the chunks off-screen?
Is there an off-screen counter part of QGLWidget
(an OpenGL
off-screen buffer) which can be used as a paint device for QPainter
?
回答1:
The document of Qt-interest Archive, August 2008 QGLContext::create()
says:
A QGLContext can only be created with a valid GL paint device, which means it needs to be bound to either a QGLWidget, QGLPixelBuffer or QPixmap when you create it. If you use a QPixmap it will give you software-only rendering, and you don't want that. A QGLFramebufferObject is not in itself a valid GL paint device, it can only be created within the context of a QGLWidget or a QGLPixelBuffer. What this means is that you need a QGLWidget or QGLPixelBuffer as the base for your QGLFramebufferObject.
As the document indicated, if you want to render in an off-screen buffer using opengl, you need QGLPixelBuffer. The code below is a very simple example which demonstrates how to use QGLPixelBuffer with OpenGL:
#include <QtGui/QApplication>
#include <Windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <QtOpenGL/QGLFormat>
#include <QtOpenGL/QGLPixelBuffer>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Construct an OpenGL pixel buffer.
QGLPixelBuffer glPixBuf(100, 100);
// Make the QGLContext object bound to pixel buffer the current context
glPixBuf.makeCurrent();
// The opengl commands
glClearColor(1.0, 1.0, 1.0, 0.0);
glViewport(0, 0, 100, 100);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 100, 0, 100);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0);
glPointSize(4.0);
glBegin(GL_TRIANGLES);
glVertex2i(10, 10);
glVertex2i(50, 50);
glVertex2i(25, 75);
glEnd();
// At last, the pixel buffer was saved as an image
QImage &pImage = glPixBuf.toImage();
pImage.save(QString::fromLocal8Bit("gl.png"));
return a.exec();
}
The result of the program is a png image file as:

For non-opengl version using QPixmap, the code maybe in forms of below:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPixmap pixmap(100, 100);
QPainter painter;
painter.begin(&pixmap);
painter.drawText(10, 45, QString::fromLocal8Bit("I love American."));
painter.end();
pixmap.save(QString::fromLocal8Bit("pixmap.png"));
return a.exec();
}
The result of the program above is a png file looks like:

Though the code is simple, but it works, maybe you can do some changes to make it suitable for you.
来源:https://stackoverflow.com/questions/11474078/efficient-off-screen-rendering-of-qpainterpaths-opengl-and-non-opengl-solution