mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-04 05:04:33 +00:00
CocoaTools: Move util functions to common
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user