MoltenVK PoC

This commit is contained in:
dcvz 2024-05-27 03:11:13 +02:00
parent 88c618c1f8
commit c648adae38
11 changed files with 201 additions and 9 deletions

2
.gitignore vendored
View File

@ -22,4 +22,6 @@
build/
.vscode/
.idea
.cache
compile_commands.json
cmake-build-debug*

View File

@ -1,8 +1,12 @@
cmake_minimum_required(VERSION 3.20)
project(rt64)
project(rt64 LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
if (APPLE)
enable_language(OBJC OBJCXX)
endif()
option(RT64_STATIC "Build RT64 as a static library" OFF)
option(RT64_BUILD_EXAMPLES "Build examples for RT64" OFF)
@ -379,6 +383,13 @@ target_link_libraries(rt64 libzstd_static)
add_subdirectory(src/tools/texture_hasher)
add_subdirectory(src/tools/texture_packer)
# Add any Apple-specific source files and libraries
if (APPLE)
target_sources(rt64 PRIVATE
"${PROJECT_SOURCE_DIR}/src/common/rt64_apple.mm"
)
endif()
# Add any Windows-specific source files and libraries
if (WIN32)
target_sources(rt64 PRIVATE

View File

@ -9,6 +9,11 @@
#include <chrono>
#include <thread>
#ifdef __APPLE__
#include <SDL.h>
#include <SDL_syswm.h>
#endif
#ifdef _WIN64
#include "shaders/RenderInterfaceTestPS.hlsl.dxil.h"
#include "shaders/RenderInterfaceTestRT.hlsl.dxil.h"
@ -800,7 +805,54 @@ namespace RT64 {
}
#elif defined(__APPLE__)
void RenderInterfaceTest(RenderInterface* renderInterface) {
assert(false);
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "SDL_Init Error: %s\n", SDL_GetError());
return;
}
SDL_Window *window = SDL_CreateWindow("Render Interface Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE | SDL_WINDOW_METAL);
if (window == nullptr) {
fprintf(stderr, "SDL_CreateWindow Error: %s\n", SDL_GetError());
SDL_Quit();
return;
}
// Setup Metal view.
SDL_MetalView view = SDL_Metal_CreateView(window);
// SDL_Window's handle can be used directly if needed
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(window, &wmInfo);
TestInitialize(renderInterface, { wmInfo.info.cocoa.window, view });
TestResize();
bool running = true;
while (running) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = false;
break;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
TestResize();
}
break;
}
}
TestDraw();
SDL_Delay(16); // Approximate 60 FPS
}
TestShutdown();
SDL_Metal_DestroyView(view);
SDL_DestroyWindow(window);
SDL_Quit();
}
#endif
};
};

18
src/common/rt64_apple.h Normal file
View File

@ -0,0 +1,18 @@
//
// RT64
//
#pragma once
#include <functional>
struct CocoaWindowAttributes {
int x, y;
int width, height;
};
const char* GetHomeDirectory();
void GetWindowAttributes(void* window, CocoaWindowAttributes *attributes);
int GetWindowRefreshRate(void* window);
void WindowToggleFullscreen(void* window);

38
src/common/rt64_apple.mm Normal file
View File

@ -0,0 +1,38 @@
#include "rt64_apple.h"
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
const char* GetHomeDirectory() {
return strdup([NSHomeDirectory() UTF8String]);
}
void GetWindowAttributes(void* window, CocoaWindowAttributes *attributes) {
NSWindow *nsWindow = (NSWindow *)window;
NSRect contentFrame = [[nsWindow contentView] frame];
attributes->x = contentFrame.origin.x;
attributes->y = contentFrame.origin.y;
attributes->width = contentFrame.size.width;
attributes->height = contentFrame.size.height;
}
int GetWindowRefreshRate(void* window) {
NSWindow *nsWindow = (NSWindow *)window;
NSScreen *screen = [nsWindow screen];
if (@available(macOS 12.0, *)) {
return (int)[screen maximumFramesPerSecond];
}
// TODO: Implement this.
return 0;
}
void WindowToggleFullscreen(void* window) {
// UI operations have to happen on the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
NSWindow *nsWindow = (NSWindow *)window;
[nsWindow toggleFullScreen:NULL];
});
}

View File

@ -1,7 +1,11 @@
// Disable SIMD on GCC due to UB when compiling with optimizations.
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
#define HLSLPP_SCALAR
#endif
// Disable SIMD on Apple Silicon due to UB when compiling with optimizations.
#if defined(__APPLE__) && defined(__aarch64__)
#define HLSLPP_SCALAR
#endif
#include "hlsl++.h"

View File

