diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj index 694bfbd5cd35e..d4c1a9d90c5a1 100644 --- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -10037,6 +10037,7 @@ DYLIB_CURRENT_VERSION = 15.1.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = "./third-party/frameworks"; GCC_ALTIVEC_EXTENSIONS = YES; GCC_AUTO_VECTORIZATION = YES; GCC_ENABLE_SSE3_EXTENSIONS = YES; @@ -10121,6 +10122,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = "./third-party/frameworks"; GCC_ALTIVEC_EXTENSIONS = YES; GCC_AUTO_VECTORIZATION = YES; GCC_ENABLE_SSE3_EXTENSIONS = YES; diff --git a/Xcode/SDL/third-party/frameworks/.gitignore b/Xcode/SDL/third-party/frameworks/.gitignore new file mode 100644 index 0000000000000..06dacc560b261 --- /dev/null +++ b/Xcode/SDL/third-party/frameworks/.gitignore @@ -0,0 +1 @@ +*.framework \ No newline at end of file diff --git a/Xcode/SDL/third-party/frameworks/README.md b/Xcode/SDL/third-party/frameworks/README.md new file mode 100644 index 0000000000000..d5da455e40041 --- /dev/null +++ b/Xcode/SDL/third-party/frameworks/README.md @@ -0,0 +1,7 @@ +# Why this folder is here? + +SDL Xcode project is using this folder for managing third-party components (like external Frameworks) that are needed during the build phase. + +### Usage: + +If you're building **SDL** with **MetalANGLE** support, just copy + paste your `MetalANGLE.framework` here. \ No newline at end of file diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index 9a748beb6616e..fee1c75a99b4e 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -175,6 +175,7 @@ #define SDL_VIDEO_OPENGL_ES 1 #define SDL_VIDEO_RENDER_OGL_ES 1 #define SDL_VIDEO_RENDER_OGL_ES2 1 +#define SDL_VIDEO_OPENGL_METALANGLE 0 #endif /* Metal supported on 64-bit devices running iOS 8.0 and tvOS 9.0 and newer diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index a5cbe69629e41..86603c5e849ee 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -43,9 +43,18 @@ /* GL and GLES2 headers conflict on Linux 32 bits */ #if SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL +#if SDL_VIDEO_OPENGL_METALANGLE +#include +#include +#ifndef APIENTRY +#define APIENTRY GL_APIENTRY +#endif +#else #include "SDL_opengles2.h" +#endif /* SDL_VIDEO_OPENGL_METALANGLE */ #endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */ + #if !SDL_VIDEO_OPENGL #ifndef GL_CONTEXT_RELEASE_BEHAVIOR_KHR #define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB diff --git a/src/video/uikit/SDL_uikitopengles.m b/src/video/uikit/SDL_uikitopengles.m index 92e3e0ddf95b2..ee2ecad3bf5bf 100644 --- a/src/video/uikit/SDL_uikitopengles.m +++ b/src/video/uikit/SDL_uikitopengles.m @@ -34,7 +34,11 @@ #include "SDL_loadso.h" #include +#if SDL_VIDEO_OPENGL_METALANGLE +@interface SDLEAGLContext : MGLContext +#else @interface SDLEAGLContext : EAGLContext +#endif /* The OpenGL ES context owns a view / drawable. */ @property (nonatomic, strong) SDL_uikitopenglview *sdlView; @@ -69,8 +73,13 @@ - (void)dealloc { @autoreleasepool { SDLEAGLContext *eaglcontext = (__bridge SDLEAGLContext *) context; - - if (![EAGLContext setCurrentContext:eaglcontext]) { + +#if SDL_VIDEO_OPENGL_METALANGLE + if (![MGLContext setCurrentContext:eaglcontext]) +#else + if (![EAGLContext setCurrentContext:eaglcontext]) +#endif + { return SDL_SetError("Could not make EAGL context current"); } @@ -140,7 +149,11 @@ int UIKit_GL_SwapWindow(_THIS, SDL_Window * window) SDL_uikitopenglview *view; SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; CGRect frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen); +#if SDL_VIDEO_OPENGL_METALANGLE + MGLSharegroup *sharegroup = nil; +#else EAGLSharegroup *sharegroup = nil; +#endif CGFloat scale = 1.0; int samples = 0; int major = _this->gl_config.major_version; @@ -148,7 +161,11 @@ int UIKit_GL_SwapWindow(_THIS, SDL_Window * window) /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES * versions. */ +#if SDL_VIDEO_OPENGL_METALANGLE + MGLRenderingAPI api = major; +#else EAGLRenderingAPI api = major; +#endif /* iOS currently doesn't support GLES >3.0. iOS 6 also only supports up * to GLES 2.0. */ @@ -162,7 +179,11 @@ int UIKit_GL_SwapWindow(_THIS, SDL_Window * window) } if (_this->gl_config.share_with_current_context) { +#if SDL_VIDEO_OPENGL_METALANGLE + MGLContext *context = (__bridge MGLContext *) SDL_GL_GetCurrentContext(); +#else EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext(); +#endif sharegroup = context.sharegroup; } @@ -237,10 +258,17 @@ int UIKit_GL_SwapWindow(_THIS, SDL_Window * window) finished running its own code for the frame. If this isn't done, the app may crash or have other nasty symptoms when Dictation is used. */ +#if SDL_VIDEO_OPENGL_METALANGLE + MGLContext *context = (__bridge MGLContext *) SDL_GL_GetCurrentContext(); + if (context != NULL && [MGLContext currentContext] != context) { + [MGLContext setCurrentContext:context]; + } +#else EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext(); if (context != NULL && [EAGLContext currentContext] != context) { [EAGLContext setCurrentContext:context]; } +#endif } } diff --git a/src/video/uikit/SDL_uikitopenglview.h b/src/video/uikit/SDL_uikitopenglview.h index 4cd19ce2bbefb..8804381825e93 100644 --- a/src/video/uikit/SDL_uikitopenglview.h +++ b/src/video/uikit/SDL_uikitopenglview.h @@ -22,8 +22,12 @@ #if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 #import +#if SDL_VIDEO_OPENGL_METALANGLE +#import +#else #import #import +#endif #import "SDL_uikitview.h" #include "SDL_uikitvideo.h" @@ -41,9 +45,17 @@ stencilBits:(int)stencilBits sRGB:(BOOL)sRGB multisamples:(int)multisamples +#if SDL_VIDEO_OPENGL_METALANGLE + context:(MGLContext *)glcontext; +#else context:(EAGLContext *)glcontext; +#endif +#if SDL_VIDEO_OPENGL_METALANGLE +@property (nonatomic, readonly, weak) MGLContext *context; +#else @property (nonatomic, readonly, weak) EAGLContext *context; +#endif /* The width and height of the drawable in pixels (as opposed to points.) */ @property (nonatomic, readonly) int backingWidth; diff --git a/src/video/uikit/SDL_uikitopenglview.m b/src/video/uikit/SDL_uikitopenglview.m index eac7a12b62e8d..804ed55af19ef 100644 --- a/src/video/uikit/SDL_uikitopenglview.m +++ b/src/video/uikit/SDL_uikitopenglview.m @@ -22,8 +22,15 @@ #if SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2) +#if SDL_VIDEO_OPENGL_METALANGLE +#import +#import +#import +#import +#else #include #include +#endif #import "SDL_uikitopenglview.h" #include "SDL_uikitwindow.h" @@ -54,7 +61,11 @@ @implementation SDL_uikitopenglview { + (Class)layerClass { +#if SDL_VIDEO_OPENGL_METALANGLE + return [MGLLayer class]; +#else return [CAEAGLLayer class]; +#endif } - (instancetype)initWithFrame:(CGRect)frame @@ -68,22 +79,31 @@ - (instancetype)initWithFrame:(CGRect)frame stencilBits:(int)stencilBits sRGB:(BOOL)sRGB multisamples:(int)multisamples +#if SDL_VIDEO_OPENGL_METALANGLE + context:(MGLContext *)glcontext +#else context:(EAGLContext *)glcontext +#endif { if ((self = [super initWithFrame:frame])) { const BOOL useStencilBuffer = (stencilBits != 0); const BOOL useDepthBuffer = (depthBits != 0); +#if SDL_VIDEO_OPENGL_METALANGLE + int colorFormat; +#else NSString *colorFormat = nil; +#endif context = glcontext; samples = multisamples; retainedBacking = retained; +#if !SDL_VIDEO_OPENGL_METALANGLE if (!context || ![EAGLContext setCurrentContext:context]) { SDL_SetError("Could not create OpenGL ES drawable (could not make context current)"); return nil; } - +#endif if (samples > 0) { GLint maxsamples = 0; glGetIntegerv(GL_MAX_SAMPLES, &maxsamples); @@ -92,6 +112,24 @@ - (instancetype)initWithFrame:(CGRect)frame samples = MIN(samples, maxsamples); } +#if SDL_VIDEO_OPENGL_METALANGLE + if (sRGB) { + colorFormat = MGLDrawableColorFormatSRGBA8888; + } else if (rBits >= 8 || gBits >= 8 || bBits >= 8 || aBits > 0) { + /* if user specifically requests rbg888 or some color format higher than 16bpp */ + colorFormat = MGLDrawableColorFormatRGBA8888; + } else { + /* default case (potentially faster) */ + colorFormat = MGLDrawableColorFormatRGB565; + } + + MGLLayer *eaglLayer = (MGLLayer *)self.layer; + + eaglLayer.drawableColorFormat = colorFormat; + eaglLayer.retainedBacking = retained; + eaglLayer.contentsScale = scale; + +#else if (sRGB) { /* sRGB EAGL drawable support was added in iOS 7. */ if (UIKit_IsSystemVersionAtLeast(7.0)) { @@ -113,15 +151,42 @@ - (instancetype)initWithFrame:(CGRect)frame CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; - eaglLayer.opaque = YES; eaglLayer.drawableProperties = @{ kEAGLDrawablePropertyRetainedBacking:@(retained), kEAGLDrawablePropertyColorFormat:colorFormat }; +#endif + + eaglLayer.opaque = YES; + + /* Set the appropriate scale (for retina display support) */ self.contentScaleFactor = scale; +#if SDL_VIDEO_OPENGL_METALANGLE + if (!context || ![MGLContext setCurrentContext:context]) { + SDL_SetError("Could not create OpenGL ES drawable (could not make context current)"); + return nil; + } + + viewFramebuffer = eaglLayer.defaultOpenGLFrameBufferID; + backingWidth = eaglLayer.drawableSize.width; + backingHeight = eaglLayer.drawableSize.height; + + if (samples > 0) { + eaglLayer.drawableMultisample = samples; + } + + if (useDepthBuffer || useStencilBuffer) { + if (useDepthBuffer) { + eaglLayer.drawableDepthFormat = MGLDrawableDepthFormat16; + } + if (useStencilBuffer) { + eaglLayer.drawableStencilFormat = MGLDrawableStencilFormat8; + } + } +#else /* Create the color Renderbuffer Object */ glGenRenderbuffers(1, &viewRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer); @@ -193,7 +258,7 @@ - (instancetype)initWithFrame:(CGRect)frame } glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer); - +#endif [self setDebugLabels]; } @@ -207,16 +272,23 @@ - (GLuint)drawableRenderbuffer - (GLuint)drawableFramebuffer { +#if SDL_VIDEO_OPENGL_METALANGLE + return viewFramebuffer; +#else /* When MSAA is used, the MSAA draw framebuffer is used for drawing. */ if (msaaFramebuffer) { return msaaFramebuffer; } else { return viewFramebuffer; } +#endif } - (GLuint)msaaResolveFramebuffer { +#if SDL_VIDEO_OPENGL_METALANGLE + return viewFramebuffer; +#else /* When MSAA is used, the MSAA draw framebuffer is used for drawing and the * view framebuffer is used as a MSAA resolve framebuffer. */ if (msaaFramebuffer) { @@ -224,10 +296,12 @@ - (GLuint)msaaResolveFramebuffer } else { return 0; } +#endif } - (void)updateFrame { +#if !SDL_VIDEO_OPENGL_METALANGLE GLint prevRenderbuffer = 0; glGetIntegerv(GL_RENDERBUFFER_BINDING, &prevRenderbuffer); @@ -253,10 +327,12 @@ - (void)updateFrame } glBindRenderbuffer(GL_RENDERBUFFER, prevRenderbuffer); +#endif } - (void)setDebugLabels { +#if !SDL_VIDEO_OPENGL_METALANGLE if (viewFramebuffer != 0) { glLabelObjectEXT(GL_FRAMEBUFFER, viewFramebuffer, 0, "context FBO"); } @@ -280,10 +356,16 @@ - (void)setDebugLabels if (msaaRenderbuffer != 0) { glLabelObjectEXT(GL_RENDERBUFFER, msaaRenderbuffer, 0, "context MSAA renderbuffer"); } +#endif } - (void)swapBuffers { +#if SDL_VIDEO_OPENGL_METALANGLE + MGLLayer *eaglLayer = (MGLLayer *)self.layer; + [MGLContext setCurrentContext:context forLayer:eaglLayer]; + [context present:eaglLayer]; +#else if (msaaFramebuffer) { const GLenum attachments[] = {GL_COLOR_ATTACHMENT0}; @@ -317,6 +399,7 @@ - (void)swapBuffers * else is responsible for rebinding viewRenderbuffer, to reduce duplicate * state changes. */ [context presentRenderbuffer:GL_RENDERBUFFER]; +#endif } - (void)layoutSubviews @@ -328,6 +411,12 @@ - (void)layoutSubviews /* Update the color and depth buffer storage if the layer size has changed. */ if (width != backingWidth || height != backingHeight) { +#if SDL_VIDEO_OPENGL_METALANGLE + MGLLayer *eaglLayer = (MGLLayer *)self.layer; + [MGLContext setCurrentContext:context forLayer:eaglLayer]; + backingWidth = eaglLayer.drawableSize.width; + backingHeight = eaglLayer.drawableSize.height; +#else EAGLContext *prevContext = [EAGLContext currentContext]; if (prevContext != context) { [EAGLContext setCurrentContext:context]; @@ -338,11 +427,14 @@ - (void)layoutSubviews if (prevContext != context) { [EAGLContext setCurrentContext:prevContext]; } + +#endif } } - (void)destroyFramebuffer { +#if !SDL_VIDEO_OPENGL_METALANGLE if (viewFramebuffer != 0) { glDeleteFramebuffers(1, &viewFramebuffer); viewFramebuffer = 0; @@ -367,14 +459,21 @@ - (void)destroyFramebuffer glDeleteRenderbuffers(1, &msaaRenderbuffer); msaaRenderbuffer = 0; } +#endif } - (void)dealloc { +#if SDL_VIDEO_OPENGL_METALANGLE + if (context && context == [MGLContext currentContext]) { + [MGLContext setCurrentContext:nil]; + } +#else if (context && context == [EAGLContext currentContext]) { [self destroyFramebuffer]; [EAGLContext setCurrentContext:nil]; } +#endif } @end