Painter object and Rendering Context

In working with the Painter class i found a few different things.

Benoit had suggested that it’s pretty memory intensive to cache all the
display lists for objects. However, it has come to my attention that
DisplayLists live in different GLContext’s. So, what i did was that
each view that gets created shares it’s context with all the other
GLWidgets in the same window. This way we can share the Painter
instances between all GLWidgets and thus the Display Lists. However, it
kinda seems like Painter should check to make sure the context’s are the
same?

Also, there is some good information on OpenGL and threading:
http://doc.trolltech.com/qq/qq06-glimpsing.html

Basically we can split our GL rendering into a separate thread somehow.
This is future stuff way in the future but just stuff i thought i’d
bring to all your attention. I haven’t sat down and thought about how
to make it happen but have it in the back of my mind. The easiest way
coding wise would be to have each widget have it’s own thread for
rendering. It would also work to somehow have a single thread for ALL
glwidgets but that would take some tricky programming.


Donald

On Saturday 19 May 2007 01:11:07 Donald Ephraim Curtis wrote:

In working with the Painter class i found a few different things.

Benoit had suggested that it’s pretty memory intensive to cache all the
display lists for objects. However, it has come to my attention that
DisplayLists live in different GLContext’s. So, what i did was that
each view that gets created shares it’s context with all the other
GLWidgets in the same window.

I think that’s a good idea (use a single context shared across all GLWidgets)
and that’s also what Trolltech recommends to do when using QPainters on
QGLWidgets. So we’re not alone doing things this way :slight_smile:

AFAICS, There’s no reason why the sharing should be limited to all GLWidgets
in the same window. I think we can share the context across all
GLWidgets.

Just FYI, it is in theory possible to let display lists be shared across
contexts, as explained in this page:
http://www.opengl.org/resources/faq/technical/displaylist.htm
However it’s not clear to me if this can be done in a portable way. QtOpenGL
doesn’t seem to support that. But since we share a single context across all
GLWidgets, we don’t need that.

This way we can share the Painter
instances between all GLWidgets and thus the Display Lists. However, it
kinda seems like Painter should check to make sure the context’s are the
same?

I don’t think that can be done easily; I’d rather suggest that libavogadro
itself makes sure that the context is shared. I.e. the GLWidget constructors
should make sure the same context is shared. This way, the rest of
libavogadro could safely assume that there’s only one context.

Also, there is some good information on OpenGL and threading:
http://doc.trolltech.com/qq/qq06-glimpsing.html

Interesting. But there’s something I don’t understand. Looking at
GLThread::run(), this function does nothing to ensure it’s not interrupted by
another thread’s run() function. In their example, this is statistically
almost impossible because of the msleep(40) that thy put at the end. 40
milliseconds is much longer than the execution time of the rest of
GLThread::run(), so GLThread::run() spends most of its time sleeping after it
has completed rendering, and it doesn’t care if it’s interrupted then. As an
experiment, try putting the msleep call near the beginning run() (for
example, right after the makeCurrent() call) instead of at the end of it. I
suspect that rendering will be broken (when there are more than one thread).
And of course, in avogadro we don’t want our threads to sleep at all.

As I said on IRC, GL functions return almost immediately and leave OpenGL
actually execute them in the background (in a separate process). So there’s
not much to gain in threading GL calls. It’s more interesting to thread the
tasks that are computationally intensive for our process.

Cheers,
Benoit

(Sat, May 19, 2007 at 11:19:41AM +0200) Benoît Jacob jacob@math.jussieu.fr:

On Saturday 19 May 2007 01:11:07 Donald Ephraim Curtis wrote:

In working with the Painter class i found a few different things.

Benoit had suggested that it’s pretty memory intensive to cache all the
display lists for objects. However, it has come to my attention that
DisplayLists live in different GLContext’s. So, what i did was that
each view that gets created shares it’s context with all the other
GLWidgets in the same window.