@ -9,6 +9,8 @@
# include <pwd.h>
#elif defined(_WIN32)
# include <Shlobj.h>
#elif defined(__APPLE__)
# include "common/rt64_apple.h"
#endif
namespace RT64 {
@ -30,10 +32,14 @@ namespace RT64 {
}
CoTaskMemFree(knownPath);
# elif defined(__linux__)
# elif defined(__linux__) || defined(__APPLE__)
const char *homeDir = getenv("HOME");
if (homeDir == nullptr) {
#if defined(__linux__)
homeDir = getpwuid(getuid())->pw_dir;
#elif defined(__APPLE__)
homeDir = GetHomeDirectory();
#endif
}
if (homeDir != nullptr) {

View File

@ -13,6 +13,8 @@
#elif defined(__linux__)
# define Status int
# include <X11/extensions/Xrandr.h>
#elif defined(__APPLE__)
# include "common/rt64_apple.h"
#endif
#include "common/rt64_common.h"
@ -198,6 +200,9 @@ namespace RT64 {
}
}
fullScreen = newFullScreen;
# elif defined(__APPLE__)
WindowToggleFullscreen(windowHandle.window);
fullScreen = newFullScreen;
# endif
}
@ -271,6 +276,8 @@ namespace RT64 {
}
XRRFreeScreenResources(screenResources);
# elif defined(__APPLE__)
refreshRate = GetWindowRefreshRate(windowHandle.window);
# endif
}
@ -292,6 +299,11 @@ namespace RT64 {
XGetWindowAttributes(windowHandle.display, windowHandle.window, &attributes);
newWindowLeft = attributes.x;
newWindowTop = attributes.y;
# elif defined(__APPLE__)
CocoaWindowAttributes attributes;
GetWindowAttributes(windowHandle.window, &attributes);
newWindowLeft = attributes.x;
newWindowTop = attributes.y;
# endif
if ((windowLeft != newWindowLeft) || (windowTop != newWindowTop)) {

View File

@ -43,7 +43,9 @@ namespace RT64 {
};
#elif defined(__APPLE__)
struct RenderWindow {
NSWindow* window;
void* window;
void* layer;
bool operator==(const struct RenderWindow& rhs) const {
return window == rhs.window;
}
@ -1689,4 +1691,4 @@ namespace RT64 {
struct RenderInterfaceCapabilities {
RenderShaderFormat shaderFormat = RenderShaderFormat::UNKNOWN;
};
};
};

View File

@ -21,6 +21,12 @@
//# define VULKAN_OBJECT_NAMES_ENABLED
#endif
#ifdef __APPLE__
#include "vulkan/vulkan_beta.h"
#include "vulkan/vulkan_metal.h"
#include "common/rt64_apple.h"
#endif
// TODO:
// - Fix resource pools.
@ -48,6 +54,9 @@ namespace RT64 {
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
# elif defined(__linux__)
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
# elif defined(__APPLE__)
VK_EXT_METAL_SURFACE_EXTENSION_NAME,
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
# endif
};
@ -58,6 +67,10 @@ namespace RT64 {
static const std::unordered_set<std::string> RequiredDeviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME,
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
# ifdef __APPLE__
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
# endif
# ifdef VULKAN_OBJECT_NAMES_ENABLED
VK_EXT_DEBUG_UTILS_EXTENSION_NAME
# endif
@ -73,6 +86,7 @@ namespace RT64 {
VK_KHR_PRESENT_ID_EXTENSION_NAME,
VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
VK_EXT_LAYER_SETTINGS_EXTENSION_NAME
};
// Common functions.
@ -546,7 +560,9 @@ namespace RT64 {
flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
#ifndef __APPLE__
flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
#endif
flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
flags |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
@ -1909,6 +1925,19 @@ namespace RT64 {
fprintf(stderr, "vkCreateXlibSurfaceKHR failed with error code 0x%X.\n", res);
return;
}
# elif defined(__APPLE__)
assert(renderWindow.window != 0);
assert(renderWindow.layer != 0);
VkMetalSurfaceCreateInfoEXT surfaceCreateInfo = {};
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
surfaceCreateInfo.pLayer = renderWindow.layer;
VulkanInterface *renderInterface = commandQueue->device->renderInterface;
res = vkCreateMetalSurfaceEXT(renderInterface->instance, &surfaceCreateInfo, nullptr, &surface);
if (res != VK_SUCCESS) {
fprintf(stderr, "vkCreateMetalSurfaceEXT failed with error code 0x%X.\n", res);
return;
}
# endif
VkBool32 presentSupported = false;
@ -2039,7 +2068,14 @@ namespace RT64 {
}
// Handle the error silently.
#if defined(__APPLE__)
// Under MoltenVK, VK_SUBOPTIMAL_KHR does not result in a valid state for rendering. We intentionally
// only check for this error during present to avoid having to synchronize manually against the semaphore
// signalled by vkAcquireNextImageKHR.
if (res != VK_SUCCESS) {
#else
if ((res != VK_SUCCESS) && (res != VK_SUBOPTIMAL_KHR)) {
#endif
return false;
}
@ -2183,6 +2219,11 @@ namespace RT64 {
// The attributes width and height members do not include the border.
dstWidth = attributes.width;
dstHeight = attributes.height;
# elif defined(__APPLE__)
CocoaWindowAttributes attributes;
GetWindowAttributes(renderWindow.window, &attributes);
dstWidth = attributes.width;
dstHeight = attributes.height;
# endif
}
@ -3919,6 +3960,10 @@ namespace RT64 {
createInfo.ppEnabledLayerNames = nullptr;
createInfo.enabledLayerCount = 0;
#ifdef __APPLE__
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
// Check for extensions.
uint32_t extensionCount;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
@ -4022,4 +4067,4 @@ namespace RT64 {
std::unique_ptr<VulkanInterface> createdInterface = std::make_unique<VulkanInterface>();
return createdInterface->isValid() ? std::move(createdInterface) : nullptr;
}
};
};

View File

@ -17,6 +17,8 @@
#define VK_USE_PLATFORM_ANDROID_KHR
#elif defined(__linux__)
#define VK_USE_PLATFORM_XLIB_KHR
#elif defined(__APPLE__)
#define VK_USE_PLATFORM_METAL_EXT
#endif
#include "volk/volk.h"
@ -403,4 +405,4 @@ namespace RT64 {
const RenderInterfaceCapabilities &getCapabilities() const override;
bool isValid() const;
};
};
};