From 6deb1e75952685a9b1c3826bf4998406c4f10a4b Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 7 Dec 2017 17:12:03 -0800 Subject: [PATCH] Fixed compiling Metal renderer on iOS --- Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj | 26 ++ include/SDL_config_iphoneos.h | 3 +- src/render/metal/SDL_render_metal.m | 297 ++++++++++---------- src/video/uikit/SDL_uikitmetalview.m | 4 + 4 files changed, 187 insertions(+), 143 deletions(-) diff --git a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj index 4557c94f0c12d..9b3bc6e7c1a06 100755 --- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj @@ -186,6 +186,13 @@ AABCC3941640643D00AB8930 /* SDL_uikitmessagebox.h in Headers */ = {isa = PBXBuildFile; fileRef = AABCC3921640643D00AB8930 /* SDL_uikitmessagebox.h */; }; AABCC3951640643D00AB8930 /* SDL_uikitmessagebox.m in Sources */ = {isa = PBXBuildFile; fileRef = AABCC3931640643D00AB8930 /* SDL_uikitmessagebox.m */; }; AADA5B8F16CCAB7C00107CF7 /* SDL_bits.h in Headers */ = {isa = PBXBuildFile; fileRef = AADA5B8E16CCAB7C00107CF7 /* SDL_bits.h */; }; + AADC5A5D1FDA104400960936 /* yuv_rgb.c in Sources */ = {isa = PBXBuildFile; fileRef = AA13B3561FB8B46300D9FEE6 /* yuv_rgb.c */; }; + AADC5A5E1FDA105300960936 /* SDL_yuv.c in Sources */ = {isa = PBXBuildFile; fileRef = AA13B34F1FB8B3CC00D9FEE6 /* SDL_yuv.c */; }; + AADC5A5F1FDA105600960936 /* SDL_vulkan_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D75171E1EE1D98200820EEA /* SDL_vulkan_utils.c */; }; + AADC5A601FDA10A400960936 /* SDL_uikitvulkan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7516FA1EE1C28A00820EEA /* SDL_uikitvulkan.m */; }; + AADC5A631FDA10C800960936 /* SDL_shaders_metal_ios.h in Headers */ = {isa = PBXBuildFile; fileRef = AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */; }; + AADC5A641FDA10C800960936 /* SDL_render_metal.m in Sources */ = {isa = PBXBuildFile; fileRef = AADC5A621FDA10C800960936 /* SDL_render_metal.m */; }; + AADC5A651FDA10CB00960936 /* SDL_render_metal.m in Sources */ = {isa = PBXBuildFile; fileRef = AADC5A621FDA10C800960936 /* SDL_render_metal.m */; }; FA1DC2721C62BE65008F99A0 /* SDL_uikitclipboard.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */; }; FA1DC2731C62BE65008F99A0 /* SDL_uikitclipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */; }; FAB5981D1BB5C31500BE72C5 /* SDL_atomic.c in Sources */ = {isa = PBXBuildFile; fileRef = 04FFAB8912E23B8D00BA343D /* SDL_atomic.c */; }; @@ -499,6 +506,8 @@ AABCC3921640643D00AB8930 /* SDL_uikitmessagebox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitmessagebox.h; sourceTree = ""; }; AABCC3931640643D00AB8930 /* SDL_uikitmessagebox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitmessagebox.m; sourceTree = ""; }; AADA5B8E16CCAB7C00107CF7 /* SDL_bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_bits.h; sourceTree = ""; }; + AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_shaders_metal_ios.h; sourceTree = ""; }; + AADC5A621FDA10C800960936 /* SDL_render_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_render_metal.m; sourceTree = ""; }; FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitclipboard.h; sourceTree = ""; }; FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitclipboard.m; sourceTree = ""; }; FAB598141BB5C1B100BE72C5 /* libSDL2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDL2.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -622,6 +631,7 @@ 041B2CE312FA0F680087D585 /* render */ = { isa = PBXGroup; children = ( + AADC5A5C1FDA100800960936 /* metal */, 041B2CE812FA0F680087D585 /* opengles */, 0402A85412FE70C600CECEE3 /* opengles2 */, 041B2CEC12FA0F680087D585 /* software */, @@ -786,6 +796,15 @@ path = yuv2rgb; sourceTree = ""; }; + AADC5A5C1FDA100800960936 /* metal */ = { + isa = PBXGroup; + children = ( + AADC5A621FDA10C800960936 /* SDL_render_metal.m */, + AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */, + ); + path = metal; + sourceTree = ""; + }; FD3F4A6F0DEA620800C5B771 /* stdlib */ = { isa = PBXGroup; children = ( @@ -1238,6 +1257,7 @@ AA7558B21595D55500BBD41B /* SDL_name.h in Headers */, AA7558B31595D55500BBD41B /* SDL_opengl.h in Headers */, AA7558B41595D55500BBD41B /* SDL_opengles.h in Headers */, + AADC5A631FDA10C800960936 /* SDL_shaders_metal_ios.h in Headers */, AA7558B51595D55500BBD41B /* SDL_opengles2.h in Headers */, AA7558B61595D55500BBD41B /* SDL_pixels.h in Headers */, AA7558B71595D55500BBD41B /* SDL_platform.h in Headers */, @@ -1426,12 +1446,16 @@ FAB598491BB5C31600BE72C5 /* SDL_rwopsbundlesupport.m in Sources */, FAB5984A1BB5C31600BE72C5 /* SDL_rwops.c in Sources */, FAB5984B1BB5C31600BE72C5 /* SDL_sysfilesystem.m in Sources */, + AADC5A5D1FDA104400960936 /* yuv_rgb.c in Sources */, FAB5984C1BB5C31600BE72C5 /* SDL_syshaptic.c in Sources */, + AADC5A5F1FDA105600960936 /* SDL_vulkan_utils.c in Sources */, + AADC5A5E1FDA105300960936 /* SDL_yuv.c in Sources */, FAB5984D1BB5C31600BE72C5 /* SDL_haptic.c in Sources */, FAB598501BB5C31600BE72C5 /* SDL_sysjoystick.m in Sources */, FAB598511BB5C31600BE72C5 /* SDL_gamecontroller.c in Sources */, FAB598521BB5C31600BE72C5 /* SDL_joystick.c in Sources */, FAB598551BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */, + AADC5A651FDA10CB00960936 /* SDL_render_metal.m in Sources */, FAB598561BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */, FAB598571BB5C31600BE72C5 /* SDL_power.c in Sources */, FAB598581BB5C31600BE72C5 /* SDL_syspower.m in Sources */, @@ -1455,6 +1479,7 @@ FAB598761BB5C31600BE72C5 /* SDL_stdlib.c in Sources */, FAB598771BB5C31600BE72C5 /* SDL_string.c in Sources */, FAB598781BB5C31600BE72C5 /* SDL_syscond.c in Sources */, + AADC5A601FDA10A400960936 /* SDL_uikitvulkan.m in Sources */, FAB598791BB5C31600BE72C5 /* SDL_sysmutex.c in Sources */, FAB5987B1BB5C31600BE72C5 /* SDL_syssem.c in Sources */, FAB5987C1BB5C31600BE72C5 /* SDL_systhread.c in Sources */, @@ -1529,6 +1554,7 @@ FD6526780DE8FCDD002AD96B /* SDL_error.c in Sources */, FD65267A0DE8FCDD002AD96B /* SDL.c in Sources */, FD65267B0DE8FCDD002AD96B /* SDL_syscond.c in Sources */, + AADC5A641FDA10C800960936 /* SDL_render_metal.m in Sources */, FD65267C0DE8FCDD002AD96B /* SDL_sysmutex.c in Sources */, FD65267D0DE8FCDD002AD96B /* SDL_syssem.c in Sources */, FD65267E0DE8FCDD002AD96B /* SDL_systhread.c in Sources */, diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index ebf6f78547eb8..abd8de98f96ec 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -154,8 +154,9 @@ #define SDL_VIDEO_RENDER_OGL_ES 1 #define SDL_VIDEO_RENDER_OGL_ES2 1 -/* Enable Vulkan support on 64-bit devices when an iOS 8+ SDK is used. */ +/* Enable Metal and Vulkan support on 64-bit devices when an iOS 8+ SDK is used. */ #if !TARGET_OS_SIMULATOR && !TARGET_CPU_ARM && defined(__IPHONE_8_0) +#define SDL_VIDEO_RENDER_METAL 1 #define SDL_VIDEO_VULKAN 1 #else #define SDL_VIDEO_VULKAN 0 diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m index 0604d28ee517a..88eeb622743f5 100644 --- a/src/render/metal/SDL_render_metal.m +++ b/src/render/metal/SDL_render_metal.m @@ -28,7 +28,11 @@ #include "SDL_syswm.h" #include "../SDL_sysrender.h" +#ifdef __MACOSX__ #include +#else +#include "../../video/uikit/SDL_uikitmetalview.h" +#endif #include #include @@ -89,27 +93,22 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect 4096} }; -typedef struct METAL_BufferList -{ - id mtlbuffer; - struct METAL_BufferPool *next; -} METAL_BufferList; - -typedef struct -{ - id mtldevice; - id mtlcmdqueue; - id mtlcmdbuffer; - id mtlcmdencoder; - id mtllibrary; - id mtlbackbuffer; - id mtlpipelineprims[4]; - id mtlpipelinecopy[4]; - id mtlbufclearverts; - CAMetalLayer *mtllayer; - MTLRenderPassDescriptor *mtlpassdesc; -} METAL_RenderData; - +@interface METAL_RenderData : NSObject + @property (atomic, retain) id mtldevice; + @property (atomic, retain) id mtlcmdqueue; + @property (atomic, retain) id mtlcmdbuffer; + @property (atomic, retain) id mtlcmdencoder; + @property (atomic, retain) id mtllibrary; + @property (atomic, retain) id mtlbackbuffer; + @property (atomic, retain) NSMutableArray *mtlpipelineprims; + @property (atomic, retain) NSMutableArray *mtlpipelinecopy; + @property (atomic, retain) id mtlbufclearverts; + @property (atomic, retain) CAMetalLayer *mtllayer; + @property (atomic, retain) MTLRenderPassDescriptor *mtlpassdesc; +@end + +@implementation METAL_RenderData +@end static int IsMetalAvailable(const SDL_SysWMinfo *syswm) @@ -132,15 +131,15 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect MakePipelineState(METAL_RenderData *data, NSString *label, NSString *vertfn, NSString *fragfn, const SDL_BlendMode blendmode) { - id mtlvertfn = [data->mtllibrary newFunctionWithName:vertfn]; - id mtlfragfn = [data->mtllibrary newFunctionWithName:fragfn]; + id mtlvertfn = [data.mtllibrary newFunctionWithName:vertfn]; + id mtlfragfn = [data.mtllibrary newFunctionWithName:fragfn]; SDL_assert(mtlvertfn != nil); SDL_assert(mtlfragfn != nil); MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init]; mtlpipedesc.vertexFunction = mtlvertfn; mtlpipedesc.fragmentFunction = mtlfragfn; - mtlpipedesc.colorAttachments[0].pixelFormat = data->mtlbackbuffer.texture.pixelFormat; + mtlpipedesc.colorAttachments[0].pixelFormat = data.mtlbackbuffer.texture.pixelFormat; switch (blendmode) { case SDL_BLENDMODE_BLEND: @@ -181,35 +180,35 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect mtlpipedesc.label = label; NSError *err = nil; - id retval = [data->mtldevice newRenderPipelineStateWithDescriptor:mtlpipedesc error:&err]; + id retval = [data.mtldevice newRenderPipelineStateWithDescriptor:mtlpipedesc error:&err]; SDL_assert(err == nil); +#if !__has_feature(objc_arc) [mtlpipedesc release]; // !!! FIXME: can these be reused for each creation, or does the pipeline obtain it? [mtlvertfn release]; [mtlfragfn release]; [label release]; - +#endif return retval; } static void -MakePipelineStates(METAL_RenderData *data, id *states, +MakePipelineStates(METAL_RenderData *data, NSMutableArray *states, NSString *label, NSString *vertfn, NSString *fragfn) { - int i = 0; - states[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=none)"], vertfn, fragfn, SDL_BLENDMODE_NONE); - states[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=blend)"], vertfn, fragfn, SDL_BLENDMODE_BLEND); - states[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=add)"], vertfn, fragfn, SDL_BLENDMODE_ADD); - states[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=mod)"], vertfn, fragfn, SDL_BLENDMODE_MOD); + [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=none)"], vertfn, fragfn, SDL_BLENDMODE_NONE)]; + [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=blend)"], vertfn, fragfn, SDL_BLENDMODE_BLEND)]; + [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=add)"], vertfn, fragfn, SDL_BLENDMODE_ADD)]; + [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=mod)"], vertfn, fragfn, SDL_BLENDMODE_MOD)]; } static inline id -ChoosePipelineState(id *states, const SDL_BlendMode blendmode) +ChoosePipelineState(NSMutableArray *states, const SDL_BlendMode blendmode) { switch (blendmode) { - case SDL_BLENDMODE_BLEND: return states[1]; - case SDL_BLENDMODE_ADD: return states[2]; - case SDL_BLENDMODE_MOD: return states[3]; - default: return states[0]; + case SDL_BLENDMODE_BLEND: return (id)states[1]; + case SDL_BLENDMODE_ADD: return (id)states[2]; + case SDL_BLENDMODE_MOD: return (id)states[3]; + default: return (id)states[0]; } return nil; } @@ -230,27 +229,28 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect return NULL; } - data = (METAL_RenderData *) SDL_calloc(1, sizeof(*data)); - if (!data) { - SDL_OutOfMemory(); - return NULL; - } - renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); if (!renderer) { - SDL_free(data); SDL_OutOfMemory(); return NULL; } + data = [[METAL_RenderData alloc] init]; + +#if __has_feature(objc_arc) + renderer->driverdata = (void*)CFBridgingRetain(data); +#else renderer->driverdata = data; +#endif renderer->window = window; #ifdef __MACOSX__ id mtldevice = MTLCreateSystemDefaultDevice(); // !!! FIXME: MTLCopyAllDevices() can find other GPUs... if (mtldevice == nil) { SDL_free(renderer); - SDL_free(data); +#if !__has_feature(objc_arc) + [data release]; +#endif SDL_SetError("Failed to obtain Metal device"); return NULL; } @@ -273,27 +273,28 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect [layer retain]; #else - + UIView *view = UIKit_Mtl_AddMetalView(window); + CAMetalLayer *layer = (CAMetalLayer *)[view layer]; #endif - data->mtldevice = layer.device; - data->mtllayer = layer; - data->mtlcmdqueue = [data->mtldevice newCommandQueue]; - data->mtlcmdqueue.label = @"SDL Metal Renderer"; + data.mtldevice = layer.device; + data.mtllayer = layer; + data.mtlcmdqueue = [data.mtldevice newCommandQueue]; + data.mtlcmdqueue.label = @"SDL Metal Renderer"; - data->mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor]; // !!! FIXME: is this autoreleased? + data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor]; // !!! FIXME: is this autoreleased? // we don't specify a depth or stencil buffer because the render API doesn't currently use them. - MTLRenderPassColorAttachmentDescriptor *colorAttachment = data->mtlpassdesc.colorAttachments[0]; - data->mtlbackbuffer = [data->mtllayer nextDrawable]; - colorAttachment.texture = data->mtlbackbuffer.texture; + MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0]; + data.mtlbackbuffer = [data.mtllayer nextDrawable]; + colorAttachment.texture = data.mtlbackbuffer.texture; colorAttachment.loadAction = MTLLoadActionClear; colorAttachment.clearColor = MTLClearColorMake(0.0f, 0.0f, 0.0f, 1.0f); - data->mtlcmdbuffer = [data->mtlcmdqueue commandBuffer]; + data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer]; // Just push a clear to the screen to start so we're in a good state. - data->mtlcmdencoder = [data->mtlcmdbuffer renderCommandEncoderWithDescriptor:data->mtlpassdesc]; - data->mtlcmdencoder.label = @"Initial drawable clear"; + data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc]; + data.mtlcmdencoder.label = @"Initial drawable clear"; METAL_RenderPresent(renderer); @@ -329,17 +330,21 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect // The compiled .metallib is embedded in a static array in a header file // but the original shader source code is in SDL_shaders_metal.metal. dispatch_data_t mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{}); - data->mtllibrary = [data->mtldevice newLibraryWithData:mtllibdata error:&err]; + data.mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err]; SDL_assert(err == nil); +#if !__has_feature(objc_arc) dispatch_release(mtllibdata); - data->mtllibrary.label = @"SDL Metal renderer shader library"; +#endif + data.mtllibrary.label = @"SDL Metal renderer shader library"; - MakePipelineStates(data, data->mtlpipelineprims, @"SDL primitives pipeline", @"SDL_Simple_vertex", @"SDL_Simple_fragment"); - MakePipelineStates(data, data->mtlpipelinecopy, @"SDL_RenderCopy pipeline", @"SDL_Copy_vertex", @"SDL_Copy_fragment"); + data.mtlpipelineprims = [[NSMutableArray alloc] init]; + MakePipelineStates(data, data.mtlpipelineprims, @"SDL primitives pipeline", @"SDL_Simple_vertex", @"SDL_Simple_fragment"); + data.mtlpipelinecopy = [[NSMutableArray alloc] init]; + MakePipelineStates(data, data.mtlpipelinecopy, @"SDL_RenderCopy pipeline", @"SDL_Copy_vertex", @"SDL_Copy_fragment"); static const float clearverts[] = { -1, -1, -1, 1, 1, 1, 1, -1, -1, -1 }; - data->mtlbufclearverts = [data->mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModePrivate]; - data->mtlbufclearverts.label = @"SDL_RenderClear vertices"; + data.mtlbufclearverts = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModePrivate]; + data.mtlbufclearverts.label = @"SDL_RenderClear vertices"; // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed. @@ -359,16 +364,16 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect static int METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) { - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; - *w = (int) data->mtlbackbuffer.texture.width; - *h = (int) data->mtlbackbuffer.texture.height; + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; + *w = (int) data.mtlbackbuffer.texture.width; + *h = (int) data.mtlbackbuffer.texture.height; return 0; } static int METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; MTLPixelFormat mtlpixfmt; switch (texture->format) { @@ -381,13 +386,15 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect MTLTextureDescriptor *mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mtlpixfmt width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO]; - id mtltexture = [data->mtldevice newTextureWithDescriptor:mtltexdesc]; + id mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc]; +#if !__has_feature(objc_arc) [mtltexdesc release]; +#endif if (mtltexture == nil) { return SDL_SetError("Texture allocation failed"); } - texture->driverdata = mtltexture; + texture->driverdata = (void*)CFBridgingRetain(mtltexture); return 0; } @@ -400,7 +407,7 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect // !!! FIXME: Maybe move this off to a thread that marks the texture as uploaded and only stall the main thread if we try to // !!! FIXME: use this texture before the marking is done? Is it worth it? Or will we basically always be uploading a bunch of // !!! FIXME: stuff way ahead of time and/or using it immediately after upload? - id mtltexture = (id) texture->driverdata; + id mtltexture = (__bridge id) texture->driverdata; [mtltexture replaceRegion:MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h) mipmapLevel:0 withBytes:pixels bytesPerRow:pitch]; return 0; } @@ -431,17 +438,17 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect static int METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) { - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; - id mtltexture = texture ? (id) texture->driverdata : nil; - data->mtlpassdesc.colorAttachments[0].texture = mtltexture; + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; + id mtltexture = texture ? (__bridge id) texture->driverdata : nil; + data.mtlpassdesc.colorAttachments[0].texture = mtltexture; return 0; } static int METAL_UpdateViewport(SDL_Renderer * renderer) { - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; - if (data->mtlcmdencoder != nil) { + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; + if (data.mtlcmdencoder != nil) { MTLViewport viewport; viewport.originX = renderer->viewport.x; viewport.originY = renderer->viewport.y; @@ -449,7 +456,7 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect viewport.height = renderer->viewport.h; viewport.znear = 0.0; viewport.zfar = 1.0; - [data->mtlcmdencoder setViewport:viewport]; + [data.mtlcmdencoder setViewport:viewport]; } return 0; } @@ -458,8 +465,8 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect METAL_UpdateClipRect(SDL_Renderer * renderer) { // !!! FIXME: should this care about the viewport? - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; - if (data->mtlcmdencoder != nil) { + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; + if (data.mtlcmdencoder != nil) { MTLScissorRect mtlrect; if (renderer->clipping_enabled) { const SDL_Rect *rect = &renderer->clip_rect; @@ -473,7 +480,7 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect mtlrect.width = renderer->viewport.w; mtlrect.height = renderer->viewport.h; } - [data->mtlcmdencoder setScissorRect:mtlrect]; + [data.mtlcmdencoder setScissorRect:mtlrect]; } return 0; } @@ -482,24 +489,24 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect METAL_RenderClear(SDL_Renderer * renderer) { // We could dump the command buffer and force a clear on a new one, but this will respect the scissor state. - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; // !!! FIXME: render color should live in a dedicated uniform buffer. const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f }; MTLViewport viewport; // RenderClear ignores the viewport state, though, so reset that. viewport.originX = viewport.originY = 0.0; - viewport.width = data->mtlbackbuffer.texture.width; - viewport.height = data->mtlbackbuffer.texture.height; + viewport.width = data.mtlbackbuffer.texture.width; + viewport.height = data.mtlbackbuffer.texture.height; viewport.znear = 0.0; viewport.zfar = 1.0; // Draw as if we're doing a simple filled rect to the screen now. - [data->mtlcmdencoder setViewport:viewport]; - [data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelineprims, renderer->blendMode)]; - [data->mtlcmdencoder setVertexBuffer:data->mtlbufclearverts offset:0 atIndex:0]; - [data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; - [data->mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5]; + [data.mtlcmdencoder setViewport:viewport]; + [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)]; + [data.mtlcmdencoder setVertexBuffer:data.mtlbufclearverts offset:0 atIndex:0]; + [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; + [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5]; // reset the viewport for the rest of our usual drawing work... viewport.originX = renderer->viewport.x; @@ -508,7 +515,7 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect viewport.height = renderer->viewport.h; viewport.znear = 0.0; viewport.zfar = 1.0; - [data->mtlcmdencoder setViewport:viewport]; + [data.mtlcmdencoder setViewport:viewport]; return 0; } @@ -546,16 +553,16 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect return SDL_OutOfMemory(); } - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; // !!! FIXME: render color should live in a dedicated uniform buffer. const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f }; - [data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelineprims, renderer->blendMode)]; - [data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; + [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)]; + [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; - const float w = (float) data->mtlpassdesc.colorAttachments[0].texture.width; - const float h = (float) data->mtlpassdesc.colorAttachments[0].texture.height; + const float w = (float) data.mtlpassdesc.colorAttachments[0].texture.width; + const float h = (float) data.mtlpassdesc.colorAttachments[0].texture.height; // !!! FIXME: we can convert this in the shader. This will save the malloc and for-loop, but we still need to upload. float *ptr = verts; @@ -564,8 +571,8 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect *ptr = normy(points->y, h); ptr++; } - [data->mtlcmdencoder setVertexBytes:verts length:vertlen atIndex:0]; - [data->mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count]; + [data.mtlcmdencoder setVertexBytes:verts length:vertlen atIndex:0]; + [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count]; SDL_free(verts); return 0; @@ -586,16 +593,16 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect static int METAL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count) { - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; // !!! FIXME: render color should live in a dedicated uniform buffer. const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f }; - [data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelineprims, renderer->blendMode)]; - [data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; + [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)]; + [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; - const float w = (float) data->mtlpassdesc.colorAttachments[0].texture.width; - const float h = (float) data->mtlpassdesc.colorAttachments[0].texture.height; + const float w = (float) data.mtlpassdesc.colorAttachments[0].texture.width; + const float h = (float) data.mtlpassdesc.colorAttachments[0].texture.height; for (int i = 0; i < count; i++, rects++) { if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) continue; @@ -608,8 +615,8 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect norm(rects->x + rects->w, w), normy(rects->y + rects->h, h) }; - [data->mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0]; - [data->mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5]; + [data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0]; + [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5]; } return 0; @@ -619,10 +626,10 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect) { - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; - id mtltexture = (id) texture->driverdata; - const float w = (float) data->mtlpassdesc.colorAttachments[0].texture.width; - const float h = (float) data->mtlpassdesc.colorAttachments[0].texture.height; + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; + id mtltexture = (__bridge id) texture->driverdata; + const float w = (float) data.mtlpassdesc.colorAttachments[0].texture.width; + const float h = (float) data.mtlpassdesc.colorAttachments[0].texture.height; const float texw = (float) mtltexture.width; const float texh = (float) mtltexture.height; @@ -650,12 +657,12 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect color[3] = ((float)texture->a) / 255.0f; } - [data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelinecopy, texture->blendMode)]; - [data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; - [data->mtlcmdencoder setFragmentTexture:mtltexture atIndex:0]; - [data->mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0]; - [data->mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1]; - [data->mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5]; + [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelinecopy, texture->blendMode)]; + [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; + [data.mtlcmdencoder setFragmentTexture:mtltexture atIndex:0]; + [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0]; + [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1]; + [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5]; return 0; } @@ -672,8 +679,8 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 pixel_format, void * pixels, int pitch) { - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; - MTLRenderPassColorAttachmentDescriptor *colorAttachment = data->mtlpassdesc.colorAttachments[0]; + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; + MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0]; id mtltexture = colorAttachment.texture; MTLRegion mtlregion; @@ -702,28 +709,30 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect static void METAL_RenderPresent(SDL_Renderer * renderer) { - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; - MTLRenderPassColorAttachmentDescriptor *colorAttachment = data->mtlpassdesc.colorAttachments[0]; - id mtlbackbuffer = data->mtlbackbuffer; + METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata; + MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0]; + id mtlbackbuffer = data.mtlbackbuffer; - [data->mtlcmdencoder endEncoding]; - [data->mtlcmdbuffer presentDrawable:mtlbackbuffer]; + [data.mtlcmdencoder endEncoding]; + [data.mtlcmdbuffer presentDrawable:mtlbackbuffer]; - [data->mtlcmdbuffer addCompletedHandler:^(id mtlcmdbuffer){ + [data.mtlcmdbuffer addCompletedHandler:^(id mtlcmdbuffer) { +#if !__has_feature(objc_arc) [mtlbackbuffer release]; +#endif }]; - [data->mtlcmdbuffer commit]; + [data.mtlcmdbuffer commit]; // Start next frame, once we can. // we don't specify a depth or stencil buffer because the render API doesn't currently use them. - data->mtlbackbuffer = [data->mtllayer nextDrawable]; - SDL_assert(data->mtlbackbuffer); - colorAttachment.texture = data->mtlbackbuffer.texture; + data.mtlbackbuffer = [data.mtllayer nextDrawable]; + SDL_assert(data.mtlbackbuffer); + colorAttachment.texture = data.mtlbackbuffer.texture; colorAttachment.loadAction = MTLLoadActionDontCare; - data->mtlcmdbuffer = [data->mtlcmdqueue commandBuffer]; - data->mtlcmdencoder = [data->mtlcmdbuffer renderCommandEncoderWithDescriptor:data->mtlpassdesc]; - data->mtlcmdencoder.label = @"SDL metal renderer frame"; + data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer]; + data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc]; + data.mtlcmdencoder.label = @"SDL metal renderer frame"; // Set up our current renderer state for the next frame... METAL_UpdateViewport(renderer); @@ -733,32 +742,36 @@ static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect static void METAL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) { - id mtltexture = (id) texture->driverdata; + id mtltexture = CFBridgingRelease(texture->driverdata); +#if !__has_feature(objc_arc) [mtltexture release]; +#endif texture->driverdata = NULL; } static void METAL_DestroyRenderer(SDL_Renderer * renderer) { - METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; + if (renderer->driverdata) { + METAL_RenderData *data = CFBridgingRelease(renderer->driverdata); - if (data) { +#if !__has_feature(objc_arc) int i; - [data->mtlcmdencoder endEncoding]; - [data->mtlcmdencoder release]; - [data->mtlcmdbuffer release]; - [data->mtlcmdqueue release]; + [data.mtlcmdencoder endEncoding]; + [data.mtlcmdencoder release]; + [data.mtlcmdbuffer release]; + [data.mtlcmdqueue release]; for (i = 0; i < 4; i++) { - [data->mtlpipelineprims[i] release]; - [data->mtlpipelinecopy[i] release]; + [data.mtlpipelineprims[i] release]; + [data.mtlpipelinecopy[i] release]; } - [data->mtlbufclearverts release]; - [data->mtllibrary release]; - [data->mtldevice release]; - [data->mtlpassdesc release]; - [data->mtllayer release]; - SDL_free(data); + [data.mtlbufclearverts release]; + [data.mtllibrary release]; + [data.mtldevice release]; + [data.mtlpassdesc release]; + [data.mtllayer release]; + [data release]; +#endif } SDL_free(renderer); } diff --git a/src/video/uikit/SDL_uikitmetalview.m b/src/video/uikit/SDL_uikitmetalview.m index b05c8906355da..385ec21a9504b 100644 --- a/src/video/uikit/SDL_uikitmetalview.m +++ b/src/video/uikit/SDL_uikitmetalview.m @@ -84,6 +84,10 @@ - (void)updateDrawableSize SDL_uikitview *view = (SDL_uikitview*)data.uiwindow.rootViewController.view; CGFloat scale = 1.0; + if ([view isKindOfClass:[SDL_uikitmetalview class]]) { + return (SDL_uikitmetalview *)view; + } + if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { /* Set the scale to the natural scale factor of the screen - the * backing dimensions of the Metal view will match the pixel