From aebaa316c7801f0d7534c31870755051e00417e3 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 5 Aug 2019 12:35:32 -0300 Subject: [PATCH] Add public APIs for creating a Metal view attached to an SDL window. Add SDL_metal.h. --- CMakeLists.txt | 99 ++++++++++++++++----- Makefile.in | 1 + Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj | 8 +- Xcode/SDL/SDL.xcodeproj/project.pbxproj | 4 + configure | 23 ++++- configure.ac | 17 ++-- include/SDL.h | 1 + include/SDL_config.h.cmake | 3 + include/SDL_config.h.in | 3 + include/SDL_config_iphoneos.h | 4 + include/SDL_config_macosx.h | 23 ++++- include/SDL_metal.h | 91 +++++++++++++++++++ src/dynapi/SDL_dynapi_overrides.h | 2 + src/dynapi/SDL_dynapi_procs.h | 2 + src/render/metal/SDL_render_metal.m | 46 ++++++---- src/video/SDL_sysvideo.h | 8 ++ src/video/SDL_video.c | 21 +++++ src/video/cocoa/SDL_cocoametalview.h | 9 +- src/video/cocoa/SDL_cocoametalview.m | 40 ++++++--- src/video/cocoa/SDL_cocoavideo.m | 6 ++ src/video/cocoa/SDL_cocoavulkan.m | 20 ++++- src/video/uikit/SDL_uikitmetalview.h | 13 +-- src/video/uikit/SDL_uikitmetalview.m | 38 ++++---- src/video/uikit/SDL_uikitvideo.m | 6 ++ src/video/uikit/SDL_uikitvulkan.m | 18 +++- 25 files changed, 412 insertions(+), 94 deletions(-) create mode 100644 include/SDL_metal.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e36a840486bf..a4ed5414f3929 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -373,8 +373,10 @@ set_option(VIDEO_COCOA "Use Cocoa video driver" ${APPLE}) set_option(DIRECTX "Use DirectX for Windows audio/video" ${WINDOWS}) set_option(WASAPI "Use the Windows WASAPI audio driver" ${WINDOWS}) set_option(RENDER_D3D "Enable the Direct3D render driver" ${WINDOWS}) +set_option(RENDER_METAL "Enable the Metal render driver" ${APPLE}) set_option(VIDEO_VIVANTE "Use Vivante EGL video driver" ${UNIX_SYS}) dep_option(VIDEO_VULKAN "Enable Vulkan support" ON "ANDROID OR APPLE OR LINUX OR WINDOWS" OFF) +set_option(VIDEO_METAL "Enable Metal support" ${APPLE}) set_option(VIDEO_KMSDRM "Use KMS DRM video driver" ${UNIX_SYS}) dep_option(KMSDRM_SHARED "Dynamically load KMS DRM support" ON "VIDEO_KMSDRM" OFF) option_string(BACKGROUNDING_SIGNAL "number to use for magic backgrounding signal or 'OFF'" "OFF") @@ -1533,6 +1535,69 @@ elseif(APPLE) set(HAVE_SDL_FILESYSTEM TRUE) endif() + # iOS hack needed - http://code.google.com/p/ios-cmake/ ? + if(SDL_VIDEO) + if (IOS) + set(SDL_VIDEO_DRIVER_UIKIT 1) + file(GLOB UIKITVIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/uikit/*.m) + set(SOURCE_FILES ${SOURCE_FILES} ${UIKITVIDEO_SOURCES}) + else() + CheckCOCOA() + if(VIDEO_OPENGL) + set(SDL_VIDEO_OPENGL 1) + set(SDL_VIDEO_OPENGL_CGL 1) + set(SDL_VIDEO_RENDER_OGL 1) + set(HAVE_VIDEO_OPENGL TRUE) + endif() + + if(VIDEO_OPENGLES) + set(SDL_VIDEO_OPENGL_EGL 1) + set(SDL_VIDEO_OPENGL_ES2 1) + set(SDL_VIDEO_RENDER_OGL_ES2 1) + set(HAVE_VIDEO_OPENGLES TRUE) + endif() + endif() + + if(VIDEO_VULKAN OR VIDEO_METAL OR RENDER_METAL) + set(ORIG_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -x objective-c") + check_c_source_compiles(" + #include + #import + #import + + #if TARGET_OS_SIMULATOR || (!TARGET_CPU_X86_64 && !TARGET_CPU_ARM64) + #error Metal doesn't work on this configuration + #endif + int main() + { + return 0; + } + " HAVE_FRAMEWORK_METAL) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) + if(HAVE_FRAMEWORK_METAL) + set(SDL_FRAMEWORK_METAL 1) + set(SDL_FRAMEWORK_QUARTZCORE 1) + else() + set(VIDEO_VULKAN 0) + set(VIDEO_METAL 0) + set(RENDER_METAL 0) + endif() + endif() + + if(VIDEO_METAL) + set(SDL_VIDEO_METAL 1) + set(HAVE_VIDEO_METAL TRUE) + endif() + + if(RENDER_METAL) + file(GLOB RENDER_METAL_SOURCES ${SDL2_SOURCE_DIR}/src/render/metal/*.m) + set(SOURCE_FILES ${SOURCE_FILES} ${RENDER_METAL_SOURCES}) + set(SDL_VIDEO_RENDER_METAL 1) + set(HAVE_RENDER_METAL TRUE) + endif() + endif() + # Actually load the frameworks at the end so we don't duplicate include. if(SDL_FRAMEWORK_COREVIDEO) find_library(COREVIDEO CoreVideo) @@ -1562,28 +1627,20 @@ elseif(APPLE) find_library(AUDIOTOOLBOX AudioToolbox) list(APPEND EXTRA_LIBS ${AUDIOTOOLBOX}) endif() - - # iOS hack needed - http://code.google.com/p/ios-cmake/ ? - if(SDL_VIDEO) - if (IOS) - set(SDL_VIDEO_DRIVER_UIKIT 1) - file(GLOB UIKITVIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/uikit/*.m) - set(SOURCE_FILES ${SOURCE_FILES} ${UIKITVIDEO_SOURCES}) + if(SDL_FRAMEWORK_METAL) + if(IOS) + find_library(METAL Metal) + list(APPEND EXTRA_LIBS ${METAL}) else() - CheckCOCOA() - if(VIDEO_OPENGL) - set(SDL_VIDEO_OPENGL 1) - set(SDL_VIDEO_OPENGL_CGL 1) - set(SDL_VIDEO_RENDER_OGL 1) - set(HAVE_VIDEO_OPENGL TRUE) - endif() - - if(VIDEO_OPENGLES) - set(SDL_VIDEO_OPENGL_EGL 1) - set(SDL_VIDEO_OPENGL_ES2 1) - set(SDL_VIDEO_RENDER_OGL_ES2 1) - set(HAVE_VIDEO_OPENGLES TRUE) - endif() + list(APPEND EXTRA_LDFLAGS "-Wl,-weak_framework,Metal") + endif() + endif() + if(SDL_FRAMEWORK_QUARTZCORE) + if(IOS) + find_library(QUARTZCORE QuartzCore) + list(APPEND EXTRA_LIBS ${QUARTZCORE}) + else() + list(APPEND EXTRA_LDFLAGS "-Wl,-weak_framework,QuartzCore") endif() endif() diff --git a/Makefile.in b/Makefile.in index 567624e90fb3a..6b4eecf738cae 100644 --- a/Makefile.in +++ b/Makefile.in @@ -84,6 +84,7 @@ HDRS = \ SDL_log.h \ SDL_main.h \ SDL_messagebox.h \ + SDL_metal.h \ SDL_mouse.h \ SDL_mutex.h \ SDL_name.h \ diff --git a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj index ef8539b1ab9f3..3146cb3e47d49 100644 --- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj @@ -717,6 +717,7 @@ F3E3C75B224138AE007D243C /* SDL_uikit_main.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C657224069CE007D243C /* SDL_uikit_main.c */; }; 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 */; }; + FA24348D21D4201400B8918A /* SDL_metal.h in Headers */ = {isa = PBXBuildFile; fileRef = FA24348C21D4201400B8918A /* SDL_metal.h */; }; FAB5981D1BB5C31500BE72C5 /* SDL_atomic.c in Sources */ = {isa = PBXBuildFile; fileRef = 04FFAB8912E23B8D00BA343D /* SDL_atomic.c */; }; FAB5981E1BB5C31500BE72C5 /* SDL_spinlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 04FFAB8A12E23B8D00BA343D /* SDL_spinlock.c */; }; FAB5981F1BB5C31500BE72C5 /* SDL_coreaudio.m in Sources */ = {isa = PBXBuildFile; fileRef = 56EA86F913E9EC2B002E47EB /* SDL_coreaudio.m */; }; @@ -1064,6 +1065,7 @@ F3E3C75F224138AE007D243C /* libSDLmain.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDLmain.a; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = ""; }; + FA24348C21D4201400B8918A /* SDL_metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_metal.h; sourceTree = ""; }; FAB598141BB5C1B100BE72C5 /* libSDL2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDL2.a; sourceTree = BUILT_PRODUCTS_DIR; }; FAD4F7011BA3C4E8008346CE /* SDL_sysjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysjoystick_c.h; sourceTree = ""; }; FD0BBFEF0E3933DD00D833B1 /* SDL_uikitview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitview.h; sourceTree = ""; }; @@ -1576,15 +1578,14 @@ children = ( AA7558651595D55500BBD41B /* begin_code.h */, AA7558661595D55500BBD41B /* close_code.h */, - AA7558971595D55500BBD41B /* SDL.h */, AA7558671595D55500BBD41B /* SDL_assert.h */, AA7558681595D55500BBD41B /* SDL_atomic.h */, AA7558691595D55500BBD41B /* SDL_audio.h */, AADA5B8E16CCAB7C00107CF7 /* SDL_bits.h */, AA75586A1595D55500BBD41B /* SDL_blendmode.h */, AA75586B1595D55500BBD41B /* SDL_clipboard.h */, - AA75586D1595D55500BBD41B /* SDL_config.h */, AA75586C1595D55500BBD41B /* SDL_config_iphoneos.h */, + AA75586D1595D55500BBD41B /* SDL_config.h */, AA75586E1595D55500BBD41B /* SDL_copying.h */, AA75586F1595D55500BBD41B /* SDL_cpuinfo.h */, AA7558701595D55500BBD41B /* SDL_endian.h */, @@ -1602,6 +1603,7 @@ AA75587B1595D55500BBD41B /* SDL_log.h */, AA75587C1595D55500BBD41B /* SDL_main.h */, AA9FF9501637C6E5000DF050 /* SDL_messagebox.h */, + FA24348C21D4201400B8918A /* SDL_metal.h */, AA75587D1595D55500BBD41B /* SDL_mouse.h */, AA75587E1595D55500BBD41B /* SDL_mutex.h */, AA75587F1595D55500BBD41B /* SDL_name.h */, @@ -1630,6 +1632,7 @@ AA7558951595D55500BBD41B /* SDL_version.h */, AA7558961595D55500BBD41B /* SDL_video.h */, 4D7516FE1EE1C5B400820EEA /* SDL_vulkan.h */, + AA7558971595D55500BBD41B /* SDL.h */, ); name = "Public Headers"; path = ../../include; @@ -2183,6 +2186,7 @@ AA75589D1595D55500BBD41B /* SDL_blendmode.h in Headers */, F30D9C9E212CD0990047DF2E /* SDL_sensor_c.h in Headers */, AA75589E1595D55500BBD41B /* SDL_clipboard.h in Headers */, + FA24348D21D4201400B8918A /* SDL_metal.h in Headers */, AA75589F1595D55500BBD41B /* SDL_config_iphoneos.h in Headers */, AA7558A01595D55500BBD41B /* SDL_config.h in Headers */, AA7558A11595D55500BBD41B /* SDL_copying.h in Headers */, diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj index 59c86f21128d1..52f13896a6cb6 100644 --- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -919,6 +919,7 @@ F3950CD8212BC88D00F51292 /* SDL_sensor.h in Headers */ = {isa = PBXBuildFile; fileRef = F3950CD7212BC88D00F51292 /* SDL_sensor.h */; settings = {ATTRIBUTES = (Public, ); }; }; F3950CD9212BC88D00F51292 /* SDL_sensor.h in Headers */ = {isa = PBXBuildFile; fileRef = F3950CD7212BC88D00F51292 /* SDL_sensor.h */; settings = {ATTRIBUTES = (Public, ); }; }; F3950CDA212BC88D00F51292 /* SDL_sensor.h in Headers */ = {isa = PBXBuildFile; fileRef = F3950CD7212BC88D00F51292 /* SDL_sensor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FA24348B21D41FFB00B8918A /* SDL_metal.h in Headers */ = {isa = PBXBuildFile; fileRef = FA24348A21D41FFB00B8918A /* SDL_metal.h */; }; FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; }; FA73671E19A54140004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; }; FA73671F19A54144004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; }; @@ -1252,6 +1253,7 @@ F59C710300D5CB5801000001 /* ReadMe.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ReadMe.txt; sourceTree = ""; }; F59C710600D5CB5801000001 /* SDL.info */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = SDL.info; sourceTree = ""; }; F5A2EF3900C6A39A01000001 /* BUGS.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = BUGS.txt; path = ../../BUGS.txt; sourceTree = SOURCE_ROOT; }; + FA24348A21D41FFB00B8918A /* SDL_metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_metal.h; sourceTree = ""; }; FA73671C19A540EF004122E4 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; FABA34C61D8B5DB100915323 /* SDL_coreaudio.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_coreaudio.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1342,6 +1344,7 @@ AA7557DD1595D4D800BBD41B /* SDL_log.h */, AA7557DE1595D4D800BBD41B /* SDL_main.h */, AA9FF9591637CBF9000DF050 /* SDL_messagebox.h */, + FA24348A21D41FFB00B8918A /* SDL_metal.h */, AA7557DF1595D4D800BBD41B /* SDL_mouse.h */, AA7557E01595D4D800BBD41B /* SDL_mutex.h */, AA7557E11595D4D800BBD41B /* SDL_name.h */, @@ -2029,6 +2032,7 @@ AA75580E1595D4D800BBD41B /* SDL_cpuinfo.h in Headers */, AA7558101595D4D800BBD41B /* SDL_endian.h in Headers */, AA7558121595D4D800BBD41B /* SDL_error.h in Headers */, + FA24348B21D41FFB00B8918A /* SDL_metal.h in Headers */, AA7558141595D4D800BBD41B /* SDL_events.h in Headers */, 567E2F2117C44C35005F1892 /* SDL_filesystem.h in Headers */, A77E6EB4167AB0A90010E40B /* SDL_gamecontroller.h in Headers */, diff --git a/configure b/configure index 8e0cefb2ae4a3..cfd6078421060 100755 --- a/configure +++ b/configure @@ -869,6 +869,7 @@ enable_video_x11_xshape enable_video_x11_vm enable_video_vivante enable_video_cocoa +enable_video_metal enable_render_metal enable_video_directfb enable_directfb_shared @@ -1647,6 +1648,7 @@ Optional Features: --enable-video-x11-vm use X11 VM extension for fullscreen [[default=yes]] --enable-video-vivante use Vivante EGL video driver [[default=yes]] --enable-video-cocoa use Cocoa video driver [[default=yes]] + --enable-video-metal include Metal support [[default=yes]] --enable-render-metal enable the Metal render driver [[default=yes]] --enable-video-directfb use DirectFB video driver [[default=no]] --enable-directfb-shared @@ -21530,6 +21532,13 @@ $as_echo "#define SDL_VIDEO_DRIVER_COCOA 1" >>confdefs.h CheckMETAL() { + # Check whether --enable-video-metal was given. +if test "${enable_video_metal+set}" = set; then : + enableval=$enable_video_metal; +else + enable_video_metal=yes +fi + # Check whether --enable-render-metal was given. if test "${enable_render_metal+set}" = set; then : enableval=$enable_render_metal; @@ -21537,7 +21546,7 @@ else enable_render_metal=yes fi - if test x$enable_render = xyes -a x$enable_render_metal = xyes; then + if test x$enable_video = xyes -a x$enable_video_metal = xyes; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -x objective-c" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Metal framework" >&5 @@ -21574,11 +21583,17 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext $as_echo "$have_metal" >&6; } if test x$have_metal = xyes; then +$as_echo "#define SDL_VIDEO_METAL 1" >>confdefs.h + + if test x$enable_render = xyes -a x$enable_render_metal = xyes; then + $as_echo "#define SDL_VIDEO_RENDER_METAL 1" >>confdefs.h - SOURCES="$SOURCES $srcdir/src/render/metal/*.m" + SOURCES="$SOURCES $srcdir/src/render/metal/*.m" + fi SUMMARY_video="${SUMMARY_video} metal" else + enable_video_metal=no enable_render_metal=no fi fi @@ -25064,7 +25079,7 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,UIKit" - if test x$enable_render = xyes -a x$enable_render_metal = xyes; then + if test x$enable_video_metal = xyes -o x$enable_video_vulkan = xyes; then EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Metal" fi ;; @@ -25158,7 +25173,7 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit" - if test x$enable_render = xyes -a x$enable_render_metal = xyes; then + if test x$enable_video_metal = xyes -o x$enable_video_vulkan = xyes; then EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-weak_framework,QuartzCore -Wl,-weak_framework,Metal" fi ;; diff --git a/configure.ac b/configure.ac index c6fd37f44afd0..62145acb16ff3 100644 --- a/configure.ac +++ b/configure.ac @@ -2048,10 +2048,13 @@ AS_HELP_STRING([--enable-video-cocoa], [use Cocoa video driver [[default=yes]]]) CheckMETAL() { + AC_ARG_ENABLE(video-metal, +AC_HELP_STRING([--enable-video-metal], [include Metal support [[default=yes]]]), + , enable_video_metal=yes) AC_ARG_ENABLE(render-metal, AS_HELP_STRING([--enable-render-metal], [enable the Metal render driver [[default=yes]]]), , enable_render_metal=yes) - if test x$enable_render = xyes -a x$enable_render_metal = xyes; then + if test x$enable_video = xyes -a x$enable_video_metal = xyes; then save_CFLAGS="$CFLAGS" dnl Work around that we don't have Objective-C support in autoconf CFLAGS="$CFLAGS -x objective-c" @@ -2072,10 +2075,14 @@ AS_HELP_STRING([--enable-render-metal], [enable the Metal render driver [[defaul CFLAGS="$save_CFLAGS" AC_MSG_RESULT($have_metal) if test x$have_metal = xyes; then - AC_DEFINE(SDL_VIDEO_RENDER_METAL, 1, [ ]) - SOURCES="$SOURCES $srcdir/src/render/metal/*.m" + AC_DEFINE(SDL_VIDEO_METAL, 1, [ ]) + if test x$enable_render = xyes -a x$enable_render_metal = xyes; then + AC_DEFINE(SDL_VIDEO_RENDER_METAL, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/render/metal/*.m" + fi SUMMARY_video="${SUMMARY_video} metal" else + enable_video_metal=no enable_render_metal=no fi fi @@ -3828,7 +3835,7 @@ AS_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,UIKit" - if test x$enable_render = xyes -a x$enable_render_metal = xyes; then + if test x$enable_video_metal = xyes -o x$enable_video_vulkan = xyes; then EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Metal" fi ;; @@ -3910,7 +3917,7 @@ AS_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit" - if test x$enable_render = xyes -a x$enable_render_metal = xyes; then + if test x$enable_video_metal = xyes -o x$enable_video_vulkan = xyes; then EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-weak_framework,QuartzCore -Wl,-weak_framework,Metal" fi ;; diff --git a/include/SDL.h b/include/SDL.h index 88dce0c03e263..e43293959a685 100644 --- a/include/SDL.h +++ b/include/SDL.h @@ -47,6 +47,7 @@ #include "SDL_loadso.h" #include "SDL_log.h" #include "SDL_messagebox.h" +#include "SDL_metal.h" #include "SDL_mutex.h" #include "SDL_power.h" #include "SDL_render.h" diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index 75ff0bb7ad956..65ba3ea70c4db 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -388,6 +388,9 @@ /* Enable Vulkan support */ #cmakedefine SDL_VIDEO_VULKAN @SDL_VIDEO_VULKAN@ +/* Enable Metal support */ +#cmakedefine SDL_VIDEO_METAL @SDL_VIDEO_METAL@ + /* Enable system power support */ #cmakedefine SDL_POWER_ANDROID @SDL_POWER_ANDROID@ #cmakedefine SDL_POWER_LINUX @SDL_POWER_LINUX@ diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index e4eb6f6487c62..6d5d13ecc3f0d 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -383,6 +383,9 @@ /* Enable Vulkan support */ #undef SDL_VIDEO_VULKAN +/* Enable Metal support */ +#undef SDL_VIDEO_METAL + /* Enable system power support */ #undef SDL_POWER_LINUX #undef SDL_POWER_WINDOWS diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index a3bf2e8ff5a60..8137085ed0156 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -181,6 +181,10 @@ #define SDL_VIDEO_VULKAN 1 #endif +#if SDL_PLATFORM_SUPPORTS_METAL +#define SDL_VIDEO_METAL 1 +#endif + /* Enable system power support */ #define SDL_POWER_UIKIT 1 diff --git a/include/SDL_config_macosx.h b/include/SDL_config_macosx.h index 16d05097dc0e3..254c36d790678 100644 --- a/include/SDL_config_macosx.h +++ b/include/SDL_config_macosx.h @@ -193,9 +193,15 @@ #define SDL_VIDEO_RENDER_OGL_ES2 1 #endif -#ifndef SDL_VIDEO_RENDER_METAL /* Metal only supported on 64-bit architectures with 10.11+ */ #if TARGET_CPU_X86_64 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101100) +#define SDL_PLATFORM_SUPPORTS_METAL 1 +#else +#define SDL_PLATFORM_SUPPORTS_METAL 0 +#endif + +#ifndef SDL_VIDEO_RENDER_METAL +#if SDL_PLATFORM_SUPPORTS_METAL #define SDL_VIDEO_RENDER_METAL 1 #else #define SDL_VIDEO_RENDER_METAL 0 @@ -219,13 +225,22 @@ #define SDL_VIDEO_OPENGL_GLX 1 #endif -/* Enable Vulkan support */ -/* Metal/Vulkan Portability only supported on 64-bit architectures with 10.11+ */ -#if TARGET_CPU_X86_64 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101100) +/* Enable Vulkan and Metal support */ +#ifndef SDL_VIDEO_VULKAN +#if SDL_PLATFORM_SUPPORTS_METAL #define SDL_VIDEO_VULKAN 1 #else #define SDL_VIDEO_VULKAN 0 #endif +#endif + +#ifndef SDL_VIDEO_METAL +#if SDL_PLATFORM_SUPPORTS_METAL +#define SDL_VIDEO_METAL 1 +#else +#define SDL_VIDEO_METAL 0 +#endif +#endif /* Enable system power support */ #define SDL_POWER_MACOSX 1 diff --git a/include/SDL_metal.h b/include/SDL_metal.h new file mode 100644 index 0000000000000..0f1e0e94d63ea --- /dev/null +++ b/include/SDL_metal.h @@ -0,0 +1,91 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2019 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/** + * \file SDL_metal.h + * + * Header file for functions to creating Metal layers and views on SDL windows. + */ + +#ifndef SDL_metal_h_ +#define SDL_metal_h_ + +#include "SDL_video.h" + +#include "begin_code.h" +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief A handle to a CAMetalLayer-backed NSView (macOS) or UIView (iOS/tvOS). + * + * \note This can be cast directly to an NSView or UIView. + */ +typedef void *SDL_MetalView; + +/** + * \name Metal support functions + */ +/* @{ */ + +/** + * \brief Create a CAMetalLayer-backed NSView/UIView and attach it to the + * specified window. + * + * On macOS, this does *not* associate a MTLDevice with the CAMetalLayer on its + * own. It is up to user code to do that. + * + * The returned handle can be casted directly to a NSView or UIView, and the + * CAMetalLayer can be accessed from the view's 'layer' property. + * + * \code + * SDL_MetalView metalview = SDL_Metal_CreateView(window); + * UIView *uiview = (__bridge UIView *)metalview; + * CAMetalLayer *metallayer = (CAMetalLayer *)uiview.layer; + * // [...] + * SDL_Metal_DestroyView(metalview); + * \endcode + * + * \sa SDL_Metal_DestroyView + */ +extern DECLSPEC SDL_MetalView SDLCALL SDL_Metal_CreateView(SDL_Window * window); + +/** + * \brief Destroy an existing SDL_MetalView object. + * + * This should be called before SDL_DestroyWindow, if SDL_Metal_CreateView was + * called after SDL_CreateWindow. + * + * \sa SDL_Metal_CreateView + */ +extern DECLSPEC void SDLCALL SDL_Metal_DestroyView(SDL_MetalView view); + +/* @} *//* Metal support functions */ + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include "close_code.h" + +#endif /* SDL_metal_h_ */ diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index f8c54334808af..c769582fdc794 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -724,3 +724,5 @@ #define SDL_RWwrite SDL_RWwrite_REAL #define SDL_RWclose SDL_RWclose_REAL #define SDL_LoadFile SDL_LoadFile_REAL +#define SDL_Metal_CreateView SDL_Metal_CreateView_REAL +#define SDL_Metal_DestroyView SDL_Metal_DestroyView_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 5a227369507a5..de5edbad73453 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -780,3 +780,5 @@ SDL_DYNAPI_PROC(size_t,SDL_RWread,(SDL_RWops *a, void *b, size_t c, size_t d),(a SDL_DYNAPI_PROC(size_t,SDL_RWwrite,(SDL_RWops *a, const void *b, size_t c, size_t d),(a,b,c,d),return) SDL_DYNAPI_PROC(int,SDL_RWclose,(SDL_RWops *a),(a),return) SDL_DYNAPI_PROC(void*,SDL_LoadFile,(const char *a, size_t *b),(a,b),return) +SDL_DYNAPI_PROC(SDL_MetalView,SDL_Metal_CreateView,(SDL_Window *a),(a),return) +SDL_DYNAPI_PROC(void,SDL_Metal_DestroyView,(SDL_MetalView a),(a),) diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m index 9233b8fee3c32..ee080f86af4b5 100644 --- a/src/render/metal/SDL_render_metal.m +++ b/src/render/metal/SDL_render_metal.m @@ -26,17 +26,17 @@ #include "SDL_log.h" #include "SDL_assert.h" #include "SDL_syswm.h" +#include "SDL_metal.h" #include "../SDL_sysrender.h" -#ifdef __MACOSX__ -#include "../../video/cocoa/SDL_cocoametalview.h" -#else -#include "../../video/uikit/SDL_uikitmetalview.h" -#endif #include #import #import +#ifdef __MACOSX__ +#import +#endif + /* Regenerate these with build-metal-shaders.sh */ #ifdef __MACOSX__ #include "SDL_shaders_metal_osx.h" @@ -118,6 +118,7 @@ @interface METAL_RenderData : NSObject @property (nonatomic, retain) id mtlsamplerlinear; @property (nonatomic, retain) id mtlbufconstants; @property (nonatomic, retain) id mtlbufquadindices; + @property (nonatomic, assign) SDL_MetalView mtlview; @property (nonatomic, retain) CAMetalLayer *mtllayer; @property (nonatomic, retain) MTLRenderPassDescriptor *mtlpassdesc; @property (nonatomic, assign) METAL_ShaderPipelines *activepipelines; @@ -1475,6 +1476,8 @@ - (void)dealloc } DestroyAllPipelines(data.allpipelines, data.pipelinescount); + + SDL_Metal_DestroyView(data.mtlview); } SDL_free(renderer); @@ -1501,6 +1504,8 @@ - (void)dealloc SDL_Renderer *renderer = NULL; METAL_RenderData *data = NULL; id mtldevice = nil; + SDL_MetalView view = NULL; + CAMetalLayer *layer = nil; SDL_SysWMinfo syswm; SDL_VERSION(&syswm.version); @@ -1527,26 +1532,36 @@ - (void)dealloc return NULL; } + view = SDL_Metal_CreateView(window); + + if (view == NULL) { + SDL_free(renderer); + return NULL; + } + // !!! FIXME: error checking on all of this. data = [[METAL_RenderData alloc] init]; + if (data == nil) { + SDL_Metal_DestroyView(view); + SDL_free(renderer); + return NULL; + } + renderer->driverdata = (void*)CFBridgingRetain(data); renderer->window = window; -#ifdef __MACOSX__ - NSView *view = Cocoa_Mtl_AddMetalView(window); - CAMetalLayer *layer = (CAMetalLayer *)[view layer]; - - layer.device = mtldevice; - - //layer.colorspace = nil; + data.mtlview = view; +#ifdef __MACOSX__ + layer = (CAMetalLayer *)[(NSView *)view layer]; #else - UIView *view = UIKit_Mtl_AddMetalView(window); - CAMetalLayer *layer = (CAMetalLayer *)[view layer]; + layer = (CAMetalLayer *)[(__bridge UIView *)view layer]; #endif - // Necessary for RenderReadPixels. + layer.device = mtldevice; + + /* Necessary for RenderReadPixels. */ layer.framebufferOnly = NO; data.mtldevice = layer.device; @@ -1763,7 +1778,6 @@ - (void)dealloc [mtlsamplerlinear release]; [mtlbufconstants release]; [mtlbufquadindices release]; - [view release]; [data release]; [mtldevice release]; #endif diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index e88a8b60eb852..ddaaf38a5ad7f 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -26,6 +26,7 @@ #include "SDL_messagebox.h" #include "SDL_shape.h" #include "SDL_thread.h" +#include "SDL_metal.h" #include "SDL_vulkan_internal.h" @@ -274,6 +275,13 @@ struct SDL_VideoDevice SDL_bool (*Vulkan_CreateSurface) (_THIS, SDL_Window *window, VkInstance instance, VkSurfaceKHR *surface); void (*Vulkan_GetDrawableSize) (_THIS, SDL_Window * window, int *w, int *h); + /* * * */ + /* + * Metal support + */ + SDL_MetalView (*Metal_CreateView) (_THIS, SDL_Window * window); + void (*Metal_DestroyView) (_THIS, SDL_MetalView view); + /* * * */ /* * Event manager functions diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index c63f74631b71f..35599f4809595 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -4183,4 +4183,25 @@ void SDL_Vulkan_GetDrawableSize(SDL_Window * window, int *w, int *h) } } +SDL_MetalView +SDL_Metal_CreateView(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, NULL); + + if (_this->Metal_CreateView) { + return _this->Metal_CreateView(_this, window); + } else { + SDL_SetError("Metal is not supported."); + return NULL; + } +} + +void +SDL_Metal_DestroyView(SDL_MetalView view) +{ + if (_this && view && _this->Metal_DestroyView) { + _this->Metal_DestroyView(_this, view); + } +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoametalview.h b/src/video/cocoa/SDL_cocoametalview.h index 6dafef3a31400..77e7256bed646 100644 --- a/src/video/cocoa/SDL_cocoametalview.h +++ b/src/video/cocoa/SDL_cocoametalview.h @@ -31,7 +31,7 @@ #import "../SDL_sysvideo.h" #import "SDL_cocoawindow.h" -#if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_RENDER_METAL) +#if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) #import #import @@ -51,11 +51,12 @@ @end -SDL_cocoametalview* Cocoa_Mtl_AddMetalView(SDL_Window* window); +SDL_MetalView Cocoa_Metal_CreateView(_THIS, SDL_Window * window); +void Cocoa_Metal_DestroyView(_THIS, SDL_MetalView view); -void Cocoa_Mtl_GetDrawableSize(SDL_Window * window, int * w, int * h); +void Cocoa_Metal_GetDrawableSize(SDL_Window * window, int * w, int * h); -#endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_RENDER_METAL) */ +#endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */ #endif /* SDL_cocoametalview_h_ */ diff --git a/src/video/cocoa/SDL_cocoametalview.m b/src/video/cocoa/SDL_cocoametalview.m index 3d7e147cb45e6..b3b8b8434e8df 100644 --- a/src/video/cocoa/SDL_cocoametalview.m +++ b/src/video/cocoa/SDL_cocoametalview.m @@ -27,7 +27,7 @@ #import "SDL_cocoametalview.h" -#if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_RENDER_METAL) +#if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) #include "SDL_assert.h" @@ -100,22 +100,38 @@ - (void)resizeWithOldSuperviewSize:(NSSize)oldSize @end -SDL_cocoametalview* -Cocoa_Mtl_AddMetalView(SDL_Window* window) -{ +SDL_MetalView +Cocoa_Metal_CreateView(_THIS, SDL_Window * window) +{ @autoreleasepool { SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata; NSView *view = data->nswindow.contentView; BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; - SDL_cocoametalview *metalview; + SDL_cocoametalview *newview; + SDL_MetalView metalview; + + newview = [[SDL_cocoametalview alloc] initWithFrame:view.frame highDPI:highDPI]; + if (newview == nil) { + return NULL; + } + + [view addSubview:newview]; + + metalview = (SDL_MetalView)CFBridgingRetain(newview); + [newview release]; - metalview = [[SDL_cocoametalview alloc] initWithFrame:view.frame highDPI:highDPI]; - [view addSubview:metalview]; return metalview; -} +}} void -Cocoa_Mtl_GetDrawableSize(SDL_Window * window, int * w, int * h) -{ +Cocoa_Metal_DestroyView(_THIS, SDL_MetalView view) +{ @autoreleasepool { + SDL_cocoametalview *metalview = CFBridgingRelease(view); + [metalview removeFromSuperview]; +}} + +void +Cocoa_Metal_GetDrawableSize(SDL_Window * window, int * w, int * h) +{ @autoreleasepool { SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; NSView *view = data->nswindow.contentView; SDL_cocoametalview* metalview = [view viewWithTag:METALVIEW_TAG]; @@ -131,8 +147,8 @@ - (void)resizeWithOldSuperviewSize:(NSSize)oldSize } else { SDL_GetWindowSize(window, w, h); } -} +}} -#endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_RENDER_METAL) */ +#endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index feb8e08a8c998..7384d6cef30ed 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -27,6 +27,7 @@ #include "SDL_cocoavideo.h" #include "SDL_cocoashape.h" #include "SDL_cocoavulkan.h" +#include "SDL_cocoametalview.h" #include "SDL_assert.h" /* Initialization/Query functions */ @@ -142,6 +143,11 @@ device->Vulkan_GetDrawableSize = Cocoa_Vulkan_GetDrawableSize; #endif +#if SDL_VIDEO_METAL + device->Metal_CreateView = Cocoa_Metal_CreateView; + device->Metal_DestroyView = Cocoa_Metal_DestroyView; +#endif + device->StartTextInput = Cocoa_StartTextInput; device->StopTextInput = Cocoa_StopTextInput; device->SetTextInputRect = Cocoa_SetTextInputRect; diff --git a/src/video/cocoa/SDL_cocoavulkan.m b/src/video/cocoa/SDL_cocoavulkan.m index 4801d768b89ec..fe2738c903e58 100644 --- a/src/video/cocoa/SDL_cocoavulkan.m +++ b/src/video/cocoa/SDL_cocoavulkan.m @@ -194,6 +194,7 @@ SDL_bool Cocoa_Vulkan_CreateSurface(_THIS, "vkCreateMacOSSurfaceMVK"); VkMacOSSurfaceCreateInfoMVK createInfo = {}; VkResult result; + SDL_MetalView metalview; if (!_this->vulkan_config.loader_handle) { SDL_SetError("Vulkan is not loaded"); @@ -205,23 +206,38 @@ SDL_bool Cocoa_Vulkan_CreateSurface(_THIS, " extension is not enabled in the Vulkan instance."); return SDL_FALSE; } + + metalview = Cocoa_Metal_CreateView(_this, window); + if (metalview == NULL) { + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = NULL; createInfo.flags = 0; - createInfo.pView = Cocoa_Mtl_AddMetalView(window); + createInfo.pView = (const void *)metalview; result = vkCreateMacOSSurfaceMVK(instance, &createInfo, NULL, surface); if (result != VK_SUCCESS) { + Cocoa_Metal_DestroyView(_this, metalview); SDL_SetError("vkCreateMacOSSurfaceMVK failed: %s", SDL_Vulkan_GetResultString(result)); return SDL_FALSE; } + + /* Unfortunately there's no SDL_Vulkan_DestroySurface function we can call + * Metal_DestroyView from. Right now the metal view's ref count is +2 (one + * from returning a new view object in CreateView, and one because it's + * a subview of the window.) If we release the view here to make it +1, it + * will be destroyed when the window is destroyed. */ + CFBridgingRelease(metalview); + return SDL_TRUE; } void Cocoa_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h) { - Cocoa_Mtl_GetDrawableSize(window, w, h); + Cocoa_Metal_GetDrawableSize(window, w, h); } #endif diff --git a/src/video/uikit/SDL_uikitmetalview.h b/src/video/uikit/SDL_uikitmetalview.h index 02d5671b915d8..ccafdcb031789 100644 --- a/src/video/uikit/SDL_uikitmetalview.h +++ b/src/video/uikit/SDL_uikitmetalview.h @@ -29,10 +29,10 @@ #ifndef SDL_uikitmetalview_h_ #define SDL_uikitmetalview_h_ -#import "../SDL_sysvideo.h" -#import "SDL_uikitwindow.h" +#include "../SDL_sysvideo.h" +#include "SDL_uikitwindow.h" -#if SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_RENDER_METAL || SDL_VIDEO_VULKAN) +#if SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) #import #import @@ -47,11 +47,12 @@ @end -SDL_uikitmetalview* UIKit_Mtl_AddMetalView(SDL_Window* window); +SDL_MetalView UIKit_Metal_CreateView(_THIS, SDL_Window * window); +void UIKit_Metal_DestroyView(_THIS, SDL_MetalView view); -void UIKit_Mtl_GetDrawableSize(SDL_Window * window, int * w, int * h); +void UIKit_Metal_GetDrawableSize(SDL_Window * window, int * w, int * h); -#endif /* SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_RENDER_METAL || SDL_VIDEO_VULKAN) */ +#endif /* SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */ #endif /* SDL_uikitmetalview_h_ */ diff --git a/src/video/uikit/SDL_uikitmetalview.m b/src/video/uikit/SDL_uikitmetalview.m index c9c93c0f195dd..548ed0ddbb28f 100644 --- a/src/video/uikit/SDL_uikitmetalview.m +++ b/src/video/uikit/SDL_uikitmetalview.m @@ -28,7 +28,7 @@ #include "../../SDL_internal.h" -#if SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_RENDER_METAL || SDL_VIDEO_VULKAN) +#if SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) #import "../SDL_sysvideo.h" #import "SDL_uikitwindow.h" @@ -73,16 +73,12 @@ - (void)updateDrawableSize @end -SDL_uikitmetalview* -UIKit_Mtl_AddMetalView(SDL_Window* window) -{ +SDL_MetalView +UIKit_Metal_CreateView(_THIS, SDL_Window * window) +{ @autoreleasepool { SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; - SDL_uikitview *view = (SDL_uikitview*)data.uiwindow.rootViewController.view; CGFloat scale = 1.0; - - if ([view isKindOfClass:[SDL_uikitmetalview class]]) { - return (SDL_uikitmetalview *)view; - } + SDL_uikitmetalview *metalview; if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { /* Set the scale to the natural scale factor of the screen - then @@ -96,16 +92,26 @@ - (void)updateDrawableSize scale = data.uiwindow.screen.scale; } } - SDL_uikitmetalview *metalview - = [[SDL_uikitmetalview alloc] initWithFrame:view.frame - scale:scale]; + + metalview = [[SDL_uikitmetalview alloc] initWithFrame:data.uiwindow.bounds + scale:scale]; [metalview setSDLWindow:window]; - return metalview; -} + return (void*)CFBridgingRetain(metalview); +}} + +void +UIKit_Metal_DestroyView(_THIS, SDL_MetalView view) +{ @autoreleasepool { + SDL_uikitmetalview *metalview = CFBridgingRelease(view); + + if ([metalview isKindOfClass:[SDL_uikitmetalview class]]) { + [metalview setSDLWindow:NULL]; + } +}} void -UIKit_Mtl_GetDrawableSize(SDL_Window * window, int * w, int * h) +UIKit_Metal_GetDrawableSize(SDL_Window * window, int * w, int * h) { @autoreleasepool { SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; @@ -126,4 +132,4 @@ - (void)updateDrawableSize } } -#endif /* SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_RENDER_METAL || SDL_VIDEO_VULKAN) */ +#endif /* SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */ diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m index cea40b2392f1b..26ff02aca0926 100644 --- a/src/video/uikit/SDL_uikitvideo.m +++ b/src/video/uikit/SDL_uikitvideo.m @@ -38,6 +38,7 @@ #include "SDL_uikitopengles.h" #include "SDL_uikitclipboard.h" #include "SDL_uikitvulkan.h" +#include "SDL_uikitmetalview.h" #define UIKITVID_DRIVER_NAME "uikit" @@ -133,6 +134,11 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device) device->Vulkan_GetDrawableSize = UIKit_Vulkan_GetDrawableSize; #endif +#if SDL_VIDEO_METAL + device->Metal_CreateView = UIKit_Metal_CreateView; + device->Metal_DestroyView = UIKit_Metal_DestroyView; +#endif + device->gl_config.accelerated = 1; return device; diff --git a/src/video/uikit/SDL_uikitvulkan.m b/src/video/uikit/SDL_uikitvulkan.m index c4b779d10ee37..c95f6fe3da615 100644 --- a/src/video/uikit/SDL_uikitvulkan.m +++ b/src/video/uikit/SDL_uikitvulkan.m @@ -200,6 +200,7 @@ SDL_bool UIKit_Vulkan_CreateSurface(_THIS, "vkCreateIOSSurfaceMVK"); VkIOSSurfaceCreateInfoMVK createInfo = {}; VkResult result; + SDL_MetalView metalview; if (!_this->vulkan_config.loader_handle) { SDL_SetError("Vulkan is not loaded"); @@ -212,24 +213,37 @@ SDL_bool UIKit_Vulkan_CreateSurface(_THIS, return SDL_FALSE; } + metalview = UIKit_Metal_CreateView(_this, window); + if (metalview == NULL) { + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = NULL; createInfo.flags = 0; - createInfo.pView = (__bridge void *)UIKit_Mtl_AddMetalView(window); + createInfo.pView = (const void *)metalview; result = vkCreateIOSSurfaceMVK(instance, &createInfo, NULL, surface); if (result != VK_SUCCESS) { + UIKit_Metal_DestroyView(_this, metalview); SDL_SetError("vkCreateIOSSurfaceMVK failed: %s", SDL_Vulkan_GetResultString(result)); return SDL_FALSE; } + /* Unfortunately there's no SDL_Vulkan_DestroySurface function we can call + * Metal_DestroyView from. Right now the metal view's ref count is +2 (one + * from returning a new view object in CreateView, and one because it's + * a subview of the window.) If we release the view here to make it +1, it + * will be destroyed when the window is destroyed. */ + CFBridgingRelease(metalview); + return SDL_TRUE; } void UIKit_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h) { - UIKit_Mtl_GetDrawableSize(window, w, h); + UIKit_Metal_GetDrawableSize(window, w, h); } #endif