mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-06-10 18:21:11 +00:00
Switch iOS renderer to Metal
This commit is contained in:
parent
bf92b2cc4d
commit
42ed8f1580
8 changed files with 639 additions and 205 deletions
|
|
@ -465,14 +465,12 @@ if (CMAKE_SYSTEM_NAME STREQUAL "iOS" AND TARGET SDL2::SDL2main)
|
|||
list(PREPEND UNLEASHED_RECOMP_SDL_LIBS SDL2::SDL2main)
|
||||
endif()
|
||||
|
||||
set(UNLEASHED_RECOMP_PLATFORM_LIBS)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
list(APPEND UNLEASHED_RECOMP_PLATFORM_LIBS MoltenVK)
|
||||
target_link_options(UnleashedRecomp PRIVATE
|
||||
"LINKER:-u,_vkGetInstanceProcAddr"
|
||||
"LINKER:-ObjC"
|
||||
)
|
||||
endif()
|
||||
set(UNLEASHED_RECOMP_PLATFORM_LIBS)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
target_link_options(UnleashedRecomp PRIVATE
|
||||
"LINKER:-ObjC"
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(UnleashedRecomp PRIVATE
|
||||
fmt::fmt
|
||||
|
|
|
|||
|
|
@ -100,17 +100,30 @@ extern "C"
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(UNLEASHED_RECOMP_IOS) && defined(__APPLE__) && !defined(SDL_VULKAN_ENABLED)
|
||||
#define UNLEASHED_RECOMP_USE_METAL 1
|
||||
#endif
|
||||
|
||||
namespace plume
|
||||
{
|
||||
#ifdef UNLEASHED_RECOMP_D3D12
|
||||
extern std::unique_ptr<RenderInterface> CreateD3D12Interface();
|
||||
#endif
|
||||
#ifdef UNLEASHED_RECOMP_USE_METAL
|
||||
extern std::unique_ptr<RenderInterface> CreateMetalInterface();
|
||||
#else
|
||||
#ifdef SDL_VULKAN_ENABLED
|
||||
extern std::unique_ptr<RenderInterface> CreateVulkanInterface(RenderWindow sdlWindow);
|
||||
#else
|
||||
extern std::unique_ptr<RenderInterface> CreateVulkanInterface();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef UNLEASHED_RECOMP_USE_METAL
|
||||
static std::unique_ptr<RenderInterface> CreateMetalInterfaceWrapper() {
|
||||
return CreateMetalInterface();
|
||||
}
|
||||
#else
|
||||
static std::unique_ptr<RenderInterface> CreateVulkanInterfaceWrapper() {
|
||||
#ifdef SDL_VULKAN_ENABLED
|
||||
return CreateVulkanInterface(GameWindow::s_renderWindow);
|
||||
|
|
@ -118,6 +131,7 @@ namespace plume
|
|||
return CreateVulkanInterface();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
|
@ -291,6 +305,15 @@ static bool g_vulkan = false;
|
|||
static constexpr bool g_vulkan = true;
|
||||
#endif
|
||||
|
||||
static const char* GetGraphicsApiName()
|
||||
{
|
||||
#ifdef UNLEASHED_RECOMP_USE_METAL
|
||||
return "Metal";
|
||||
#else
|
||||
return g_vulkan ? "Vulkan" : "D3D12";
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool g_triangleStripWorkaround = false;
|
||||
|
||||
static bool g_hardwareResolve = true;
|
||||
|
|
@ -1755,6 +1778,8 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry)
|
|||
|
||||
interfaceFunctions.push_back(g_vulkan ? CreateVulkanInterfaceWrapper : CreateD3D12Interface);
|
||||
interfaceFunctions.push_back(g_vulkan ? CreateD3D12Interface : CreateVulkanInterfaceWrapper);
|
||||
#elif defined(UNLEASHED_RECOMP_USE_METAL)
|
||||
interfaceFunctions.push_back(CreateMetalInterfaceWrapper);
|
||||
#else
|
||||
interfaceFunctions.push_back(CreateVulkanInterfaceWrapper);
|
||||
#endif
|
||||
|
|
@ -2529,7 +2554,7 @@ static void DrawProfiler()
|
|||
ImGui::Text("Hardware Depth Resolve: %s", g_hardwareDepthResolve ? "Enabled" : "Disabled");
|
||||
ImGui::NewLine();
|
||||
|
||||
ImGui::Text("API: %s", g_vulkan ? "Vulkan" : "D3D12");
|
||||
ImGui::Text("API: %s", GetGraphicsApiName());
|
||||
ImGui::Text("Device: %s", g_device->getDescription().name.c_str());
|
||||
ImGui::Text("Device Type: %s", DeviceTypeName(g_device->getDescription().type));
|
||||
ImGui::Text("VRAM: %.2f MiB", (double)(g_device->getDescription().dedicatedVideoMemory) / (1024.0 * 1024.0));
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#include <app.h>
|
||||
#include <sdl_listener.h>
|
||||
#include <SDL_syswm.h>
|
||||
#ifdef __APPLE__
|
||||
#include <SDL_metal.h>
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
#include <dwmapi.h>
|
||||
|
|
@ -227,8 +230,13 @@ void GameWindow::Init(const char* sdlVideoDriver)
|
|||
#elif defined(__linux__)
|
||||
s_renderWindow = { info.info.x11.display, info.info.x11.window };
|
||||
#elif defined(__APPLE__)
|
||||
s_metalView = SDL_Metal_CreateView(s_pWindow);
|
||||
#ifdef UNLEASHED_RECOMP_IOS
|
||||
s_renderWindow.window = s_metalView;
|
||||
#else
|
||||
s_renderWindow.window = info.info.cocoa.window;
|
||||
s_renderWindow.view = SDL_Metal_GetLayer(SDL_Metal_CreateView(s_pWindow));
|
||||
#endif
|
||||
s_renderWindow.view = s_metalView != nullptr ? SDL_Metal_GetLayer(s_metalView) : nullptr;
|
||||
#else
|
||||
static_assert(false, "Unknown platform.");
|
||||
#endif
|
||||
|
|
@ -449,6 +457,8 @@ uint32_t GameWindow::GetWindowFlags()
|
|||
|
||||
#ifdef SDL_VULKAN_ENABLED
|
||||
flags |= SDL_WINDOW_VULKAN;
|
||||
#elif defined(__APPLE__)
|
||||
flags |= SDL_WINDOW_METAL;
|
||||
#endif
|
||||
|
||||
return flags;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
#include <plume_render_interface_types.h>
|
||||
#include <user/config.h>
|
||||
#include <sdl_events.h>
|
||||
#ifdef __APPLE__
|
||||
#include <SDL_metal.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_WIDTH 1280
|
||||
#define DEFAULT_HEIGHT 720
|
||||
|
|
@ -14,6 +17,9 @@ class GameWindow
|
|||
public:
|
||||
static inline SDL_Window* s_pWindow = nullptr;
|
||||
static inline plume::RenderWindow s_renderWindow;
|
||||
#ifdef __APPLE__
|
||||
static inline SDL_MetalView s_metalView = nullptr;
|
||||
#endif
|
||||
|
||||
static inline int s_x;
|
||||
static inline int s_y;
|
||||
|
|
|
|||
8
thirdparty/CMakeLists.txt
vendored
8
thirdparty/CMakeLists.txt
vendored
|
|
@ -15,7 +15,10 @@ set(SDL2MIXER_OPUS OFF)
|
|||
set(SDL2MIXER_VORBIS "VORBISFILE")
|
||||
set(SDL2MIXER_WAVPACK OFF)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
set(SDL_VULKAN_ENABLED OFF CACHE BOOL "" FORCE)
|
||||
set(SDL_VULKAN OFF CACHE BOOL "" FORCE)
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
set(SDL_VULKAN_ENABLED ON CACHE BOOL "")
|
||||
endif()
|
||||
|
||||
|
|
@ -38,8 +41,9 @@ endif()
|
|||
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/o1heap")
|
||||
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/SDL")
|
||||
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/SDL_mixer")
|
||||
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/plume")
|
||||
|
||||
if (APPLE)
|
||||
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/MoltenVK")
|
||||
endif()
|
||||
|
||||
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/plume")
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@ set -euo pipefail
|
|||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
PLUME_DIR="$ROOT/thirdparty/plume"
|
||||
PLUME_PATCH_FILE="$ROOT/tools/patches/plume-ios-sdl-vulkan.patch"
|
||||
PLUME_PATCH_FILE="$ROOT/tools/patches/plume-ios-metal.patch"
|
||||
XENON_RECOMP_DIR="$ROOT/tools/XenonRecomp"
|
||||
XENON_RECOMP_PATCH_FILE="$ROOT/tools/patches/xenonrecomp-ios-streaming-memory-map.patch"
|
||||
PLUME_VOLK_HEADER="$PLUME_DIR/contrib/volk/volk.h"
|
||||
PLUME_VOLK_RENAME_HEADER="$PLUME_DIR/plume_volk_rename_ios.h"
|
||||
|
||||
if [[ ! -d "$PLUME_DIR/.git" && ! -f "$PLUME_DIR/.git" ]]; then
|
||||
printf 'Missing Plume submodule. Run: git submodule update --init --recursive\n' >&2
|
||||
|
|
@ -31,18 +29,6 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
if [[ ! -f "$PLUME_VOLK_HEADER" ]]; then
|
||||
printf 'Missing Plume volk header: %s\n' "$PLUME_VOLK_HEADER" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
{
|
||||
printf '#pragma once\n\n'
|
||||
printf '// Keep Plume'\''s embedded volk function-pointer globals from colliding with statically linked MoltenVK on iOS.\n'
|
||||
awk '/^extern PFN_vk/ { name = $3; sub(/;$/, "", name); print "#define " name " plumeVolk_" name }' "$PLUME_VOLK_HEADER"
|
||||
} > "$PLUME_VOLK_RENAME_HEADER"
|
||||
printf 'Generated Plume iOS volk rename header.\n'
|
||||
|
||||
if git -C "$XENON_RECOMP_DIR" apply --check "$XENON_RECOMP_PATCH_FILE" >/dev/null 2>&1; then
|
||||
git -C "$XENON_RECOMP_DIR" apply "$XENON_RECOMP_PATCH_FILE"
|
||||
printf 'Applied XenonRecomp iOS patch.\n'
|
||||
|
|
|
|||
583
tools/patches/plume-ios-metal.patch
Normal file
583
tools/patches/plume-ios-metal.patch
Normal file
|
|
@ -0,0 +1,583 @@
|
|||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 6a7645a..5417620 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -98,6 +98,34 @@ if(APPLE)
|
||||
target_include_directories(plume PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/contrib/metal-cpp
|
||||
)
|
||||
+
|
||||
+ if(TARGET spirv-cross-msl)
|
||||
+ target_link_libraries(plume PUBLIC spirv-cross-msl)
|
||||
+ endif()
|
||||
+
|
||||
+ find_library(FOUNDATION_LIBRARY Foundation REQUIRED)
|
||||
+ find_library(METAL_LIBRARY Metal REQUIRED)
|
||||
+ find_library(QUARTZCORE_LIBRARY QuartzCore REQUIRED)
|
||||
+
|
||||
+ if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
+ find_library(UIKIT_LIBRARY UIKit REQUIRED)
|
||||
+ target_link_libraries(plume PUBLIC
|
||||
+ ${FOUNDATION_LIBRARY}
|
||||
+ ${METAL_LIBRARY}
|
||||
+ ${QUARTZCORE_LIBRARY}
|
||||
+ ${UIKIT_LIBRARY}
|
||||
+ )
|
||||
+ else()
|
||||
+ find_library(APPKIT_LIBRARY AppKit REQUIRED)
|
||||
+ find_library(IOKIT_LIBRARY IOKit REQUIRED)
|
||||
+ target_link_libraries(plume PUBLIC
|
||||
+ ${APPKIT_LIBRARY}
|
||||
+ ${FOUNDATION_LIBRARY}
|
||||
+ ${IOKIT_LIBRARY}
|
||||
+ ${METAL_LIBRARY}
|
||||
+ ${QUARTZCORE_LIBRARY}
|
||||
+ )
|
||||
+ endif()
|
||||
endif()
|
||||
|
||||
# Add examples if requested
|
||||
diff --git a/plume_apple.mm b/plume_apple.mm
|
||||
index 64e4dc9..1d14600 100644
|
||||
--- a/plume_apple.mm
|
||||
+++ b/plume_apple.mm
|
||||
@@ -7,10 +7,20 @@
|
||||
|
||||
#include "plume_apple.h"
|
||||
|
||||
+#include <TargetConditionals.h>
|
||||
+
|
||||
+#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
|
||||
+#import <UIKit/UIKit.h>
|
||||
+#else
|
||||
#import <AppKit/AppKit.h>
|
||||
-#import <Foundation/Foundation.h>
|
||||
#import <IOKit/IOKitLib.h>
|
||||
+#endif
|
||||
+
|
||||
+#import <Foundation/Foundation.h>
|
||||
|
||||
+#include <cmath>
|
||||
+
|
||||
+#if !(TARGET_OS_IOS && !TARGET_OS_MACCATALYST)
|
||||
static uint32_t plumeGetEntryProperty(io_registry_entry_t entry, CFStringRef propertyName) {
|
||||
uint32_t value = 0;
|
||||
CFTypeRef cfProp = IORegistryEntrySearchCFProperty(entry, kIOServicePlane, propertyName, kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
|
||||
@@ -27,9 +37,62 @@ static uint32_t plumeGetEntryProperty(io_registry_entry_t entry, CFStringRef pro
|
||||
|
||||
return value;
|
||||
}
|
||||
+#endif
|
||||
+
|
||||
+static plume::CocoaWindowAttributes plumeGetWindowAttributes(void* windowHandle) {
|
||||
+#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
|
||||
+ UIView *view = (__bridge UIView *)windowHandle;
|
||||
+ CGRect bounds = [view bounds];
|
||||
+ CGFloat scaleFactor = [view contentScaleFactor];
|
||||
+ if (scaleFactor <= 0.0) {
|
||||
+ scaleFactor = [[UIScreen mainScreen] scale];
|
||||
+ }
|
||||
+
|
||||
+ return {
|
||||
+ 0,
|
||||
+ 0,
|
||||
+ (int)round(bounds.size.width * scaleFactor),
|
||||
+ (int)round(bounds.size.height * scaleFactor)
|
||||
+ };
|
||||
+#else
|
||||
+ NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
|
||||
+ NSRect contentFrame = [[nsWindow contentView] frame];
|
||||
+ CGFloat scaleFactor = [nsWindow backingScaleFactor];
|
||||
+
|
||||
+ return {
|
||||
+ (int)round(contentFrame.origin.x),
|
||||
+ (int)round(contentFrame.origin.y),
|
||||
+ (int)round(contentFrame.size.width * scaleFactor),
|
||||
+ (int)round(contentFrame.size.height * scaleFactor)
|
||||
+ };
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static int plumeGetRefreshRate(void* windowHandle, int fallbackRate) {
|
||||
+#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
|
||||
+ UIView *view = (__bridge UIView *)windowHandle;
|
||||
+ UIScreen *screen = [[view window] screen] ?: [UIScreen mainScreen];
|
||||
+ if (@available(iOS 10.3, *)) {
|
||||
+ return (int)[screen maximumFramesPerSecond];
|
||||
+ }
|
||||
+
|
||||
+ return fallbackRate > 0 ? fallbackRate : 60;
|
||||
+#else
|
||||
+ NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
|
||||
+ NSScreen *screen = [nsWindow screen];
|
||||
+ if (@available(macOS 12.0, *)) {
|
||||
+ return (int)[screen maximumFramesPerSecond];
|
||||
+ }
|
||||
+
|
||||
+ return fallbackRate;
|
||||
+#endif
|
||||
+}
|
||||
|
||||
namespace plume {
|
||||
RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
|
||||
+#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
|
||||
+ return RenderDeviceVendor::APPLE;
|
||||
+#else
|
||||
io_service_t entry = IOServiceGetMatchingService(MACH_PORT_NULL, IORegistryEntryIDMatching(registryID));
|
||||
|
||||
if (entry) {
|
||||
@@ -44,6 +107,7 @@ RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
|
||||
}
|
||||
|
||||
return RenderDeviceVendor::UNKNOWN;
|
||||
+#endif
|
||||
}
|
||||
|
||||
// MARK: - CocoaWindow
|
||||
@@ -53,19 +117,8 @@ RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
|
||||
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]);
|
||||
- }
|
||||
+ cachedAttributes = plumeGetWindowAttributes(windowHandle);
|
||||
+ cachedRefreshRate.store(plumeGetRefreshRate(windowHandle, cachedRefreshRate.load()));
|
||||
} else {
|
||||
updateWindowAttributesInternal(true);
|
||||
updateRefreshRateInternal(true);
|
||||
@@ -76,15 +129,8 @@ RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
|
||||
|
||||
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);
|
||||
+ cachedAttributes = plumeGetWindowAttributes(windowHandle);
|
||||
};
|
||||
|
||||
if (forceSync) {
|
||||
@@ -96,11 +142,7 @@ RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
|
||||
|
||||
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]);
|
||||
- }
|
||||
+ cachedRefreshRate.store(plumeGetRefreshRate(windowHandle, cachedRefreshRate.load()));
|
||||
};
|
||||
|
||||
if (forceSync) {
|
||||
@@ -112,16 +154,9 @@ RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
|
||||
|
||||
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);
|
||||
+ const_cast<CocoaWindow*>(this)->cachedAttributes = plumeGetWindowAttributes(windowHandle);
|
||||
|
||||
*attributes = cachedAttributes;
|
||||
}
|
||||
@@ -137,16 +172,9 @@ RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
|
||||
|
||||
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();
|
||||
+ int freshRate = plumeGetRefreshRate(windowHandle, cachedRefreshRate.load());
|
||||
+ const_cast<CocoaWindow*>(this)->cachedRefreshRate.store(freshRate);
|
||||
+ return freshRate;
|
||||
} else {
|
||||
int rate = cachedRefreshRate.load();
|
||||
|
||||
@@ -157,6 +185,9 @@ RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
|
||||
}
|
||||
|
||||
void CocoaWindow::toggleFullscreen() {
|
||||
+#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
|
||||
+ return;
|
||||
+#else
|
||||
if ([NSThread isMainThread]) {
|
||||
NSWindow *nsWindow = (__bridge NSWindow *)windowHandle;
|
||||
[nsWindow toggleFullScreen:NULL];
|
||||
@@ -166,5 +197,6 @@ RenderDeviceVendor getRenderDeviceVendor(uint64_t registryID) {
|
||||
[nsWindow toggleFullScreen:NULL];
|
||||
});
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
}
|
||||
diff --git a/plume_metal.cpp b/plume_metal.cpp
|
||||
index ebbbaa3..6f5a82c 100644
|
||||
--- a/plume_metal.cpp
|
||||
+++ b/plume_metal.cpp
|
||||
@@ -14,8 +14,12 @@
|
||||
#include <QuartzCore/QuartzCore.hpp>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
+#include <spirv_msl.hpp>
|
||||
+
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
+#include <stdexcept>
|
||||
+#include <string>
|
||||
|
||||
#include "plume_metal.h"
|
||||
|
||||
@@ -38,6 +42,141 @@ namespace plume {
|
||||
return (n + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
+ uint32_t getSpirvResourceArrayCount(const spirv_cross::SPIRType& type) {
|
||||
+ uint32_t count = 1;
|
||||
+ for (const uint32_t dimension : type.array) {
|
||||
+ if (dimension == 0) {
|
||||
+ return count;
|
||||
+ }
|
||||
+ count *= dimension;
|
||||
+ }
|
||||
+
|
||||
+ return count;
|
||||
+ }
|
||||
+
|
||||
+ void addSpirvResourceBinding(spirv_cross::CompilerMSL& compiler, const spirv_cross::Resource& resource) {
|
||||
+ if (!compiler.has_decoration(resource.id, spv::DecorationDescriptorSet) ||
|
||||
+ !compiler.has_decoration(resource.id, spv::DecorationBinding)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ const uint32_t descriptorSet = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||
+ const uint32_t bindingIndex = compiler.get_decoration(resource.id, spv::DecorationBinding);
|
||||
+ const spirv_cross::SPIRType& type = compiler.get_type(resource.type_id);
|
||||
+
|
||||
+ spirv_cross::MSLResourceBinding binding = {};
|
||||
+ binding.stage = compiler.get_execution_model();
|
||||
+ binding.basetype = type.basetype;
|
||||
+ binding.desc_set = descriptorSet;
|
||||
+ binding.binding = bindingIndex;
|
||||
+ binding.count = getSpirvResourceArrayCount(type);
|
||||
+ binding.msl_buffer = bindingIndex;
|
||||
+ binding.msl_texture = bindingIndex;
|
||||
+ binding.msl_sampler = bindingIndex;
|
||||
+
|
||||
+ compiler.add_msl_resource_binding(binding);
|
||||
+ }
|
||||
+
|
||||
+ struct MetalShaderSource {
|
||||
+ std::string source;
|
||||
+ std::string entryPointName;
|
||||
+ };
|
||||
+
|
||||
+ MetalShaderSource compileSpirvToMetalSource(const MetalDevice* device, const void* data, const uint64_t size, const char* entryPointName) {
|
||||
+ if ((size % sizeof(uint32_t)) != 0) {
|
||||
+ throw std::runtime_error("SPIR-V shader data is not 32-bit aligned.");
|
||||
+ }
|
||||
+
|
||||
+ spirv_cross::CompilerMSL compiler(static_cast<const uint32_t*>(data), size / sizeof(uint32_t));
|
||||
+ std::string spirvEntryPointName = entryPointName != nullptr ? entryPointName : "";
|
||||
+ spv::ExecutionModel executionModel = compiler.get_execution_model();
|
||||
+
|
||||
+ if (!spirvEntryPointName.empty()) {
|
||||
+ for (const auto& entryPoint : compiler.get_entry_points_and_stages()) {
|
||||
+ if (entryPoint.name == spirvEntryPointName) {
|
||||
+ compiler.set_entry_point(entryPoint.name, entryPoint.execution_model);
|
||||
+ executionModel = entryPoint.execution_model;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (spirvEntryPointName.empty()) {
|
||||
+ const auto entryPoints = compiler.get_entry_points_and_stages();
|
||||
+ if (!entryPoints.empty()) {
|
||||
+ spirvEntryPointName = entryPoints.front().name;
|
||||
+ executionModel = entryPoints.front().execution_model;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ spirv_cross::CompilerMSL::Options options = compiler.get_msl_options();
|
||||
+#if PLUME_IOS
|
||||
+ options.platform = spirv_cross::CompilerMSL::Options::iOS;
|
||||
+ options.ios_support_base_vertex_instance = true;
|
||||
+ options.emulate_cube_array = true;
|
||||
+#else
|
||||
+ options.platform = spirv_cross::CompilerMSL::Options::macOS;
|
||||
+#endif
|
||||
+ options.set_msl_version(3, 0);
|
||||
+ options.argument_buffers = true;
|
||||
+ options.argument_buffers_tier =
|
||||
+ device->mtl->argumentBuffersSupport() == MTL::ArgumentBuffersTier2
|
||||
+ ? spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier2
|
||||
+ : spirv_cross::CompilerMSL::Options::ArgumentBuffersTier::Tier1;
|
||||
+ options.enable_base_index_zero = true;
|
||||
+ options.enable_decoration_binding = true;
|
||||
+ options.force_active_argument_buffer_resources = true;
|
||||
+ options.texture_buffer_native = true;
|
||||
+
|
||||
+ compiler.set_msl_options(options);
|
||||
+
|
||||
+ for (uint32_t descriptorSet = 0; descriptorSet < MAX_DESCRIPTOR_SET_BINDINGS; descriptorSet++) {
|
||||
+ spirv_cross::MSLResourceBinding argumentBufferBinding = {};
|
||||
+ argumentBufferBinding.stage = executionModel;
|
||||
+ argumentBufferBinding.desc_set = descriptorSet;
|
||||
+ argumentBufferBinding.binding = spirv_cross::kArgumentBufferBinding;
|
||||
+ argumentBufferBinding.msl_buffer = DESCRIPTOR_SETS_BINDING_INDEX + descriptorSet;
|
||||
+ compiler.add_msl_resource_binding(argumentBufferBinding);
|
||||
+ }
|
||||
+
|
||||
+ const spirv_cross::ShaderResources resources = compiler.get_shader_resources();
|
||||
+ const auto addResourceList = [&](const auto& list) {
|
||||
+ for (const spirv_cross::Resource& resource : list) {
|
||||
+ addSpirvResourceBinding(compiler, resource);
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ addResourceList(resources.uniform_buffers);
|
||||
+ addResourceList(resources.storage_buffers);
|
||||
+ addResourceList(resources.stage_inputs);
|
||||
+ addResourceList(resources.stage_outputs);
|
||||
+ addResourceList(resources.subpass_inputs);
|
||||
+ addResourceList(resources.storage_images);
|
||||
+ addResourceList(resources.sampled_images);
|
||||
+ addResourceList(resources.separate_images);
|
||||
+ addResourceList(resources.separate_samplers);
|
||||
+ addResourceList(resources.atomic_counters);
|
||||
+ addResourceList(resources.acceleration_structures);
|
||||
+
|
||||
+ if (!resources.push_constant_buffers.empty()) {
|
||||
+ const spirv_cross::SPIRType& pushConstantType = compiler.get_type(resources.push_constant_buffers.front().type_id);
|
||||
+ spirv_cross::MSLResourceBinding pushConstantsBinding = {};
|
||||
+ pushConstantsBinding.stage = executionModel;
|
||||
+ pushConstantsBinding.basetype = pushConstantType.basetype;
|
||||
+ pushConstantsBinding.desc_set = spirv_cross::kPushConstDescSet;
|
||||
+ pushConstantsBinding.binding = spirv_cross::kPushConstBinding;
|
||||
+ pushConstantsBinding.count = 1;
|
||||
+ pushConstantsBinding.msl_buffer = PUSH_CONSTANTS_BINDING_INDEX;
|
||||
+ compiler.add_msl_resource_binding(pushConstantsBinding);
|
||||
+ }
|
||||
+
|
||||
+ MetalShaderSource translatedSource = {};
|
||||
+ translatedSource.source = compiler.compile();
|
||||
+ translatedSource.entryPointName = compiler.get_cleansed_entry_point_name(spirvEntryPointName, executionModel);
|
||||
+
|
||||
+ return translatedSource;
|
||||
+ }
|
||||
+
|
||||
uint64_t createClearPipelineKey(MTL::RenderPipelineDescriptor *pipelineDesc, bool depthWriteEnabled, bool stencilWriteEnabled) {
|
||||
auto colorFormat = [&](uint32_t index) {
|
||||
if (auto colorAttachment = pipelineDesc->colorAttachments()->object(index)) {
|
||||
@@ -1278,24 +1417,46 @@ namespace plume {
|
||||
assert(device != nullptr);
|
||||
assert(data != nullptr);
|
||||
assert(size > 0);
|
||||
- assert(format == RenderShaderFormat::METAL);
|
||||
|
||||
this->format = format;
|
||||
this->functionName = (entryPointName != nullptr) ? NS::String::string(entryPointName, NS::UTF8StringEncoding) : MTLSTR("");
|
||||
|
||||
NS::Error *error = nullptr;
|
||||
- const dispatch_data_t dispatchData = dispatch_data_create(data, size, dispatch_get_main_queue(), ^{});
|
||||
- library = device->mtl->newLibrary(dispatchData, &error);
|
||||
+ if (format == RenderShaderFormat::METAL) {
|
||||
+ const dispatch_data_t dispatchData = dispatch_data_create(data, size, dispatch_get_main_queue(), ^{});
|
||||
+ library = device->mtl->newLibrary(dispatchData, &error);
|
||||
+ } else if (format == RenderShaderFormat::SPIRV) {
|
||||
+ try {
|
||||
+ const MetalShaderSource metalSource = compileSpirvToMetalSource(device, data, size, entryPointName);
|
||||
+ functionName->release();
|
||||
+ functionName = NS::String::string(metalSource.entryPointName.c_str(), NS::UTF8StringEncoding);
|
||||
+ MTL::CompileOptions *compileOptions = MTL::CompileOptions::alloc()->init();
|
||||
+ compileOptions->setFastMathEnabled(true);
|
||||
+ compileOptions->setLanguageVersion(MTL::LanguageVersion3_0);
|
||||
+ library = device->mtl->newLibrary(NS::String::string(metalSource.source.c_str(), NS::UTF8StringEncoding), compileOptions, &error);
|
||||
+ compileOptions->release();
|
||||
+ } catch (const std::exception& e) {
|
||||
+ fprintf(stderr, "SPIR-V to MSL translation failed: %s.\n", e.what());
|
||||
+ return;
|
||||
+ }
|
||||
+ } else {
|
||||
+ assert(false && "Unsupported Metal shader format.");
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
if (error != nullptr) {
|
||||
- fprintf(stderr, "MTLDevice newLibraryWithSource: failed with error %s.\n", error->localizedDescription()->utf8String());
|
||||
+ fprintf(stderr, "MTLDevice newLibrary: failed with error %s.\n", error->localizedDescription()->utf8String());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MetalShader::~MetalShader() {
|
||||
- functionName->release();
|
||||
- library->release();
|
||||
+ if (functionName) {
|
||||
+ functionName->release();
|
||||
+ }
|
||||
+ if (library) {
|
||||
+ library->release();
|
||||
+ }
|
||||
if (debugName) {
|
||||
debugName->release();
|
||||
}
|
||||
@@ -1306,10 +1467,16 @@ namespace plume {
|
||||
debugName->release();
|
||||
}
|
||||
debugName = NS::String::string(name.c_str(), NS::UTF8StringEncoding);
|
||||
- library->setLabel(debugName);
|
||||
+ if (library) {
|
||||
+ library->setLabel(debugName);
|
||||
+ }
|
||||
}
|
||||
|
||||
MTL::Function* MetalShader::createFunction(const RenderSpecConstant *specConstants, const uint32_t specConstantsCount) const {
|
||||
+ if (library == nullptr) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+
|
||||
MTL::FunctionConstantValues *values = MTL::FunctionConstantValues::alloc()->init();
|
||||
if (specConstants != nullptr) {
|
||||
for (uint32_t i = 0; i < specConstantsCount; i++) {
|
||||
@@ -3308,6 +3475,9 @@ namespace plume {
|
||||
this->renderInterface = renderInterface;
|
||||
|
||||
// Device Selection
|
||||
+#if PLUME_IOS
|
||||
+ mtl = MTL::CreateSystemDefaultDevice();
|
||||
+#else
|
||||
const NS::Array* devices = MTL::CopyAllDevices();
|
||||
MTL::Device *preferredDevice = nullptr;
|
||||
for (NS::UInteger i = 0; i < devices->count(); i++) {
|
||||
@@ -3320,9 +3490,18 @@ namespace plume {
|
||||
}
|
||||
|
||||
mtl = preferredDevice ? preferredDevice : MTL::CreateSystemDefaultDevice();;
|
||||
+#endif
|
||||
+ if (mtl == nullptr) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
const std::string deviceName(mtl->name()->utf8String());
|
||||
description.name = deviceName;
|
||||
+#if PLUME_IOS
|
||||
+ description.type = RenderDeviceType::INTEGRATED;
|
||||
+#else
|
||||
description.type = mapDeviceType(mtl->location());
|
||||
+#endif
|
||||
description.driverVersion = 1; // Unavailable
|
||||
description.vendor = mtl->supportsFamily(MTL::GPUFamilyApple1) ? RenderDeviceVendor::APPLE : getRenderDeviceVendor(mtl->registryID());
|
||||
description.dedicatedVideoMemory = mtl->recommendedMaxWorkingSetSize();
|
||||
@@ -3357,17 +3536,19 @@ namespace plume {
|
||||
}
|
||||
|
||||
MetalDevice::~MetalDevice() {
|
||||
- mtl->release();
|
||||
+ if (mtl) {
|
||||
+ mtl->release();
|
||||
+ }
|
||||
|
||||
for (const auto& [key, state] : clearRenderPipelineStates) {
|
||||
state->release();
|
||||
}
|
||||
|
||||
- resolveTexturePipelineState->release();
|
||||
- clearVertexFunction->release();
|
||||
- clearColorFunction->release();
|
||||
- clearDepthFunction->release();
|
||||
- sharedBlitDescriptor->release();
|
||||
+ if (resolveTexturePipelineState) resolveTexturePipelineState->release();
|
||||
+ if (clearVertexFunction) clearVertexFunction->release();
|
||||
+ if (clearColorFunction) clearColorFunction->release();
|
||||
+ if (clearDepthFunction) clearDepthFunction->release();
|
||||
+ if (sharedBlitDescriptor) sharedBlitDescriptor->release();
|
||||
}
|
||||
|
||||
std::unique_ptr<RenderDescriptorSet> MetalDevice::createDescriptorSet(const RenderDescriptorSetDesc &desc) {
|
||||
@@ -3635,16 +3816,24 @@ namespace plume {
|
||||
|
||||
MetalInterface::MetalInterface() {
|
||||
NS::AutoreleasePool *releasePool = NS::AutoreleasePool::alloc()->init();
|
||||
- capabilities.shaderFormat = RenderShaderFormat::METAL;
|
||||
+ capabilities.shaderFormat = RenderShaderFormat::SPIRV;
|
||||
|
||||
releasePool->release();
|
||||
|
||||
// Fill device names.
|
||||
+#if PLUME_IOS
|
||||
+ MTL::Device* device = MTL::CreateSystemDefaultDevice();
|
||||
+ if (device != nullptr) {
|
||||
+ deviceNames.push_back(std::string(device->name()->utf8String()));
|
||||
+ device->release();
|
||||
+ }
|
||||
+#else
|
||||
const NS::Array* devices = MTL::CopyAllDevices();
|
||||
for (NS::UInteger i = 0; i < devices->count(); i++) {
|
||||
NS::String* deviceName = ((MTL::Device *)devices->object(i))->name();
|
||||
deviceNames.push_back(std::string(deviceName->utf8String()));
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
MetalInterface::~MetalInterface() {}
|
||||
diff --git a/plume_metal.h b/plume_metal.h
|
||||
index fd367ed..557686b 100644
|
||||
--- a/plume_metal.h
|
||||
+++ b/plume_metal.h
|
||||
@@ -608,16 +608,16 @@ namespace plume {
|
||||
RenderDeviceDescription description;
|
||||
|
||||
// Resolve functionality
|
||||
- MTL::ComputePipelineState *resolveTexturePipelineState;
|
||||
+ MTL::ComputePipelineState *resolveTexturePipelineState = nullptr;
|
||||
|
||||
// Clear functionality
|
||||
- MTL::Function* clearVertexFunction;
|
||||
- MTL::Function* clearColorFunction;
|
||||
- MTL::Function* clearDepthFunction;
|
||||
- MTL::Function* clearStencilFunction;
|
||||
- MTL::DepthStencilState *clearDepthState;
|
||||
- MTL::DepthStencilState *clearStencilState;
|
||||
- MTL::DepthStencilState *clearDepthStencilState;
|
||||
+ MTL::Function* clearVertexFunction = nullptr;
|
||||
+ MTL::Function* clearColorFunction = nullptr;
|
||||
+ MTL::Function* clearDepthFunction = nullptr;
|
||||
+ MTL::Function* clearStencilFunction = nullptr;
|
||||
+ MTL::DepthStencilState *clearDepthState = nullptr;
|
||||
+ MTL::DepthStencilState *clearStencilState = nullptr;
|
||||
+ MTL::DepthStencilState *clearDepthStencilState = nullptr;
|
||||
|
||||
std::mutex clearPipelineStateMutex;
|
||||
std::unordered_map<uint64_t, MTL::RenderPipelineState *> clearRenderPipelineStates;
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 6a7645a..6e6e887 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -8,10 +8,16 @@ if(APPLE)
|
||||
endif()
|
||||
|
||||
string(COMPARE EQUAL ${CMAKE_SYSTEM_NAME} "Linux" IS_LINUX)
|
||||
+string(COMPARE EQUAL ${CMAKE_SYSTEM_NAME} "iOS" IS_IOS)
|
||||
+if(IS_LINUX OR IS_IOS)
|
||||
+ set(IS_SDL_VULKAN_PLATFORM ON)
|
||||
+else()
|
||||
+ set(IS_SDL_VULKAN_PLATFORM OFF)
|
||||
+endif()
|
||||
|
||||
# Project options
|
||||
include(CMakeDependentOption)
|
||||
-cmake_dependent_option(SDL_VULKAN_ENABLED "Enable SDL Vulkan integration" OFF IS_LINUX OFF)
|
||||
+cmake_dependent_option(SDL_VULKAN_ENABLED "Enable SDL Vulkan integration" OFF IS_SDL_VULKAN_PLATFORM OFF)
|
||||
cmake_dependent_option(D3D12_AGILITY_SDK_ENABLED "Enable D3D12 Agility SDK" OFF WIN32 OFF)
|
||||
option(PLUME_BUILD_EXAMPLES "Build example applications" OFF)
|
||||
|
||||
@@ -50,7 +56,7 @@ set(PLUME_SOURCES
|
||||
)
|
||||
|
||||
# Platform-specific files
|
||||
-if(APPLE)
|
||||
+if(APPLE AND NOT IS_IOS)
|
||||
list(APPEND PLUME_SOURCES
|
||||
plume_metal.cpp
|
||||
plume_metal.h
|
||||
@@ -94,7 +100,7 @@ if(D3D12_AGILITY_SDK_ENABLED)
|
||||
endif()
|
||||
|
||||
# Platform-specific includes
|
||||
-if(APPLE)
|
||||
+if(APPLE AND NOT IS_IOS)
|
||||
target_include_directories(plume PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/contrib/metal-cpp
|
||||
)
|
||||
diff --git a/plume_vulkan.cpp b/plume_vulkan.cpp
|
||||
index 9103ca8..63de1cc 100644
|
||||
--- a/plume_vulkan.cpp
|
||||
+++ b/plume_vulkan.cpp
|
||||
@@ -8,6 +8,9 @@
|
||||
#define VMA_IMPLEMENTATION
|
||||
#define VOLK_IMPLEMENTATION
|
||||
|
||||
+#if defined(__APPLE__) && defined(SDL_VULKAN_ENABLED)
|
||||
+#include "plume_volk_rename_ios.h"
|
||||
+#endif
|
||||
#include "plume_vulkan.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -19,6 +22,10 @@
|
||||
# include "render/plume_dlss.h"
|
||||
#endif
|
||||
|
||||
+#if defined(__APPLE__) && defined(SDL_VULKAN_ENABLED)
|
||||
+extern "C" VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL mvkGetInstanceProcAddr(VkInstance instance, const char *pName) __asm("_vkGetInstanceProcAddr");
|
||||
+#endif
|
||||
+
|
||||
#ifndef NDEBUG
|
||||
# define VULKAN_VALIDATION_LAYER_ENABLED
|
||||
# define VULKAN_OBJECT_NAMES_ENABLED
|
||||
@@ -88,6 +95,19 @@ namespace plume {
|
||||
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
+ static std::unordered_set<std::string> getRequiredDeviceExtensions(uint32_t apiVersion) {
|
||||
+ std::unordered_set<std::string> extensions = RequiredDeviceExtensions;
|
||||
+
|
||||
+ // MoltenVK and other Vulkan 1.2+ implementations expose these as core features
|
||||
+ // and no longer enumerate them as separate device extensions.
|
||||
+ if (apiVersion >= VK_API_VERSION_1_2) {
|
||||
+ extensions.erase(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||
+ extensions.erase(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME);
|
||||
+ }
|
||||
+
|
||||
+ return extensions;
|
||||
+ }
|
||||
+
|
||||
// Common functions.
|
||||
|
||||
static uint32_t roundUp(uint32_t value, uint32_t powerOf2Alignment) {
|
||||
@@ -2112,6 +2132,12 @@ namespace plume {
|
||||
fprintf(stderr, "vkCreateXlibSurfaceKHR failed with error code 0x%X.\n", res);
|
||||
return;
|
||||
}
|
||||
+# elif defined(__APPLE__) && defined(SDL_VULKAN_ENABLED)
|
||||
+ VulkanInterface *renderInterface = commandQueue->device->renderInterface;
|
||||
+ if (!SDL_Vulkan_CreateSurface(renderWindow, renderInterface->instance, &surface)) {
|
||||
+ fprintf(stderr, "SDL_Vulkan_CreateSurface failed: %s.\n", SDL_GetError());
|
||||
+ return;
|
||||
+ }
|
||||
# elif defined(__APPLE__)
|
||||
assert(renderWindow.window != 0);
|
||||
assert(renderWindow.view != 0);
|
||||
@@ -2443,7 +2469,7 @@ namespace plume {
|
||||
// The attributes width and height members do not include the border.
|
||||
dstWidth = attributes.width;
|
||||
dstHeight = attributes.height;
|
||||
-# elif defined(__APPLE__)
|
||||
+# elif defined(__APPLE__) && !defined(SDL_VULKAN_ENABLED)
|
||||
CocoaWindowAttributes attributes;
|
||||
windowWrapper->getWindowAttributes(&attributes);
|
||||
dstWidth = attributes.width;
|
||||
@@ -3754,6 +3780,10 @@ namespace plume {
|
||||
return;
|
||||
}
|
||||
|
||||
+ VkPhysicalDeviceProperties selectedDeviceProperties;
|
||||
+ vkGetPhysicalDeviceProperties(physicalDevice, &selectedDeviceProperties);
|
||||
+ const std::unordered_set<std::string> requiredDeviceExtensions = getRequiredDeviceExtensions(selectedDeviceProperties.apiVersion);
|
||||
+
|
||||
// Check for extensions.
|
||||
uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr);
|
||||
@@ -3761,7 +3791,7 @@ namespace plume {
|
||||
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
||||
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, availableExtensions.data());
|
||||
|
||||
- std::unordered_set<std::string> missingRequiredExtensions = RequiredDeviceExtensions;
|
||||
+ std::unordered_set<std::string> missingRequiredExtensions = requiredDeviceExtensions;
|
||||
std::unordered_set<std::string> supportedOptionalExtensions;
|
||||
# if DLSS_ENABLED
|
||||
const std::unordered_set<std::string> dlssExtensions = DLSS::getRequiredDeviceExtensionsVulkan(this);
|
||||
@@ -3969,7 +3999,7 @@ namespace plume {
|
||||
}
|
||||
|
||||
std::vector<const char *> enabledExtensions;
|
||||
- for (const std::string &extension : RequiredDeviceExtensions) {
|
||||
+ for (const std::string &extension : requiredDeviceExtensions) {
|
||||
enabledExtensions.push_back(extension.c_str());
|
||||
}
|
||||
|
||||
@@ -4398,11 +4428,16 @@ namespace plume {
|
||||
#else
|
||||
VulkanInterface::VulkanInterface() {
|
||||
#endif
|
||||
- VkResult res = volkInitialize();
|
||||
+ VkResult res = VK_SUCCESS;
|
||||
+#if defined(__APPLE__) && defined(SDL_VULKAN_ENABLED)
|
||||
+ volkInitializeCustom(mvkGetInstanceProcAddr);
|
||||
+#else
|
||||
+ res = volkInitialize();
|
||||
if (res != VK_SUCCESS) {
|
||||
fprintf(stderr, "volkInitialize failed with error code 0x%X.\n", res);
|
||||
return;
|
||||
}
|
||||
+#endif
|
||||
|
||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
appInfo.pApplicationName = "plume";
|
||||
diff --git a/plume_vulkan.h b/plume_vulkan.h
|
||||
index 73022bb..9d89adf 100644
|
||||
--- a/plume_vulkan.h
|
||||
+++ b/plume_vulkan.h
|
||||
@@ -22,8 +22,10 @@
|
||||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#elif defined(__APPLE__)
|
||||
#define VK_USE_PLATFORM_METAL_EXT
|
||||
+#ifndef SDL_VULKAN_ENABLED
|
||||
#include "plume_apple.h"
|
||||
#endif
|
||||
+#endif
|
||||
|
||||
// For VK_KHR_portability_subset
|
||||
#define VK_ENABLE_BETA_EXTENSIONS
|
||||
@@ -226,7 +228,7 @@ namespace plume {
|
||||
VulkanCommandQueue *commandQueue = nullptr;
|
||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||
RenderWindow renderWindow = {};
|
||||
-#if defined(__APPLE__)
|
||||
+#if defined(__APPLE__) && !defined(SDL_VULKAN_ENABLED)
|
||||
std::unique_ptr<CocoaWindow> windowWrapper;
|
||||
#endif
|
||||
uint32_t textureCount = 0;
|
||||
Loading…
Add table
Reference in a new issue