diff --git a/cmake/Pcsx2Utils.cmake b/cmake/Pcsx2Utils.cmake
index 0dda0f7379..78a5ba4af4 100644
--- a/cmake/Pcsx2Utils.cmake
+++ b/cmake/Pcsx2Utils.cmake
@@ -229,3 +229,20 @@ function(find_optional_system_library library bundled_path)
set(${library}_TYPE "Bundled" PARENT_SCOPE)
endif()
endfunction()
+
+function(fixup_file_properties target)
+ get_target_property(SOURCES ${target} SOURCES)
+ if(APPLE)
+ foreach(source IN LISTS SOURCES)
+ # Set the right file types for .inl files in Xcode
+ if("${source}" MATCHES "\\.(inl|h)$")
+ set_source_files_properties("${source}" PROPERTIES XCODE_EXPLICIT_FILE_TYPE sourcecode.cpp.h)
+ endif()
+ # CMake makefile and ninja generators will attempt to share one PCH for both cpp and mm files
+ # That's not actually OK
+ if("${source}" MATCHES "\\.mm$")
+ set_source_files_properties("${source}" PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
+ endif()
+ endforeach()
+ endif()
+endfunction()
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 22bd3f08c5..2295beeca5 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -191,6 +191,15 @@ if(WIN32)
)
endif()
+if(APPLE)
+ target_sources(common PRIVATE
+ CocoaTools.mm
+ CocoaTools.h
+ )
+ target_compile_options(common PRIVATE -fobjc-arc)
+ target_link_options(common PRIVATE -fobjc-link-runtime)
+endif()
+
if(USE_OPENGL)
if(WIN32)
target_sources(common PRIVATE
@@ -203,9 +212,6 @@ if(USE_OPENGL)
GL/ContextAGL.mm
GL/ContextAGL.h
)
- set_source_files_properties(GL/ContextAGL.mm PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
- target_compile_options(common PRIVATE -fobjc-arc)
- target_link_options(common PRIVATE -fobjc-link-runtime)
else()
if(X11_API OR WAYLAND_API)
target_sources(common PRIVATE
@@ -263,6 +269,7 @@ target_link_libraries(common PUBLIC
fmt::fmt
)
+fixup_file_properties(common)
target_compile_features(common PUBLIC cxx_std_17)
target_include_directories(common PUBLIC ../3rdparty/include ../)
target_compile_definitions(common PUBLIC "${PCSX2_DEFS}")
diff --git a/common/CocoaTools.h b/common/CocoaTools.h
new file mode 100644
index 0000000000..0ea11e747c
--- /dev/null
+++ b/common/CocoaTools.h
@@ -0,0 +1,27 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2022 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#ifdef __APPLE__
+
+struct WindowInfo;
+
+/// Helper functions for things that need Objective-C
+namespace CocoaTools
+{
+ bool CreateMetalLayer(WindowInfo* wi);
+ void DestroyMetalLayer(WindowInfo* wi);
+}
+
+#endif // __APPLE__
diff --git a/common/CocoaTools.mm b/common/CocoaTools.mm
new file mode 100644
index 0000000000..d0b6e5e117
--- /dev/null
+++ b/common/CocoaTools.mm
@@ -0,0 +1,66 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2022 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#if ! __has_feature(objc_arc)
+ #error "Compile this with -fobjc-arc"
+#endif
+
+#include "CocoaTools.h"
+#include "Console.h"
+#include "WindowInfo.h"
+#include
+#include
+
+bool CocoaTools::CreateMetalLayer(WindowInfo* wi)
+{
+ if (![NSThread isMainThread])
+ {
+ bool ret;
+ dispatch_sync(dispatch_get_main_queue(), [&ret, wi]{ ret = CreateMetalLayer(wi); });
+ return ret;
+ }
+
+ CAMetalLayer* layer = [CAMetalLayer layer];
+ if (!layer)
+ {
+ Console.Error("Failed to create Metal layer.");
+ return false;
+ }
+
+ NSView* view = (__bridge NSView*)wi->window_handle;
+ [view setWantsLayer:YES];
+ [view setLayer:layer];
+ [layer setContentsScale:[[[view window] screen] backingScaleFactor]];
+ // Store the layer pointer, that way MoltenVK doesn't call [NSView layer] outside the main thread.
+ wi->surface_handle = (__bridge_retained void*)layer;
+ return true;
+}
+
+void CocoaTools::DestroyMetalLayer(WindowInfo* wi)
+{
+ if (![NSThread isMainThread])
+ {
+ dispatch_sync_f(dispatch_get_main_queue(), wi, [](void* ctx){ DestroyMetalLayer(static_cast(ctx)); });
+ return;
+ }
+
+ NSView* view = (__bridge NSView*)wi->window_handle;
+ CAMetalLayer* layer = (__bridge_transfer CAMetalLayer*)wi->surface_handle;
+ if (!layer)
+ return;
+ wi->surface_handle = nullptr;
+ [view setLayer:nil];
+ [view setWantsLayer:NO];
+}
diff --git a/common/Vulkan/SwapChain.cpp b/common/Vulkan/SwapChain.cpp
index 46f0c13822..c444ef3c7e 100644
--- a/common/Vulkan/SwapChain.cpp
+++ b/common/Vulkan/SwapChain.cpp
@@ -15,6 +15,7 @@
#include "common/Vulkan/SwapChain.h"
#include "common/Assertions.h"
+#include "common/CocoaTools.h"
#include "common/Console.h"
#include "common/Vulkan/Context.h"
#include "common/Vulkan/Util.h"
@@ -26,96 +27,6 @@
#include
#endif
-#if defined(__APPLE__)
-#include
-#include
-
-#ifdef __i386__
-typedef float CGFloat;
-#else
-typedef double CGFloat;
-#endif
-
-template
-Ret msgsend(Self self, const char* sel, Args... args)
-{
- void (*fn)(void) = objc_msgSend;
-#ifdef __i386__
- if (std::is_same::value || std::is_same::value || std::is_same::value)
- fn = objc_msgSend_fpret;
-#endif
-#ifdef __x86_64__
- if (std::is_same::value)
- fn = objc_msgSend_fpret;
-#endif
- return reinterpret_cast(fn)(self, sel_getUid(sel), args...);
-}
-
-static bool CreateMetalLayer(WindowInfo* wi)
-{
- // if (![NSThread isMainThread])
- if (!msgsend(objc_getClass("NSThread"), "isMainThread"))
- {
- __block bool ret;
- dispatch_sync(dispatch_get_main_queue(), ^{ ret = CreateMetalLayer(wi); });
- return ret;
- }
-
- id view = reinterpret_cast(wi->window_handle);
-
- Class clsCAMetalLayer = objc_getClass("CAMetalLayer");
- if (!clsCAMetalLayer)
- {
- Console.Error("Failed to get CAMetalLayer class.");
- return false;
- }
-
- // [CAMetalLayer layer]
- id layer = msgsend(clsCAMetalLayer, "layer");
- if (!layer)
- {
- Console.Error("Failed to create Metal layer.");
- return false;
- }
-
- // This needs to be retained, otherwise we double release below.
- msgsend(layer, "retain");
-
- // [view setWantsLayer:YES]
- msgsend(view, "setWantsLayer:", YES);
-
- // [view setLayer:layer]
- msgsend(view, "setLayer:", layer);
-
- // NSScreen* screen = [NSScreen mainScreen]
- id screen = msgsend(objc_getClass("NSScreen"), "mainScreen");
-
- // CGFloat factor = [screen backingScaleFactor]
- CGFloat factor = msgsend(screen, "backingScaleFactor");
-
- // layer.contentsScale = factor
- msgsend(layer, "setContentsScale:", factor);
-
- // Store the layer pointer, that way MoltenVK doesn't call [NSView layer] outside the main thread.
- wi->surface_handle = layer;
- return true;
-}
-
-static void DestroyMetalLayer(WindowInfo* wi)
-{
- id view = reinterpret_cast(wi->window_handle);
- id layer = reinterpret_cast(wi->surface_handle);
- if (layer == nil)
- return;
-
- reinterpret_cast(objc_msgSend)(view, sel_getUid("setLayer:"), nil);
- reinterpret_cast(objc_msgSend)(view, sel_getUid("setWantsLayer:"), NO);
- reinterpret_cast(objc_msgSend)(layer, sel_getUid("release"));
- wi->surface_handle = nullptr;
-}
-
-#endif
-
namespace Vulkan
{
SwapChain::SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR preferred_present_mode)
@@ -435,7 +346,7 @@ namespace Vulkan
#if defined(VK_USE_PLATFORM_METAL_EXT)
if (wi->type == WindowInfo::Type::MacOS)
{
- if (!wi->surface_handle && !CreateMetalLayer(wi))
+ if (!wi->surface_handle && !CocoaTools::CreateMetalLayer(wi))
return VK_NULL_HANDLE;
VkMetalSurfaceCreateInfoEXT surface_create_info = {VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, nullptr,
@@ -483,7 +394,7 @@ namespace Vulkan
#if defined(__APPLE__)
if (wi->type == WindowInfo::Type::MacOS && wi->surface_handle)
- DestroyMetalLayer(wi);
+ CocoaTools::DestroyMetalLayer(wi);
#endif
}
diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt
index 8d645bf9dc..2f1224d7a5 100644
--- a/pcsx2/CMakeLists.txt
+++ b/pcsx2/CMakeLists.txt
@@ -1749,6 +1749,8 @@ if(GETTEXT_FOUND AND NOT NO_TRANSLATION AND NOT PCSX2_CORE)
GETTEXT_CREATE_TRANSLATIONS_PCSX2(${CMAKE_SOURCE_DIR}/locales/templates/pcsx2_Main.pot ${PO_MAIN_FILES})
endif()
+fixup_file_properties(PCSX2)
+
if (APPLE)
find_library(METAL_LIBRARY Metal)
find_library(QUARTZCORE_LIBRARY QuartzCore)
@@ -1758,19 +1760,6 @@ if (APPLE)
# We have a bunch of page-sized arrays in bss that we use for jit
# Obviously not being able to make those arrays executable would be a problem
target_link_options(PCSX2_FLAGS INTERFACE -Wl,-segprot,__DATA,rwx,rw)
-
- get_target_property(PCSX2_SOURCES PCSX2 SOURCES)
- foreach(source IN LISTS PCSX2_SOURCES)
- # Set the right file types for .inl files in Xcode
- if("${source}" MATCHES "\\.(inl|h)$")
- set_source_files_properties("${source}" PROPERTIES XCODE_EXPLICIT_FILE_TYPE sourcecode.cpp.h)
- endif()
- # CMake makefile and ninja generators will attempt to share one PCH for both cpp and mm files
- # That's not actually OK
- if("${source}" MATCHES "\\.mm$")
- set_source_files_properties("${source}" PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
- endif()
- endforeach()
endif()
set_property(GLOBAL PROPERTY PCSX2_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})