Compare commits

..

23 Commits

Author SHA1 Message Date
lizzie f963035133 2026-09-28 06:28:30
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 06:28:39 +00:00
lizzie bf236de610 Fix license headers 2026-09-28 06:28:39 +00:00
lizzie 2025483ef3 2026-09-25 11:30:23
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 06:28:39 +00:00
lizzie cc5c8635e5 2026-09-25 09:07:07
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 06:28:39 +00:00
lizzie eda3fb776f 2026-09-25 06:28:08
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 06:28:39 +00:00
lizzie d72c2e90b9 2026-09-24 08:50:24
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 06:28:39 +00:00
lizzie 6a6b64a83c 2026-09-24 05:58:35
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 06:28:39 +00:00
lizzie 94723686ea 2026-09-24 04:59:33
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 06:28:39 +00:00
lizzie cf1cf6b5f5 2026-09-24 01:05:18
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 06:28:39 +00:00
lizzie 0a68665a7c remove evil hacks: TODO: patch in later pr 2026-09-28 06:28:39 +00:00
lizzie d06beb71a1 no x11 find 2026-09-28 06:28:39 +00:00
lizzie 19852c453f extra portability adjustments 2026-09-28 06:28:39 +00:00
lizzie 9195b1ede4 let openbsd be fucked then i guess (FOR NOW) 2026-09-28 06:28:39 +00:00
lizzie 04243947f1 fx 2026-09-28 06:28:38 +00:00
lizzie 63b08471ce qt diffs 2026-09-28 06:28:38 +00:00
lizzie 33093c2207 oops stray file 2026-09-28 06:28:38 +00:00
lizzie f2983604a1 oh, we were the ones doing it wrong, ok 2026-09-28 06:28:38 +00:00
lizzie f51932477b correct qt6 instructions 2026-09-28 06:28:38 +00:00
lizzie a0bb051641 ok x11 fine 2026-09-28 06:28:38 +00:00
lizzie 494fe96308 nvm not x11::x11 2026-09-28 06:28:38 +00:00
lizzie 391f69d70a better x11 2026-09-28 06:28:38 +00:00
lizzie 968bc20e95 [dynarmic] fix NetBSD builds on gcc14
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-28 06:28:38 +00:00
PavelBARABANOV 815325ccec [loader] add ZBIC (zstd variant) NSO decompression support for Switch 22.0+ (#4482)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
A new NSO compression method was introduced in Switch 22.0.0. This is a
customized variant of zstd and is used when NSO flags have bit 7 set.

Key characteristics:
  - ZSTD_MAGICNUMBER is set to 0x4349425A (b'ZBIC') instead of 0xFD2FB528
  - ZSTD_LEGACY_SUPPORT is set to 0
  - ZSTD_TRACE is set to 1, zstd version used is 1.5.7 (10507)
  - FSE_readNCount is replaced with a BIC (Binary Interpolative Coding)
    version which improves compression of entropy tables significantly

Source: https://switchbrew.org/wiki/22.0.0

Implementation:
  - Detect ZBIC segments via NSO flag bit 7 (NsoFlags_UseZbicCompression)
    and/or ZBIC magic scan in nso.cpp
  - Fall back to LZ4 when ZBIC is not detected or returns unexpected size
  - Handle segment 0 alternate offset (0x100 vs 0x108) for both ZBIC and LZ4

References:
  - Atmosphère loader/strat zstd-zbic integration:
    https://github.com/Atmosphere-NX/Atmosphere/commit/082115187a0509cb6b8a757de639a4e4741b8712
  - nxdumptool ZBIC segment compression support:
    https://github.com/DarkMatterCore/nxdumptool/commit/441e5c0904f29427987433be4eb057a2843d222a
  - STORM_SWITCH ZBIC implementation:
    https://github.com/ReiKatari/STORM_SWITCH/commit/1e09eb82b760aaf340b810031400991c0740c091

Tested with firmware 23.0.0 and ZBIC-compressed NSOs.

Co-authored-by: xbzk <xbzk@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4482
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-09-27 12:48:45 +02:00
39 changed files with 250 additions and 136 deletions
+8 -18
View File
@@ -24,20 +24,8 @@ include(CMakeDependentOption)
include(CTest)
include(CPMUtil)
if (NOT DEFINED ARCHITECTURE)
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")
endif()
# Needed for FFmpeg w/ VAAPI and DRM
if (OPENBSD)
# OpenBSD 7.8 broke libcxx when upgrading, so we must define the PSTL backend manually
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R6/lib")
elseif (NETBSD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R7/lib")
if (CXX_GCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14.0")
message(FATAL_ERROR "GCC versions older than 14.0 are not supported. Update your system, or use clang/clang++ instead.")
endif()
# NetBSD: Fun for the whole family!
@@ -85,7 +73,7 @@ option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
# Lossless Scaling frame generation. Only Android.
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON)
cmake_dependent_option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON "WIN32 OR ANDROID OR APPLE OR LINUX OR FREEBSD" OFF)
# non-linux bundled qt are static
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
@@ -276,7 +264,7 @@ cmake_dependent_option(YUZU_USE_BUNDLED_MOLTENVK "Download bundled MoltenVK lib"
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL OFF)
if (EXT_DEFAULT OR SOLARIS OR OPENBSD)
if (EXT_DEFAULT)
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL ON)
endif()
@@ -309,10 +297,12 @@ if (YUZU_ROOM)
endif()
if (UNIX AND NOT (LINUX OR WIN32))
if(CXX_APPLE OR CXX_CLANG)
if(CXX_APPLE OR (CXX_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "20.0"))
# libc++ has stop_token and jthread as experimental
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexperimental-library")
elseif(CXX_CLANG)
# New clang >=20.0, so do nothing
else()
# Uses glibc, mostly?
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_LIBCPP_ENABLE_EXPERIMENTAL=1")
@@ -618,7 +608,7 @@ if (ENABLE_QT)
# Best practice is to ask for all components at once, so they are from the same version
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent Gui)
if (LINUX OR FREEBSD)
if (NOT WIN32 AND NOT APPLE)
list(APPEND YUZU_QT_COMPONENTS DBus)
# yes Qt, we get it
set(QT_NO_PRIVATE_MODULE_WARNING ON)
+5
View File
@@ -333,6 +333,11 @@
"repo": "herumi/xbyak",
"version": "v7.40.1"
},
"zbic": {
"hash": "fbe2f37986377d7f0d96ae3224c80b5971df6e8b6961f68061f1975ebb2e8cb78f07b90f014b007be4023dbf5513581504e7f7d61a5237cb2a8a7a61ae11e482",
"repo": "kinnay/zbic",
"version": "11b08f2712264bbed731545085cbd9702096ceb7"
},
"zlib": {
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
"min_version": "1.2",
+11 -17
View File
@@ -65,7 +65,7 @@ export LIBGL_ALWAYS_SOFTWARE=1
## OmniOS
Install `developer/gcc14` on OmniOS using pkgsrc.
Install `developer/gcc15` on OmniOS using pkgsrc.
Since so many dependencies are missing on `OmniOS`, you may wish to use `-DCPMUTIL_FORCE_BUNDLED=ON` and `-DYUZU_USE_BUNDLED_OPENSSL=OFF`.
@@ -74,21 +74,15 @@ For OmniOS you are required to build glslang yourself:
sudo pkg install python-313
git clone --depth=1 https://github.com/KhronosGroup/glslang.git
cd glslang
python3.13 ./update_glslang_sources.py
python3 ./update_glslang_sources.py
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j `nproc`
cmake --build build -- -j`nproc`
cmake --install build
```
It may be tempting to specify `-t glslang`, but this will cause installation to fail. So don't.
Use `gmake` to properly build all utilities. You require an X11 server, [this guide](https://web.archive.org/web/20260424200928/https://geekblood.wordpress.com/2017/10/26/installing-x11-and-a-desktop-environment-on-omnios/) details how to attain one, the links to pkgsrc on said guide [are better found here](https://pkgsrc.smartos.org/install-on-illumos/).
Using `--parallel` on CMake incorrectly passes `dmake ... -jn` instead of `dmake ... -j n`, this is a bug with OmniOS's CMake, it's recommended to not use this option until it's fixed.
You may also need to install `gmake` in order to properly build FFmpeg, this is provided by the `build-essential` package.
If it wasn't obvious already, you require a X11 server to properly run the emulator within OmniOS, [this guide](https://web.archive.org/web/20260424200928/https://geekblood.wordpress.com/2017/10/26/installing-x11-and-a-desktop-environment-on-omnios/) is a great starting point for that, the links to pkgsrc are outdated so follow [this exemplar](https://pkgsrc.smartos.org/install-on-illumos/) as well.
For Solaris based OSes, `${CMAKE_SYSTEM_NAME}` isn't properly set on CMake (it's set to i686 on AMD64), you may find issues when building OpenSSL from `openssl-cmake`.
For Solaris based OSes, `${CMAKE_SYSTEM_PROCESSOR}` isn't properly set on CMake (it's set to i686 on AMD64, must be `amd64`), you may find issues when building OpenSSL from `openssl-cmake`.
## HaikuOS
@@ -108,6 +102,8 @@ If you have `quazip1_qt6_devel`, uninstall it. It may call `Core5Compat` on CMak
## OpenBSD
OpenSSL 4.0 is available via ports, needs to be pointed to directly via `-DOPENSSL_ROOT_DIR=/usr/local/include/eopenssl40`.
System boost doesn't have `context` (as of 7.8); so you may need to specify `-DYUZU_USE_CPM=ON -DBoost_FORCE_BUNDLED=ON`.
After configuration, you may need to modify `externals/ffmpeg/CMakeFiles/ffmpeg-build/build.make` to use `-j$(nproc)` instead of just `-j`.
@@ -147,15 +143,13 @@ System provides a default `g++-10` which doesn't support the current C++ codebas
Make may error out when generating C++ headers of SPIRV shaders, hence it's recommended to use `gmake` over the default system one.
[parallel/spirv-tools](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/parallel/spirv-tools/index.html) isn't available in binary form and must be built from source.
glslang is not available on NetBSD, to circumvent this simply build glslang by yourself:
If [parallel/spirv-tools](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/parallel/spirv-tools/index.html) isn't available in binary, build from source:
```sh
pkgin python313
pkgin install python314
git clone --depth=1 https://github.com/KhronosGroup/glslang.git
cd glslang
python3.13 ./update_glslang_sources.py
python3.14 ./update_glslang_sources.py
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j`nproc`
cmake --install build
@@ -163,7 +157,7 @@ cmake --install build
However, pkgsrc is highly recommended, see [getting pkgsrc](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/doc/pkgsrc.html#getting). You must get `current` not the `2025Q2` version.
`QtCore` on NetBSD is included, but due to misconfigurations(!) we MUST include one of the standard headers that include `bits/c++config.h`, since source_location (required by `QtCore`) isn't properly configured to intake `bits/c++config.h` (none of the experimental library is). This is a bug with NetBSD packaging and not our fault, but alas.
`QtCore` on NetBSD is included, but due to misconfigurations you must include `bits/c++config.h`, since source_location (required by `QtCore`) isn't properly configured to intake `bits/c++config.h` (none of the experimental library is).
## DragonFlyBSD
+3 -3
View File
@@ -213,7 +213,7 @@ First, enable the community repository; [see here](https://wiki.alpinelinux.org/
# Enable the community repository
setup-apkrepos -c
# Install
apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-charts-dev libusb-dev libtool boost-dev sdl3-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev jq patch
apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-qtcharts-dev libusb-dev boost-dev sdl3-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev enet-dev glslang libtool jq patch
```
</details>
@@ -286,7 +286,7 @@ pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tool
```sh
pkg_add -u
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl3 libusb1-1.0.29 quazip-qt6
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl3 libusb1-1.0.29 quazip-qt6 openssl-4.0.2v0
```
[Caveats](./Caveats.md#openbsd).
@@ -316,7 +316,7 @@ sudo pkg install git cmake qt6 boost glslang libzip library/lz4 libusb-1 nlohman
<summary>OmniOS</summary>
```sh
sudo pkgin install git cmake autoconf build-essential libusb-1 nasm gcc13
sudo pkg install git cmake autoconf build-essential libusb-1 nasm gcc15 ffmpeg lz4 pkg-config unzip bash jq xsvc
```
[Caveats](./Caveats.md#omnios).
+1 -1
View File
@@ -15,7 +15,7 @@
## Cloning Eden with Git
```sh
git clone --recursive https://git.eden-emu.dev/eden-emu/eden.git
git clone --depth=1 https://git.eden-emu.dev/eden-emu/eden.git
```
Eden by default will be cloned into:
+5
View File
@@ -48,6 +48,11 @@ if (NOT TARGET stb::headers)
add_library(stb::headers ALIAS stb)
endif()
AddJsonPackage(NAME zbic DOWNLOAD_ONLY)
set(ZBIC_INCLUDE_DIR
"${zbic_SOURCE_DIR}/src"
PARENT_SCOPE)
# ItaniumDemangle (Windows only)
if (WIN32 AND NOT TARGET LLVM::Demangle)
add_library(demangle demangle/ItaniumDemangle.cpp)
+6
View File
@@ -137,6 +137,8 @@ add_library(
uuid.cpp
uuid.h
vector_math.h
zbic_compression.cpp
zbic_compression.h
zstd_compression.cpp
zstd_compression.h
fs/ryujinx_compat.h fs/ryujinx_compat.cpp
@@ -147,6 +149,10 @@ add_library(
net/net.h net/net.cpp
container/unordered_map.h container/unordered_set.h)
set_source_files_properties(zbic_compression.cpp PROPERTIES
INCLUDE_DIRECTORIES "${ZBIC_INCLUDE_DIR}"
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:Clang,GNU>:-Wno-unused-function;-Wno-missing-declarations;-Wno-shadow>")
if(WIN32)
target_sources(common PRIVATE windows/timer_resolution.cpp
windows/timer_resolution.h)
+46
View File
@@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstring>
#include "common/zbic_compression.h"
#define ZSTD_ZBIC_SUPPORT 1
#define ZSTDLIB_VISIBLE static
#define ZSTDLIB_HIDDEN static
#define ZSTDERRORLIB_VISIBLE static
#define ZSTDERRORLIB_HIDDEN static
#undef ZSTD_MULTITHREAD
#if defined(__ANDROID__)
#undef _GNU_SOURCE
#endif
#include "zstd.h"
#define g_ZSTD_threading_useless_symbol g_ZSTD_zbic_threading_useless_symbol
#include "zstd.c"
#undef g_ZSTD_threading_useless_symbol
namespace Common::Compression {
bool IsZBIC(std::span<const u8> src) {
if (src.size() < sizeof(u32)) {
return false;
}
u32 magic = 0;
std::memcpy(&magic, src.data(), sizeof(u32));
return magic == ZSTD_MAGICNUMBER; // 0x4349425A ("ZBIC")
}
int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src) {
if (dst.empty() || src.empty()) {
return -1;
}
const size_t res = ZSTD_decompress(dst.data(), dst.size(), src.data(), src.size());
if (ZSTD_isError(res)) {
return -1;
}
return static_cast<int>(res);
}
} // namespace Common::Compression
+15
View File
@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <span>
#include "common/common_types.h"
namespace Common::Compression {
[[nodiscard]] bool IsZBIC(std::span<const u8> src);
[[nodiscard]] int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src);
} // namespace Common::Compression
@@ -9,6 +9,7 @@
#include <functional>
#include <optional>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "core/file_sys/vfs/vfs_types.h"
+31 -4
View File
@@ -7,12 +7,14 @@
#include <algorithm>
#include <cinttypes>
#include <cstring>
#include <span>
#include <vector>
#include "common/common_funcs.h"
#include "common/hex_util.h"
#include "common/logging.h"
#include "common/lz4_compression.h"
#include "common/zbic_compression.h"
#include "common/settings.h"
#include "common/swap.h"
#include "core/core.h"
@@ -104,11 +106,36 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
nso_file.Read(compressed_data.data(), nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
if (nso_header.IsSegmentCompressed(i)) {
int r = Common::Compression::DecompressDataLZ4(decompressed_size.data(), nso_header.segments[i].size, compressed_data.data(), nso_header.segments_compressed_size[i]);
ASSERT(r == int(nso_header.segments[i].size));
std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, decompressed_size.data(), nso_header.segments[i].size);
if (nso_header.IsZBICCompressed()) {
// ZBIC compression
const int r = Common::Compression::DecompressDataZBIC(
std::span<u8>{decompressed_size}.first(nso_header.segments[i].size),
std::span<const u8>{compressed_data}.first(nso_header.segments_compressed_size[i])
);
ASSERT(r > 0);
} else {
// LZ4 compression
int r = Common::Compression::DecompressDataLZ4(
decompressed_size.data(),
nso_header.segments[i].size,
compressed_data.data(),
nso_header.segments_compressed_size[i]
);
ASSERT(r == int(nso_header.segments[i].size));
}
std::memcpy(
codeset.memory.data() + module_start + nso_header.segments[i].location,
decompressed_size.data(),
nso_header.segments[i].size
);
} else {
std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, compressed_data.data(), nso_header.segments[i].size);
// Not compressed
std::memcpy(
codeset.memory.data() + module_start + nso_header.segments[i].location,
compressed_data.data(),
nso_header.segments[i].size
);
}
codeset.segments[i].addr = module_start + nso_header.segments[i].location;
codeset.segments[i].offset = module_start + nso_header.segments[i].location;
+6
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -58,6 +61,9 @@ struct NSOHeader {
std::array<SHA256Hash, 3> segment_hashes;
bool IsSegmentCompressed(size_t segment_num) const;
bool IsZBICCompressed() const {
return ((flags >> 7) & 1) != 0;
}
};
static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
@@ -201,7 +201,7 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf)
void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
ir_block.Reset(descriptor);
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf);
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
Optimization::Optimize(ir_block, conf, {});
}
@@ -366,7 +366,8 @@ A64AddressSpace::A64AddressSpace(const A64::UserConfig& conf)
void A64AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
ir_block.Reset(descriptor);
A64::Translate(ir_block, A64::LocationDescriptor{descriptor}, conf);
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
A64::Translate(ir_block, A64::LocationDescriptor{descriptor}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
Optimization::Optimize(ir_block, conf, {});
}
@@ -21,7 +21,7 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf)
}
void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf);
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
Optimization::Optimize(ir_block, conf, {.sha256 = true});
}
@@ -27,7 +27,7 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf)
}
void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf);
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
Optimization::Optimize(ir_block, conf, {});
}
@@ -202,7 +202,7 @@ private:
// LocationDescriptor ctor() does important ops (like tflags) do not skip
auto const arch_descriptor = A32::LocationDescriptor{descriptor};
ir_block.Reset(arch_descriptor);
A32::Translate(ir_block, arch_descriptor, conf);
A32::Translate(ir_block, arch_descriptor, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
Optimization::Optimize(ir_block, conf, polyfill_options);
return emitter.Emit(ir_block);
}
@@ -254,10 +254,11 @@ private:
block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE);
// JIT Compile
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
// LocationDescriptor ctor() does important ops (like tflags) do not skip
auto const arch_descriptor = A64::LocationDescriptor{descriptor};
ir_block.Reset(arch_descriptor);
A64::Translate(ir_block, arch_descriptor, conf);
A64::Translate(ir_block, arch_descriptor, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
Optimization::Optimize(ir_block, conf, polyfill_options);
return emitter.Emit(ir_block).entrypoint;
}
+1 -3
View File
@@ -67,9 +67,7 @@
#else
# define CTX_SP (_UC_MACHINE_SP(ucontext))
#endif
#endif
#if defined(ARCHITECTURE_arm64)
#elif defined(ARCHITECTURE_arm64)
# if defined(__APPLE__)
# define CTX_PC (mctx->__ss.__pc)
# define CTX_SP (mctx->__ss.__sp)
@@ -9,16 +9,15 @@
#include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/interface/A32/config.h"
#include "dynarmic/ir/basic_block.h"
namespace Dynarmic::A32 {
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf);
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf);
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
void Translate(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) {
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, conf);
void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, tcb, options);
}
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
@@ -10,7 +10,6 @@
#include "common/common_types.h"
#include "dynarmic/interface/A32/arch_version.h"
#include "dynarmic/interface/A32/config.h"
namespace Dynarmic::IR {
class Block;
@@ -21,14 +20,28 @@ namespace Dynarmic::A32 {
class LocationDescriptor;
struct TranslateCallbacks;
struct TranslationOptions {
ArchVersion arch_version;
/// This changes what IR we emit when we translate an unpredictable instruction.
/// If this is false, the ExceptionRaised IR instruction is emitted.
/// If this is true, we define some behaviour for some instructions.
bool define_unpredictable_behaviour = false;
/// This changes what IR we emit when we translate a hint instruction.
/// If this is false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true;
};
/**
* This function translates instructions in memory into our intermediate representation.
* @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c.
* @param tcb The callbacks we should use to read emulated memory.
* @param conf Configures how certain instructions are translated.
* @param options Configures how certain instructions are translated.
* @return A translated basic block in the intermediate representation.
*/
void Translate(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf);
void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
/**
* This function translates a single provided instruction into our intermediate representation.
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -13,7 +10,7 @@ namespace Dynarmic::A32 {
// BKPT #<imm16>
bool TranslatorVisitor::arm_BKPT(Cond cond, Imm<12> /*imm12*/, Imm<4> /*imm4*/) {
if (cond != Cond::AL && !conf.define_unpredictable_behaviour) {
if (cond != Cond::AL && !options.define_unpredictable_behaviour) {
return UnpredictableInstruction();
}
// UNPREDICTABLE: The instruction executes conditionally.
@@ -9,7 +9,6 @@
#pragma once
#include "common/assert.h"
#include "dynarmic/interface/A32/config.h"
#include "dynarmic/mcl/bit.hpp"
#include "dynarmic/frontend/A32/a32_ir_emitter.h"
@@ -26,14 +25,12 @@ enum class Exception;
struct TranslatorVisitor final {
using instruction_return_type = bool;
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf)
: ir(block, descriptor, conf.arch_version)
, conf(conf)
{}
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options)
: ir(block, descriptor, options.arch_version), options(options) {}
A32::IREmitter ir;
ConditionalState cond_state = ConditionalState::None;
A32::UserConfig const& conf;
TranslationOptions options;
size_t current_instruction_size;
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2019 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -12,7 +9,7 @@
namespace Dynarmic::A32 {
bool TranslatorVisitor::arm_PLD_imm(bool /*add*/, bool R, Reg /*n*/, Imm<12> /*imm12*/) {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
@@ -21,7 +18,7 @@ bool TranslatorVisitor::arm_PLD_imm(bool /*add*/, bool R, Reg /*n*/, Imm<12> /*i
}
bool TranslatorVisitor::arm_PLD_reg(bool /*add*/, bool R, Reg /*n*/, Imm<5> /*imm5*/, ShiftType /*shift*/, Reg /*m*/) {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
@@ -30,7 +27,7 @@ bool TranslatorVisitor::arm_PLD_reg(bool /*add*/, bool R, Reg /*n*/, Imm<5> /*im
}
bool TranslatorVisitor::arm_SEV() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
@@ -38,7 +35,7 @@ bool TranslatorVisitor::arm_SEV() {
}
bool TranslatorVisitor::arm_SEVL() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
@@ -46,7 +43,7 @@ bool TranslatorVisitor::arm_SEVL() {
}
bool TranslatorVisitor::arm_WFE() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
@@ -54,7 +51,7 @@ bool TranslatorVisitor::arm_WFE() {
}
bool TranslatorVisitor::arm_WFI() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
@@ -62,7 +59,7 @@ bool TranslatorVisitor::arm_WFI() {
}
bool TranslatorVisitor::arm_YIELD() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
@@ -642,7 +642,7 @@ bool TranslatorVisitor::thumb16_SUB_sp(Imm<7> imm7) {
// SEV<c>
bool TranslatorVisitor::thumb16_SEV() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::SendEvent);
@@ -650,7 +650,7 @@ bool TranslatorVisitor::thumb16_SEV() {
// SEVL<c>
bool TranslatorVisitor::thumb16_SEVL() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::SendEventLocal);
@@ -658,7 +658,7 @@ bool TranslatorVisitor::thumb16_SEVL() {
// WFE<c>
bool TranslatorVisitor::thumb16_WFE() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::WaitForEvent);
@@ -666,7 +666,7 @@ bool TranslatorVisitor::thumb16_WFE() {
// WFI<c>
bool TranslatorVisitor::thumb16_WFI() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::WaitForInterrupt);
@@ -674,7 +674,7 @@ bool TranslatorVisitor::thumb16_WFI() {
// YIELD<c>
bool TranslatorVisitor::thumb16_YIELD() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::Yield);
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2021 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -11,7 +8,7 @@
namespace Dynarmic::A32 {
static bool PLDHandler(TranslatorVisitor& v, bool W) {
if (!v.conf.hook_hint_instructions) {
if (!v.options.hook_hint_instructions) {
return true;
}
@@ -21,7 +18,7 @@ static bool PLDHandler(TranslatorVisitor& v, bool W) {
}
static bool PLIHandler(TranslatorVisitor& v) {
if (!v.conf.hook_hint_instructions) {
if (!v.options.hook_hint_instructions) {
return true;
}
@@ -22,12 +22,10 @@
namespace Dynarmic::A32 {
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) {
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
const bool single_step = descriptor.SingleStepping();
TranslatorVisitor visitor{block, descriptor, conf};
TranslatorVisitor visitor{block, descriptor, options};
bool should_continue = true;
auto tcb = conf.callbacks;
do {
const u32 arm_pc = visitor.ir.current_location.PC();
u64 ticks_for_instruction = 1;
@@ -103,12 +103,10 @@ inline bool MaybeVFPOrASIMDInstruction(u32 thumb_instruction) noexcept {
} // namespace
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) {
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
const bool single_step = descriptor.SingleStepping();
TranslatorVisitor visitor{block, descriptor, conf};
TranslatorVisitor visitor{block, descriptor, options};
bool should_continue = true;
auto tcb = conf.callbacks;
do {
const u32 arm_pc = visitor.ir.current_location.PC();
u64 ticks_for_instruction = 1;
@@ -11,20 +11,19 @@
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/decoder/a64.h"
#include "dynarmic/frontend/A64/translate/impl/impl.h"
#include "dynarmic/interface/A64/config.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/terminal.h"
namespace Dynarmic::A64 {
void Translate(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf) {
void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options) {
const bool single_step = descriptor.SingleStepping();
TranslatorVisitor visitor{block, descriptor, conf};
TranslatorVisitor visitor{block, descriptor, std::move(options)};
bool should_continue = true;
do {
const u64 pc = visitor.ir.current_location->PC();
if (const auto instruction = conf.callbacks->MemoryReadCode(pc)) {
if (const auto instruction = memory_read_code(pc)) {
if (auto decoder = Decode<TranslatorVisitor, bool>(visitor, *instruction)) {
should_continue = *decoder;
} else {
@@ -11,7 +11,6 @@
#include <optional>
#include "common/common_types.h"
#include "dynarmic/interface/A64/config.h"
namespace Dynarmic {
@@ -23,14 +22,32 @@ namespace A64 {
class LocationDescriptor;
using MemoryReadCodeFuncType = std::function<std::optional<u32>(u64 vaddr)>;
struct TranslationOptions {
/// This changes what IR we emit when we translate an unpredictable instruction.
/// If this is false, the ExceptionRaised IR instruction is emitted.
/// If this is true, we define some behaviour for some instructions.
bool define_unpredictable_behaviour = false;
/// This tells the translator a wall clock will be used, thus allowing it
/// to avoid writting certain unnecessary code only needed for cycle timers.
bool wall_clock_cntpct = false;
/// This changes what IR we emit when we translate a hint instruction.
/// If this is false, we treat the instruction as a NOP.
/// If this is true, we emit an ExceptionRaised instruction.
bool hook_hint_instructions = true;
};
/**
* This function translates instructions in memory into our intermediate representation.
* @param descriptor The starting location of the basic block. Includes information like PC, FPCR state, &c.
* @param memory_read_code The function we should use to read emulated memory.
* @param conf Configures how certain instructions are translated.
* @param options Configures how certain instructions are translated.
* @return A translated basic block in the intermediate representation.
*/
void Translate(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf);
void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options);
/**
* This function translates a single provided instruction into our intermediate representation.
@@ -15,20 +15,17 @@
#include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/frontend/A64/translate/a64_translate.h"
#include "dynarmic/frontend/imm.h"
#include "dynarmic/interface/A64/config.h"
namespace Dynarmic::A64 {
struct TranslatorVisitor final {
using instruction_return_type = bool;
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf)
: ir(block, descriptor)
, conf(conf)
{}
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, TranslationOptions options)
: ir(block, descriptor), options(std::move(options)) {}
A64::IREmitter ir;
A64::UserConfig const& conf;
TranslationOptions options;
bool UnpredictableInstruction();
bool DecodeError();
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
@@ -28,7 +25,7 @@ static bool ExclusiveSharedDecodeAndOperation(TranslatorVisitor& v, bool pair, s
if (memop == IR::MemOp::LOAD && pair && Rt == *Rt2) {
return v.UnpredictableInstruction();
} else if (memop == IR::MemOp::STORE && (*Rs == Rt || (pair && *Rs == *Rt2))) {
if (!v.conf.define_unpredictable_behaviour) {
if (!v.options.define_unpredictable_behaviour) {
return v.UnpredictableInstruction();
}
// UNPREDICTABLE: The Constraint_NONE case is executed.
@@ -42,35 +42,35 @@ bool TranslatorVisitor::NOP() {
}
bool TranslatorVisitor::YIELD() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::Yield);
}
bool TranslatorVisitor::WFE() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::WaitForEvent);
}
bool TranslatorVisitor::WFI() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::WaitForInterrupt);
}
bool TranslatorVisitor::SEV() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::SendEvent);
}
bool TranslatorVisitor::SEVL() {
if (!conf.hook_hint_instructions) {
if (!options.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::SendEventLocal);
@@ -129,7 +129,7 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3
return true;
case SystemRegisterEncoding::CNTPCT_EL0:
// HACK: Ensure that this is the first instruction in the block it's emitted in, so the cycle count is most up-to-date.
if (!ir.block.instructions.empty() && !conf.wall_clock_cntpct) {
if (!ir.block.instructions.empty() && !options.wall_clock_cntpct) {
ir.block.CycleCount()--;
ir.SetTerm(IR::Term::LinkBlock{*ir.current_location});
return false;
+1 -1
View File
@@ -180,7 +180,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32::UserConf
while (num_insts < instructions_to_execute_count) {
A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, A32::FPSCR{}};
ir_block.Reset(descriptor);
A32::Translate(ir_block, descriptor, config);
A32::Translate(ir_block, descriptor, &test_env, {});
Optimization::Optimize(ir_block, config, {});
printf("\n\nIR:\n%s", IR::DumpBlock(ir_block).c_str());
printf("\n\nx86_64:\n");
+1 -1
View File
@@ -268,7 +268,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv
// const auto get_code = [&jit_env](u64 vaddr) { return jit_env.MemoryReadCode(vaddr); };
// const A64::LocationDescriptor location{instructions_start, FP::FPCR{fpcr}};
// IR::Block ir_block{location};
// A64::Translate(ir_block, location, config);
// A64::Translate(ir_block, location, get_code, {});
// fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block));
// Optimization::Optimize(ir_block, conf, {});
// fmt::print("Optimized IR:\n{}\n", IR::DumpBlock(ir_block));
+2 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -6,6 +6,7 @@
#pragma once
#include <vector>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
+1 -1
View File
@@ -92,7 +92,7 @@ if (ENABLE_OPENGL)
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
endif()
if (UNIX AND NOT APPLE)
if (LINUX OR FREEBSD)
if (DEFINED Qt6Gui_PRIVATE_INCLUDE_DIRS)
target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
else()
@@ -43,26 +43,32 @@ namespace {
switch (window_type) {
case Core::Frontend::WindowSystemType::Headless:
break;
#ifdef _WIN32
#if defined(VK_USE_PLATFORM_WIN32_KHR)
case Core::Frontend::WindowSystemType::Windows:
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
break;
#elif defined(__APPLE__)
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
case Core::Frontend::WindowSystemType::Cocoa:
extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
break;
#elif defined(__ANDROID__)
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
case Core::Frontend::WindowSystemType::Android:
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
break;
#elif defined(__HAIKU__)
#endif
#if defined(VK_USE_PLATFORM_XCB_KHR)
case Core::Frontend::WindowSystemType::Xcb:
extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
break;
#else
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
case Core::Frontend::WindowSystemType::X11:
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
break;
#endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
case Core::Frontend::WindowSystemType::Wayland:
extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
break;
@@ -8,6 +8,7 @@
#include "core/frontend/emu_window.h"
#include "video_core/vulkan_common/vulkan_surface.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
#include "video_core/vulkan_common/vulkan.h"
namespace Vulkan {
@@ -17,7 +18,7 @@ vk::SurfaceKHR CreateSurface(
[[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch();
VkSurfaceKHR unsafe_surface = VkSurfaceKHR{};
#ifdef _WIN32
#if defined(VK_USE_PLATFORM_WIN32_KHR)
if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
const HWND hWnd = static_cast<HWND>(window_info.render_surface);
const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
@@ -30,7 +31,8 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#elif defined(__APPLE__)
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) {
const VkMetalSurfaceCreateInfoEXT metal_ci = {
.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT,
@@ -45,7 +47,8 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#elif defined(__ANDROID__)
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
if (window_info.type == Core::Frontend::WindowSystemType::Android) {
const VkAndroidSurfaceCreateInfoKHR android_ci{
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0,
@@ -59,7 +62,8 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#elif defined(__HAIKU__)
#endif
#if defined(VK_USE_PLATFORM_XCB_KHR)
if (window_info.type == Core::Frontend::WindowSystemType::Xcb) {
const VkXcbSurfaceCreateInfoKHR xcb_ci{
.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
@@ -76,7 +80,8 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#else
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
if (window_info.type == Core::Frontend::WindowSystemType::X11) {
const VkXlibSurfaceCreateInfoKHR xlib_ci{
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
@@ -90,6 +95,8 @@ vk::SurfaceKHR CreateSurface(
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
const VkWaylandSurfaceCreateInfoKHR wayland_ci{
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
@@ -105,7 +112,6 @@ vk::SurfaceKHR CreateSurface(
}
}
#endif
if (!unsafe_surface) {
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);