views:

482

answers:

3

I have a simple iPhone application which uses OpenGL ES (v1) to draw a line based on the touches of the user. In the XCode Simulator, the code works perfectly. However, when I install the app onto an iPod or iPhone, the OpenGL ES view "flashes" when drawing the line. If I disable the line drawing, the flash disappears. By "flash", I mean that the background image (which is an OpenGL texture) disappears momentarily, and then reappears. It appears as if the entire scene is completely erased and redrawn.

The code which handles the line drawing is the following:

renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end
{
    static GLfloat*       vertexBuffer = NULL;
    static NSUInteger vertexMax = 64;
    NSUInteger            vertexCount = 0,
    count,
    i;

    //Allocate vertex array buffer
    if(vertexBuffer == NULL)
        vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));

    //Add points to the buffer so there are drawing points every X pixels
    count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / kBrushPixelStep), 1);
    for(i = 0; i < count; ++i) {
        if(vertexCount == vertexMax) {
            vertexMax = 2 * vertexMax;
            vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));
        }

        vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count);
        vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count);
        vertexCount += 1;
    }

    //Render the vertex array
    glVertexPointer(2, GL_FLOAT, 0, vertexBuffer);
    glDrawArrays(GL_POINTS, 0, vertexCount);

    //Display the buffer
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}

(This function is based on the function of the same name from the GLPaint sample application.) For the life of me, I can not figure out why this causes the screen to flash. The line is drawn properly (both in the Simulator and in the iPod). But, the flash makes it unusable.

Anyone have ideas on how to prevent the "flash"?

A: 

I had exactly the same problem once. I had a UIWindow, in which I placed an OpenGLES UIView. The drawing process was nice, until I tried to add a subview (UIImageView) in the OpenGLES view. The screen was flashing. I was able to fix the problem by adding the UIImageView as a subview of the UIWindow instead. It seems the OpenGLES rendering doesn't like subviews...

So in your OpenGLES view, if you have something like:

[ self addSubView: ... ]

You can replace it, for instance, by:

[ self.superview addSubView: ... ]

Can't see in your code if you have similar stuff, but I hope this will help a bit... : )

Macmade
A: 

After much testing, I have found a solution to this issue, although I'm not sure if it's a best-practice.

The solution was changing the kEAGLDrawablePropertyRetainedBacking from NO to YES. This stopped the flashing. Specifically, the code to setup the OpenGL view now looks like this:

CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithBool:YES], 
                                kEAGLDrawablePropertyRetainedBacking, 
                                kEAGLColorFormatRGB565, kEAGLDrawablePropertyColorFormat, nil];

Again, I'm not sure if it's a best practice to use the RetainedBacking strategy, but it stopped the flashing. According to http://developer.apple.com/iphone/library/documentation/iPhone/Reference/EAGLDrawable_Ref/EAGLDrawable/EAGLDrawable.html#jumpTo_6 one should set RetainedBacking to YES only in certain circumstances.

Setting the value to YES is recommended only when you need the content to remain unchanged, as using it can result in both reduced performance and additional memory usage.

It's not clear how the performance or memory is impacted, but this one change completely stopped all "flashing" that I was seeing.

Dave Viner
This is almost definitely not the correct solution. You are just masking the problem. I went through this once too and initially came to the same conclusion.
Rob Jones
A: 

Is it possible you are calling glRenderBuffer() and sending the presentRenderBuffer message to your EAGLContext without having done any OpenGL updates, that is, no new glDrawElements or glDrawArrays. Perhaps you are sending the presentRenderBuffer message at another point in your code? If you do this without kEAGLDrawablePropertyRetainedBacking set to YES, then you can get an annoying flicker.

Take a look a the kEAGLDrawablePropertyRetainedBacking on your CAEAGLLayer's drawableProperties property. This property determines the behavior of the drawable surface after it has displayed its contents. If this property is set to NO, then the contents are not retained and therefore not guaranteed to remain unchanged after display. If you set it to YES, then the contents are retained and will remain unchanged after display.

I believe setting kEAGLDrawablePropertyRetainedBacking to YES will mask the issue, but not fix it.

Rob Jones