Common: Move ObjC methods to CocoaTools

This commit is contained in:
TellowKrinkle 2022-05-25 16:43:11 -05:00 committed by refractionpcsx2
parent dbfb93a50f
commit beab9870cf
6 changed files with 125 additions and 108 deletions

View File

@ -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()

View File

@ -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}")

27
common/CocoaTools.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifdef __APPLE__
struct WindowInfo;
/// Helper functions for things that need Objective-C
namespace CocoaTools
{
bool CreateMetalLayer(WindowInfo* wi);
void DestroyMetalLayer(WindowInfo* wi);
}
#endif // __APPLE__

66
common/CocoaTools.mm Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#if ! __has_feature(objc_arc)
#error "Compile this with -fobjc-arc"
#endif
#include "CocoaTools.h"
#include "Console.h"
#include "WindowInfo.h"
#include <Cocoa/Cocoa.h>
#include <QuartzCore/QuartzCore.h>
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<WindowInfo*>(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];
}

View File

@ -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 <X11/Xlib.h>
#endif
#if defined(__APPLE__)
#include <objc/message.h>
#include <dispatch/dispatch.h>
#ifdef __i386__
typedef float CGFloat;
#else
typedef double CGFloat;
#endif
template <typename Ret, typename Self, typename... Args>
Ret msgsend(Self self, const char* sel, Args... args)
{
void (*fn)(void) = objc_msgSend;
#ifdef __i386__
if (std::is_same<Ret, float>::value || std::is_same<Ret, double>::value || std::is_same<Ret, long double>::value)
fn = objc_msgSend_fpret;
#endif
#ifdef __x86_64__
if (std::is_same<Ret, long double>::value)
fn = objc_msgSend_fpret;
#endif
return reinterpret_cast<Ret(*)(Self, SEL, Args...)>(fn)(self, sel_getUid(sel), args...);
}
static bool CreateMetalLayer(WindowInfo* wi)
{
// if (![NSThread isMainThread])
if (!msgsend<BOOL, Class>(objc_getClass("NSThread"), "isMainThread"))
{
__block bool ret;
dispatch_sync(dispatch_get_main_queue(), ^{ ret = CreateMetalLayer(wi); });
return ret;
}
id view = reinterpret_cast<id>(wi->window_handle);
Class clsCAMetalLayer = objc_getClass("CAMetalLayer");
if (!clsCAMetalLayer)
{
Console.Error("Failed to get CAMetalLayer class.");
return false;
}
// [CAMetalLayer layer]
id layer = msgsend<id, Class>(clsCAMetalLayer, "layer");
if (!layer)
{
Console.Error("Failed to create Metal layer.");
return false;
}
// This needs to be retained, otherwise we double release below.
msgsend<void, id>(layer, "retain");
// [view setWantsLayer:YES]
msgsend<void, id, BOOL>(view, "setWantsLayer:", YES);
// [view setLayer:layer]
msgsend<void, id, id>(view, "setLayer:", layer);
// NSScreen* screen = [NSScreen mainScreen]
id screen = msgsend<id, Class>(objc_getClass("NSScreen"), "mainScreen");
// CGFloat factor = [screen backingScaleFactor]
CGFloat factor = msgsend<CGFloat, id>(screen, "backingScaleFactor");
// layer.contentsScale = factor
msgsend<void, id, CGFloat>(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<id>(wi->window_handle);
id layer = reinterpret_cast<id>(wi->surface_handle);
if (layer == nil)
return;
reinterpret_cast<void (*)(id, SEL, id)>(objc_msgSend)(view, sel_getUid("setLayer:"), nil);
reinterpret_cast<void (*)(id, SEL, BOOL)>(objc_msgSend)(view, sel_getUid("setWantsLayer:"), NO);
reinterpret_cast<void (*)(id, SEL)>(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
}

View File

@ -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})