[compat] HaikuOS port (#2805)
All checks were successful
GitHub Actions [CI] Build succeeded
GitHub Releases [CD] Build succeeded – Release published

Still had the issues with libusb, but that should get solved with the other PRs anyways
Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: #2805
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2025-10-22 04:53:40 +02:00 committed by crueter
parent 992bae4e2a
commit 87cacbeed4
Signed by: crueter
GPG key ID: 425ACD2D4830EBC6
28 changed files with 250 additions and 129 deletions

View file

@ -0,0 +1,49 @@
diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index be7f442..5fd0438 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -1766,9 +1766,10 @@ int singleMain()
glslang::FinalizeProcess();
} else {
ShInitialize();
+#ifndef __HAIKU__
ShInitialize(); // also test reference counting of users
ShFinalize(); // also test reference counting of users
-
+#endif
bool printShaderNames = workList.size() > 1;
if (Options & EOptionMultiThreaded) {
@@ -1793,8 +1794,9 @@ int singleMain()
PutsIfNonEmpty(WorkItems[w]->results.c_str());
}
}
-
+#ifndef __HAIKU__
ShFinalize();
+#endif
}
if (CompileFailed.load())
@@ -1809,8 +1811,10 @@ int C_DECL main(int argc, char* argv[])
{
ProcessArguments(WorkItems, argc, argv);
+#ifdef __HAIKU__
+ return singleMain();
+#else
int ret = 0;
-
// Loop over the entire init/finalize cycle to watch memory changes
const int iterations = 1;
if (iterations > 1)
@@ -1820,8 +1824,8 @@ int C_DECL main(int argc, char* argv[])
if (iterations > 1)
glslang::OS_DumpMemoryCounters();
}
-
return ret;
+#endif
}
//

View file

