4

In an OpenGL ES app I'm working on, I noticed that the glReadPixels() function fails to work across all devices/simulators. To test this, I created a bare-bones sample OpenGL app. I set the background color on an EAGLContext context and tried to read the pixels using glReadPixels() as follows:

int bytesPerPixel = 4;
int bufferSize = _backingWidth * _backingHeight * bytesPerPixel;

void* pixelBuffer = malloc(bufferSize);
glReadPixels(0, 0, _backingWidth, _backingHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixelBuffer);

// pixelBuffer should now have meaningful color/pixel data, but it's null for iOS 7 devices

free(pixelBuffer);

This works as expected on the simulator for iOS 6 and 7 and a physical iOS 6 device, but it fails on a physical iOS 7 device. The scenarios tested are shown in the table below (YES/NO = works/doesn't):

Test

I'm using OpenGL ES v1.1 (though v2 also fails to work after a quick test).

Has anyone encountered this problem? Am I missing something? The strangest part of this is that it only fails on iOS 7 physical devices.

Here is a gist with all the relevant code and the bare-bones GitHub project for reference. I've made it very easy to build and demonstrate the issue.

UPDATE:

Here is the updated gist, and the GitHub project has been updated too. I've updated the sample project so that you can easily view the memory output from glReadPixels.

Also, I have a new observation: When the EAGLContext is layer-backed ([self.context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer]), glReadPixels can successfully read data on all devices/simulators (iOS 6 and 7). However, when you toggle the flag in GLView.m so that the context is not layer-backed ([self.context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:nil]), glReadPixels exhibits the condition expressed in the initial post (works on iOS 6 sim/device, iOS 7 sim, but fails on iOS 7 device).

Allen W
  • 3
  • 1
  • 3
Sagar Patel
  • 187
  • 1
  • 10

2 Answers2

3

As posted in the comments I managed to use your code and it worked. However, I defined your BACKING_TYPE_LAYERBACKED which generates the render buffer from the view.

The other pipeline that creates the FBO did not work though. The issue in your FBO pipeline is calling [self.context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:nil]. Remove this line and you should be fine.

Matic Oblak
  • 16,318
  • 3
  • 24
  • 43
  • Thanks! Do you know why that line worked differently in iOS 6 compared to iOS 7? Was the iOS 6 implementation wrong? – Sagar Patel Mar 17 '14 at 21:39
  • 1
    I have no idea, there are no docs about passing a nil parameter. All that says is "the value of this parameter must be a CAEAGLLayer object". Anyway there is no sense in calling it, on iOS 6 it seems to do nothing while on iOS 7 it definitely does something evil :) – Matic Oblak Mar 18 '14 at 07:12
0

To continue from Matic Oblak's answer, for those who might encounter this issue when using a second back buffer( data backed - storage not from layer ) for tasks like object picking, on device, you will need to rebind frameBuffer, renderBuffer and then re-attach renderBuffer to frameBuffer. For e.g the bindBuffers function in gist would be as below

- (void)bindBuffers
{
  glBindFramebufferOES(GL_FRAMEBUFFER_OES, _framebuffer);
  glBindRenderbufferOES(GL_RENDERBUFFER_OES, _renderbuffer);
  glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _renderbuffer);
}
kiranpradeep
  • 10,859
  • 4
  • 50
  • 82