From beab9870cf1db47a8f3699ce898a566372dff3b2 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Wed, 25 May 2022 16:43:11 -0500 Subject: [PATCH] Common: Move ObjC methods to CocoaTools --- cmake/Pcsx2Utils.cmake | 17 +++++++ common/CMakeLists.txt | 13 +++-- common/CocoaTools.h | 27 +++++++++++ common/CocoaTools.mm | 66 ++++++++++++++++++++++++++ common/Vulkan/SwapChain.cpp | 95 ++----------------------------------- pcsx2/CMakeLists.txt | 15 +----- 6 files changed, 125 insertions(+), 108 deletions(-) create mode 100644 common/CocoaTools.h create mode 100644 common/CocoaTools.mm 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})