PDA

View Full Version : Checking for gui events



mgb
8th February 2011, 19:35
I have an app that is displaying full HD video at 60fps.
This is maxing out the CPU and since all the display has to be done in the gui thread it is missing any mouse or keyboard events.

I tried putting a QApplication::processEvents() in the paint event but this halves my frame rate. Other than hacks - like calling this every 60frames and living with the glitch, is there a way of quickly checking if any key/mouse event is pending?

high_flyer
8th February 2011, 19:45
The proper way is not doing in on the CPU, but the GPU (OpenGL)

mgb
8th February 2011, 20:13
I am doing it in openGL thats the problem!
Painting a QImage in paintEvent is too slow so I'm doing a full screen openGL texture in paintGL.
Repaint with a QPaintEvent does seem to check mouse/key events but paintGL doesn't

high_flyer
8th February 2011, 20:40
OpenGL doesn't nesseraly runs on the GPU!

In any case since you are using OpenGL you can do the rendering in a worker thread, releasing the GUI thread to be bored with mouse events.
Just take care:


Threading

It is possible to render into a QGLWidget from another thread, but it requires that all access to the GL context is safe guarded. The Qt GUI thread will try to use the context in resizeEvent and paintEvent, so in order for threaded rendering using a GL widget to work, these functions need to be intercepted in the GUI thread and handled accordingly in the application.

wysota
8th February 2011, 20:55
Repaint with a QPaintEvent does seem to check mouse/key events but paintGL doesn't
What exactly do you mean by "does seem to check mouse/key events"? What does painting have to do with handling input events? Aren't you running an endless loop somewhere?

mgb
8th February 2011, 21:08
A new set of 1920x1080x3 pixels arrives at 60hz, I have to get the block of memory and throw it at the screen.
If I override paintEvent() and use Qpainter->drawImage() or Qpixmap::fromImage I manage about 30-40fps.
But at least I have some mouse/keyboard response.

If I use paintGL and draw a full screen texture quad I can get 60fps but any mouse, keyboard events are ignored - unless I explicitly call QApp::processEvents() periodically.

Being able to draw openGL in a non-gui thread might be a usefull approach - I didn't know that was possible.
My problem was that input events have to be processed in the gui thread but it is the gui thread I am maxing out trying to push that many pixels to the screen.

wysota
8th February 2011, 21:12
How exactly are you trying to achieve 60Hz refresh rate? What makes your window refresh?

mgb
8th February 2011, 21:35
The image data arrives from the camera at 60 fps in a separate thread.
I emit() an event when each new frame is buffered and in the gui thread hook that event to repaint.

I also wrap the repaint in a QMutex because if it can't keep up with 60hz you don't want two QPainters running at once.

wysota
8th February 2011, 22:07
And what if something else calls your paint event? This is not a good approach.

Have a variable that will keep the current frame to be displayed. Protect it with a mutex if you wish to feed the frames from a separate thread. Setup a timer that will fire either 60 times per second or every time the application has time to update the widget (which is done by setting the timeout to 0). Have the timer call update() on your widget. In the paint routine read the image data from the variable you have and render it. The variable keeps the current frame to be rendered. If it happens that the application can't keep up the pace, frames will be dropped by overwriting the current frame with a new one. Definitely don't put any mutexes in the paint event unless you have to. This all will make sure all your input events get processed on time.