Fixed compiling Metal renderer on iOS

This commit is contained in:
Sam Lantinga 2017-12-07 17:12:03 -08:00
parent 1ae73a2be8
commit 6deb1e7595
4 changed files with 186 additions and 142 deletions

View File

@ -186,6 +186,13 @@
AABCC3941640643D00AB8930 /* SDL_uikitmessagebox.h in Headers */ = {isa = PBXBuildFile; fileRef = AABCC3921640643D00AB8930 /* SDL_uikitmessagebox.h */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 = "<group>"; }; AABCC3921640643D00AB8930 /* SDL_uikitmessagebox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitmessagebox.h; sourceTree = "<group>"; };
AABCC3931640643D00AB8930 /* SDL_uikitmessagebox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitmessagebox.m; sourceTree = "<group>"; }; AABCC3931640643D00AB8930 /* SDL_uikitmessagebox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitmessagebox.m; sourceTree = "<group>"; };
AADA5B8E16CCAB7C00107CF7 /* SDL_bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_bits.h; sourceTree = "<group>"; }; AADA5B8E16CCAB7C00107CF7 /* SDL_bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_bits.h; sourceTree = "<group>"; };
AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_shaders_metal_ios.h; sourceTree = "<group>"; };
AADC5A621FDA10C800960936 /* SDL_render_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_render_metal.m; sourceTree = "<group>"; };
FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitclipboard.h; sourceTree = "<group>"; }; FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitclipboard.h; sourceTree = "<group>"; };
FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitclipboard.m; sourceTree = "<group>"; }; FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitclipboard.m; sourceTree = "<group>"; };
FAB598141BB5C1B100BE72C5 /* libSDL2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDL2.a; sourceTree = BUILT_PRODUCTS_DIR; }; FAB598141BB5C1B100BE72C5 /* libSDL2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDL2.a; sourceTree = BUILT_PRODUCTS_DIR; };
@ -622,6 +631,7 @@
041B2CE312FA0F680087D585 /* render */ = { 041B2CE312FA0F680087D585 /* render */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
AADC5A5C1FDA100800960936 /* metal */,
041B2CE812FA0F680087D585 /* opengles */, 041B2CE812FA0F680087D585 /* opengles */,
0402A85412FE70C600CECEE3 /* opengles2 */, 0402A85412FE70C600CECEE3 /* opengles2 */,
041B2CEC12FA0F680087D585 /* software */, 041B2CEC12FA0F680087D585 /* software */,
@ -786,6 +796,15 @@
path = yuv2rgb; path = yuv2rgb;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
AADC5A5C1FDA100800960936 /* metal */ = {
isa = PBXGroup;
children = (
AADC5A621FDA10C800960936 /* SDL_render_metal.m */,
AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */,
);
path = metal;
sourceTree = "<group>";
};
FD3F4A6F0DEA620800C5B771 /* stdlib */ = { FD3F4A6F0DEA620800C5B771 /* stdlib */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1238,6 +1257,7 @@
AA7558B21595D55500BBD41B /* SDL_name.h in Headers */, AA7558B21595D55500BBD41B /* SDL_name.h in Headers */,
AA7558B31595D55500BBD41B /* SDL_opengl.h in Headers */, AA7558B31595D55500BBD41B /* SDL_opengl.h in Headers */,
AA7558B41595D55500BBD41B /* SDL_opengles.h in Headers */, AA7558B41595D55500BBD41B /* SDL_opengles.h in Headers */,
AADC5A631FDA10C800960936 /* SDL_shaders_metal_ios.h in Headers */,
AA7558B51595D55500BBD41B /* SDL_opengles2.h in Headers */, AA7558B51595D55500BBD41B /* SDL_opengles2.h in Headers */,
AA7558B61595D55500BBD41B /* SDL_pixels.h in Headers */, AA7558B61595D55500BBD41B /* SDL_pixels.h in Headers */,
AA7558B71595D55500BBD41B /* SDL_platform.h in Headers */, AA7558B71595D55500BBD41B /* SDL_platform.h in Headers */,
@ -1426,12 +1446,16 @@
FAB598491BB5C31600BE72C5 /* SDL_rwopsbundlesupport.m in Sources */, FAB598491BB5C31600BE72C5 /* SDL_rwopsbundlesupport.m in Sources */,
FAB5984A1BB5C31600BE72C5 /* SDL_rwops.c in Sources */, FAB5984A1BB5C31600BE72C5 /* SDL_rwops.c in Sources */,
FAB5984B1BB5C31600BE72C5 /* SDL_sysfilesystem.m in Sources */, FAB5984B1BB5C31600BE72C5 /* SDL_sysfilesystem.m in Sources */,
AADC5A5D1FDA104400960936 /* yuv_rgb.c in Sources */,
FAB5984C1BB5C31600BE72C5 /* SDL_syshaptic.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 */, FAB5984D1BB5C31600BE72C5 /* SDL_haptic.c in Sources */,
FAB598501BB5C31600BE72C5 /* SDL_sysjoystick.m in Sources */, FAB598501BB5C31600BE72C5 /* SDL_sysjoystick.m in Sources */,
FAB598511BB5C31600BE72C5 /* SDL_gamecontroller.c in Sources */, FAB598511BB5C31600BE72C5 /* SDL_gamecontroller.c in Sources */,
FAB598521BB5C31600BE72C5 /* SDL_joystick.c in Sources */, FAB598521BB5C31600BE72C5 /* SDL_joystick.c in Sources */,
FAB598551BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */, FAB598551BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */,
AADC5A651FDA10CB00960936 /* SDL_render_metal.m in Sources */,
FAB598561BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */, FAB598561BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */,
FAB598571BB5C31600BE72C5 /* SDL_power.c in Sources */, FAB598571BB5C31600BE72C5 /* SDL_power.c in Sources */,
FAB598581BB5C31600BE72C5 /* SDL_syspower.m in Sources */, FAB598581BB5C31600BE72C5 /* SDL_syspower.m in Sources */,
@ -1455,6 +1479,7 @@
FAB598761BB5C31600BE72C5 /* SDL_stdlib.c in Sources */, FAB598761BB5C31600BE72C5 /* SDL_stdlib.c in Sources */,
FAB598771BB5C31600BE72C5 /* SDL_string.c in Sources */, FAB598771BB5C31600BE72C5 /* SDL_string.c in Sources */,
FAB598781BB5C31600BE72C5 /* SDL_syscond.c in Sources */, FAB598781BB5C31600BE72C5 /* SDL_syscond.c in Sources */,
AADC5A601FDA10A400960936 /* SDL_uikitvulkan.m in Sources */,
FAB598791BB5C31600BE72C5 /* SDL_sysmutex.c in Sources */, FAB598791BB5C31600BE72C5 /* SDL_sysmutex.c in Sources */,
FAB5987B1BB5C31600BE72C5 /* SDL_syssem.c in Sources */, FAB5987B1BB5C31600BE72C5 /* SDL_syssem.c in Sources */,
FAB5987C1BB5C31600BE72C5 /* SDL_systhread.c in Sources */, FAB5987C1BB5C31600BE72C5 /* SDL_systhread.c in Sources */,
@ -1529,6 +1554,7 @@
FD6526780DE8FCDD002AD96B /* SDL_error.c in Sources */, FD6526780DE8FCDD002AD96B /* SDL_error.c in Sources */,
FD65267A0DE8FCDD002AD96B /* SDL.c in Sources */, FD65267A0DE8FCDD002AD96B /* SDL.c in Sources */,
FD65267B0DE8FCDD002AD96B /* SDL_syscond.c in Sources */, FD65267B0DE8FCDD002AD96B /* SDL_syscond.c in Sources */,
AADC5A641FDA10C800960936 /* SDL_render_metal.m in Sources */,
FD65267C0DE8FCDD002AD96B /* SDL_sysmutex.c in Sources */, FD65267C0DE8FCDD002AD96B /* SDL_sysmutex.c in Sources */,
FD65267D0DE8FCDD002AD96B /* SDL_syssem.c in Sources */, FD65267D0DE8FCDD002AD96B /* SDL_syssem.c in Sources */,
FD65267E0DE8FCDD002AD96B /* SDL_systhread.c in Sources */, FD65267E0DE8FCDD002AD96B /* SDL_systhread.c in Sources */,

View File

@ -154,8 +154,9 @@
#define SDL_VIDEO_RENDER_OGL_ES 1 #define SDL_VIDEO_RENDER_OGL_ES 1
#define SDL_VIDEO_RENDER_OGL_ES2 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) #if !TARGET_OS_SIMULATOR && !TARGET_CPU_ARM && defined(__IPHONE_8_0)
#define SDL_VIDEO_RENDER_METAL 1
#define SDL_VIDEO_VULKAN 1 #define SDL_VIDEO_VULKAN 1
#else #else
#define SDL_VIDEO_VULKAN 0 #define SDL_VIDEO_VULKAN 0

View File

@ -28,7 +28,11 @@
#include "SDL_syswm.h" #include "SDL_syswm.h"
#include "../SDL_sysrender.h" #include "../SDL_sysrender.h"
#ifdef __MACOSX__
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#else
#include "../../video/uikit/SDL_uikitmetalview.h"
#endif
#include <Metal/Metal.h> #include <Metal/Metal.h>
#include <QuartzCore/CAMetalLayer.h> #include <QuartzCore/CAMetalLayer.h>
@ -89,27 +93,22 @@ SDL_RenderDriver METAL_RenderDriver = {
4096} 4096}
}; };
typedef struct METAL_BufferList @interface METAL_RenderData : NSObject
{ @property (atomic, retain) id<MTLDevice> mtldevice;
id<MTLBuffer> mtlbuffer; @property (atomic, retain) id<MTLCommandQueue> mtlcmdqueue;
struct METAL_BufferPool *next; @property (atomic, retain) id<MTLCommandBuffer> mtlcmdbuffer;
} METAL_BufferList; @property (atomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
@property (atomic, retain) id<MTLLibrary> mtllibrary;
typedef struct @property (atomic, retain) id<CAMetalDrawable> mtlbackbuffer;
{ @property (atomic, retain) NSMutableArray *mtlpipelineprims;
id<MTLDevice> mtldevice; @property (atomic, retain) NSMutableArray *mtlpipelinecopy;
id<MTLCommandQueue> mtlcmdqueue; @property (atomic, retain) id<MTLBuffer> mtlbufclearverts;
id<MTLCommandBuffer> mtlcmdbuffer; @property (atomic, retain) CAMetalLayer *mtllayer;
id<MTLRenderCommandEncoder> mtlcmdencoder; @property (atomic, retain) MTLRenderPassDescriptor *mtlpassdesc;
id<MTLLibrary> mtllibrary; @end
id<CAMetalDrawable> mtlbackbuffer;
id<MTLRenderPipelineState> mtlpipelineprims[4];
id<MTLRenderPipelineState> mtlpipelinecopy[4];
id<MTLBuffer> mtlbufclearverts;
CAMetalLayer *mtllayer;
MTLRenderPassDescriptor *mtlpassdesc;
} METAL_RenderData;
@implementation METAL_RenderData
@end
static int static int
IsMetalAvailable(const SDL_SysWMinfo *syswm) IsMetalAvailable(const SDL_SysWMinfo *syswm)
@ -132,15 +131,15 @@ static id<MTLRenderPipelineState>
MakePipelineState(METAL_RenderData *data, NSString *label, NSString *vertfn, MakePipelineState(METAL_RenderData *data, NSString *label, NSString *vertfn,
NSString *fragfn, const SDL_BlendMode blendmode) NSString *fragfn, const SDL_BlendMode blendmode)
{ {
id<MTLFunction> mtlvertfn = [data->mtllibrary newFunctionWithName:vertfn]; id<MTLFunction> mtlvertfn = [data.mtllibrary newFunctionWithName:vertfn];
id<MTLFunction> mtlfragfn = [data->mtllibrary newFunctionWithName:fragfn]; id<MTLFunction> mtlfragfn = [data.mtllibrary newFunctionWithName:fragfn];
SDL_assert(mtlvertfn != nil); SDL_assert(mtlvertfn != nil);
SDL_assert(mtlfragfn != nil); SDL_assert(mtlfragfn != nil);
MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init]; MTLRenderPipelineDescriptor *mtlpipedesc = [[MTLRenderPipelineDescriptor alloc] init];
mtlpipedesc.vertexFunction = mtlvertfn; mtlpipedesc.vertexFunction = mtlvertfn;
mtlpipedesc.fragmentFunction = mtlfragfn; mtlpipedesc.fragmentFunction = mtlfragfn;
mtlpipedesc.colorAttachments[0].pixelFormat = data->mtlbackbuffer.texture.pixelFormat; mtlpipedesc.colorAttachments[0].pixelFormat = data.mtlbackbuffer.texture.pixelFormat;
switch (blendmode) { switch (blendmode) {
case SDL_BLENDMODE_BLEND: case SDL_BLENDMODE_BLEND:
@ -181,35 +180,35 @@ MakePipelineState(METAL_RenderData *data, NSString *label, NSString *vertfn,
mtlpipedesc.label = label; mtlpipedesc.label = label;
NSError *err = nil; NSError *err = nil;
id<MTLRenderPipelineState> retval = [data->mtldevice newRenderPipelineStateWithDescriptor:mtlpipedesc error:&err]; id<MTLRenderPipelineState> retval = [data.mtldevice newRenderPipelineStateWithDescriptor:mtlpipedesc error:&err];
SDL_assert(err == nil); 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? [mtlpipedesc release]; // !!! FIXME: can these be reused for each creation, or does the pipeline obtain it?
[mtlvertfn release]; [mtlvertfn release];
[mtlfragfn release]; [mtlfragfn release];
[label release]; [label release];
#endif
return retval; return retval;
} }
static void static void
MakePipelineStates(METAL_RenderData *data, id<MTLRenderPipelineState> *states, MakePipelineStates(METAL_RenderData *data, NSMutableArray *states,
NSString *label, NSString *vertfn, NSString *fragfn) NSString *label, NSString *vertfn, NSString *fragfn)
{ {
int i = 0; [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=none)"], vertfn, fragfn, SDL_BLENDMODE_NONE)];
states[i++] = 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[i++] = 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[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=add)"], vertfn, fragfn, SDL_BLENDMODE_ADD); [states addObject:MakePipelineState(data, [label stringByAppendingString:@" (blendmode=mod)"], vertfn, fragfn, SDL_BLENDMODE_MOD)];
states[i++] = MakePipelineState(data, [label stringByAppendingString:@" (blendmode=mod)"], vertfn, fragfn, SDL_BLENDMODE_MOD);
} }
static inline id<MTLRenderPipelineState> static inline id<MTLRenderPipelineState>
ChoosePipelineState(id<MTLRenderPipelineState> *states, const SDL_BlendMode blendmode) ChoosePipelineState(NSMutableArray *states, const SDL_BlendMode blendmode)
{ {
switch (blendmode) { switch (blendmode) {
case SDL_BLENDMODE_BLEND: return states[1]; case SDL_BLENDMODE_BLEND: return (id<MTLRenderPipelineState>)states[1];
case SDL_BLENDMODE_ADD: return states[2]; case SDL_BLENDMODE_ADD: return (id<MTLRenderPipelineState>)states[2];
case SDL_BLENDMODE_MOD: return states[3]; case SDL_BLENDMODE_MOD: return (id<MTLRenderPipelineState>)states[3];
default: return states[0]; default: return (id<MTLRenderPipelineState>)states[0];
} }
return nil; return nil;
} }
@ -230,27 +229,28 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
return NULL; return NULL;
} }
data = (METAL_RenderData *) SDL_calloc(1, sizeof(*data));
if (!data) {
SDL_OutOfMemory();
return NULL;
}
renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
if (!renderer) { if (!renderer) {
SDL_free(data);
SDL_OutOfMemory(); SDL_OutOfMemory();
return NULL; return NULL;
} }
data = [[METAL_RenderData alloc] init];
#if __has_feature(objc_arc)
renderer->driverdata = (void*)CFBridgingRetain(data);
#else
renderer->driverdata = data; renderer->driverdata = data;
#endif
renderer->window = window; renderer->window = window;
#ifdef __MACOSX__ #ifdef __MACOSX__
id<MTLDevice> mtldevice = MTLCreateSystemDefaultDevice(); // !!! FIXME: MTLCopyAllDevices() can find other GPUs... id<MTLDevice> mtldevice = MTLCreateSystemDefaultDevice(); // !!! FIXME: MTLCopyAllDevices() can find other GPUs...
if (mtldevice == nil) { if (mtldevice == nil) {
SDL_free(renderer); SDL_free(renderer);
SDL_free(data); #if !__has_feature(objc_arc)
[data release];
#endif
SDL_SetError("Failed to obtain Metal device"); SDL_SetError("Failed to obtain Metal device");
return NULL; return NULL;
} }
@ -273,27 +273,28 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
[layer retain]; [layer retain];
#else #else
UIView *view = UIKit_Mtl_AddMetalView(window);
CAMetalLayer *layer = (CAMetalLayer *)[view layer];
#endif #endif
data->mtldevice = layer.device; data.mtldevice = layer.device;
data->mtllayer = layer; data.mtllayer = layer;
data->mtlcmdqueue = [data->mtldevice newCommandQueue]; data.mtlcmdqueue = [data.mtldevice newCommandQueue];
data->mtlcmdqueue.label = @"SDL Metal Renderer"; 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. // we don't specify a depth or stencil buffer because the render API doesn't currently use them.
MTLRenderPassColorAttachmentDescriptor *colorAttachment = data->mtlpassdesc.colorAttachments[0]; MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0];
data->mtlbackbuffer = [data->mtllayer nextDrawable]; data.mtlbackbuffer = [data.mtllayer nextDrawable];
colorAttachment.texture = data->mtlbackbuffer.texture; colorAttachment.texture = data.mtlbackbuffer.texture;
colorAttachment.loadAction = MTLLoadActionClear; colorAttachment.loadAction = MTLLoadActionClear;
colorAttachment.clearColor = MTLClearColorMake(0.0f, 0.0f, 0.0f, 1.0f); 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. // 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 = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc];
data->mtlcmdencoder.label = @"Initial drawable clear"; data.mtlcmdencoder.label = @"Initial drawable clear";
METAL_RenderPresent(renderer); METAL_RenderPresent(renderer);
@ -329,17 +330,21 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
// The compiled .metallib is embedded in a static array in a header file // 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. // 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), ^{}); 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); SDL_assert(err == nil);
#if !__has_feature(objc_arc)
dispatch_release(mtllibdata); 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"); data.mtlpipelineprims = [[NSMutableArray alloc] init];
MakePipelineStates(data, data->mtlpipelinecopy, @"SDL_RenderCopy pipeline", @"SDL_Copy_vertex", @"SDL_Copy_fragment"); 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 }; 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 = [data.mtldevice newBufferWithBytes:clearverts length:sizeof(clearverts) options:MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModePrivate];
data->mtlbufclearverts.label = @"SDL_RenderClear vertices"; 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. // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
@ -359,16 +364,16 @@ METAL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
static int static int
METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
{ {
METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
*w = (int) data->mtlbackbuffer.texture.width; *w = (int) data.mtlbackbuffer.texture.width;
*h = (int) data->mtlbackbuffer.texture.height; *h = (int) data.mtlbackbuffer.texture.height;
return 0; return 0;
} }
static int static int
METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 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; MTLPixelFormat mtlpixfmt;
switch (texture->format) { switch (texture->format) {
@ -381,13 +386,15 @@ METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
MTLTextureDescriptor *mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mtlpixfmt MTLTextureDescriptor *mtltexdesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mtlpixfmt
width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO]; width:(NSUInteger)texture->w height:(NSUInteger)texture->h mipmapped:NO];
id<MTLTexture> mtltexture = [data->mtldevice newTextureWithDescriptor:mtltexdesc]; id<MTLTexture> mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
#if !__has_feature(objc_arc)
[mtltexdesc release]; [mtltexdesc release];
#endif
if (mtltexture == nil) { if (mtltexture == nil) {
return SDL_SetError("Texture allocation failed"); return SDL_SetError("Texture allocation failed");
} }
texture->driverdata = mtltexture; texture->driverdata = (void*)CFBridgingRetain(mtltexture);
return 0; return 0;
} }
@ -400,7 +407,7 @@ METAL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
// !!! 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: 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: 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? // !!! FIXME: stuff way ahead of time and/or using it immediately after upload?
id<MTLTexture> mtltexture = (id<MTLTexture>) texture->driverdata; id<MTLTexture> mtltexture = (__bridge id<MTLTexture>) texture->driverdata;
[mtltexture replaceRegion:MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h) mipmapLevel:0 withBytes:pixels bytesPerRow:pitch]; [mtltexture replaceRegion:MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h) mipmapLevel:0 withBytes:pixels bytesPerRow:pitch];
return 0; return 0;
} }
@ -431,17 +438,17 @@ METAL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
static int static int
METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
{ {
METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
id<MTLTexture> mtltexture = texture ? (id<MTLTexture>) texture->driverdata : nil; id<MTLTexture> mtltexture = texture ? (__bridge id<MTLTexture>) texture->driverdata : nil;
data->mtlpassdesc.colorAttachments[0].texture = mtltexture; data.mtlpassdesc.colorAttachments[0].texture = mtltexture;
return 0; return 0;
} }
static int static int
METAL_UpdateViewport(SDL_Renderer * renderer) METAL_UpdateViewport(SDL_Renderer * renderer)
{ {
METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
if (data->mtlcmdencoder != nil) { if (data.mtlcmdencoder != nil) {
MTLViewport viewport; MTLViewport viewport;
viewport.originX = renderer->viewport.x; viewport.originX = renderer->viewport.x;
viewport.originY = renderer->viewport.y; viewport.originY = renderer->viewport.y;
@ -449,7 +456,7 @@ METAL_UpdateViewport(SDL_Renderer * renderer)
viewport.height = renderer->viewport.h; viewport.height = renderer->viewport.h;
viewport.znear = 0.0; viewport.znear = 0.0;
viewport.zfar = 1.0; viewport.zfar = 1.0;
[data->mtlcmdencoder setViewport:viewport]; [data.mtlcmdencoder setViewport:viewport];
} }
return 0; return 0;
} }
@ -458,8 +465,8 @@ static int
METAL_UpdateClipRect(SDL_Renderer * renderer) METAL_UpdateClipRect(SDL_Renderer * renderer)
{ {
// !!! FIXME: should this care about the viewport? // !!! FIXME: should this care about the viewport?
METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
if (data->mtlcmdencoder != nil) { if (data.mtlcmdencoder != nil) {
MTLScissorRect mtlrect; MTLScissorRect mtlrect;
if (renderer->clipping_enabled) { if (renderer->clipping_enabled) {
const SDL_Rect *rect = &renderer->clip_rect; const SDL_Rect *rect = &renderer->clip_rect;
@ -473,7 +480,7 @@ METAL_UpdateClipRect(SDL_Renderer * renderer)
mtlrect.width = renderer->viewport.w; mtlrect.width = renderer->viewport.w;
mtlrect.height = renderer->viewport.h; mtlrect.height = renderer->viewport.h;
} }
[data->mtlcmdencoder setScissorRect:mtlrect]; [data.mtlcmdencoder setScissorRect:mtlrect];
} }
return 0; return 0;
} }
@ -482,24 +489,24 @@ static int
METAL_RenderClear(SDL_Renderer * renderer) 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. // 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. // !!! 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 }; 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. MTLViewport viewport; // RenderClear ignores the viewport state, though, so reset that.
viewport.originX = viewport.originY = 0.0; viewport.originX = viewport.originY = 0.0;
viewport.width = data->mtlbackbuffer.texture.width; viewport.width = data.mtlbackbuffer.texture.width;
viewport.height = data->mtlbackbuffer.texture.height; viewport.height = data.mtlbackbuffer.texture.height;
viewport.znear = 0.0; viewport.znear = 0.0;
viewport.zfar = 1.0; viewport.zfar = 1.0;
// Draw as if we're doing a simple filled rect to the screen now. // Draw as if we're doing a simple filled rect to the screen now.
[data->mtlcmdencoder setViewport:viewport]; [data.mtlcmdencoder setViewport:viewport];
[data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelineprims, renderer->blendMode)]; [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
[data->mtlcmdencoder setVertexBuffer:data->mtlbufclearverts offset:0 atIndex:0]; [data.mtlcmdencoder setVertexBuffer:data.mtlbufclearverts offset:0 atIndex:0];
[data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
[data->mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5]; [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5];
// reset the viewport for the rest of our usual drawing work... // reset the viewport for the rest of our usual drawing work...
viewport.originX = renderer->viewport.x; viewport.originX = renderer->viewport.x;
@ -508,7 +515,7 @@ METAL_RenderClear(SDL_Renderer * renderer)
viewport.height = renderer->viewport.h; viewport.height = renderer->viewport.h;
viewport.znear = 0.0; viewport.znear = 0.0;
viewport.zfar = 1.0; viewport.zfar = 1.0;
[data->mtlcmdencoder setViewport:viewport]; [data.mtlcmdencoder setViewport:viewport];
return 0; return 0;
} }
@ -546,16 +553,16 @@ DrawVerts(SDL_Renderer * renderer, const SDL_FPoint * points, int count,
return SDL_OutOfMemory(); 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. // !!! 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 }; 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 setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
[data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
const float w = (float) data->mtlpassdesc.colorAttachments[0].texture.width; const float w = (float) data.mtlpassdesc.colorAttachments[0].texture.width;
const float h = (float) data->mtlpassdesc.colorAttachments[0].texture.height; 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. // !!! 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; float *ptr = verts;
@ -564,8 +571,8 @@ DrawVerts(SDL_Renderer * renderer, const SDL_FPoint * points, int count,
*ptr = normy(points->y, h); ptr++; *ptr = normy(points->y, h); ptr++;
} }
[data->mtlcmdencoder setVertexBytes:verts length:vertlen atIndex:0]; [data.mtlcmdencoder setVertexBytes:verts length:vertlen atIndex:0];
[data->mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count]; [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
SDL_free(verts); SDL_free(verts);
return 0; return 0;
@ -586,16 +593,16 @@ METAL_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points, int co
static int static int
METAL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count) 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. // !!! 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 }; 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 setRenderPipelineState:ChoosePipelineState(data.mtlpipelineprims, renderer->blendMode)];
[data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
const float w = (float) data->mtlpassdesc.colorAttachments[0].texture.width; const float w = (float) data.mtlpassdesc.colorAttachments[0].texture.width;
const float h = (float) data->mtlpassdesc.colorAttachments[0].texture.height; const float h = (float) data.mtlpassdesc.colorAttachments[0].texture.height;
for (int i = 0; i < count; i++, rects++) { for (int i = 0; i < count; i++, rects++) {
if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) continue; if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) continue;
@ -608,8 +615,8 @@ METAL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int coun
norm(rects->x + rects->w, w), normy(rects->y + rects->h, h) norm(rects->x + rects->w, w), normy(rects->y + rects->h, h)
}; };
[data->mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0]; [data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
[data->mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5]; [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5];
} }
return 0; return 0;
@ -619,10 +626,10 @@ static int
METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_FRect * dstrect) const SDL_Rect * srcrect, const SDL_FRect * dstrect)
{ {
METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
id<MTLTexture> mtltexture = (id<MTLTexture>) texture->driverdata; id<MTLTexture> mtltexture = (__bridge id<MTLTexture>) texture->driverdata;
const float w = (float) data->mtlpassdesc.colorAttachments[0].texture.width; const float w = (float) data.mtlpassdesc.colorAttachments[0].texture.width;
const float h = (float) data->mtlpassdesc.colorAttachments[0].texture.height; const float h = (float) data.mtlpassdesc.colorAttachments[0].texture.height;
const float texw = (float) mtltexture.width; const float texw = (float) mtltexture.width;
const float texh = (float) mtltexture.height; const float texh = (float) mtltexture.height;
@ -650,12 +657,12 @@ METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
color[3] = ((float)texture->a) / 255.0f; color[3] = ((float)texture->a) / 255.0f;
} }
[data->mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data->mtlpipelinecopy, texture->blendMode)]; [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data.mtlpipelinecopy, texture->blendMode)];
[data->mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0]; [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
[data->mtlcmdencoder setFragmentTexture:mtltexture atIndex:0]; [data.mtlcmdencoder setFragmentTexture:mtltexture atIndex:0];
[data->mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0]; [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
[data->mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1]; [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
[data->mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5]; [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:5];
return 0; 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) Uint32 pixel_format, void * pixels, int pitch)
{ {
METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
MTLRenderPassColorAttachmentDescriptor *colorAttachment = data->mtlpassdesc.colorAttachments[0]; MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0];
id<MTLTexture> mtltexture = colorAttachment.texture; id<MTLTexture> mtltexture = colorAttachment.texture;
MTLRegion mtlregion; MTLRegion mtlregion;
@ -702,28 +709,30 @@ METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
static void static void
METAL_RenderPresent(SDL_Renderer * renderer) METAL_RenderPresent(SDL_Renderer * renderer)
{ {
METAL_RenderData *data = (METAL_RenderData *) renderer->driverdata; METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
MTLRenderPassColorAttachmentDescriptor *colorAttachment = data->mtlpassdesc.colorAttachments[0]; MTLRenderPassColorAttachmentDescriptor *colorAttachment = data.mtlpassdesc.colorAttachments[0];
id<CAMetalDrawable> mtlbackbuffer = data->mtlbackbuffer; id<CAMetalDrawable> mtlbackbuffer = data.mtlbackbuffer;
[data->mtlcmdencoder endEncoding]; [data.mtlcmdencoder endEncoding];
[data->mtlcmdbuffer presentDrawable:mtlbackbuffer]; [data.mtlcmdbuffer presentDrawable:mtlbackbuffer];
[data->mtlcmdbuffer addCompletedHandler:^(id <MTLCommandBuffer> mtlcmdbuffer){ [data.mtlcmdbuffer addCompletedHandler:^(id <MTLCommandBuffer> mtlcmdbuffer) {
#if !__has_feature(objc_arc)
[mtlbackbuffer release]; [mtlbackbuffer release];
#endif
}]; }];
[data->mtlcmdbuffer commit]; [data.mtlcmdbuffer commit];
// Start next frame, once we can. // Start next frame, once we can.
// we don't specify a depth or stencil buffer because the render API doesn't currently use them. // we don't specify a depth or stencil buffer because the render API doesn't currently use them.
data->mtlbackbuffer = [data->mtllayer nextDrawable]; data.mtlbackbuffer = [data.mtllayer nextDrawable];
SDL_assert(data->mtlbackbuffer); SDL_assert(data.mtlbackbuffer);
colorAttachment.texture = data->mtlbackbuffer.texture; colorAttachment.texture = data.mtlbackbuffer.texture;
colorAttachment.loadAction = MTLLoadActionDontCare; colorAttachment.loadAction = MTLLoadActionDontCare;
data->mtlcmdbuffer = [data->mtlcmdqueue commandBuffer]; data.mtlcmdbuffer = [data.mtlcmdqueue commandBuffer];
data->mtlcmdencoder = [data->mtlcmdbuffer renderCommandEncoderWithDescriptor:data->mtlpassdesc]; data.mtlcmdencoder = [data.mtlcmdbuffer renderCommandEncoderWithDescriptor:data.mtlpassdesc];
data->mtlcmdencoder.label = @"SDL metal renderer frame"; data.mtlcmdencoder.label = @"SDL metal renderer frame";
// Set up our current renderer state for the next frame... // Set up our current renderer state for the next frame...
METAL_UpdateViewport(renderer); METAL_UpdateViewport(renderer);
@ -733,32 +742,36 @@ METAL_RenderPresent(SDL_Renderer * renderer)
static void static void
METAL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) METAL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{ {
id<MTLTexture> mtltexture = (id<MTLTexture>) texture->driverdata; id<MTLTexture> mtltexture = CFBridgingRelease(texture->driverdata);
#if !__has_feature(objc_arc)
[mtltexture release]; [mtltexture release];
#endif
texture->driverdata = NULL; texture->driverdata = NULL;
} }
static void static void
METAL_DestroyRenderer(SDL_Renderer * renderer) 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; int i;
[data->mtlcmdencoder endEncoding]; [data.mtlcmdencoder endEncoding];
[data->mtlcmdencoder release]; [data.mtlcmdencoder release];
[data->mtlcmdbuffer release]; [data.mtlcmdbuffer release];
[data->mtlcmdqueue release]; [data.mtlcmdqueue release];
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
[data->mtlpipelineprims[i] release]; [data.mtlpipelineprims[i] release];
[data->mtlpipelinecopy[i] release]; [data.mtlpipelinecopy[i] release];
} }
[data->mtlbufclearverts release]; [data.mtlbufclearverts release];
[data->mtllibrary release]; [data.mtllibrary release];
[data->mtldevice release]; [data.mtldevice release];
[data->mtlpassdesc release]; [data.mtlpassdesc release];
[data->mtllayer release]; [data.mtllayer release];
SDL_free(data); [data release];
#endif
} }
SDL_free(renderer); SDL_free(renderer);
} }

View File

@ -84,6 +84,10 @@ UIKit_Mtl_AddMetalView(SDL_Window* window)
SDL_uikitview *view = (SDL_uikitview*)data.uiwindow.rootViewController.view; SDL_uikitview *view = (SDL_uikitview*)data.uiwindow.rootViewController.view;
CGFloat scale = 1.0; CGFloat scale = 1.0;
if ([view isKindOfClass:[SDL_uikitmetalview class]]) {
return (SDL_uikitmetalview *)view;
}
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
/* Set the scale to the natural scale factor of the screen - the /* Set the scale to the natural scale factor of the screen - the
* backing dimensions of the Metal view will match the pixel * backing dimensions of the Metal view will match the pixel