PDA

View Full Version : Fast(est) way of drawing simple objects



eperfa
7th April 2011, 00:36
Hi,

I would like to be able to make an item (let's say a rectangle) flash at constant high frequencies on the screen. I know this isn't something that can be solved prefectly (due to the scheduler of the OS, imperfect timing, etc.) but I would like to get fairly good results.

The objects to be drawn are extremely simple, so I guess that most of the time is spent on actually redrawing the image on the screen. For this reason I'd like to ask your opinion on what you think is the fastest method of performing this.

Right now I've come up with something like this:



MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
rect = scene.addRect(QRectF(0, 0, 100, 100), QPen(), Qt::black);

ui->graphicsView->setViewport(new QGLWidget);
ui->graphicsView->setScene(&scene);
ui->graphicsView->show();

timeLine = new QTimeLine(40000, this);
timeLine->setCurveShape(QTimeLine::LinearCurve);
timeLine->setFrameRange(0, 1000);
connect(timeLine, SIGNAL(frameChanged(int)), this, SLOT(updateRect(int)));
timeLine->start();
}

void MainWindow::updateRect(int frame)
{
if (frame % 2)
{
this->rect->setBrush(Qt::blue);
}
else
{
this->rect->setBrush(Qt::black);
}
this->rect->update();
}


This works, but it can be clearly seen that redrawing isn't done "instantaneously". Searching on the forum I've found that OpenGL should be used as the viewport renderer, and it did actually make a difference, but I think this could still be improved.

This is something that is really difficult to measure (I don't really know if this could be measured at all), that's why I ask you to share your thoughts on this matter. If you have something in your mind that you think could significantly improve the drawing performance (throwing out Graphics View in favor of a simple QWidget? using two fixed QPixmaps?), please share it with me.

Thanks,
Adam

tbscope
7th April 2011, 04:22
If you want the code to run real time, that is, without interruptions, keep the code small and keep everything else (events, other programs asking cpu time, ...) to a minimum.

If this is software to test some psychological aspect of a subject, you might want to invest some time in understanding how to use the hardware timers on your system. This will require you to look into the api's of the operating system.

My first try would be a simple subclassed widget.

eperfa
7th April 2011, 22:02
Yes, I know that, however as a first version I wanted to implement something that is platform-independent.

Regarding the timing issues, I have changed from QTimeLine to a simple QTImer implementation (I can't even tell you why it wasn't my first choice), and it also made a difference.


timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateRect()));
timer->start(35);

QTimer *timer2 = new QTimer(this);
timer2->singleShot(2000, this, SLOT(endTest()));


Still, if you have some ideas about optimizing the redrawing itself, I'm open to any suggestions. (I'll try the simple widget method soon)

JohannesMunk
7th April 2011, 23:30
Hi!

Concerning QTimer accuracy: Also we get slightly off topic we get back to it at the end:
http://www.qtcentre.org/threads/40317-frame-rate-and-QTimer-accuracy

So I recommend timer->start(16); That will give you approximately 60 fps. Just change your modulo for slower flips accordingly.

If you want really accurate timing, you will need to sync your updates with the screen refresh. Thats called vertical-sync (vsync) and can easily be enabled on a QGLWidget.



QGLFormat glFormat(QGL::SampleBuffers);
glFormat.setSwapInterval(1);
QGLWidget* glwidget = new QGLWidget(glFormat);
Implement a frames per second counter - while that one is fixed at your screen refresh rate you don't need to worry about faster drawing routines.

You will probably want to subclass a QGLWidget. Manual swapbuffer is shown in the helloGL ES examples shipped with qt. Couldn't find a doc link for them. when vsync is active the call to swapBuffers will not return until the refresh occured. Thats how the timing is going to be very precise. If you update your GLWidget with a timer as the helloGL example does, you should call qApp()->processEvents() somewhere to keep your GUI responsive. The FPS counter implementation of that example is mod 100. You will have to adapt that logic, maybe by starting a custom timer with an intervall of 1000ms and resetting the frames-counter in it.

HIH

Joh

wysota
7th April 2011, 23:45
Still, if you have some ideas about optimizing the redrawing itself, I'm open to any suggestions. (I'll try the simple widget method soon)
I would second what tbscope says - get rid of GraphicsView and use a plain widget.

JohannesMunk
8th April 2011, 06:25
That was quite a cross posting.. Guess I spent too long editing that post.

Joh

eperfa
9th April 2011, 20:24
Thank you guys, especially Joh! That was exactly the knowledge I was missing - I'll definitely give it a try in the next couple of days.