@ -13,6 +13,8 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
set(PLATFORM_OPENBSD ON) set(PLATFORM_OPENBSD ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD") elseif (${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
set(PLATFORM_NETBSD ON) set(PLATFORM_NETBSD ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Haiku")
set(PLATFORM_HAIKU ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(PLATFORM_LINUX ON) set(PLATFORM_LINUX ON)
endif() endif()
@ -745,6 +747,13 @@ elseif (WIN32)
# PSAPI is the Process Status API # PSAPI is the Process Status API
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version) set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
endif() endif()
elseif (PLATFORM_HAIKU)
# Haiku is so special :)
# Some fucking genius decided to name an entire module "network" in 2019
# this caused great disaster amongst the Haiku community who had came first with
# their "libnetwork.so"; since CMake doesn't do magic, we have to use an ABSOLUTE PATH
# to the library itself, otherwise it will think we are linking to... our network thing
set(PLATFORM_LIBRARIES bsd /boot/system/lib/libnetwork.so)
elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
set(PLATFORM_LIBRARIES rt) set(PLATFORM_LIBRARIES rt)
endif() endif()

View file

@ -41,6 +41,18 @@ export LIBGL_ALWAYS_SOFTWARE=1
- If using OpenIndiana, due to a bug in SDL2's CMake configuration, audio driver defaults to SunOS `<sys/audioio.h>`, which does not exist on OpenIndiana. Using external or bundled SDL2 may solve this. - If using OpenIndiana, due to a bug in SDL2's CMake configuration, audio driver defaults to SunOS `<sys/audioio.h>`, which does not exist on OpenIndiana. Using external or bundled SDL2 may solve this.
- System OpenSSL generally does not work. Instead, use `-DYUZU_USE_BUNDLED_OPENSSL=ON` to use a bundled static OpenSSL, or build a system dependency from source. - System OpenSSL generally does not work. Instead, use `-DYUZU_USE_BUNDLED_OPENSSL=ON` to use a bundled static OpenSSL, or build a system dependency from source.
## HaikuOS
It's recommended to do a `pkgman full-sync` before installing. See [HaikuOS: Installing applications](https://www.haiku-os.org/guides/daily-tasks/install-applications/). Sometimes the process may be interrupted by an error like "Interrupted syscall". Simply firing the command again fixes the issue. By default `g++` is included on the default installation.
GPU support is generally lacking/buggy, hence it's recommended to only install `pkgman install mesa_lavapipe`. Performance is acceptable for most homebrew applications and even some retail games.
For reasons unberknownst to any human being, `glslangValidator` will crash upon trying to be executed, the solution to this is to build `glslang` yourself. Apply the patch in `.patch/glslang/0001-haikuos-fix.patch`. The main issue is `ShFinalize()` is deallocating already destroyed memory; the "fix" in question is allowing the program to just leak memory and the OS will take care of the rest. See [this issue](https://web.archive.org/web/20251021183604/https://github.com/haikuports/haikuports/issues/13083).
For this reason this patch is NOT applied to default on all platforms (for obvious reasons) - instead this is a HaikuOS specific patch, apply with `git apply <absolute path to patch>` after cloning SPIRV-Tools then `make -C build` and add the resulting binary (in `build/StandAlone/glslang`) into PATH.
`cubeb_devel` will also not work, either disable cubeb or uninstall it.
## OpenBSD ## OpenBSD
After configuration, you may need to modify `externals/ffmpeg/CMakeFiles/ffmpeg-build/build.make` to use `-j$(nproc)` instead of just `-j`. After configuration, you may need to modify `externals/ffmpeg/CMakeFiles/ffmpeg-build/build.make` to use `-j$(nproc)` instead of just `-j`.
@ -57,6 +69,23 @@ The available OpenSSL port (3.0.17) is out-of-date, and using a bundled static l
## NetBSD ## NetBSD
Install `pkgin` if not already `pkg_add pkgin`, see also the general [pkgsrc guide](https://www.netbsd.org/docs/pkgsrc/using.html). For NetBSD 10.1 provide `echo 'PKG_PATH="https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/10.0_2025Q3/All/"' >/etc/pkg_install.conf`. If `pkgin` is taking too much time consider adding the following to `/etc/rc.conf`:
```sh
ip6addrctl=YES
ip6addrctl_policy=ipv4_prefer
```
System provides a default `g++-10` which doesn't support the current C++ codebase; install `clang-19` with `pkgin install clang-19`. Then build with `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -B build`. System provides a default `g++-10` which doesn't support the current C++ codebase; install `clang-19` with `pkgin install clang-19`. Then build with `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -B build`.
Make may error out when generating C++ headers of SPIRV shaders, hence it's recommended to use `gmake` over the default system one. Make may error out when generating C++ headers of SPIRV shaders, hence it's recommended to use `gmake` over the default system one.
glslang is not available on NetBSD, to circumvent this simply build glslang by yourself:
```sh
pkgin python313
git clone --depth=1 https://github.com/KhronosGroup/glslang.git
cd glslang
python3.13 ./update_glslang_sources.py
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j`nproc`
cmake --install build
```

View file

@ -150,37 +150,25 @@ To run with MoltenVK, install additional dependencies:
brew install molten-vk vulkan-loader brew install molten-vk vulkan-loader
``` ```
</details> [Caveats](./Caveats.md#macos).
</details>
<details> <details>
<summary>FreeBSD</summary> <summary>FreeBSD</summary>
As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/jwt-cpp devel/unordered-dense devel/zydis` As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/jwt-cpp devel/unordered-dense devel/zydis`
If using FreeBSD 12 or prior, use `devel/pkg-config` instead. If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
</details>
[Caveats](./Caveats.md#freebsd).
</details>
<details> <details>
<summary>NetBSD</summary> <summary>NetBSD</summary>
Install `pkgin` if not already `pkg_add pkgin`, see also the general [pkgsrc guide](https://www.netbsd.org/docs/pkgsrc/using.html). For NetBSD 10.1 provide `cat 'PKG_PATH="https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/10.0_2025Q3/All/"' >/etc/pkg_install.conf`. If `pkgin` is taking too much time consider adding the following to `/etc/rc.conf`:
```
ip6addrctl=YES
ip6addrctl_policy=ipv4_prefer
```
For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv-headers ffmpeg7 libva nlohmann-json jq libopus qt6 mbedtls3 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1`. For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv-headers ffmpeg7 libva nlohmann-json jq libopus qt6 mbedtls3 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1`.
glslang is not available on NetBSD, to circumvent this simply build glslang by yourself: [Caveats](./Caveats.md#netbsd).
```sh
pkgin python313
git clone https://github.com/KhronosGroup/glslang.git
cd glslang
python3.13 ./update_glslang_sources.py
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j`nproc`
cmake --install build
```
</details> </details>
@ -192,6 +180,8 @@ pkg_add -u
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake llvm-19.1.7p3 qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl2 libusb1-1.0.27 pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake llvm-19.1.7p3 qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl2 libusb1-1.0.27
``` ```
[Caveats](./Caveats.md#openbsd).
</details> </details>
<details> <details>
@ -205,6 +195,9 @@ Run the usual update + install of essential toolings: `sudo pkg update && sudo p
- **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`. - **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`.
Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt`. Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt`.
[Caveats](./Caveats.md#solaris).
</details> </details>
<details> <details>
@ -220,8 +213,18 @@ Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/l
</details> </details>
<details> <details>
<summary>HaikuOS</summary>
```sh
pkgman install git cmake libfmt_devel nlohmann_json lz4_devel opus_devel boost1.89_devel vulkan_devel qt6_base_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt6_devel qt6_5compat_devel zydis_devel glslang
```
[Caveats](./Caveats.md#haikuos).
</details>
<summary>RedoxOS</summary> <summary>RedoxOS</summary>
TODO: Fix syscall crashes (heavy IO stalls and hangup due to net mutexes?)
```sh ```sh
sudo pkg update && sudo pkg install git cmake sudo pkg update && sudo pkg install git cmake
sudo pkg install ffmpeg6 sdl2 zlib llvm18 sudo pkg install ffmpeg6 sdl2 zlib llvm18

View file

@ -52,6 +52,7 @@ IA-64 (Itanium) support is completely unknown. Existing amd64 packages will not
The vast majority of Eden's testing is done on Windows, Linux, and Android. However, first-class support is also provided for: The vast majority of Eden's testing is done on Windows, Linux, and Android. However, first-class support is also provided for:
- HaikuOS
- FreeBSD - FreeBSD
- OpenBSD - OpenBSD
- NetBSD - NetBSD
@ -126,6 +127,13 @@ BSD and Solaris distributions tend to lag behind Linux in terms of Vulkan and ot
AMD GPU support on these platforms is limited or nonexistent. AMD GPU support on these platforms is limited or nonexistent.
## HaikuOS
HaikuOS supports (see below) Vulkan 1.3 and has Mesa 24.0. Because OpenGL ES is used instead of the desktop flavour of OpenGL the OpenGL backend is actually worse than the Vulkan one in terms of stability and system support. OpenGL is highly not recommended due to it being: out of tree builds of Mesa and generally unstable ones at that. Users are advised to use Vulkan whenever possible.
- Additionally system drivers for NVIDIA and Intel iGPUs exist and provide a native Vulkan ICD with the `Xcb` interface as opposed to the native `BView`
- In order to obtain Vulkan 1.3 support with native `BView` support; Swiftshader can be compiled from source [see this thread](https://discuss.haiku-os.org/t/swiftshader-vulkan-software-renderer-on-haiku/11526/6).
## VMs ## VMs
Eden "can" run in a VM, but only with the software renderer, *unless* you create a hardware-accelerated KVM with GPU passthrough. If you *really* want to do this and don't have a spare GPU lying around, RX 570 and 580 GPUs are extremely cheap on the black market and are powerful enough to run most commercial games at 60 FPS. Eden "can" run in a VM, but only with the software renderer, *unless* you create a hardware-accelerated KVM with GPU passthrough. If you *really* want to do this and don't have a spare GPU lying around, RX 570 and 580 GPUs are extremely cheap on the black market and are powerful enough to run most commercial games at 60 FPS.

View file

@ -25,6 +25,7 @@ Eden will store configuration files in the following directories:
- **Windows**: `%AppData%\Roaming`. - **Windows**: `%AppData%\Roaming`.
- **Android**: Data is stored internally. - **Android**: Data is stored internally.
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`. - **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
- **HaikuOS**: `/boot/home/config/settings/eden`
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use that instead. If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use that instead.

View file

@ -60,3 +60,7 @@ Unstable multithreaded optimisations are offered by the stock proprietary NVIDIA
### swrast/LLVMpipe crashes under high load ### swrast/LLVMpipe crashes under high load
The OpenGL backend would invoke behaviour that would result in swarst/LLVMpipe writing an invalid SSA IR (on old versions of Mesa), and then proceeding to crash. The solution is using a script found in [tools/llvmpipe-run.sh](../../tools/llvmpipe-run.sh). The OpenGL backend would invoke behaviour that would result in swarst/LLVMpipe writing an invalid SSA IR (on old versions of Mesa), and then proceeding to crash. The solution is using a script found in [tools/llvmpipe-run.sh](../../tools/llvmpipe-run.sh).
### HaikuOS compatibility
HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (required by the emulator). This leads to HaikuOS being one of the few computer platforms where Vulkan is the only available option for users. If OpenGL is desired, Mesa has to be built manually from source. For debugging purpouses `lavapipe` is recommended over the GPU driver; there is in-kernel support for NVIDIA cards through.

View file

@ -39,14 +39,12 @@
#include <stdint.h> #include <stdint.h>
#endif #endif
// TODO: We should likely vendor this in the future and just make a patch that makes the code section be like this
// this kind of macro stupidity is beyond me, but again upstream rejects patches so...
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define RENDERDOC_CC __cdecl #define RENDERDOC_CC __cdecl
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__)
#define RENDERDOC_CC
#elif defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
#define RENDERDOC_CC
#else #else
#error "Unknown platform" #define RENDERDOC_CC
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -12,7 +12,7 @@
#include <windows.h> #include <windows.h>
#include "common/dynamic_library.h" #include "common/dynamic_library.h"
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) || defined(__APPLE__) // ^^^ Windows ^^^ vvv POSIX vvv #else // ^^^ Windows ^^^ vvv POSIX vvv
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
@ -394,7 +394,7 @@ private:
std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset
}; };
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) || defined(__APPLE__) // ^^^ Windows ^^^ vvv POSIX vvv #else // ^^^ Windows ^^^ vvv POSIX vvv
#ifdef ARCHITECTURE_arm64 #ifdef ARCHITECTURE_arm64
@ -679,32 +679,7 @@ private:
FreeRegionManager free_manager{}; FreeRegionManager free_manager{};
}; };
#else // ^^^ POSIX ^^^ vvv Generic vvv #endif // ^^^ POSIX ^^^
class HostMemory::Impl {
public:
explicit Impl([[maybe_unused]] size_t backing_size, [[maybe_unused]] size_t virtual_size) {
// This is just a place holder.
ASSERT_MSG(false, "Please implement fastmem in a proper way on your platform.");
}
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm) {}
void Unmap(size_t virtual_offset, size_t length) {}
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {}
bool ClearBackingRegion(size_t physical_offset, size_t length) {
return false;
}
void EnableDirectMappedAddress() {}
u8* backing_base{nullptr};
u8* virtual_base{nullptr};
};
#endif // ^^^ Generic ^^^
HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_) HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_)
: backing_size(backing_size_), virtual_size(virtual_size_) { : backing_size(backing_size_), virtual_size(virtual_size_) {

View file

@ -169,7 +169,7 @@ bool IsFastmemEnabled() {
if (values.cpu_accuracy.GetValue() == CpuAccuracy::Unsafe) { if (values.cpu_accuracy.GetValue() == CpuAccuracy::Unsafe) {
return bool(values.cpuopt_unsafe_host_mmu); return bool(values.cpuopt_unsafe_host_mmu);
} }
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__)
return false; return false;
#else #else
return true; return true;

View file

@ -296,7 +296,7 @@ struct Values {
Category::CpuDebug}; Category::CpuDebug};
SwitchableSetting<bool> cpuopt_unsafe_host_mmu{linkage, SwitchableSetting<bool> cpuopt_unsafe_host_mmu{linkage,
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__)
false, false,
#else #else
true, true,

View file

@ -11,6 +11,8 @@
#include "common/thread.h" #include "common/thread.h"
#ifdef __APPLE__ #ifdef __APPLE__
#include <mach/mach.h> #include <mach/mach.h>
#elif defined(__HAIKU__)
#include <kernel/OS.h>
#elif defined(_WIN32) #elif defined(_WIN32)
#include <windows.h> #include <windows.h>
#include "common/string_util.h" #include "common/string_util.h"
@ -31,43 +33,38 @@
namespace Common { namespace Common {
void SetCurrentThreadPriority(ThreadPriority new_priority) {
#ifdef _WIN32 #ifdef _WIN32
int windows_priority = [&]() {
void SetCurrentThreadPriority(ThreadPriority new_priority) { switch (new_priority) {
auto handle = GetCurrentThread(); case ThreadPriority::Low: return THREAD_PRIORITY_BELOW_NORMAL;
int windows_priority = 0; case ThreadPriority::Normal: return THREAD_PRIORITY_NORMAL;
switch (new_priority) { case ThreadPriority::High: return THREAD_PRIORITY_ABOVE_NORMAL;
case ThreadPriority::Low: case ThreadPriority::VeryHigh: return THREAD_PRIORITY_HIGHEST;
windows_priority = THREAD_PRIORITY_BELOW_NORMAL; case ThreadPriority::Critical: return THREAD_PRIORITY_TIME_CRITICAL;
break; default: return THREAD_PRIORITY_NORMAL;
case ThreadPriority::Normal: }
windows_priority = THREAD_PRIORITY_NORMAL; }();
break; SetThreadPriority(GetCurrentThread(), windows_priority);
case ThreadPriority::High: #elif defined(__HAIKU__)
windows_priority = THREAD_PRIORITY_ABOVE_NORMAL; // TODO: We have priorities for 3D rendering applications - may help lavapipe?
break; int priority = [&]() {
case ThreadPriority::VeryHigh: switch (new_priority) {
windows_priority = THREAD_PRIORITY_HIGHEST; case ThreadPriority::Low: return B_LOW_PRIORITY;
break; case ThreadPriority::Normal: return B_NORMAL_PRIORITY;
case ThreadPriority::Critical: case ThreadPriority::High: return B_DISPLAY_PRIORITY;
windows_priority = THREAD_PRIORITY_TIME_CRITICAL; case ThreadPriority::VeryHigh: return B_URGENT_DISPLAY_PRIORITY;
break; case ThreadPriority::Critical: return B_URGENT_PRIORITY;
default: default: return B_NORMAL_PRIORITY;
windows_priority = THREAD_PRIORITY_NORMAL; }
break; }();
} set_thread_priority(find_thread(NULL), priority);
SetThreadPriority(handle, windows_priority);
}
#else #else
void SetCurrentThreadPriority(ThreadPriority new_priority) {
pthread_t this_thread = pthread_self(); pthread_t this_thread = pthread_self();
const auto scheduling_type = SCHED_OTHER; const auto scheduling_type = SCHED_OTHER;
s32 max_prio = sched_get_priority_max(scheduling_type); s32 max_prio = sched_get_priority_max(scheduling_type);
s32 min_prio = sched_get_priority_min(scheduling_type); s32 min_prio = sched_get_priority_min(scheduling_type);
u32 level = (std::max)(static_cast<u32>(new_priority) + 1, 4U); u32 level = (std::max)(u32(new_priority) + 1, 4U);
struct sched_param params; struct sched_param params;
if (max_prio > min_prio) { if (max_prio > min_prio) {
@ -77,9 +74,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
} }
pthread_setschedparam(this_thread, scheduling_type, &params); pthread_setschedparam(this_thread, scheduling_type, &params);
}
#endif #endif
}
#ifdef _MSC_VER #ifdef _MSC_VER

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -14,24 +17,19 @@ namespace Common {
void* AllocateMemoryPages(std::size_t size) noexcept { void* AllocateMemoryPages(std::size_t size) noexcept {
#ifdef _WIN32 #ifdef _WIN32
void* base{VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE)}; void* base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
#else #else
void* base{mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0)}; void* base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (base == MAP_FAILED)
if (base == MAP_FAILED) {
base = nullptr; base = nullptr;
}
#endif #endif
ASSERT(base); ASSERT(base);
return base; return base;
} }
void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept { void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
if (!base) { if (!base)
return; return;
}
#ifdef _WIN32 #ifdef _WIN32
ASSERT(VirtualFree(base, 0, MEM_RELEASE)); ASSERT(VirtualFree(base, 0, MEM_RELEASE));
#else #else

View file

@ -295,7 +295,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* pa
// Curated optimizations // Curated optimizations
case Settings::CpuAccuracy::Auto: case Settings::CpuAccuracy::Auto:
config.unsafe_optimizations = true; config.unsafe_optimizations = true;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__)
config.fastmem_pointer = std::nullopt; config.fastmem_pointer = std::nullopt;
config.fastmem_exclusive_access = false; config.fastmem_exclusive_access = false;
#endif #endif

View file

@ -354,7 +354,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
// Safe optimisations // Safe optimisations
case Settings::CpuAccuracy::Auto: case Settings::CpuAccuracy::Auto:
config.unsafe_optimizations = true; config.unsafe_optimizations = true;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__)
config.fastmem_pointer = std::nullopt; config.fastmem_pointer = std::nullopt;
config.fastmem_exclusive_access = false; config.fastmem_exclusive_access = false;
#endif #endif

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -13,7 +16,7 @@ namespace Core::Frontend {
class GraphicsContext; class GraphicsContext;
/// Information for the Graphics Backends signifying what type of screen pointer is in /// @brief Information for the Graphics Backends signifying what type of screen pointer is in
/// WindowInformation /// WindowInformation
enum class WindowSystemType { enum class WindowSystemType {
Headless, Headless,
@ -22,6 +25,7 @@ enum class WindowSystemType {
Wayland, Wayland,
Cocoa, Cocoa,
Android, Android,
Xcb,
}; };
/** /**

View file

@ -15,7 +15,7 @@
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(__unix__) || defined(__APPLE__) #else
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
@ -24,8 +24,6 @@
#include <poll.h> #include <poll.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#else
#error "Unimplemented platform"
#endif #endif
#include "common/assert.h" #include "common/assert.h"
@ -165,7 +163,7 @@ Errno TranslateNativeError(int e, CallType call_type = CallType::Other) {
} }
} }
#elif defined(__unix__) || defined(__APPLE__) // ^ _WIN32 v __unix__ #else // ^^^ Windows vvv POSIX
using SOCKET = int; using SOCKET = int;
using WSAPOLLFD = pollfd; using WSAPOLLFD = pollfd;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -104,7 +107,7 @@ constexpr IPv4Address TranslateIPv4(in_addr addr) {
auto& bytes = addr.S_un.S_un_b; auto& bytes = addr.S_un.S_un_b;
return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4}; return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
} }
#elif defined(__unix__) || defined(__APPLE__) #else
constexpr IPv4Address TranslateIPv4(in_addr addr) { constexpr IPv4Address TranslateIPv4(in_addr addr) {
const u32 bytes = addr.s_addr; const u32 bytes = addr.s_addr;
return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8), return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -8,15 +11,6 @@
#include <span> #include <span>
#include <utility> #include <utility>
#if defined(_WIN32)
// windows
#elif defined(__unix__) || defined(__APPLE__)
// unix
#else
// haiku
#error "Platform not implemented"
#endif
#include "common/common_types.h" #include "common/common_types.h"
#include "core/internal_network/network.h" #include "core/internal_network/network.h"
@ -28,7 +22,7 @@ struct ProxyPacket;
class SocketBase { class SocketBase {
public: public:
#if defined(__unix__) || defined(__APPLE__) #ifndef _WIN32
using SOCKET = int; using SOCKET = int;
static constexpr SOCKET INVALID_SOCKET = -1; static constexpr SOCKET INVALID_SOCKET = -1;
static constexpr SOCKET SOCKET_ERROR = -1; static constexpr SOCKET SOCKET_ERROR = -1;

View file

@ -28,6 +28,8 @@ RenderdocAPI::RenderdocAPI() {
ASSERT(ret == 1); ASSERT(ret == 1);
} }
} }
#elif defined(__HAIKU__)
// no rtld on haiku
#else #else
#ifdef ANDROID #ifdef ANDROID
static constexpr const char RENDERDOC_LIB[] = "libVkLayer_GLES_RenderDoc.so"; static constexpr const char RENDERDOC_LIB[] = "libVkLayer_GLES_RenderDoc.so";

View file

@ -345,7 +345,8 @@ elseif (APPLE)
backend/exception_handler_macos_mig.c backend/exception_handler_macos_mig.c
) )
endif() endif()
elseif (UNIX) elseif (UNIX AND NOT PLATFORM_HAIKU)
# Haiku lacks <ucontext.h>
if (CMAKE_SYSTEM_NAME STREQUAL "Linux") if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(dynarmic PRIVATE rt) target_link_libraries(dynarmic PRIVATE rt)
endif() endif()

View file

@ -33,8 +33,7 @@ std::unique_ptr<Core::System> system = nullptr;
std::shared_ptr<FileSys::RealVfsFilesystem> vfs = nullptr; std::shared_ptr<FileSys::RealVfsFilesystem> vfs = nullptr;
std::unique_ptr<FileSys::ManualContentProvider> provider = nullptr; std::unique_ptr<FileSys::ManualContentProvider> provider = nullptr;
Core::Frontend::WindowSystemType GetWindowSystemType() Core::Frontend::WindowSystemType GetWindowSystemType() {
{
// Determine WSI type based on Qt platform. // Determine WSI type based on Qt platform.
QString platform_name = QGuiApplication::platformName(); QString platform_name = QGuiApplication::platformName();
if (platform_name == QStringLiteral("windows")) if (platform_name == QStringLiteral("windows"))
@ -49,6 +48,8 @@ Core::Frontend::WindowSystemType GetWindowSystemType()
return Core::Frontend::WindowSystemType::Cocoa; return Core::Frontend::WindowSystemType::Cocoa;
else if (platform_name == QStringLiteral("android")) else if (platform_name == QStringLiteral("android"))
return Core::Frontend::WindowSystemType::Android; return Core::Frontend::WindowSystemType::Android;
else if (platform_name == QStringLiteral("haiku"))
return Core::Frontend::WindowSystemType::Xcb;
LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString()); LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString());
return Core::Frontend::WindowSystemType::Windows; return Core::Frontend::WindowSystemType::Windows;

View file

@ -149,7 +149,7 @@ bool MakeShortcutIcoPath(const u64 program_id,
#if defined(_WIN32) #if defined(_WIN32)
out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir); out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir);
ico_extension = "ico"; ico_extension = "ico";
#elif defined(__linux__) || defined(__FreeBSD__) #elif !defined(__ANDROID__) // Any *nix but android
out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256";
#endif #endif
// Create icons directory if it doesn't exist // Create icons directory if it doesn't exist

View file

@ -86,7 +86,15 @@ set(SHADER_FILES
dynamic_resolution_scale.comp dynamic_resolution_scale.comp
) )
find_program(GLSLANGVALIDATOR "glslangValidator") if (PLATFORM_HAIKU)
# glslangValidator WILL crash, glslang will not - why? Who the fuck knows
#/boot/home/glslang/build/StandAlone/glslangValidator
set(GLSLANGVALIDATOR "glslang")
else()
# Normal sane platform who doesn't have a CRASHING glslangValidator
find_program(GLSLANGVALIDATOR "glslangValidator")
endif()
if ("${GLSLANGVALIDATOR}" STREQUAL "GLSLANGVALIDATOR-NOTFOUND") if ("${GLSLANGVALIDATOR}" STREQUAL "GLSLANGVALIDATOR-NOTFOUND")
message(FATAL_ERROR "Required program `glslangValidator` not found.") message(FATAL_ERROR "Required program `glslangValidator` not found.")
endif() endif()

View file

@ -50,20 +50,24 @@ bool TestProgram(const GLchar* glsl) {
return link_status == GL_TRUE; return link_status == GL_TRUE;
} }
std::vector<std::string_view> GetExtensions() { /// @brief Query OpenGL extensions
/// DO NOT use string_view, the driver can immediately free up the extension name and such
/// do NOT under ANY circumstances use string_view, make a copy, it's required
std::vector<std::string> GetExtensions() {
GLint num_extensions; GLint num_extensions;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
std::vector<std::string_view> extensions; std::vector<std::string> extensions;
extensions.reserve(num_extensions);
for (GLint index = 0; index < num_extensions; ++index) { for (GLint index = 0; index < num_extensions; ++index) {
extensions.push_back( auto const* p = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, GLuint(index)));
reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(index)))); if (p != nullptr) // Fuck you? - sincerely, buggy mesa drivers
extensions.push_back(std::string{p});
} }
return extensions; return extensions;
} }
bool HasExtension(std::span<const std::string_view> extensions, std::string_view extension) { /// @brief Find extension in set of extensions (string)
return std::ranges::find(extensions, extension) != extensions.end(); bool HasExtension(std::span<const std::string> extensions, std::string_view extension) {
return std::ranges::find(extensions, std::string{extension}) != extensions.end();
} }
std::array<u32, Shader::MaxStageTypes> BuildMaxUniformBuffers() noexcept { std::array<u32, Shader::MaxStageTypes> BuildMaxUniformBuffers() noexcept {
@ -148,7 +152,7 @@ static bool HasSlowSoftwareAstc(std::string_view vendor_name, std::string_view r
return false; return false;
} }
[[nodiscard]] bool IsDebugToolAttached(std::span<const std::string_view> extensions) { [[nodiscard]] bool IsDebugToolAttached(std::span<const std::string> extensions) {
const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED"); const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED");
return nsight || HasExtension(extensions, "GL_EXT_debug_tool") || return nsight || HasExtension(extensions, "GL_EXT_debug_tool") ||
Settings::values.renderer_debug.GetValue(); Settings::values.renderer_debug.GetValue();
@ -160,10 +164,17 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available"); LOG_ERROR(Render_OpenGL, "OpenGL 4.6 is not available");
throw std::runtime_error{"Insufficient version"}; throw std::runtime_error{"Insufficient version"};
} }
#ifdef __HAIKU__
if (glad_glCreateProgramPipelines == nullptr) {
LOG_ERROR(Render_OpenGL, "You must compile Mesa +22 manually or use a different libGL.so (GLES is not supported)");
throw std::runtime_error{"Outdated mesa"};
}
#endif
vendor_name = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); vendor_name = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
const std::string_view version = reinterpret_cast<const char*>(glGetString(GL_VERSION)); const std::string version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
const std::string_view renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
const std::vector extensions = GetExtensions(); const std::vector<std::string> extensions = GetExtensions();
const bool is_nvidia = vendor_name == "NVIDIA Corporation"; const bool is_nvidia = vendor_name == "NVIDIA Corporation";
const bool is_amd = vendor_name == "ATI Technologies Inc."; const bool is_amd = vendor_name == "ATI Technologies Inc.";

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -10,6 +13,8 @@
#define VK_USE_PLATFORM_METAL_EXT #define VK_USE_PLATFORM_METAL_EXT
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
#define VK_USE_PLATFORM_ANDROID_KHR #define VK_USE_PLATFORM_ANDROID_KHR
#elif defined(__HAIKU__)
#define VK_USE_PLATFORM_XCB_KHR
#else #else
#define VK_USE_PLATFORM_XLIB_KHR #define VK_USE_PLATFORM_XLIB_KHR
#define VK_USE_PLATFORM_WAYLAND_KHR #define VK_USE_PLATFORM_WAYLAND_KHR

View file

@ -59,6 +59,10 @@ namespace {
case Core::Frontend::WindowSystemType::Android: case Core::Frontend::WindowSystemType::Android:
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
break; break;
#elif defined(__HAIKU__)
case Core::Frontend::WindowSystemType::Xcb:
extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
break;
#else #else
case Core::Frontend::WindowSystemType::X11: case Core::Frontend::WindowSystemType::X11:
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -54,6 +57,23 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
} }
} }
#elif defined(__HAIKU__)
if (window_info.type == Core::Frontend::WindowSystemType::Xcb) {
const VkXcbSurfaceCreateInfoKHR xcb_ci{
.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
.pNext = nullptr,
.flags = 0,
.connection = static_cast<xcb_connection_t*>(window_info.display_connection),
.window = xcb_window_t(uintptr_t(window_info.render_surface))
};
const auto vkCreateXcbSurfaceKHR = reinterpret_cast<PFN_vkCreateXcbSurfaceKHR>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateXcbSurfaceKHR"));
if (!vkCreateXcbSurfaceKHR ||
vkCreateXcbSurfaceKHR(*instance, &xcb_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Xcb surface");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#else #else
if (window_info.type == Core::Frontend::WindowSystemType::X11) { if (window_info.type == Core::Frontend::WindowSystemType::X11) {
const VkXlibSurfaceCreateInfoKHR xlib_ci{ const VkXlibSurfaceCreateInfoKHR xlib_ci{