Fixed compiling Metal renderer on iOS
authorSam Lantinga <slouken@libsdl.org>
Thu, 07 Dec 2017 17:12:03 -0800
changeset 11732ad13456d6e7f
parent 11731 30f337dc8c74
child 11733 490588c02a65
Fixed compiling Metal renderer on iOS
Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj
include/SDL_config_iphoneos.h
src/render/metal/SDL_render_metal.m
src/video/uikit/SDL_uikitmetalview.m
     1.1 --- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj	Thu Dec 07 16:08:47 2017 -0800
     1.2 +++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj	Thu Dec 07 17:12:03 2017 -0800
     1.3 @@ -186,6 +186,13 @@
     1.4  		AABCC3941640643D00AB8930 /* SDL_uikitmessagebox.h in Headers */ = {isa = PBXBuildFile; fileRef = AABCC3921640643D00AB8930 /* SDL_uikitmessagebox.h */; };
     1.5  		AABCC3951640643D00AB8930 /* SDL_uikitmessagebox.m in Sources */ = {isa = PBXBuildFile; fileRef = AABCC3931640643D00AB8930 /* SDL_uikitmessagebox.m */; };
     1.6  		AADA5B8F16CCAB7C00107CF7 /* SDL_bits.h in Headers */ = {isa = PBXBuildFile; fileRef = AADA5B8E16CCAB7C00107CF7 /* SDL_bits.h */; };
     1.7 +		AADC5A5D1FDA104400960936 /* yuv_rgb.c in Sources */ = {isa = PBXBuildFile; fileRef = AA13B3561FB8B46300D9FEE6 /* yuv_rgb.c */; };
     1.8 +		AADC5A5E1FDA105300960936 /* SDL_yuv.c in Sources */ = {isa = PBXBuildFile; fileRef = AA13B34F1FB8B3CC00D9FEE6 /* SDL_yuv.c */; };
     1.9 +		AADC5A5F1FDA105600960936 /* SDL_vulkan_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D75171E1EE1D98200820EEA /* SDL_vulkan_utils.c */; };
    1.10 +		AADC5A601FDA10A400960936 /* SDL_uikitvulkan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7516FA1EE1C28A00820EEA /* SDL_uikitvulkan.m */; };
    1.11 +		AADC5A631FDA10C800960936 /* SDL_shaders_metal_ios.h in Headers */ = {isa = PBXBuildFile; fileRef = AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */; };
    1.12 +		AADC5A641FDA10C800960936 /* SDL_render_metal.m in Sources */ = {isa = PBXBuildFile; fileRef = AADC5A621FDA10C800960936 /* SDL_render_metal.m */; };
    1.13 +		AADC5A651FDA10CB00960936 /* SDL_render_metal.m in Sources */ = {isa = PBXBuildFile; fileRef = AADC5A621FDA10C800960936 /* SDL_render_metal.m */; };
    1.14  		FA1DC2721C62BE65008F99A0 /* SDL_uikitclipboard.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */; };
    1.15  		FA1DC2731C62BE65008F99A0 /* SDL_uikitclipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */; };
    1.16  		FAB5981D1BB5C31500BE72C5 /* SDL_atomic.c in Sources */ = {isa = PBXBuildFile; fileRef = 04FFAB8912E23B8D00BA343D /* SDL_atomic.c */; };
    1.17 @@ -499,6 +506,8 @@
    1.18  		AABCC3921640643D00AB8930 /* SDL_uikitmessagebox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitmessagebox.h; sourceTree = "<group>"; };
    1.19  		AABCC3931640643D00AB8930 /* SDL_uikitmessagebox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitmessagebox.m; sourceTree = "<group>"; };
    1.20  		AADA5B8E16CCAB7C00107CF7 /* SDL_bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_bits.h; sourceTree = "<group>"; };
    1.21 +		AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_shaders_metal_ios.h; sourceTree = "<group>"; };
    1.22 +		AADC5A621FDA10C800960936 /* SDL_render_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_render_metal.m; sourceTree = "<group>"; };
    1.23  		FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitclipboard.h; sourceTree = "<group>"; };
    1.24  		FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitclipboard.m; sourceTree = "<group>"; };
    1.25  		FAB598141BB5C1B100BE72C5 /* libSDL2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDL2.a; sourceTree = BUILT_PRODUCTS_DIR; };
    1.26 @@ -622,6 +631,7 @@
    1.27  		041B2CE312FA0F680087D585 /* render */ = {
    1.28  			isa = PBXGroup;
    1.29  			children = (
    1.30 +				AADC5A5C1FDA100800960936 /* metal */,
    1.31  				041B2CE812FA0F680087D585 /* opengles */,
    1.32  				0402A85412FE70C600CECEE3 /* opengles2 */,
    1.33  				041B2CEC12FA0F680087D585 /* software */,
    1.34 @@ -786,6 +796,15 @@
    1.35  			path = yuv2rgb;
    1.36  			sourceTree = "<group>";
    1.37  		};
    1.38 +		AADC5A5C1FDA100800960936 /* metal */ = {
    1.39 +			isa = PBXGroup;
    1.40 +			children = (
    1.41 +				AADC5A621FDA10C800960936 /* SDL_render_metal.m */,
    1.42 +				AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */,
    1.43 +			);
    1.44 +			path = metal;
    1.45 +			sourceTree = "<group>";
    1.46 +		};
    1.47  		FD3F4A6F0DEA620800C5B771 /* stdlib */ = {
    1.48  			isa = PBXGroup;
    1.49  			children = (
    1.50 @@ -1238,6 +1257,7 @@
    1.51  				AA7558B21595D55500BBD41B /* SDL_name.h in Headers */,
    1.52  				AA7558B31595D55500BBD41B /* SDL_opengl.h in Headers */,
    1.53  				AA7558B41595D55500BBD41B /* SDL_opengles.h in Headers */,
    1.54 +				AADC5A631FDA10C800960936 /* SDL_shaders_metal_ios.h in Headers */,
    1.55  				AA7558B51595D55500BBD41B /* SDL_opengles2.h in Headers */,
    1.56  				AA7558B61595D55500BBD41B /* SDL_pixels.h in Headers */,
    1.57  				AA7558B71595D55500BBD41B /* SDL_platform.h in Headers */,
    1.58 @@ -1426,12 +1446,16 @@
    1.59  				FAB598491BB5C31600BE72C5 /* SDL_rwopsbundlesupport.m in Sources */,
    1.60  				FAB5984A1BB5C31600BE72C5 /* SDL_rwops.c in Sources */,
    1.61  				FAB5984B1BB5C31600BE72C5 /* SDL_sysfilesystem.m in Sources */,
    1.62 +				AADC5A5D1FDA104400960936 /* yuv_rgb.c in Sources */,
    1.63  				FAB5984C1BB5C31600BE72C5 /* SDL_syshaptic.c in Sources */,
    1.64 +				AADC5A5F1FDA105600960936 /* SDL_vulkan_utils.c in Sources */,
    1.65 +				AADC5A5E1FDA105300960936 /* SDL_yuv.c in Sources */,
    1.66  				FAB5984D1BB5C31600BE72C5 /* SDL_haptic.c in Sources */,
    1.67  				FAB598501BB5C31600BE72C5 /* SDL_sysjoystick.m in Sources */,
    1.68  				FAB598511BB5C31600BE72C5 /* SDL_gamecontroller.c in Sources */,
    1.69  				FAB598521BB5C31600BE72C5 /* SDL_joystick.c in Sources */,
    1.70  				FAB598551BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */,
    1.71 +				AADC5A651FDA10CB00960936 /* SDL_render_metal.m in Sources */,
    1.72  				FAB598561BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */,
    1.73  				FAB598571BB5C31600BE72C5 /* SDL_power.c in Sources */,
    1.74  				FAB598581BB5C31600BE72C5 /* SDL_syspower.m in Sources */,
    1.75 @@ -1455,6 +1479,7 @@
    1.76  				FAB598761BB5C31600BE72C5 /* SDL_stdlib.c in Sources */,
    1.77  				FAB598771BB5C31600BE72C5 /* SDL_string.c in Sources */,
    1.78  				FAB598781BB5C31600BE72C5 /* SDL_syscond.c in Sources */,
    1.79 +				AADC5A601FDA10A400960936 /* SDL_uikitvulkan.m in Sources */,
    1.80  				FAB598791BB5C31600BE72C5 /* SDL_sysmutex.c in Sources */,
    1.81  				FAB5987B1BB5C31600BE72C5 /* SDL_syssem.c in Sources */,
    1.82  				FAB5987C1BB5C31600BE72C5 /* SDL_systhread.c in Sources */,
    1.83 @@ -1529,6 +1554,7 @@
    1.84  				FD6526780DE8FCDD002AD96B /* SDL_error.c in Sources */,
    1.85  				FD65267A0DE8FCDD002AD96B /* SDL.c in Sources */,
    1.86  				FD65267B0DE8FCDD002AD96B /* SDL_syscond.c in Sources */,
    1.87 +				AADC5A641FDA10C800960936 /* SDL_render_metal.m in Sources */,
    1.88  				FD65267C0DE8FCDD002AD96B /* SDL_sysmutex.c in Sources */,
    1.89  				FD65267D0DE8FCDD002AD96B /* SDL_syssem.c in Sources */,
    1.90  				FD65267E0DE8FCDD002AD96B /* SDL_systhread.c in Sources */,
     2.1 --- a/include/SDL_config_iphoneos.h	Thu Dec 07 16:08:47 2017 -0800
     2.2 +++ b/include/SDL_config_iphoneos.h	Thu Dec 07 17:12:03 2017 -0800
     2.3 @@ -154,8 +154,9 @@
     2.4  #define SDL_VIDEO_RENDER_OGL_ES 1
     2.5  #define SDL_VIDEO_RENDER_OGL_ES2    1
     2.6  
     2.7 -/* Enable Vulkan support on 64-bit devices when an iOS 8+ SDK is used. */
     2.8 +/* Enable Metal and Vulkan support on 64-bit devices when an iOS 8+ SDK is used. */
     2.9  #if !TARGET_OS_SIMULATOR && !TARGET_CPU_ARM && defined(__IPHONE_8_0)
    2.10 +#define SDL_VIDEO_RENDER_METAL  1
    2.11  #define SDL_VIDEO_VULKAN 1
    2.12  #else
    2.13  #define SDL_VIDEO_VULKAN 0
     3.1 --- a/src/render/metal/SDL_render_metal.m	Thu Dec 07 16:08:47 2017 -0800
     3.2 +++ b/src/render/metal/SDL_render_metal.m	Thu Dec 07 17:12:03 2017 -0800
     3.3 @@ -28,7 +28,11 @@
     3.4  #include "SDL_syswm.h"
     3.5  #include "../SDL_sysrender.h"
     3.6  
     3.7 +#ifdef __MACOSX__
     3.8  #include <Cocoa/Cocoa.h>
     3.9 +#else
    3.10 +#include "../../video/uikit/SDL_uikitmetalview.h"
    3.11 +#endif
    3.12  #include <Metal/Metal.h>
    3.13  #include <QuartzCore/CAMetalLayer.h>
    3.14  
    3.15 @@ -89,27 +93,22 @@
    3.16       4096}
    3.17  };
    3.18  
    3.19 -typedef struct METAL_BufferList
    3.20 -{
    3.21 -    id<MTLBuffer> mtlbuffer;
    3.22 -    struct METAL_BufferPool *next;
    3.23 -} METAL_BufferList;
    3.24 +@interface METAL_RenderData : NSObject
    3.25 +    @property (atomic, retain) id<MTLDevice> mtldevice;
    3.26 +    @property (atomic, retain) id<MTLCommandQueue> mtlcmdqueue;
    3.27 +    @property (atomic, retain) id<MTLCommandBuffer> mtlcmdbuffer;
    3.28 +    @property (atomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
    3.29 +    @property (atomic, retain) id<MTLLibrary> mtllibrary;
    3.30 +    @property (atomic, retain) id<CAMetalDrawable> mtlbackbuffer;
    3.31 +    @property (atomic, retain) NSMutableArray *mtlpipelineprims;
    3.32 +    @property (atomic, retain) NSMutableArray *mtlpipelinecopy;
    3.33 +    @property (atomic, retain) id<MTLBuffer> mtlbufclearverts;
    3.34 +    @property (atomic, retain) CAMetalLayer *mtllayer;
    3.35 +    @property (atomic, retain) MTLRenderPassDescriptor *mtlpassdesc;
    3.36 +@end
    3.37  
    3.38 -typedef struct
    3.39 -{
    3.40 -    id<MTLDevice> mtldevice;
    3.41 -    id<MTLCommandQueue> mtlcmdqueue;
    3.42 -    id<MTLCommandBuffer> mtlcmdbuffer;
    3.43 -    id<MTLRenderCommandEncoder> mtlcmdencoder;
    3.44 -    id<MTLLibrary> mtllibrary;
    3.45 -    id<CAMetalDrawable> mtlbackbuffer;
    3.46 -    id<MTLRenderPipelineState> mtlpipelineprims[4];
    3.47 -    id<MTLRenderPipelineState> mtlpipelinecopy[4];
    3.48 -    id<MTLBuffer> mtlbufclearverts;
    3.49 -    CAMetalLayer *mtllayer;
    3.50 -    MTLRenderPassDescriptor *mtlpassdesc;
    3.51 -} METAL_RenderData;
    3.52 -
    3.53 +@implementation METAL_RenderData
    3.54 +@end
    3.55  
    3.56  static int
    3.57  IsMetalAvailable(const SDL_SysWMinfo *syswm)
    3.58 @@ -132,15 +131,15 @@
    3.59  MakePipelineState(METAL_RenderData *data, NSString *label, NSString *vertfn,
    3.60                    NSString *fragfn, const SDL_BlendMode blendmode)
    3.61  {
    3.62 -    id<MTLFunction> mtlvertfn = [data->mtllibrary newFunctionWithName:vertfn];
    3.63 -    id<MTLFunction> mtlfragfn = [data->mtllibrary newFunctionWithName:fragfn];
    3.64 +    id<MTLFunction> mtlvertfn = [data.mtllibrary newFunctionWithName:vertfn];
    3.65 +    id<MTLFunction> mtlfragfn = [data.mtllibrary newFunctionWithName:fragfn];
    3.66      SDL_assert(mtlvertfn != nil);
    3.67      SDL_assert(mtlfragfn != nil);
    3.68  
    3.69      MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init];
    3.70      mtlpipedesc.vertexFunction = mtlvertfn;
    3.71      mtlpipedesc.fragmentFunction = mtlfragfn;
    3.72 -    mtlpipedesc.colorAttachments[0].pixelFormat = data->mtlbackbuffer.texture.pixelFormat;
    3.73 +    mtlpipedesc.colorAttachments[0].pixelFormat = data.mtlbackbuffer.texture.pixelFormat;
    3.74  
    3.75      switch (blendmode) {
    3.76          case SDL_BLENDMODE_BLEND:
    3.77 @@ -181,35 +180,35 @@
    3.78      mtlpipedesc.label = label;
    3.79  
    3.80      NSError *err = nil;
    3.81 -    id<MTLRenderPipelineState> retval = [data->mtldevice newRenderPipelineStateWithDescriptor:mtlpipedesc error:&err];
    3.82 +    id<MTLRenderPipelineState> retval = [data.mtldevice newRenderPipelineStateWithDescriptor:mtlpipedesc error:&err];
    3.83      SDL_assert(err == nil);
    3.84 +#if !__has_feature(objc_arc)
    3.85      [mtlpipedesc release];  // !!! FIXME: can these be reused for each creation, or does the pipeline obtain it?
    3.86      [mtlvertfn release];
    3.87      [mtlfragfn release];
    3.88      [label release];
    3.89 -
    3.90 +#endif
    3.91      return retval;
    3.92  }
    3.93  
    3.94  static void
    3.95 -MakePipelineStates(METAL_RenderData *data, id<MTLRenderPipelineState> *states,
    3.96 +MakePipelineStates(METAL_RenderData *data, NSMutableArray *states,
    3.97                     NSString *label, NSString *vertfn, NSString *fragfn)
    3.98  {
    3.99 -    int i = 0;
   3.100 -    states[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=none)"], vertfn, fragfn, SDL_BLENDMODE_NONE);
   3.101 -    states[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=blend)"], vertfn, fragfn, SDL_BLENDMODE_BLEND);
   3.102 -    states[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=add)"], vertfn, fragfn, SDL_BLENDMODE_ADD);
   3.103 -    states[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=mod)"], vertfn, fragfn, SDL_BLENDMODE_MOD);
   3.104 +    [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=none)"], vertfn, fragfn, SDL_BLENDMODE_NONE)];
   3.105 +    [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=blend)"], vertfn, fragfn, SDL_BLENDMODE_BLEND)];
   3.106 +    [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=add)"], vertfn, fragfn, SDL_BLENDMODE_ADD)];
   3.107 +    [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=mod)"], vertfn, fragfn, SDL_BLENDMODE_MOD)];
   3.108  }
   3.109  
   3.110  static inline id<MTLRenderPipelineState>
   3.111 -ChoosePipelineState(id<MTLRenderPipelineState> *states, const SDL_BlendMode blendmode)
   3.112 +ChoosePipelineState(NSMutableArray *states, const SDL_BlendMode blendmode)
   3.113  {
   3.114      switch (blendmode) {
   3.115 -        case SDL_BLENDMODE_BLEND: return states[1];
   3.116 -        case SDL_BLENDMODE_ADD: return states[2];
   3.117 -        case SDL_BLENDMODE_MOD: return states[3];
   3.118 -        default: return states[0];
   3.119 +        case SDL_BLENDMODE_BLEND: return (id<MTLRenderPipelineState>)states[1];
   3.120 +        case SDL_BLENDMODE_ADD: return (id<MTLRenderPipelineState>)states[2];
   3.121 +        case SDL_BLENDMODE_MOD: return (id<MTLRenderPipelineState>)states[3];
   3.122 +        default: return (id<MTLRenderPipelineState>)states[0];
   3.123      }
   3.124      return nil;
   3.125  }
   3.126 @@ -230,27 +229,28 @@
   3.127          return NULL;
   3.128      }
   3.129  
   3.130 -    data = (METAL_RenderData *) SDL_calloc(1, sizeof(*data));
   3.131 -    if (!data) {
   3.132 +    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   3.133 +    if (!renderer) {
   3.134          SDL_OutOfMemory();
   3.135          return NULL;
   3.136      }
   3.137  
   3.138 -    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   3.139 -    if (!renderer) {
   3.140 -        SDL_free(data);
   3.141 -        SDL_OutOfMemory();
   3.142 -        return NULL;
   3.143 -    }
   3.144 +    data = [[METAL_RenderData alloc] init];
   3.145  
   3.146 +#if __has_feature(objc_arc)
   3.147 +    renderer->driverdata = (void*)CFBridgingRetain(data);
   3.148 +#else
   3.149      renderer->driverdata = data;
   3.150 +#endif
   3.151      renderer->window = window;
   3.152  
   3.153  #ifdef __MACOSX__
   3.154      id<MTLDevice> mtldevice = MTLCreateSystemDefaultDevice();  // !!! FIXME: MTLCopyAllDevices() can find other GPUs...
   3.155      if (mtldevice == nil) {
   3.156          SDL_free(renderer);
   3.157 -        SDL_free(data);
   3.158 +#if !__has_feature(objc_arc)
   3.159 +        [data release];
   3.160 +#endif
   3.161          SDL_SetError("Failed to obtain Metal device");
   3.162          return NULL;
   3.163      }
   3.164 @@ -273,27 +273,28 @@
   3.165  
   3.166      [layer retain];
   3.167  #else
   3.168 -
   3.169 +    UIView *view = UIKit_Mtl_AddMetalView(window);
   3.170 +    CAMetalLayer *layer = (CAMetalLayer *)[view layer];
   3.171  #endif
   3.172  
   3.173 -    data->mtldevice = layer.device;
   3.174 -    data->mtllayer = layer;
   3.175 -    data->mtlcmdqueue = [data->mtldevice newCommandQueue];
   3.176 -    data->mtlcmdqueue.label = @"SDL Metal Renderer";
   3.177 +    data.mtldevice = layer.device;
   3.178 +    data.mtllayer = layer;
   3.179 +    data.mtlcmdqueue = [data.mtldevice newCommandQueue];
   3.180 +    data.mtlcmdqueue.label = @"SDL Metal Renderer";
   3.181  
   3.182 -    data->mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];  // !!! FIXME: is this autoreleased?
   3.183 +    data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];  // !!! FIXME: is this autoreleased?
   3.184  
   3.185      // we don't specify a depth or stencil buffer because the render API doesn't currently use them.
   3.186 -    MTLRenderPassColorAttachmentDescriptor *colorAttachment = data->mtlpassdesc.colorAttachments[0];
   3.187 -    data->mtlbackbuffer = [data->mtllayer nextDrawable];
   3.188 -    colorAttachment.texture = data->mtlbackbuffer.texture;
   3.189 +    MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0];
   3.190 +    data.mtlbackbuffer = [data.mtllayer nextDrawable];
   3.191 +    colorAttachment.texture = data.mtlbackbuffer.texture;
   3.192      colorAttachment.loadAction = MTLLoadActionClear;
   3.193      colorAttachment.clearColor = MTLClearColorMake(0.0f, 0.0f, 0.0f, 1.0f);
   3.194 -    data->mtlcmdbuffer = [data->mtlcmdqueue commandBuffer];
   3.195 +    data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
   3.196  
   3.197      // Just push a clear to the screen to start so we're in a good state.
   3.198 -    data->mtlcmdencoder = [data->mtlcmdbuffer renderCommandEncoderWithDescriptor:data->mtlpassdesc];
   3.199 -    data->mtlcmdencoder.label = @"Initial drawable clear";
   3.200 +    data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc];
   3.201 +    data.mtlcmdencoder.label = @"Initial drawable clear";
   3.202  
   3.203      METAL_RenderPresent(renderer);
   3.204  
   3.205 @@ -329,17 +330,21 @@
   3.206      // The compiled .metallib is embedded in a static array in a header file
   3.207      // but the original shader source code is in SDL_shaders_metal.metal.
   3.208      dispatch_data_t mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{});
   3.209 -    data->mtllibrary = [data->mtldevice newLibraryWithData:mtllibdata error:&err];
   3.210 +    data.mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
   3.211      SDL_assert(err == nil);
   3.212 +#if !__has_feature(objc_arc)
   3.213      dispatch_release(mtllibdata);
   3.214 -    data->mtllibrary.label = @"SDL Metal renderer shader library";
   3.215 +#endif
   3.216 +    data.mtllibrary.label = @"SDL Metal renderer shader library";
   3.217  
   3.218 -    MakePipelineStates(data, data->mtlpipelineprims, @"SDL primitives pipeline", @"SDL_Simple_vertex", @"SDL_Simple_fragment");
   3.219 -    MakePipelineStates(data, data->mtlpipelinecopy, @"SDL_RenderCopy pipeline", @"SDL_Copy_vertex", @"SDL_Copy_fragment");
   3.220 +    data.mtlpipelineprims = [[NSMutableArray alloc] init];
   3.221 +    MakePipelineStates(data, data.mtlpipelineprims, @"SDL primitives pipeline", @"SDL_Simple_vertex", @"SDL_Simple_fragment");
   3.222 +    data.mtlpipelinecopy = [[NSMutableArray alloc] init];
   3.223 +    MakePipelineStates(data, data.mtlpipelinecopy, @"SDL_RenderCopy pipeline", @"SDL_Copy_vertex", @"SDL_Copy_fragment");
   3.224  
   3.225      static const float clearverts[] = { -1, -1, -1, 1, 1, 1, 1, -1, -1, -1 };
   3.226 -    data->mtlbufclearverts = [data->mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModePrivate];
   3.227 -    data->mtlbufclearverts.label = @"SDL_RenderClear vertices";
   3.228 +    data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModePrivate];
   3.229 +    data.mtlbufclearverts.label = @"SDL_RenderClear vertices";
   3.230  
   3.231      // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
   3.232  
   3.233 @@ -359,16 +364,16 @@
   3.234  static int
   3.235  METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
   3.236  {
   3.237 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.238 -    *w = (int) data->mtlbackbuffer.texture.width;
   3.239 -    *h = (int) data->mtlbackbuffer.texture.height;
   3.240 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.241 +    *w = (int) data.mtlbackbuffer.texture.width;
   3.242 +    *h = (int) data.mtlbackbuffer.texture.height;
   3.243      return 0;
   3.244  }
   3.245  
   3.246  static int
   3.247  METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   3.248  {
   3.249 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.250 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.251      MTLPixelFormat mtlpixfmt;
   3.252  
   3.253      switch (texture->format) {
   3.254 @@ -381,13 +386,15 @@
   3.255      MTLTextureDescriptor *mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mtlpixfmt
   3.256                                              width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO];
   3.257  
   3.258 -    id<MTLTexture> mtltexture = [data->mtldevice newTextureWithDescriptor:mtltexdesc];
   3.259 +    id<MTLTexture> mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
   3.260 +#if !__has_feature(objc_arc)
   3.261      [mtltexdesc release];
   3.262 +#endif
   3.263      if (mtltexture == nil) {
   3.264          return SDL_SetError("Texture allocation failed");
   3.265      }
   3.266  
   3.267 -    texture->driverdata = mtltexture;
   3.268 +    texture->driverdata = (void*)CFBridgingRetain(mtltexture);
   3.269  
   3.270      return 0;
   3.271  }
   3.272 @@ -400,7 +407,7 @@
   3.273      // !!! FIXME:  Maybe move this off to a thread that marks the texture as uploaded and only stall the main thread if we try to
   3.274      // !!! FIXME:  use this texture before the marking is done? Is it worth it? Or will we basically always be uploading a bunch of
   3.275      // !!! FIXME:  stuff way ahead of time and/or using it immediately after upload?
   3.276 -    id<MTLTexture> mtltexture = (id<MTLTexture>) texture->driverdata;
   3.277 +    id<MTLTexture> mtltexture = (__bridge id<MTLTexture>) texture->driverdata;
   3.278      [mtltexture replaceRegion:MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h) mipmapLevel:0 withBytes:pixels bytesPerRow:pitch];
   3.279      return 0;
   3.280  }
   3.281 @@ -431,17 +438,17 @@
   3.282  static int
   3.283  METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   3.284  {
   3.285 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.286 -    id<MTLTexture> mtltexture = texture ? (id<MTLTexture>) texture->driverdata : nil;
   3.287 -    data->mtlpassdesc.colorAttachments[0].texture = mtltexture;
   3.288 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.289 +    id<MTLTexture> mtltexture = texture ? (__bridge id<MTLTexture>) texture->driverdata : nil;
   3.290 +    data.mtlpassdesc.colorAttachments[0].texture = mtltexture;
   3.291      return 0;
   3.292  }
   3.293  
   3.294  static int
   3.295  METAL_UpdateViewport(SDL_Renderer * renderer)
   3.296  {
   3.297 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.298 -    if (data->mtlcmdencoder != nil) {
   3.299 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.300 +    if (data.mtlcmdencoder != nil) {
   3.301          MTLViewport viewport;
   3.302          viewport.originX = renderer->viewport.x;
   3.303          viewport.originY = renderer->viewport.y;
   3.304 @@ -449,7 +456,7 @@
   3.305          viewport.height = renderer->viewport.h;
   3.306          viewport.znear = 0.0;
   3.307          viewport.zfar = 1.0;
   3.308 -        [data->mtlcmdencoder setViewport:viewport];
   3.309 +        [data.mtlcmdencoder setViewport:viewport];
   3.310      }
   3.311      return 0;
   3.312  }
   3.313 @@ -458,8 +465,8 @@
   3.314  METAL_UpdateClipRect(SDL_Renderer * renderer)
   3.315  {
   3.316      // !!! FIXME: should this care about the viewport?
   3.317 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.318 -    if (data->mtlcmdencoder != nil) {
   3.319 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.320 +    if (data.mtlcmdencoder != nil) {
   3.321          MTLScissorRect mtlrect;
   3.322          if (renderer->clipping_enabled) {
   3.323              const SDL_Rect *rect = &renderer->clip_rect;
   3.324 @@ -473,7 +480,7 @@
   3.325              mtlrect.width = renderer->viewport.w;
   3.326              mtlrect.height = renderer->viewport.h;
   3.327          }
   3.328 -        [data->mtlcmdencoder setScissorRect:mtlrect];
   3.329 +        [data.mtlcmdencoder setScissorRect:mtlrect];
   3.330      }
   3.331      return 0;
   3.332  }
   3.333 @@ -482,24 +489,24 @@
   3.334  METAL_RenderClear(SDL_Renderer * renderer)
   3.335  {
   3.336      // We could dump the command buffer and force a clear on a new one, but this will respect the scissor state.
   3.337 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.338 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.339  
   3.340      // !!! FIXME: render color should live in a dedicated uniform buffer.
   3.341      const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
   3.342  
   3.343      MTLViewport viewport;  // RenderClear ignores the viewport state, though, so reset that.
   3.344      viewport.originX = viewport.originY = 0.0;
   3.345 -    viewport.width = data->mtlbackbuffer.texture.width;
   3.346 -    viewport.height = data->mtlbackbuffer.texture.height;
   3.347 +    viewport.width = data.mtlbackbuffer.texture.width;
   3.348 +    viewport.height = data.mtlbackbuffer.texture.height;
   3.349      viewport.znear = 0.0;
   3.350      viewport.zfar = 1.0;
   3.351  
   3.352      // Draw as if we're doing a simple filled rect to the screen now.
   3.353 -    [data->mtlcmdencoder setViewport:viewport];
   3.354 -    [data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelineprims, renderer->blendMode)];
   3.355 -    [data->mtlcmdencoder setVertexBuffer:data->mtlbufclearverts offset:0 atIndex:0];
   3.356 -    [data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
   3.357 -    [data->mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5];
   3.358 +    [data.mtlcmdencoder setViewport:viewport];
   3.359 +    [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
   3.360 +    [data.mtlcmdencoder setVertexBuffer:data.mtlbufclearverts offset:0 atIndex:0];
   3.361 +    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
   3.362 +    [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5];
   3.363  
   3.364      // reset the viewport for the rest of our usual drawing work...
   3.365      viewport.originX = renderer->viewport.x;
   3.366 @@ -508,7 +515,7 @@
   3.367      viewport.height = renderer->viewport.h;
   3.368      viewport.znear = 0.0;
   3.369      viewport.zfar = 1.0;
   3.370 -    [data->mtlcmdencoder setViewport:viewport];
   3.371 +    [data.mtlcmdencoder setViewport:viewport];
   3.372  
   3.373      return 0;
   3.374  }
   3.375 @@ -546,16 +553,16 @@
   3.376          return SDL_OutOfMemory();
   3.377      }
   3.378  
   3.379 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.380 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.381  
   3.382      // !!! FIXME: render color should live in a dedicated uniform buffer.
   3.383      const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
   3.384  
   3.385 -    [data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelineprims, renderer->blendMode)];
   3.386 -    [data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
   3.387 +    [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
   3.388 +    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
   3.389  
   3.390 -    const float w = (float) data->mtlpassdesc.colorAttachments[0].texture.width;
   3.391 -    const float h = (float) data->mtlpassdesc.colorAttachments[0].texture.height;
   3.392 +    const float w = (float) data.mtlpassdesc.colorAttachments[0].texture.width;
   3.393 +    const float h = (float) data.mtlpassdesc.colorAttachments[0].texture.height;
   3.394  
   3.395      // !!! FIXME: we can convert this in the shader. This will save the malloc and for-loop, but we still need to upload.
   3.396      float *ptr = verts;
   3.397 @@ -564,8 +571,8 @@
   3.398          *ptr = normy(points->y, h); ptr++;
   3.399      }
   3.400  
   3.401 -    [data->mtlcmdencoder setVertexBytes:verts length:vertlen atIndex:0];
   3.402 -    [data->mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
   3.403 +    [data.mtlcmdencoder setVertexBytes:verts length:vertlen atIndex:0];
   3.404 +    [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
   3.405  
   3.406      SDL_free(verts);
   3.407      return 0;
   3.408 @@ -586,16 +593,16 @@
   3.409  static int
   3.410  METAL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
   3.411  {
   3.412 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.413 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.414  
   3.415      // !!! FIXME: render color should live in a dedicated uniform buffer.
   3.416      const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
   3.417  
   3.418 -    [data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelineprims, renderer->blendMode)];
   3.419 -    [data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
   3.420 +    [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
   3.421 +    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
   3.422  
   3.423 -    const float w = (float) data->mtlpassdesc.colorAttachments[0].texture.width;
   3.424 -    const float h = (float) data->mtlpassdesc.colorAttachments[0].texture.height;
   3.425 +    const float w = (float) data.mtlpassdesc.colorAttachments[0].texture.width;
   3.426 +    const float h = (float) data.mtlpassdesc.colorAttachments[0].texture.height;
   3.427  
   3.428      for (int i = 0; i < count; i++, rects++) {
   3.429          if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) continue;
   3.430 @@ -608,8 +615,8 @@
   3.431              norm(rects->x + rects->w, w), normy(rects->y + rects->h, h)
   3.432          };
   3.433  
   3.434 -        [data->mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
   3.435 -        [data->mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5];
   3.436 +        [data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
   3.437 +        [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5];
   3.438      }
   3.439  
   3.440      return 0;
   3.441 @@ -619,10 +626,10 @@
   3.442  METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   3.443                const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   3.444  {
   3.445 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.446 -    id<MTLTexture> mtltexture = (id<MTLTexture>) texture->driverdata;
   3.447 -    const float w = (float) data->mtlpassdesc.colorAttachments[0].texture.width;
   3.448 -    const float h = (float) data->mtlpassdesc.colorAttachments[0].texture.height;
   3.449 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.450 +    id<MTLTexture> mtltexture = (__bridge id<MTLTexture>) texture->driverdata;
   3.451 +    const float w = (float) data.mtlpassdesc.colorAttachments[0].texture.width;
   3.452 +    const float h = (float) data.mtlpassdesc.colorAttachments[0].texture.height;
   3.453      const float texw = (float) mtltexture.width;
   3.454      const float texh = (float) mtltexture.height;
   3.455  
   3.456 @@ -650,12 +657,12 @@
   3.457          color[3] = ((float)texture->a) / 255.0f;
   3.458      }
   3.459  
   3.460 -    [data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelinecopy, texture->blendMode)];
   3.461 -    [data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
   3.462 -    [data->mtlcmdencoder setFragmentTexture:mtltexture atIndex:0];
   3.463 -    [data->mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
   3.464 -    [data->mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
   3.465 -    [data->mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5];
   3.466 +    [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelinecopy, texture->blendMode)];
   3.467 +    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
   3.468 +    [data.mtlcmdencoder setFragmentTexture:mtltexture atIndex:0];
   3.469 +    [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
   3.470 +    [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
   3.471 +    [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5];
   3.472  
   3.473      return 0;
   3.474  }
   3.475 @@ -672,8 +679,8 @@
   3.476  METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   3.477                      Uint32 pixel_format, void * pixels, int pitch)
   3.478  {
   3.479 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.480 -    MTLRenderPassColorAttachmentDescriptor *colorAttachment = data->mtlpassdesc.colorAttachments[0];
   3.481 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.482 +    MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0];
   3.483      id<MTLTexture> mtltexture = colorAttachment.texture;
   3.484      MTLRegion mtlregion;
   3.485  
   3.486 @@ -702,28 +709,30 @@
   3.487  static void
   3.488  METAL_RenderPresent(SDL_Renderer * renderer)
   3.489  {
   3.490 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.491 -    MTLRenderPassColorAttachmentDescriptor *colorAttachment = data->mtlpassdesc.colorAttachments[0];
   3.492 -    id<CAMetalDrawable> mtlbackbuffer = data->mtlbackbuffer;
   3.493 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
   3.494 +    MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0];
   3.495 +    id<CAMetalDrawable> mtlbackbuffer = data.mtlbackbuffer;
   3.496  
   3.497 -    [data->mtlcmdencoder endEncoding];
   3.498 -    [data->mtlcmdbuffer presentDrawable:mtlbackbuffer];
   3.499 +    [data.mtlcmdencoder endEncoding];
   3.500 +    [data.mtlcmdbuffer presentDrawable:mtlbackbuffer];
   3.501  
   3.502 -    [data->mtlcmdbuffer addCompletedHandler:^(id <MTLCommandBuffer> mtlcmdbuffer){
   3.503 +    [data.mtlcmdbuffer addCompletedHandler:^(id <MTLCommandBuffer> mtlcmdbuffer) {
   3.504 +#if !__has_feature(objc_arc)
   3.505          [mtlbackbuffer release];
   3.506 +#endif
   3.507      }];
   3.508  
   3.509 -    [data->mtlcmdbuffer commit];
   3.510 +    [data.mtlcmdbuffer commit];
   3.511  
   3.512      // Start next frame, once we can.
   3.513      // we don't specify a depth or stencil buffer because the render API doesn't currently use them.
   3.514 -    data->mtlbackbuffer = [data->mtllayer nextDrawable];
   3.515 -    SDL_assert(data->mtlbackbuffer);
   3.516 -    colorAttachment.texture = data->mtlbackbuffer.texture;
   3.517 +    data.mtlbackbuffer = [data.mtllayer nextDrawable];
   3.518 +    SDL_assert(data.mtlbackbuffer);
   3.519 +    colorAttachment.texture = data.mtlbackbuffer.texture;
   3.520      colorAttachment.loadAction = MTLLoadActionDontCare;
   3.521 -    data->mtlcmdbuffer = [data->mtlcmdqueue commandBuffer];
   3.522 -    data->mtlcmdencoder = [data->mtlcmdbuffer renderCommandEncoderWithDescriptor:data->mtlpassdesc];
   3.523 -    data->mtlcmdencoder.label = @"SDL metal renderer frame";
   3.524 +    data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
   3.525 +    data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc];
   3.526 +    data.mtlcmdencoder.label = @"SDL metal renderer frame";
   3.527  
   3.528      // Set up our current renderer state for the next frame...
   3.529      METAL_UpdateViewport(renderer);
   3.530 @@ -733,32 +742,36 @@
   3.531  static void
   3.532  METAL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   3.533  {
   3.534 -    id<MTLTexture> mtltexture = (id<MTLTexture>) texture->driverdata;
   3.535 +    id<MTLTexture> mtltexture = CFBridgingRelease(texture->driverdata);
   3.536 +#if !__has_feature(objc_arc)
   3.537      [mtltexture release];
   3.538 +#endif
   3.539      texture->driverdata = NULL;
   3.540  }
   3.541  
   3.542  static void
   3.543  METAL_DestroyRenderer(SDL_Renderer * renderer)
   3.544  {
   3.545 -    METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata;
   3.546 +    if (renderer->driverdata) {
   3.547 +        METAL_RenderData *data = CFBridgingRelease(renderer->driverdata);
   3.548  
   3.549 -    if (data) {
   3.550 +#if !__has_feature(objc_arc)
   3.551          int i;
   3.552 -        [data->mtlcmdencoder endEncoding];
   3.553 -        [data->mtlcmdencoder release];
   3.554 -        [data->mtlcmdbuffer release];
   3.555 -        [data->mtlcmdqueue release];
   3.556 +        [data.mtlcmdencoder endEncoding];
   3.557 +        [data.mtlcmdencoder release];
   3.558 +        [data.mtlcmdbuffer release];
   3.559 +        [data.mtlcmdqueue release];
   3.560          for (i = 0; i < 4; i++) {
   3.561 -            [data->mtlpipelineprims[i] release];
   3.562 -            [data->mtlpipelinecopy[i] release];
   3.563 +            [data.mtlpipelineprims[i] release];
   3.564 +            [data.mtlpipelinecopy[i] release];
   3.565          }
   3.566 -        [data->mtlbufclearverts release];
   3.567 -        [data->mtllibrary release];
   3.568 -        [data->mtldevice release];
   3.569 -        [data->mtlpassdesc release];
   3.570 -        [data->mtllayer release];
   3.571 -        SDL_free(data);
   3.572 +        [data.mtlbufclearverts release];
   3.573 +        [data.mtllibrary release];
   3.574 +        [data.mtldevice release];
   3.575 +        [data.mtlpassdesc release];
   3.576 +        [data.mtllayer release];
   3.577 +        [data release];
   3.578 +#endif
   3.579      }
   3.580      SDL_free(renderer);
   3.581  }
     4.1 --- a/src/video/uikit/SDL_uikitmetalview.m	Thu Dec 07 16:08:47 2017 -0800
     4.2 +++ b/src/video/uikit/SDL_uikitmetalview.m	Thu Dec 07 17:12:03 2017 -0800
     4.3 @@ -84,6 +84,10 @@
     4.4      SDL_uikitview *view = (SDL_uikitview*)data.uiwindow.rootViewController.view;
     4.5      CGFloat scale = 1.0;
     4.6  
     4.7 +	if ([view isKindOfClass:[SDL_uikitmetalview class]]) {
     4.8 +		return (SDL_uikitmetalview *)view;
     4.9 +	}
    4.10 +
    4.11      if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
    4.12          /* Set the scale to the natural scale factor of the screen - the
    4.13           * backing dimensions of the Metal view will match the pixel