Pushing OpenGL to its limits


#1

I’m currently working on a app that needs 4 or more OpenGLComponents, all located in the same main app window.

I’m using some extra Timer thread to make the OpenGLComponents animate smoothly. Actually I use my own OpenGLComponentEx class, but it’s more or less the same as the JUCE one.

Now my problem: The more OpenGLComponents are on the screen, the slower the animations get. It has nothing to do with the rendering complexity, but it seems that the OpenGL context switching is the culprit. I have tried to share the contexts between each other, but performancewise it didn’t change anything. The only true solution I could imagine is to create an OpenGLComponent type that uses the whole app’s main window size, but whose viewport would be adapted to match the different rectangular areas for drawing as it is being drawn. Is this idea something that is feasible (remember, there will be other components, probably laid over that OpenGL component), or is this approach completely irrealistic? Or maybe, is there another approach, much more simple, I’m not thinking of?

Correct me if I’m wrong, but AFAIK one OpenGL context is always bound to one native window (DC - device context), so it’s not possible to use the same OpenGL context with different native windows.


#2

Well, it seems unlikely you’re actually pushing OpenGL to it’s limits, and if you are, then the juce windows won’t have any effect.

Your idea of a whole screen is interesting, but I wouldn’t be too sure about the culprit. I’d guess you have something simpler going on. Question: what are you running the render calls from? A Timer, or Thread?

Here’s an OpenGL scheme that does work (or did until a tiny change in juce OpenGl context clean-up a while ago):

Roll a thread per OpenGL component. Do all context work - creation, deletion, rendering, on that thread. Work hard to minimize contact between that and the main thread.

The best rule is: one context per thread, one thread per context. Then there’s no switching. You really don’t want to try to move the context between windows, no. I think each OpenGL component actually has it’s own desktop window, so some of that is moot.

I did find that attempts to run OpenGL rendering from a timer is problematic, to say the least. I’ve done with one OGLComponent, but that was borderline.

Bruce


#3

I’ve tried your suggestion, one thread for one context. Doesnt’ make a difference. It really seems that the number of OpenGL contexts per process is the problem, at least on this machine here which has a very old NVIDIA card from 2000 or 2001. I’ll try my very hacky approach then.


#4

Wait - how much VRAM then? If you are running out of video memory, and textures are being switched on and off the card, that will be a huge slowdown. Sharing contexts and just using one set of textures would help in that case.

Bruce


#5

I’m only using 1 very small texture of let’s say 1MB, with very low rendering complexity. I’ve tried sharing the texture, it makes no difference.


#6
struct ScopeContext
{
    OpenGLComponent * component;
    ScopeContext(OpenGLComponent * comp) : component(comp)
    {
        if (component)
        {
            component->makeCurrentContextActive();
            if (component->getCurrentContext()) component->getCurrentContext()->setSwapInterval(1);
        }
    }
    /** This is faster that making the current context active every time, as makeCurrentContextActive takes up to 20ms to complete */
    void reownLostContext()
    {
        if (component && (!component->isActiveContext()))
        {
            component->makeCurrentContextInactive();
            component->makeCurrentContextActive();
            if (component->getCurrentContext()) component->getCurrentContext()->setSwapInterval(1);
        }
    }
    ~ScopeContext() { if (component) component->makeCurrentContextInactive(); }
};