Take the 2-minute tour ×

This has been bugging me recently. It is quite straightforward to put together an OpenGL ES app that supports both portrait and landscape. But during autorotation, the system seems to just forcibly stretch the render buffer to the new dimensions once, autorotate, and then call the usual -layoutSubviews -> -resizeFromLayer: etc. so the drawables can be adjusted to the new viewport dimensions.

Most apps I've seen that support both portrait and landscape seem to settle for this easy approach. But I wonder if I can do better...

Perhaps I should intercept the autorotation before it happens (using UIViewController's usual methods), "expand" once the render buffer to a perfect square of the longest screen size (e.g., 1136px x 1136px on an iPhone 5) - so that it 'bleeds' off screen, perform the autorrotation (no renderbuffer size change and hence no stretching, just as when you switch between e.g. two landscape orientations), and finally adjust the framebuffer again to dispose the invisible, "wasted" margins off screen? (of course I could have a square framebuffer all along, but that would be inefficient fillrate-wise)

Any suggestions? Any better way to accomplish this that I haven't thought about?


I modified my -resizeFromLayer: code as follows:

CGRect bounds = [layer bounds];

// Enlarge layer to square of the longest side:
if (bounds.size.width < bounds.size.height) {
    bounds.size.width = bounds.size.height;
    bounds.size.height = bounds.size.width;

[layer setBounds:bounds];

// Adjust size to match view's layer:
[_mainContext renderbufferStorage:GL_RENDERBUFFER
                         fromDrawable:(CAEAGLLayer*) [_view layer]];

// Query the new size:
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,  &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);

// (etc., you know the drill...)

...And it works! As it stands right now, I have a wasteful, off-screen-bleeding square renderbuffer all along, but this is just a proof of concept. On production code, I would perform said resizing-to-square just before autorotation, and resize back to screen dimesions afterwards.

share|improve this question
I haven't had time to try the approach mentioned above, yet. As soon as I can test it, I'll post the results here. –  NicolasMiari Sep 11 '13 at 12:10
add comment

1 Answer

up vote 2 down vote accepted

I managed to fix this fairly easily in my 3D app by fetching the view size from the GLKView presentationLayer. This will give the current view size during the rotation animation, and the correct projection matrix can be calculated based on this size during the update step. This prevents any incorrect aspect ratio distortion.

If you want to try this, you can add the following lines to the OpenGL Game template in Xcode:

- (void)update
    // get the size from the presentation layer, so that animating does not squish
    CALayer *presentationLayer = [self.view.layer presentationLayer];
    CGSize layerSize = presentationLayer.bounds.size;
    float aspect = fabsf(layerSize.width / layerSize.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);

share|improve this answer
I'm not using GLKit, and I'm not familiar with this -update method; does it get called every frame? –  NicolasMiari Sep 11 '13 at 14:00
Yes. I assume you have an update and render loop for this app, so all you need to do is to get the size of the presentation layer of your CAEAGLLayer in the update loop and use this to calculate your projection matrix. –  Tark Sep 11 '13 at 14:03
Thank you. Although I'm not using GLKit right now, and my own solution seems to do the trick, I'm accepting your answer because it looks clean, complying with the frameworks, and it might come in handy in the near future! –  NicolasMiari Sep 11 '13 at 14:07
Nice trick. And the core idea stands regardless of whether you use GLKit: every layer has a presentationLayer, so whatever your draw code is doing it can use that layer's size to figure out the aspect ratio it should draw at. However, Calculating your projection matrix every frame is needless -- if not performance-killing -- computation. You might consider conditionalizing this so it only happens during rotation (the beginning and end of which you can catch in your view controller). –  rickster Sep 14 '13 at 0:18
@rickster I agree that it is needless to calculate the projection matrix every update step, this is taken directly from the Xcode template as a simple example. I dispute it is a performance killer though, it is just a single tanf and a few divides and multiplies. If you want a simple way to check for animations before adjusting the matrix, you can check if the layer.animationKeys property is non nil. –  Tark Sep 14 '13 at 8:40
show 6 more comments

Your Answer


