CocoaTools: Move util functions to common

This commit is contained in:
Stenzek
2026-01-17 16:41:09 +10:00
parent 8135aefacf
commit 9c07d9bf7c
9 changed files with 93 additions and 98 deletions

View File

@@ -107,7 +107,8 @@ if(APPLE)
target_sources(common PRIVATE ${MAC_SOURCES})
set_source_files_properties(${MAC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE)
find_library(COCOA_LIBRARY Cocoa REQUIRED)
target_link_libraries(common PRIVATE ${COCOA_LIBRARY})
find_library(QUARTZCORE_LIBRARY QuartzCore)
target_link_libraries(common PRIVATE ${COCOA_LIBRARY} ${QUARTZCORE_LIBRARY})
endif()
if(NOT WIN32 AND NOT ANDROID AND NOT APPLE)

View File

@@ -20,16 +20,19 @@ class Error;
#import <Cocoa/Cocoa.h>
namespace CocoaTools {
NSString* StringViewToNSString(std::string_view str);
void NSErrorToErrorObject(Error* errptr, std::string_view message, NSError* error);
/// Converts NSError to a human-readable string.
std::string NSErrorToString(NSError* error);
} // namespace CocoaTools
#endif
namespace CocoaTools {
// Converts to Mach timebase.
u64 ConvertMachTimeBaseToNanoseconds(u64 ns);
u64 ConvertNanosecondsToMachTimeBase(u64 ns);
@@ -51,4 +54,14 @@ std::optional<std::pair<int, int>> GetViewSizeInPixels(const void* view);
/// Returns the "real" scaling factor for a given view, on its current display.
std::optional<double> GetViewRealScalingFactor(const void* view);
/// Returns the refresh rate of the display the window is placed on.
std::optional<float> GetViewRefreshRate(const void* view, Error* error);
/// Creates metal layer on specified window surface.
void* CreateMetalLayer(void* view, Error* error);
/// Destroys metal layer on specified window surface.
void DestroyMetalLayer(void* view, void* layer);
} // namespace CocoaTools

View File

@@ -11,6 +11,7 @@
#include <AppKit/AppKit.h>
#include <Cocoa/Cocoa.h>
#include <QuartzCore/QuartzCore.h>
#include <cinttypes>
#include <dlfcn.h>
#include <mach/mach_time.h>
@@ -209,6 +210,75 @@ std::optional<double> CocoaTools::GetViewRealScalingFactor(const void* view)
return static_cast<double>(scale);
}
std::optional<float> CocoaTools::GetViewRefreshRate(const void* view, Error* error)
{
if (!view)
return std::nullopt;
if (![NSThread isMainThread])
{
std::optional<float> ret;
dispatch_sync(dispatch_get_main_queue(), [&ret, view, error] { ret = GetViewRefreshRate(view, error); });
return ret;
}
std::optional<float> ret;
NSView* const nsview = (__bridge NSView*)view;
const u32 did = [[[[[nsview window] screen] deviceDescription] valueForKey:@"NSScreenNumber"] unsignedIntValue];
if (CGDisplayModeRef mode = CGDisplayCopyDisplayMode(did))
{
ret = CGDisplayModeGetRefreshRate(mode);
CGDisplayModeRelease(mode);
}
else
{
Error::SetStringView(error, "CGDisplayCopyDisplayMode() failed");
}
return ret;
}
void* CocoaTools::CreateMetalLayer(void* view, Error* error)
{
// Punt off to main thread if we're not calling from it already.
if (![NSThread isMainThread])
{
void* ret;
dispatch_sync(dispatch_get_main_queue(), [&ret, view, error]() { ret = CreateMetalLayer(view, error); });
return ret;
}
CAMetalLayer* layer = [[CAMetalLayer layer] retain];
if (layer == nil)
{
Error::SetStringView(error, "Failed to create CAMetalLayer");
return nullptr;
}
NSView* nsview = (__bridge NSView*)view;
[nsview setWantsLayer:TRUE];
[nsview setLayer:layer];
[layer setContentsScale:[[[nsview window] screen] backingScaleFactor]];
return layer;
}
void CocoaTools::DestroyMetalLayer(void* view, void* layer)
{
// Punt off to main thread if we're not calling from it already.
if (![NSThread isMainThread])
{
dispatch_sync(dispatch_get_main_queue(), [view, layer]() { DestroyMetalLayer(view, layer); });
return;
}
NSView* nsview = (__bridge NSView*)view;
CAMetalLayer* clayer = (CAMetalLayer*)layer;
[nsview setLayer:nil];
[nsview setWantsLayer:NO];
[clayer release];
}
void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
{
if (![NSThread isMainThread])

View File

@@ -264,7 +264,6 @@ elseif(APPLE)
set(MAC_SOURCES
metal_device.h
metal_device.mm
metal_layer.h
metal_stream_buffer.h
metal_stream_buffer.mm
platform_misc_mac.mm

View File

@@ -1,13 +0,0 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
class Error;
struct WindowInfo;
namespace CocoaTools {
/// Creates metal layer on specified window surface.
void* CreateMetalLayer(const WindowInfo& wi, Error* error);
/// Destroys metal layer on specified window surface.
void DestroyMetalLayer(const WindowInfo& wi, void* layer);
} // namespace CocoaTools

View File

@@ -19,11 +19,3 @@ namespace Host {
std::optional<WindowInfo> GetTopLevelWindowInfo();
} // namespace Host
// TODO: Move all the other Cocoa stuff in here.
namespace CocoaTools {
/// Returns the refresh rate of the display the window is placed on.
std::optional<float> GetViewRefreshRate(const WindowInfo& wi, Error* error);
} // namespace CocoaTools

View File

@@ -8,7 +8,6 @@
#include <optional>
#include <vector>
#include "metal_layer.h"
#include "platform_misc.h"
#include "window_info.h"
@@ -26,69 +25,3 @@ bool PlatformMisc::InitializeSocketSupport(Error* error)
{
return true;
}
void* CocoaTools::CreateMetalLayer(const WindowInfo& wi, Error* error)
{
// Punt off to main thread if we're not calling from it already.
if (![NSThread isMainThread])
{
void* ret;
dispatch_sync(dispatch_get_main_queue(), [&ret, &wi, error]() { ret = CreateMetalLayer(wi, error); });
return ret;
}
CAMetalLayer* layer = [[CAMetalLayer layer] retain];
if (layer == nil)
{
Error::SetStringView(error, "Failed to create CAMetalLayer");
return nullptr;
}
NSView* view = (NSView*)wi.window_handle;
[view setWantsLayer:TRUE];
[view setLayer:layer];
[layer setContentsScale:[[[view window] screen] backingScaleFactor]];
return layer;
}
void CocoaTools::DestroyMetalLayer(const WindowInfo& wi, void* layer)
{
// Punt off to main thread if we're not calling from it already.
if (![NSThread isMainThread])
{
dispatch_sync(dispatch_get_main_queue(), [&wi, layer]() { DestroyMetalLayer(wi, layer); });
return;
}
NSView* view = (NSView*)wi.window_handle;
CAMetalLayer* clayer = (CAMetalLayer*)layer;
[view setLayer:nil];
[view setWantsLayer:NO];
[clayer release];
}
std::optional<float> CocoaTools::GetViewRefreshRate(const WindowInfo& wi, Error* error)
{
if (![NSThread isMainThread])
{
std::optional<float> ret;
dispatch_sync(dispatch_get_main_queue(), [&ret, wi, error] { ret = GetViewRefreshRate(wi, error); });
return ret;
}
std::optional<float> ret;
NSView* const view = (NSView*)wi.window_handle;
const u32 did = [[[[[view window] screen] deviceDescription] valueForKey:@"NSScreenNumber"] unsignedIntValue];
if (CGDisplayModeRef mode = CGDisplayCopyDisplayMode(did))
{
ret = CGDisplayModeGetRefreshRate(mode);
CGDisplayModeRelease(mode);
}
else
{
Error::SetStringView(error, "CGDisplayCopyDisplayMode() failed");
}
return ret;
}

View File

@@ -10,14 +10,14 @@
#include "common/error.h"
#include "common/log.h"
#ifdef __APPLE__
#include "common/cocoa_tools.h"
#endif
#include <algorithm>
#include <array>
#include <cmath>
#if defined(VK_USE_PLATFORM_METAL_EXT)
#include "util/metal_layer.h"
#endif
#ifdef ENABLE_SDL
#include <SDL3/SDL_vulkan.h>
#endif
@@ -108,7 +108,7 @@ bool VulkanSwapChain::CreateSurface(VkPhysicalDevice physical_device, Error* err
#if defined(VK_USE_PLATFORM_METAL_EXT)
if (m_window_info.type == WindowInfoType::MacOS)
{
m_metal_layer = CocoaTools::CreateMetalLayer(m_window_info, error);
m_metal_layer = CocoaTools::CreateMetalLayer(m_window_info.window_handle, error);
if (!m_metal_layer)
return false;
@@ -219,7 +219,7 @@ void VulkanSwapChain::DestroySurface()
#if defined(__APPLE__)
if (m_metal_layer)
{
CocoaTools::DestroyMetalLayer(m_window_info, m_metal_layer);
CocoaTools::DestroyMetalLayer(m_window_info.window_handle, m_metal_layer);
m_metal_layer = nullptr;
}
#endif

View File

@@ -209,12 +209,12 @@ std::optional<float> WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi,
#elif defined(__APPLE__)
#include "util/platform_misc.h"
#include "common/cocoa_tools.h"
std::optional<float> WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, Error* error)
{
if (wi.type == WindowInfoType::MacOS)
return CocoaTools::GetViewRefreshRate(wi, error);
return CocoaTools::GetViewRefreshRate(wi.window_handle, error);
Error::SetStringView(error, "Invalid window type.");
return std::nullopt;