PDA

View Full Version : QGLWidget updateGL()



Lele
29th May 2006, 08:26
Hi all,
I'm working on a custom QGLWidget used to perform 2d display for a camera acquisition.
Basically I grab the image buffer and display in my QGLWidget.
I noticed that if I call a method from my external grabbing thread the updateGL() doesn't work



void MyDisplayGL::DrawBuffer(BYTE* apBuffer)
{
data=apBuffer;
updateGL();
}


The same for all the OpenGL functions (glTexSubImage2D).

So there are three ways for me to do the rendering
- use an internal QTimer that call asyncronusly updateGL()
- call update() method in my DrawBuffer instead of updateGL()
- emit a signal in my DrawBuffer and connect to a slot with updateGL()

But the first method is asyncronous and I should save the buffer(memcpy), the second is much slow and the third doesn't provide a good timing and the video has strange slowings down.

So hoping this small research helps, I'd like to know your opinion about that and to tell my possible mistakes.

Thanks in advance

wysota
29th May 2006, 09:14
I think you should connect updateGL() to a timer and either store the data from the other thread in some kind of queue, so that it won't interfere, or synchronise threads and store image in a shared buffer(but it'll be slower then) -- shared memory could come in handy here, you might even get away with synchronising here -- make buffers separate (so like a queue) and only assign a pointer to the current buffer in a shared variable. You can use Qt atomic operations for that to avoid the need to block the other thread.

Lele
29th May 2006, 10:42
Hi,
thanks for answering,
well what I'm trying to understand is if there is a way to have all OpenGL functions calls (including UpdateGL() which is simply a glDraw) perform correctly when called from an external thread. In fact I believe the problem is when calling those functions from the "outside", if I use the internal Qtimer events everything works nice.
The reason for this is that the external thread must have the control of the display rate in a syncrounous mode, basically it waits until the image is displayed.

wysota
29th May 2006, 12:28
Hi,
thanks for answering,
well what I'm trying to understand is if there is a way to have all OpenGL functions calls (including UpdateGL() which is simply a glDraw) perform correctly when called from an external thread.
No.


The reason for this is that the external thread must have the control of the display rate in a syncrounous mode, basically it waits until the image is displayed.

You can use custom events for that.

Lele
29th May 2006, 13:36
thanks again for answering,
even with custom events there's the same problem, since you cannot send an event from different threads.
Basically I'm looking for a workaround in order to perform UpdateGL() synchronously from different thread.

wysota
29th May 2006, 16:43
thanks again for answering,
even with custom events there's the same problem, since you cannot send an event from different threads.
Yes, you can. postEvent just enqueues an event and the event loop from the thread which owns the receiver will eventually process it.


Basically I'm looking for a workaround in order to perform UpdateGL() synchronously from different thread.
If you want to do it synchronously, you'll have to synchronise threads. And I doubt you want it, as it doesn't make much sense to use threads then.

Why do you want it to be a synchronous call? When some data is ready, just post an event to the GL widget and it will redraw itself ASAP. In the meantime you can continue processing in the worker thread.

Lele
30th May 2006, 13:57
I want to do it synchronously in order to prevent another memcpy of the buffer, I'd like to receive the buffer pointer and write the content directly to the framebuffer of the graphic board. (the display must be as fast as possible, now I have to use update() )
But there's no way to make OpenGl calls work when called from external thread.

wysota
30th May 2006, 15:08
I want to do it synchronously in order to prevent another memcpy of the buffer, I'd like to receive the buffer pointer and write the content directly to the framebuffer of the graphic board. (the display must be as fast as possible, now I have to use update() )
But there's no way to make OpenGl calls work when called from external thread.

It doesn't have to be a synchronous call. Buffers can be allocated dynamically and pushed onto a list or something like that...

Worker thread:

MyBufer *b = new MyBuffer();
b->fillWithData(somedata);
mutex.lock();
bufferqueue.push(b);
mutex.unlock();
//...

Main thread:

mutex.lock();
MyBuffer *buf =bufferqueue.pop();
bufferqueue.clear(); // clear unused items (aka "skip frames")
mutex.unlock();
Display(buf);
//...

Of course the code is simply an idea and not a complete solution. Another possibility would be to use custom events instead of the queue.