OpenGL confusion


#1

On iOS, I was playing around with OpenGL a bit to see if I could get really smooth animations. The idea is to have a circle that follows the finger movements and also bounces around a bit after “finger-up”. Anyway, using only a content component that is an OpenGLRenderer, just like in the demo, and painting the circle in renderOpenGL using a LowLevelGraphicsContext, again just like in the demo, everything works great, with fps of about 60. However, ultimately I’d like to use child components, so I created a “small circle component” that simply draws that same circle at its current position. Now here’s the issue: when I make the small circle component an ordinary component with a paint() routine, things are significantly less smooth compared to the previous approach. Shouldn’t it be equally fast, now that all child components are being drawn using OpenGL as well? And if I try to make the small circle component an OpenGLRenderer itself, it doesn’t get drawn at all. So the question is, is there a way to have a parent component/OpenGLRenderer with various child components that can be animated as smoothly as if the content of the child components was rendered directly into the parent component?


#2

Digging the juce_OpenGLContext.cpp, found this:

    void waitForNextFrame (const uint32 frameRenderStartTime)
    {
        const int defaultFPS = 60;

        const int elapsed = (int) (Time::getMillisecondCounter() - frameRenderStartTime);
        wait (jmax (1, (1000 / defaultFPS - 1) - elapsed));
    }

Nasty boy… :slight_smile:

P.S. did you ever gain something like this?


#3

Well, 60 fps is definitely sufficient, that’s not the issue… :smiley:

Doing some more research, this is what I was getting at: http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=9476&hilit=OpenGL . Jules, it seems this is still an open issue at the moment? I should mention that things can be made much smoother already by setting setComponentPaintingEnabled(false) in the parent component and calling

void ContentComponent::renderOpenGL()
{
    OpenGLHelpers::clear (Colours::white);
    MessageManagerLock mm (Thread::getCurrentThread());
    if (! mm.lockWasGained())
        return;
    ScopedPointer<LowLevelGraphicsContext> glRenderer(createOpenGLGraphicsContext (openGLContext));
    
    if (glRenderer != nullptr)
    {
        Graphics g (glRenderer);
       //.. 
       //paint the background stuff here and then...
       //.. 
       paintEntireComponent(g, false);
    }
    
}

With this approach, all child components still have to be ordinary components, i.e. not OpenGLRenderers. Like I said, this definitely improves the situation but whenever one of the child components is moved, the setBounds method triggers a non-OpenGL-repaint, so it would be really desirable to have the possibility for having child components that are pure OpenGLRenderers.


#4

Sorry, really struggling to make sense of what you’re asking/suggesting, and how it relates to the other thread you linked to…?


#5

Ok, I probably didn’t explain it very well, let’s see:

  • Situation A: the whole app is made up by just a content component, which is an OpenGLRenderer. It paints some animated geometric figures, for instance a circle that follows your finger and keeps moving after releasing the finger. All is well and smooth.
  • Situation B: However, in a real app you’d usually want to make the geometric figures child components and make use of their mouse interaction methods etc. So now they are no longer painted in the renderOpenGL method of the content component, but in their respective paint methods, and the app slows down considerably. Ideally one would think that the child components could be OpenGLRenderers as well, but this seems not yet possible in JUCE. Alternatively, for the moment, we can use
  • Situation C, which is shown in the piece of code in my last code. Here, the automatic painting of the child components is switched off, using SetComponentPaintingEnabled(false). Instead, call paintEntireComponent in the renderOpenGL routine of the content component, which basically inlines the paint routines of the child components in the renderOpenGL routine of the content component. I was surprised initially that situation B and C really differ, but there seem to be some extra calls when SetComponentPainting is enabled, which, at least on iOS, make a noticable difference.

So the suggestion, like in the thread I linked to, is to allow for child components being pure OpenGLRenderers, without a paint routine. Does this make things clearer? :slight_smile:


#6

Yep, I see. It’s certainly an area I want to get deeper into, as I think it’s going to be the best way to get good performance in the future, but obviously needs some refinement.


#7

Great! On a related note, I’m trying to make some sense of the OpenGL redundancy/inefficiency warnings that XCode gives me when using the profiler. I’m not too deep in the OpenGL code, but one redundant call I have identified is glViewport (0, 0, viewportArea.getWidth(), viewportArea.getHeight()); at line 161 of juce_OpenGLContext.cpp (latest tip). It seems that this call should indeed be made only once, not for every frame?


#8

Well, the second glviewport call may often be redundant, but it can’t be removed because the renderOpenGL callback could have changed the viewport.

Looking at the code, I could improve it a bit by moving the first one like this:

[code] JUCE_CHECK_OPENGL_ERROR

    if (context.renderer != nullptr)
    {
        glViewport (0, 0, viewportArea.getWidth(), viewportArea.getHeight());
        context.renderer->renderOpenGL();[/code]

#9

Ok… here’s another observation: somewhere between 2.0.27 and 2.0.31, a lot of drawing efficiency has been lost. With 2.0.27 I was able to draw a draggable OpenGL-image with 60 fps. Now, it’s only 15-20 fps, if the image is reasonably large. The recent changes in JUCE targeted at correctly scaling the desktop for retina devices seem like a possible suspect, but this is actually on an iPhone4 (running iOS 6.0.1), i.e. a non-retina device…


#10

The iPhone 4 is the first retina device.


#11

Can’t think of any changes that would be relevant, but if you’re running at 4x the resolution, and getting 4x slower performance, that sounds fair enough.

Haven’t you tried profiling it to see what the hotspots are?


#12

You’re right… :oops: Somehow I thought the 4S was the first one. So the scaling probably is the likely explanation, but the situation is not satisfactory, of course. XCode’s profiler states, unsurprisingly, that 92% of CPU is needed for drawImageAt…


#13

Odd… drawImageAt should be extremely fast for GL.

If it’s a normal software-based image, it might just be uploading it each time you draw. I’m planning to do some image-caching that’ll help with that.


#14

No, it’s an OpenGLImageType…


#15

Here’s some output from XCode’s OpenGL performance analyzer:

EDIT: depending on the mood of XCode, I also get “Performance is limited by the GPU texture lookup. This texture uses 8-bits per channel for RGB or RGBA data. If the image quality is acceptable, save memory by using a compressed or 16-bit per pixel format.”. Just saying…

I’m still not fluent enough in OpenGL to know whether this is really helpful… what do you think?