I think that’s a good idea (use a single context shared across all GLWidgets)
and that’s also what Trolltech recommends to do when using QPainters on
QGLWidgets. So we’re not alone doing things this way :slight_smile:

AFAICS, There’s no reason why the sharing should be limited to all GLWidgets
in the same window. I think we can share the context across all
GLWidgets.

Just FYI, it is in theory possible to let display lists be shared across
contexts, as explained in this page:
http://www.opengl.org/resources/faq/technical/displaylist.htm
However it’s not clear to me if this can be done in a portable way. QtOpenGL
doesn’t seem to support that. But since we share a single context across all
GLWidgets, we don’t need that.

This way we can share the Painter
instances between all GLWidgets and thus the Display Lists. However, it
kinda seems like Painter should check to make sure the context’s are the
same?

I don’t think that can be done easily; I’d rather suggest that libavogadro
itself makes sure that the context is shared. I.e. the GLWidget constructors
should make sure the same context is shared. This way, the rest of
libavogadro could safely assume that there’s only one context.

Also, there is some good information on OpenGL and threading:
http://doc.trolltech.com/qq/qq06-glimpsing.html

Interesting. But there’s something I don’t understand. Looking at
GLThread::run(), this function does nothing to ensure it’s not interrupted by
another thread’s run() function. In their example, this is statistically
almost impossible because of the msleep(40) that thy put at the end. 40
milliseconds is much longer than the execution time of the rest of
GLThread::run(), so GLThread::run() spends most of its time sleeping after it
has completed rendering, and it doesn’t care if it’s interrupted then. As an
experiment, try putting the msleep call near the beginning run() (for
example, right after the makeCurrent() call) instead of at the end of it. I
suspect that rendering will be broken (when there are more than one thread).
And of course, in avogadro we don’t want our threads to sleep at all.

all the thread is doing is calling ::swapBuffer which isn’t doing
anything. there is that simple loop “while(running) { … }” or
something like that and yeah, that’s the only opengl call. but yes, i
know exactly what you mean.

As I said on IRC, GL functions return almost immediately and leave OpenGL
actually execute them in the background (in a separate process). So there’s
not much to gain in threading GL calls. It’s more interesting to thread the
tasks that are computationally intensive for our process.

Cheers,
Benoit

all the thread is doing is calling ::swapBuffer which isn’t doing
anything. there is that simple loop “while(running) { … }” or
something like that and yeah, that’s the only opengl call. but yes, i
know exactly what you mean.

Indeed, I had misunderstood something: that the only code that’s executed
repeatedly is the loop while (doRendering).

Now I don’t think anymore that I understand that code! Since the makeCurrent()
call is done only once at the beginning, how is it possible that rendering
always goes to the right glWidget?

I mean, suppose there are three glWidgets. All three call makeCurrent once. So
there are three makeCurrent calls, and the third one overrides the two
previous ones, so all subsequent rendering goes to the third glWidget!

I know I must be wrong so can you explain me my error?

Cheers,
-Benoit

On Sunday 20 May 2007 18:22:08 Donald Ephraim Curtis wrote:

So, swapBuffers() does the following call:

glXSwapBuffers(qt_x11Info(d->paintDevice)->display(),
static_cast<QWidget *>(d->paintDevice)->winId());

I think since it’s expliciting pointing out which buffers to switch it
doesn’t need to worry about context.

OK, so that explains how things work when all rendering is done by QPainter.

But, looking at this code,

    while (doRendering) {
        if (doResize) {
            glViewport(0, 0, w, h);
            doResize = false;
        }
        // Rendering code goes here
        glw->swapBuffers();
        msleep(40);
    }

See the " Rendering code goes here" placeholder? I was assuming this was
intended to be replaced by GL commands. And those could very realistically
get interrupted by another thread, and subsequently render to the wrong
widget.

But yes, if all rendering is done by QPainter, I guess things are OK.

It just wasn’t made clear by this example code that it only works with
QPainter, not with general GL commands.

Benoit