iOS: Fixed some cases where SDL_DestroyWindow or SDL_GL_DeleteContext can cause crashes.
authorAlex Szpakowski <slime73@gmail.com>
Tue, 09 Jun 2015 21:08:24 -0300
changeset 9727b845f659e015
parent 9726 c45180a5db6e
child 9728 161fee58e36f
iOS: Fixed some cases where SDL_DestroyWindow or SDL_GL_DeleteContext can cause crashes.
src/video/uikit/SDL_uikitopengles.m
src/video/uikit/SDL_uikitopenglview.h
src/video/uikit/SDL_uikitopenglview.m
src/video/uikit/SDL_uikitview.m
src/video/uikit/SDL_uikitwindow.m
     1.1 --- a/src/video/uikit/SDL_uikitopengles.m	Tue Jun 09 21:06:55 2015 +0200
     1.2 +++ b/src/video/uikit/SDL_uikitopengles.m	Tue Jun 09 21:08:24 2015 -0300
     1.3 @@ -34,6 +34,24 @@
     1.4  #include "SDL_loadso.h"
     1.5  #include <dlfcn.h>
     1.6  
     1.7 +@interface SDLEAGLContext : EAGLContext
     1.8 +
     1.9 +/* The OpenGL ES context owns a view / drawable. */
    1.10 +@property (nonatomic, strong) SDL_uikitopenglview *sdlView;
    1.11 +
    1.12 +@end
    1.13 +
    1.14 +@implementation SDLEAGLContext
    1.15 +
    1.16 +- (void)dealloc
    1.17 +{
    1.18 +    /* When the context is deallocated, its view should be removed from any
    1.19 +     * SDL window that it's attached to. */
    1.20 +    [self.sdlView setSDLWindow:NULL];
    1.21 +}
    1.22 +
    1.23 +@end
    1.24 +
    1.25  static int UIKit_GL_Initialize(_THIS);
    1.26  
    1.27  void *
    1.28 @@ -117,12 +135,17 @@
    1.29  UIKit_GL_CreateContext(_THIS, SDL_Window * window)
    1.30  {
    1.31      @autoreleasepool {
    1.32 +        SDLEAGLContext *context = nil;
    1.33          SDL_uikitopenglview *view;
    1.34          SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata;
    1.35          CGRect frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen);
    1.36          EAGLSharegroup *sharegroup = nil;
    1.37          CGFloat scale = 1.0;
    1.38  
    1.39 +        /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES
    1.40 +         * versions. */
    1.41 +        EAGLRenderingAPI api = _this->gl_config.major_version;
    1.42 +
    1.43          if (_this->gl_config.share_with_current_context) {
    1.44              EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext();
    1.45              sharegroup = context.sharegroup;
    1.46 @@ -142,6 +165,12 @@
    1.47              }
    1.48          }
    1.49  
    1.50 +        context = [[SDLEAGLContext alloc] initWithAPI:api sharegroup:sharegroup];
    1.51 +        if (!context) {
    1.52 +            SDL_SetError("OpenGL ES %d context could not be created", _this->gl_config.major_version);
    1.53 +            return NULL;
    1.54 +        }
    1.55 +
    1.56          /* construct our view, passing in SDL's OpenGL configuration data */
    1.57          view = [[SDL_uikitopenglview alloc] initWithFrame:frame
    1.58                                                      scale:scale
    1.59 @@ -153,13 +182,15 @@
    1.60                                                  depthBits:_this->gl_config.depth_size
    1.61                                                stencilBits:_this->gl_config.stencil_size
    1.62                                                       sRGB:_this->gl_config.framebuffer_srgb_capable
    1.63 -                                             majorVersion:_this->gl_config.major_version
    1.64 -                                               shareGroup:sharegroup];
    1.65 +                                                  context:context];
    1.66 +
    1.67          if (!view) {
    1.68              return NULL;
    1.69          }
    1.70  
    1.71 -        SDLEAGLContext *context = view.context;
    1.72 +        /* The context owns the view / drawable. */
    1.73 +        context.sdlView = view;
    1.74 +
    1.75          if (UIKit_GL_MakeCurrent(_this, window, (__bridge SDL_GLContext) context) < 0) {
    1.76              UIKit_GL_DeleteContext(_this, (SDL_GLContext) CFBridgingRetain(context));
    1.77              return NULL;
    1.78 @@ -175,11 +206,10 @@
    1.79  UIKit_GL_DeleteContext(_THIS, SDL_GLContext context)
    1.80  {
    1.81      @autoreleasepool {
    1.82 -        /* Transfer ownership the +1'd context to ARC. */
    1.83 -        SDLEAGLContext *eaglcontext = (SDLEAGLContext *) CFBridgingRelease(context);
    1.84 -
    1.85 -        /* Detach the context's view from its window. */
    1.86 -        [eaglcontext.sdlView setSDLWindow:NULL];
    1.87 +        /* The context was retained in SDL_GL_CreateContext, so we release it
    1.88 +         * here. The context's view will be detached from its window when the
    1.89 +         * context is deallocated. */
    1.90 +        CFRelease(context);
    1.91      }
    1.92  }
    1.93  
     2.1 --- a/src/video/uikit/SDL_uikitopenglview.h	Tue Jun 09 21:06:55 2015 +0200
     2.2 +++ b/src/video/uikit/SDL_uikitopenglview.h	Tue Jun 09 21:08:24 2015 -0300
     2.3 @@ -26,14 +26,6 @@
     2.4  #import "SDL_uikitview.h"
     2.5  #include "SDL_uikitvideo.h"
     2.6  
     2.7 -@class SDL_uikitopenglview;
     2.8 -
     2.9 -@interface SDLEAGLContext : EAGLContext
    2.10 -
    2.11 -@property (nonatomic, weak) SDL_uikitopenglview *sdlView;
    2.12 -
    2.13 -@end
    2.14 -
    2.15  @interface SDL_uikitopenglview : SDL_uikitview
    2.16  
    2.17  - (instancetype)initWithFrame:(CGRect)frame
    2.18 @@ -46,10 +38,9 @@
    2.19                      depthBits:(int)depthBits
    2.20                    stencilBits:(int)stencilBits
    2.21                           sRGB:(BOOL)sRGB
    2.22 -                 majorVersion:(int)majorVersion
    2.23 -                   shareGroup:(EAGLSharegroup*)shareGroup;
    2.24 +                      context:(EAGLContext *)glcontext;
    2.25  
    2.26 -@property (nonatomic, readonly, strong) SDLEAGLContext *context;
    2.27 +@property (nonatomic, readonly, weak) EAGLContext *context;
    2.28  
    2.29  /* The width and height of the drawable in pixels (as opposed to points.) */
    2.30  @property (nonatomic, readonly) int backingWidth;
    2.31 @@ -59,7 +50,6 @@
    2.32  @property (nonatomic, readonly) GLuint drawableFramebuffer;
    2.33  
    2.34  - (void)swapBuffers;
    2.35 -- (void)setCurrentContext;
    2.36  
    2.37  - (void)updateFrame;
    2.38  
     3.1 --- a/src/video/uikit/SDL_uikitopenglview.m	Tue Jun 09 21:06:55 2015 +0200
     3.2 +++ b/src/video/uikit/SDL_uikitopenglview.m	Tue Jun 09 21:08:24 2015 -0300
     3.3 @@ -27,10 +27,6 @@
     3.4  #import "SDL_uikitopenglview.h"
     3.5  #include "SDL_uikitwindow.h"
     3.6  
     3.7 -@implementation SDLEAGLContext
     3.8 -
     3.9 -@end
    3.10 -
    3.11  @implementation SDL_uikitopenglview {
    3.12      /* The renderbuffer and framebuffer used to render to this layer. */
    3.13      GLuint viewRenderbuffer, viewFramebuffer;
    3.14 @@ -61,26 +57,20 @@
    3.15                      depthBits:(int)depthBits
    3.16                    stencilBits:(int)stencilBits
    3.17                           sRGB:(BOOL)sRGB
    3.18 -                 majorVersion:(int)majorVersion
    3.19 -                   shareGroup:(EAGLSharegroup*)shareGroup
    3.20 +                      context:(EAGLContext *)glcontext
    3.21  {
    3.22      if ((self = [super initWithFrame:frame])) {
    3.23          const BOOL useStencilBuffer = (stencilBits != 0);
    3.24          const BOOL useDepthBuffer = (depthBits != 0);
    3.25          NSString *colorFormat = nil;
    3.26  
    3.27 -        /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES
    3.28 -         * versions, and this allows us to handle future OpenGL ES versions. */
    3.29 -        EAGLRenderingAPI api = majorVersion;
    3.30 +        context = glcontext;
    3.31  
    3.32 -        context = [[SDLEAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
    3.33          if (!context || ![EAGLContext setCurrentContext:context]) {
    3.34 -            SDL_SetError("OpenGL ES %d not supported", majorVersion);
    3.35 +            SDL_SetError("Could not create OpenGL ES drawable (could not make context current)");
    3.36              return nil;
    3.37          }
    3.38  
    3.39 -        context.sdlView = self;
    3.40 -
    3.41          if (sRGB) {
    3.42              /* sRGB EAGL drawable support was added in iOS 7. */
    3.43              if (UIKit_IsSystemVersionAtLeast(7.0)) {
    3.44 @@ -209,11 +199,6 @@
    3.45      }
    3.46  }
    3.47  
    3.48 -- (void)setCurrentContext
    3.49 -{
    3.50 -    [EAGLContext setCurrentContext:context];
    3.51 -}
    3.52 -
    3.53  - (void)swapBuffers
    3.54  {
    3.55      /* viewRenderbuffer should always be bound here. Code that binds something
    3.56 @@ -264,7 +249,7 @@
    3.57  
    3.58  - (void)dealloc
    3.59  {
    3.60 -    if ([EAGLContext currentContext] == context) {
    3.61 +    if (context && context == [EAGLContext currentContext]) {
    3.62          [self destroyFramebuffer];
    3.63          [EAGLContext setCurrentContext:nil];
    3.64      }
     4.1 --- a/src/video/uikit/SDL_uikitview.m	Tue Jun 09 21:06:55 2015 +0200
     4.2 +++ b/src/video/uikit/SDL_uikitview.m	Tue Jun 09 21:08:24 2015 -0300
     4.3 @@ -62,6 +62,7 @@
     4.4          return;
     4.5      }
     4.6  
     4.7 +    /* Remove ourself from the old window. */
     4.8      if (sdlwindow) {
     4.9          SDL_uikitview *view = nil;
    4.10          data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
    4.11 @@ -71,9 +72,7 @@
    4.12          [self removeFromSuperview];
    4.13  
    4.14          /* Restore the next-oldest view in the old window. */
    4.15 -        if (data.views.count > 0) {
    4.16 -            view = data.views[data.views.count - 1];
    4.17 -        }
    4.18 +        view = data.views.lastObject;
    4.19  
    4.20          data.viewcontroller.view = view;
    4.21  
    4.22 @@ -83,6 +82,7 @@
    4.23          [data.uiwindow layoutIfNeeded];
    4.24      }
    4.25  
    4.26 +    /* Add ourself to the new window. */
    4.27      if (window) {
    4.28          data = (__bridge SDL_WindowData *) window->driverdata;
    4.29  
     5.1 --- a/src/video/uikit/SDL_uikitwindow.m	Tue Jun 09 21:06:55 2015 +0200
     5.2 +++ b/src/video/uikit/SDL_uikitwindow.m	Tue Jun 09 21:08:24 2015 -0300
     5.3 @@ -305,7 +305,17 @@
     5.4      @autoreleasepool {
     5.5          if (window->driverdata != NULL) {
     5.6              SDL_WindowData *data = (SDL_WindowData *) CFBridgingRelease(window->driverdata);
     5.7 +            NSArray *views = nil;
     5.8 +
     5.9              [data.viewcontroller stopAnimation];
    5.10 +
    5.11 +            /* Detach all views from this window. We use a copy of the array
    5.12 +             * because setSDLWindow will remove the object from the original
    5.13 +             * array, which would be undesirable if we were iterating over it. */
    5.14 +            views = [data.views copy];
    5.15 +            for (SDL_uikitview *view in views) {
    5.16 +                [view setSDLWindow:NULL];
    5.17 +            }
    5.18          }
    5.19      }
    5.20      window->driverdata = NULL;