views:

149

answers:

2

I need to read content of CAEAGLLayer, which has various widths and heights (based on background image size). on iPad emulator everything is okay, but on device I have crashes or weird horizontal lines instead of content. Crashes not happens on width, for example, from 537 to 544 pixels

I'm using following code

- (UIImage*)image
{
        // Get the size of the backing CAEAGLLayer
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);

    NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight;
    NSInteger dataLength = width * height * 4;
    GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));

        // Read pixel data from the framebuffer
    glPixelStorei(GL_PACK_ALIGNMENT, 4);
    glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);

        // Create a CGImage with the pixel data
        // If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel
        // otherwise, use kCGImageAlphaPremultipliedLast
    CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
                                    ref, NULL, true, kCGRenderingIntentDefault);

        // OpenGL ES measures data in PIXELS
        // Create a graphics context with the target size measured in POINTS
    NSInteger widthInPoints, heightInPoints;
        // if (NULL != UIGraphicsBeginImageContextWithOptions) {
        // // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
        // // Set the scale parameter to your OpenGL ES view's contentScaleFactor
        // // so that you get a high-resolution snapshot when its value is greater than 1.0
        // CGFloat scale = eaglview.contentScaleFactor;
        // widthInPoints = width / scale;
        // heightInPoints = height / scale;
        // UIGraphicsBeginImageContextWithOptions(CGSizeMake( widthInPoints, heightInPoints), NO, scale);
        // }
        // else {
        // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
    widthInPoints = width;
    heightInPoints = height;
    UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints));
        // }

    CGContextRef cgcontext = UIGraphicsGetCurrentContext();

        // UIKit coordinate system is upside down to GL/Quartz coordinate system
        // Flip the CGImage by rendering it to the flipped bitmap context
        // The size of the destination area is measured in POINTS
    CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
    CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref);

        // Retrieve the UIImage from the current context
    UIImage *image1 = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

        // Clean up
    free(data);
    CFRelease(ref);
    CFRelease(colorspace);
    CGImageRelease(iref);

    return image1;
}
A: 

The view you are reading from, or your drawable area, must be a multiple of 32 (possibly 16, but I haven't tested this yet). Maybe you can try resizing your draw area to a multiple of 32? I had the horizontal line issue previously and resizing the section I was reading from 400x300 to 384x288 fixed everything.

Ginamin
Forgot to add that this only seems to apply to glReadPixels.
Ginamin
Thank you for answer! It is not an option for me - I'm using background image with variable width, so drawable area should be equal to this image. It is a very weird problem. Why 537 works?
Vladimir
Looks like, that multiple of 24 works (RGBA, 4*8?). Maximum buffer width may be 1088. Now, it is solved my problem, Thank you, Ginamin!
Vladimir
No worries! I had considered that any multiple of 2 would work. However, when I tried this it still biffed at 400x300. I'm not exactly sure why this happens...
Ginamin
just found, that 816 does not working. So only 32 multiplier works. And occasional 24/16. For OpenGL (not iOS), I found, that this problem is linked with buffer alignment. But iOS does not have additional alignment parameters, provided by other platforms
Vladimir
Yes, I also tried a 24 last night (800x600) and I couldn't get it running. Good note on the buffer alignment. Thanks!
Ginamin
A: 

Thanks a ton Ginamin! I was getting nightmares with this issue and your fix solved it.

I just wanted to know whether this a documented limitation by Apple/OpenGL or not? I didnt find this anywhere else.

Sanyam Bhasin
I didn't found any description of this problem in documentation. At least in 3.2.2 this problem is exists.
Vladimir