Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

project("MarathonRecomp-ALL")

if(APPLE)
enable_language(OBJC OBJCXX)
endif()

if (CMAKE_OSX_ARCHITECTURES)
set(MARATHON_RECOMP_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES})
elseif(CMAKE_SYSTEM_PROCESSOR)
Expand Down
51 changes: 27 additions & 24 deletions MarathonRecomp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
project("MarathonRecomp")

if (WIN32)
option(MARATHON_RECOMP_D3D12 "Add D3D12 support for rendering" OFF)
option(MARATHON_RECOMP_D3D12 "Add D3D12 support for rendering" ON)
endif()

if (CMAKE_SYSTEM_NAME MATCHES "Linux")
Expand Down Expand Up @@ -125,6 +125,12 @@ if (MARATHON_RECOMP_D3D12)
)
endif()

if (APPLE)
list(APPEND MARATHON_RECOMP_GPU_CXX_SOURCES
"gpu/rhi/plume_apple.mm"
)
endif()

set(MARATHON_RECOMP_APU_CXX_SOURCES
"apu/audio.cpp"
"apu/xma_decoder.cpp"
Expand Down Expand Up @@ -381,31 +387,28 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
target_compile_definitions(MarathonRecomp PRIVATE SDL_VULKAN_ENABLED)
endif()

#find_package(directx-dxc REQUIRED)
find_package(CURL REQUIRED)

#if (MARATHON_RECOMP_D3D12)
# file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
# add_custom_command(TARGET MarathonRecomp POST_BUILD
# COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Core,IMPORTED_LOCATION_RELEASE> ${CMAKE_CURRENT_BINARY_DIR}/D3D12
# COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Layers,IMPORTED_LOCATION_DEBUG> ${CMAKE_CURRENT_BINARY_DIR}/D3D12
# COMMAND_EXPAND_LISTS
# )
#
# find_file(DIRECTX_DXIL_LIBRARY "dxil.dll")
# file(COPY ${DIRECTX_DXIL_LIBRARY} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
#
# target_link_libraries(MarathonRecomp PRIVATE
# Microsoft::DirectX-Headers
# Microsoft::DirectX-Guids
# Microsoft::DirectX12-Agility
# Microsoft::DirectXShaderCompiler
# Microsoft::DXIL
# dxgi
# )
#endif()

#file(CHMOD ${DIRECTX_DXC_TOOL} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)

if (MARATHON_RECOMP_D3D12)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
add_custom_command(TARGET MarathonRecomp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Core,IMPORTED_LOCATION_RELEASE> $<TARGET_FILE_DIR:MarathonRecomp>/D3D12
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Layers,IMPORTED_LOCATION_DEBUG> $<TARGET_FILE_DIR:MarathonRecomp>/D3D12
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectXShaderCompiler,IMPORTED_LOCATION> $<TARGET_FILE_DIR:MarathonRecomp>
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DXIL,IMPORTED_LOCATION> $<TARGET_FILE_DIR:MarathonRecomp>
COMMAND_EXPAND_LISTS
)

target_link_libraries(MarathonRecomp PRIVATE
Microsoft::DirectX-Headers
Microsoft::DirectX-Guids
Microsoft::DirectX12-Agility
Microsoft::DirectXShaderCompiler
Microsoft::DXIL
dxgi
)
endif()

if (WIN32)
target_link_libraries(MarathonRecomp PRIVATE
Expand Down
43 changes: 43 additions & 0 deletions MarathonRecomp/gpu/rhi/plume_apple.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//

#pragma once

#include <atomic>
#include <mutex>
#include "plume_render_interface_types.h"

namespace plume {
RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID);

struct CocoaWindowAttributes {
int x, y;
int width, height;
};

class CocoaWindow {
void* windowHandle;
CocoaWindowAttributes cachedAttributes;
std::atomic<int> cachedRefreshRate;
mutable std::mutex attributesMutex;

void updateWindowAttributesInternal(bool forceSync = false);
void updateRefreshRateInternal(bool forceSync = false);
public:
CocoaWindow(void* window);
~CocoaWindow();

// Get cached window attributes, may trigger async update
void getWindowAttributes(CocoaWindowAttributes* attributes) const;

// Get cached refresh rate, may trigger async update
int getRefreshRate() const;

// Toggle fullscreen
void toggleFullscreen();
};
}
170 changes: 170 additions & 0 deletions MarathonRecomp/gpu/rhi/plume_apple.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
//
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//

#include "plume_apple.h"

#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import <IOKit/IOKitLib.h>

static uint32_t plumeGetEntryProperty(io_registry_entry_t entry, CFStringRef propertyName) {
uint32_t value = 0;
CFTypeRef cfProp = IORegistryEntrySearchCFProperty(entry, kIOServicePlane, propertyName, kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);

if (cfProp) {
if (CFGetTypeID(cfProp) == CFDataGetTypeID()) {
const uint32_t* pValue = reinterpret_cast<const uint32_t*>(CFDataGetBytePtr((CFDataRef)cfProp));
if (pValue) {
value = *pValue;
}
}
CFRelease(cfProp);
}

return value;
}

namespace plume {
RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
io_service_t entry = IOServiceGetMatchingService(MACH_PORT_NULL, IORegistryEntryIDMatching(registryID));

if (entry) {
io_registry_entry_t parent;
if (IORegistryEntryGetParentEntry(entry, kIOServicePlane, &parent) == kIOReturnSuccess) {
uint32_t vendorId = plumeGetEntryProperty(parent, CFSTR("vendor-id"));
IOObjectRelease(parent); // Release the parent
IOObjectRelease(entry); // Release the entry
return RenderDeviceVendor(vendorId);
}
IOObjectRelease(entry); // Release the entry if we couldn't get parent
}

return RenderDeviceVendor::UNKNOWN;
}

// MARK: - CocoaWindow

CocoaWindow::CocoaWindow(void* window)
: windowHandle(window), cachedRefreshRate(0) {
cachedAttributes = {0, 0, 0, 0};

if ([NSThread isMainThread]) {
NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
NSRect contentFrame = [[nsWindow contentView] frame];
CGFloat scaleFactor = [nsWindow backingScaleFactor];

cachedAttributes.x = (int)round(contentFrame.origin.x);
cachedAttributes.y = (int)round(contentFrame.origin.y);
cachedAttributes.width = (int)round(contentFrame.size.width * scaleFactor);
cachedAttributes.height = (int)round(contentFrame.size.height * scaleFactor);

NSScreen *screen = [nsWindow screen];
if (@available(macOS 12.0, *)) {
cachedRefreshRate.store((int)[screen maximumFramesPerSecond]);
}
} else {
updateWindowAttributesInternal(true);
updateRefreshRateInternal(true);
}
}

CocoaWindow::~CocoaWindow() {}

void CocoaWindow::updateWindowAttributesInternal(bool forceSync) {
auto updateBlock = ^{
NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
NSRect contentFrame = [[nsWindow contentView] frame];
CGFloat scaleFactor = [nsWindow backingScaleFactor];

std::lock_guard<std::mutex> lock(attributesMutex);
cachedAttributes.x = (int)round(contentFrame.origin.x);
cachedAttributes.y = (int)round(contentFrame.origin.y);
cachedAttributes.width = (int)round(contentFrame.size.width * scaleFactor);
cachedAttributes.height = (int)round(contentFrame.size.height * scaleFactor);
};

if (forceSync) {
dispatch_sync(dispatch_get_main_queue(), updateBlock);
} else {
dispatch_async(dispatch_get_main_queue(), updateBlock);
}
}

void CocoaWindow::updateRefreshRateInternal(bool forceSync) {
auto updateBlock = ^{
NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
NSScreen *screen = [nsWindow screen];
if (@available(macOS 12.0, *)) {
cachedRefreshRate.store((int)[screen maximumFramesPerSecond]);
}
};

if (forceSync) {
dispatch_sync(dispatch_get_main_queue(), updateBlock);
} else {
dispatch_async(dispatch_get_main_queue(), updateBlock);
}
}

void CocoaWindow::getWindowAttributes(CocoaWindowAttributes* attributes) const {
if ([NSThread isMainThread]) {
NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
NSRect contentFrame = [[nsWindow contentView] frame];
CGFloat scaleFactor = [nsWindow backingScaleFactor];

{
std::lock_guard<std::mutex> lock(attributesMutex);
const_cast<CocoaWindow*>(this)->cachedAttributes.x = (int)round(contentFrame.origin.x);
const_cast<CocoaWindow*>(this)->cachedAttributes.y = (int)round(contentFrame.origin.y);
const_cast<CocoaWindow*>(this)->cachedAttributes.width = (int)round(contentFrame.size.width * scaleFactor);
const_cast<CocoaWindow*>(this)->cachedAttributes.height = (int)round(contentFrame.size.height * scaleFactor);

*attributes = cachedAttributes;
}
} else {
{
std::lock_guard<std::mutex> lock(attributesMutex);
*attributes = cachedAttributes;
}

const_cast<CocoaWindow*>(this)->updateWindowAttributesInternal(false);
}
}

int CocoaWindow::getRefreshRate() const {
if ([NSThread isMainThread]) {
NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
NSScreen *screen = [nsWindow screen];

if (@available(macOS 12.0, *)) {
int freshRate = (int)[screen maximumFramesPerSecond];
const_cast<CocoaWindow*>(this)->cachedRefreshRate.store(freshRate);
return freshRate;
}

return cachedRefreshRate.load();
} else {
int rate = cachedRefreshRate.load();

const_cast<CocoaWindow*>(this)->updateRefreshRateInternal(false);

return rate;
}
}

void CocoaWindow::toggleFullscreen() {
if ([NSThread isMainThread]) {
NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
[nsWindow toggleFullScreen:NULL];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
[nsWindow toggleFullScreen:NULL];
});
}
}
}
Loading
Loading