Take the 2-minute tour ×

I need to write OpenGL ES 2-dimensional renderer on iOS. It should draw some primitives such as lines and polygons into 2d image (it will be rendering of vector map). Which way is the best for getting image from OpenGL context in that task? I mean, should I render these primitives into texture and then get image from it, or what? Also, it will be great if someone give examples or tutorials which look like the thing I need (2d GL rendering into image). Thanks in advance!

share|improve this question

2 Answers 2

up vote 13 down vote accepted

If you need to render an OpenGL ES 2-D scene, then extract an image of that scene to use outside of OpenGL ES, you have two main options.

The first is to simply render your scene and use glReadPixels() to grab RGBA data for the scene and place it in a byte array, like in the following:

GLubyte *rawImagePixels = (GLubyte *)malloc(totalBytesForImage);
glReadPixels(0, 0, (int)currentFBOSize.width, (int)currentFBOSize.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels);
// Do something with the image

The second, and much faster, way of doing this is to render your scene to a texture-backed framebuffer object (FBO), where the texture has been provided by iOS 5.0's texture caches. I describe this approach in this answer, although I don't show the code for raw data access there.

You do the following to set up the texture cache and bind the FBO texture:

    CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, (__bridge void *)[[GPUImageOpenGLESContext sharedImageProcessingOpenGLESContext] context], NULL, &rawDataTextureCache);
    if (err) 
        NSAssert(NO, @"Error at CVOpenGLESTextureCacheCreate %d");

    // Code originally sourced from http://allmybrain.com/2011/12/08/rendering-to-a-texture-with-ios-5-texture-cache-api/

    CFDictionaryRef empty; // empty value for attr value.
    CFMutableDictionaryRef attrs;
    empty = CFDictionaryCreate(kCFAllocatorDefault, // our empty IOSurface properties dictionary
    attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,


    //CVPixelBufferPoolCreatePixelBuffer (NULL, [assetWriterPixelBufferInput pixelBufferPool], &renderTarget);


    CVOpenGLESTextureRef renderTexture;
    CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault,
                                                  rawDataTextureCache, renderTarget,
                                                  NULL, // texture attributes
                                                  GL_RGBA, // opengl format
                                                  GL_BGRA, // native iOS format
    glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture));

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0);

and then you can just read directly from the bytes that back this texture (in BGRA format, not the RGBA of glReadPixels()) using something like:

    CVPixelBufferLockBaseAddress(renderTarget, 0);
    _rawBytesForImage = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget);
    // Do something with the bytes
    CVPixelBufferUnlockBaseAddress(renderTarget, 0);

However, if you just want to reuse your image within OpenGL ES, you just need to render your scene to a texture-backed FBO and then use that texture in your second level of rendering.

I show an example of rendering to a texture, and then performing some processing on it, within the CubeExample sample application within my open source GPUImage framework, if you want to see this in action.

share|improve this answer
thanks a lot, but does this works only with iOS 5? –  medvedNick May 4 '12 at 20:30
@medvedNick - glReadPixels() works on all OS versions, but the texture caches were only first introduced in iOS 5.0. They are much, much faster, but are 5.0-only. You can do a runtime check, though, and fall back to the slower glReadPixels() on older OS versions. Again, check my GPUImage code, because I do this in there. –  Brad Larson May 4 '12 at 20:55
Texture caches are 5.0 and above, but aren't they fast only on certain devices? e.g. Fast on 4S/iPad2 and equivalent to glReadPixels/glTexImage2D everywhere else –  Rhythmic Fistman May 5 '12 at 6:56
@RhythmicFistman - They are faster than glReadPixels() on every device running 5.0 in my benchmarks, if used properly. You avoid an expensive color conversion and directly access the raw pixel data in memory for a cached texture. I've seen significant benefits on iPad 1 and iPhone 4 (I don't have a 3G S running 5.0, but I've heard good things there, too). –  Brad Larson May 5 '12 at 13:47
No accidental colour conversion is definitely an API bonus. I tried texture caches as a replacement for glTexImage2D in a video player & confusingly the results were indistinguishable from the traditional implementation, not sure what went wrong yet. However I'm confused - if you can directly access the memory of a texture, surely you have hardware support? In any case I plan to revisit them in v1.1, there must be performance gains in there somewhere. –  Rhythmic Fistman May 7 '12 at 15:20

You can draw the image content to a FBO, then read the pixels with glReadPixels.

share|improve this answer
is it the best way for performence? Speed is very important there)) –  medvedNick May 4 '12 at 20:13
glReadPixels in always slow, on texture or when reading from the back buffer. –  demi May 5 '12 at 9:41

Your Answer


