31

I'm trying to port Apples GLPaint example to use GLKit. Using a UIView, its possible to return the CAEAGLLayer of the view and set the drawableProperties to include kEAGLDrawablePropertyRetainedBacking. This has the effect of retaining the drawable contents after presenting the render buffer, as expected. Removing this property results in flickering after the draw call with part of the drawable content seemingly being drawn to different buffers.

The problem is this is exactly the issue I am now having in my GLKView, but there doesn't seem to be a way to set the drawable properties. Returning a CAEAGLLayer and setting the properties has no effect and I don't see any relevant properties of GLKView to set retained backing.

Has anybody else come across this or have a solution?

danielrvt
  • 10,177
  • 20
  • 80
  • 121
Brett
  • 2,635
  • 22
  • 35
  • i don't have a solution, but be aware that there is a driver bug in the new iPad in retina mode where retained backing mode totally messes up. there's discussion and a workaround here: http://stackoverflow.com/questions/9753230/ipad-3-opengl-bug-with-keagldrawablepropertyretainedbacking-and-retina – orion elenzil May 06 '12 at 05:21
  • are you drawing in the delegate method? Are you using a clear step? – nielsbot Jul 30 '12 at 21:48
  • I don't remember to be honest. I ended up just using a CAEAGLLayer but used GLKit for the matrix math and texture loading. – Brett Jul 31 '12 at 13:49
  • Also, see http://stackoverflow.com/questions/9753230/ipad-3-opengl-bug-with-keagldrawablepropertyretainedbacking-and-retina. It seems that whoever wrote that post knows definitively how to do what you want. – Liron Aug 01 '12 at 14:02

5 Answers5

8

If you want to get kEAGLDrawablePropertyRetainedBacking in a GLKView, add the following category to your project.

@interface CAEAGLLayer (Retained)

@end 

@implementation CAEAGLLayer (Retained)

- (NSDictionary*) drawableProperties
{
    return @{kEAGLDrawablePropertyRetainedBacking : @(YES)};
}

@end

Setting the drawableProperties on the CAEAGLLayer maintained by the GLKView doesn't work because the GLKView overwrites those properties when it binds its drawable and generates its render storage. Using this method forces the GLKView to use your category's returned drawableProperties instead.

simeon
  • 4,466
  • 2
  • 38
  • 42
  • Would this work for reading the depth buffer too? I tried with and without this code, but Z values read are always 0? – Bram Dec 10 '16 at 01:49
7

Simeon's answer works but changes the behavior for all EAGL-based views in an application. I have some views which need the backing forced and others which don't, so I came up with a slightly different solution by creating subclasses of GLKView and CEAGLLayer, like this:

@interface RetainedEAGLLayer : CAEAGLLayer
@end

@implementation RetainedEAGLLayer
- (void)setDrawableProperties:(NSDictionary *)drawableProperties {
    // Copy the dictionary and add/modify the retained property
    NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc] initWithCapacity:drawableProperties.count + 1];
    [drawableProperties enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
        // Copy all keys except the retained backing
        if (![key isKindOfClass:[NSString class]]
        || ![(NSString *)key isEqualToString:kEAGLDrawablePropertyRetainedBacking])
            [mutableDictionary setObject:object forKey:key];
    }];
    // Add the retained backing setting
    [mutableDictionary setObject:@(YES) forKey:kEAGLDrawablePropertyRetainedBacking];
    // Continue
    [super setDrawableProperties:mutableDictionary];
    [mutableDictionary release];
}
@end

and this

@interface RetainedGLKView : GLKView
@end

@implementation RetainedGLKView
+ (Class)layerClass {
    return [RetainedEAGLLayer class];
}
@end

Now I can just use RetainedGLKView instead of GLKView for those views where I want to force a retained backing.

John Stephen
  • 7,625
  • 2
  • 31
  • 45
2

Not sure if this will work but here is some code we have:

GLKView * const view = (GLKView *)self.view;  
view.context = self.context;
view.delegate = self;
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
view.drawableMultisample = GLKViewDrawableMultisampleNone;
self.preferredFramesPerSecond = 30;

[EAGLContext setCurrentContext:self.context];
CAEAGLLayer * const eaglLayer = (CAEAGLLayer*) view.layer;
eaglLayer.opaque = YES;

You should be able to access eaglLayer.drawableProperties. Hopefully that lets you set the parameter you want.

Liron
  • 2,012
  • 19
  • 39
  • This answer doesn't actually work for setting the kEAGLDrawablePropertyRetainedBacking (at least, on iPad 3). The GLKView overwrites the layer properties when it generates the renderBufferStorage from the context. I've posted an answer below that lets you get around this. – simeon Dec 03 '12 at 13:39
1

In your GLKView implementation file:

- (id)initWithCoder:(NSCoder *)aDecoder
{
    if ((self = [super initWithCoder:aDecoder]))
    {
        _eaglLayer = (CAEAGLLayer *)self.layer;

        _eaglLayer.opaque = TRUE;
        _eaglLayer.drawableProperties = @{ kEAGLDrawablePropertyRetainedBacking : [NSNumber numberWithBool:NO],
                                           kEAGLDrawablePropertyColorFormat     : kEAGLColorFormatRGBA8};

    }
    return self;
}

I don't know how people manage to make things so complicated; it's like this, and only this.

James Bush
  • 1,485
  • 14
  • 19
-2

Hi Please try this one

GLKView * const view = (GLKView *)self.view;  
view.context = self.context;
view.delegate = self;
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
view.drawableMultisample = GLKViewDrawableMultisampleNone;
self.preferredFramesPerSecond = 10;

[EAGLContext setCurrentContext:self.context];
CAEAGLLayer * const eaglLayer = (CAEAGLLayer*) view.layer;
vni
  • 56
  • 5