mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-29 01:56:06 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 825a6b30ad | |||
| 5e2c294d7b | |||
| e2e2a4ee9c | |||
| dfd23821d7 | |||
| d1761a1331 | |||
| 8005c11b40 | |||
| bcfab23498 | |||
| 27ab01fd1d | |||
| de6e0ffd4c | |||
| 6e32151d9c | |||
| 518971f4eb | |||
| 46433279af | |||
| 47822d1606 | |||
| 8462bd501e | |||
| 11280e18d3 | |||
| e5fd0b8ef5 | |||
| e8246f42b2 | |||
| d8cf5caeac | |||
| 219920fbd0 | |||
| 5acadadaa2 | |||
| 7bf1ed8ce6 | |||
| 4b3b735486 | |||
| 4a891bee92 | |||
| e7a9c4af3e | |||
| 936e5b56eb | |||
| d8a8169eb2 | |||
| 81c6e56713 | |||
| b4b41ee62c | |||
| 0d6a2158f0 | |||
| 09b6b3b71e | |||
| 629ebf1bde | |||
| c993bc01a4 | |||
| 6bdb03d8ac | |||
| 599ab16288 | |||
| 30a42c5a6a | |||
| 3aa0d46259 |
@@ -0,0 +1,92 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
NUM_JOBS=$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo 2)
|
||||
|
||||
: "${CCACHE:=false}"
|
||||
RETURN=0
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [-b|--build-type BUILD_TYPE] [-o|--outdir OUTPUT_DIRECTORY]
|
||||
|
||||
Build script for Emscripten (using wasm64).
|
||||
|
||||
Options:
|
||||
--build-type Set the CMake build type (Release|RelWithDebInfo|MinSizeRel|Debug)
|
||||
Default: Release
|
||||
--outdir Set the output directory
|
||||
Default: build
|
||||
|
||||
EOF
|
||||
exit "$RETURN"
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "-- ! $*" >&2
|
||||
RETURN=1 usage
|
||||
}
|
||||
|
||||
type() {
|
||||
[ -z "$1" ] && die "You must specify a valid type."
|
||||
TYPE="$1"
|
||||
}
|
||||
|
||||
outdir() {
|
||||
[ -z "$1" ] && die "You must specify a valid output directory."
|
||||
OUTDIR="$1"
|
||||
}
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-r|--release) DEVEL=false ;;
|
||||
-b|--build-type) type "$2"; shift ;;
|
||||
-o|--outdir) outdir "$2"; shift ;;
|
||||
-h|--help) usage ;;
|
||||
*) break ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
: "${TYPE:=Release}"
|
||||
: "${DEVEL:=true}"
|
||||
: "${OUTDIR:=build}"
|
||||
|
||||
# -sMEMORY64 must be specified twice, see below
|
||||
# The CMake toolchain file will match against MEMORY64 but will fail to match if:
|
||||
# - it's either -sMEMORY64
|
||||
# - or it's either -sMEMORY64=1
|
||||
# The line in question:
|
||||
# if (CMAKE_C_FLAGS MATCHES "MEMORY64")
|
||||
# However why need to specify -sMEMORY64=1 then? Oh that's because if you didn't set
|
||||
# the =1, it would assume you meant =0, which equates to not specifying it at all
|
||||
# This seems to be fixed in later versions but occurs atleast on 4.0.3-git and below.
|
||||
emcmake cmake -B "$OUTDIR" -G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=${TYPE} \
|
||||
-DENABLE_OPENGL=OFF \
|
||||
-DENABLE_LTO=OFF \
|
||||
-DENABLE_QT=OFF \
|
||||
-DENABLE_UNITY_BUILD=OFF \
|
||||
-DENABLE_QT_TRANSLATION=OFF \
|
||||
-DENABLE_CUBEB=OFF \
|
||||
-DENABLE_LIBUSB=OFF \
|
||||
-DENABLE_UPDATE_CHECKER=OFF \
|
||||
-DENABLE_WEB_SERVICE=OFF \
|
||||
-DUSE_DISCORD_PRESENCE=OFF \
|
||||
-DENABLE_WIFI_SCAN=OFF \
|
||||
-DUSE_FASTER_LINKER=ON \
|
||||
-DYUZU_STATIC_BUILD=ON \
|
||||
-DYUZU_USE_BUNDLED_OPENSSL=OFF \
|
||||
-DYUZU_USE_EXTERNAL_FFMPEG=ON \
|
||||
-Dzstd_FORCE_BUNDLED=ON \
|
||||
-DOpenSSL_FORCE_BUNDLED=ON \
|
||||
-DEMSCRIPTEN_SYSTEM_PROCESSOR=wasm \
|
||||
-DCMAKE_C_FLAGS="-s MEMORY64 -m64 -pipe -sMEMORY64=1" \
|
||||
-DCMAKE_CXX_FLAGS="-s MEMORY64 -m64 -pipe -sMEMORY64=1" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-sMEMORY64=1 -m64 -Wl,-mwasm64 -sASYNCIFY=1" \
|
||||
-DCMAKE_C_LINK_FLAGS="-sMEMORY64=1 -m64 -Wl,-mwasm64 -sASYNCIFY=1" \
|
||||
-DCMAKE_CXX_LINK_FLAGS="-sMEMORY64=1 -m64 -Wl,-mwasm64 -sASYNCIFY=1"
|
||||
|
||||
cmake --build "$OUTDIR" -- -j$NUM_JOBS
|
||||
@@ -7,7 +7,6 @@
|
||||
# Build directory
|
||||
/[Bb]uild*/
|
||||
doc-build/
|
||||
out/
|
||||
AppDir/
|
||||
uruntime
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
diff --git a/cmake/ConfigureOpenSSL.cmake b/cmake/ConfigureOpenSSL.cmake
|
||||
index 3012e05..2ae23ff 100644
|
||||
--- a/cmake/ConfigureOpenSSL.cmake
|
||||
+++ b/cmake/ConfigureOpenSSL.cmake
|
||||
@@ -108,7 +108,8 @@ function(configure_openssl)
|
||||
)
|
||||
|
||||
if(NOT "${CONFIGURE_OPTIONS_OLD}" STREQUAL "")
|
||||
- if(CONFIGURE_OPTIONS STREQUAL CONFIGURE_OPTIONS_OLD)
|
||||
+ # TODO(lizzie): Emscripten has issues with rebuilding due to the wrapper it uses
|
||||
+ if(CMAKE_SYSTEM_NAME MATCHES "Emscripten" OR CONFIGURE_OPTIONS STREQUAL CONFIGURE_OPTIONS_OLD)
|
||||
message(STATUS "Found previous configure results. Don't perform configuration")
|
||||
return()
|
||||
endif()
|
||||
@@ -134,10 +135,24 @@ function(configure_openssl)
|
||||
set(VERBOSE_OPTION OUTPUT_QUIET)
|
||||
endif()
|
||||
|
||||
+ if (CMAKE_SYSTEM_NAME MATCHES "Emscripten")
|
||||
+ set(EMSCRIPTEN_CMAKE_WRAPPER "emcmake")
|
||||
+ find_program(EMCC emcc REQUIRED)
|
||||
+ set(EMSCRIPTEN_LINKER ${EMCC})
|
||||
+ list(APPEND CONFIGURE_COMMAND wasm64)
|
||||
+ else()
|
||||
+ set(EMSCRIPTEN_CMAKE_WRAPPER "")
|
||||
+ set(EMSCRIPTEN_LINKER ${CMAKE_LINKER})
|
||||
+ endif ()
|
||||
+
|
||||
execute_process(
|
||||
- COMMAND ${CMAKE_COMMAND} -E env
|
||||
+ COMMAND ${EMSCRIPTEN_CMAKE_WRAPPER} ${CMAKE_COMMAND} -E env
|
||||
"CFLAGS=${CMAKE_C_FLAGS}"
|
||||
"CXXFLAGS=${CMAKE_CXX_FLAGS}"
|
||||
+ "LDFLAGS=${CMAKE_CXX_LINK_FLAGS}"
|
||||
+ "CC=${CMAKE_C_COMPILER}"
|
||||
+ "CXX=${CMAKE_CXX_COMPILER}"
|
||||
+ "LD=${EMSCRIPTEN_LINKER}"
|
||||
${CONFIGURE_COMMAND}
|
||||
WORKING_DIRECTORY ${CONFIGURE_BUILD_DIR}
|
||||
${VERBOSE_OPTION}
|
||||
@@ -0,0 +1,112 @@
|
||||
diff --git a/Configurations/10-main.conf b/Configurations/10-main.conf
|
||||
index e62721e..243feb4 100644
|
||||
--- a/Configurations/10-main.conf
|
||||
+++ b/Configurations/10-main.conf
|
||||
@@ -1970,6 +1970,26 @@ my %targets = (
|
||||
multilib => "64",
|
||||
},
|
||||
|
||||
+ "wasm32" => {
|
||||
+ inherit_from => [ "BASE_unix" ],
|
||||
+ CC => "emcc",
|
||||
+ CXX => "emc++",
|
||||
+ cflags => combine("--target=wasm32-unknown-emscripten", threads("-pthread")),
|
||||
+ cxxflags => combine("--target=wasm32-unknown-emscripten", threads("-pthread")),
|
||||
+ lib_cppflags => add("-DL_ENDIAN"),
|
||||
+ bn_ops => "THIRTY_TWO_BIT",
|
||||
+ },
|
||||
+ "wasm64" => {
|
||||
+ inherit_from => [ "BASE_unix" ],
|
||||
+ CC => "emcc",
|
||||
+ CXX => "emc++",
|
||||
+ cflags => combine("--target=wasm64-unknown-emscripten", threads("-pthread")),
|
||||
+ cxxflags => combine("--target=wasm64-unknown-emscripten", threads("-pthread")),
|
||||
+ lib_cppflags => add("-DL_ENDIAN"),
|
||||
+ bn_ops => "SIXTY_FOUR_BIT_LONG",
|
||||
+ },
|
||||
+
|
||||
+
|
||||
#### uClinux
|
||||
"uClinux-dist" => {
|
||||
inherit_from => [ "BASE_unix" ],
|
||||
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
|
||||
index d9e8f02..7faf347 100644
|
||||
--- a/crypto/rand/rand_lib.c
|
||||
+++ b/crypto/rand/rand_lib.c
|
||||
@@ -379,17 +379,27 @@ void RAND_add(const void *buf, int num, double randomness)
|
||||
#if !defined(OPENSSL_NO_DEPRECATED_1_1_0)
|
||||
int RAND_pseudo_bytes(unsigned char *buf, int num)
|
||||
{
|
||||
+#if defined(__wasi__)
|
||||
+ arc4random_buf(buf, num);
|
||||
+ return 1;
|
||||
+#elif defined(__EMSCRIPTEN__)
|
||||
+ return 1;
|
||||
+#else
|
||||
const RAND_METHOD *meth = RAND_get_rand_method();
|
||||
|
||||
if (meth != NULL && meth->pseudorand != NULL)
|
||||
return meth->pseudorand(buf, num);
|
||||
ERR_raise(ERR_LIB_RAND, RAND_R_FUNC_NOT_IMPLEMENTED);
|
||||
return -1;
|
||||
+#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int RAND_status(void)
|
||||
{
|
||||
+#if defined(__EMSCRIPTEN__) || defined(__wasi__)
|
||||
+ return 1;
|
||||
+#else
|
||||
EVP_RAND_CTX *rand;
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
const RAND_METHOD *meth = RAND_get_rand_method();
|
||||
@@ -401,6 +411,7 @@ int RAND_status(void)
|
||||
if ((rand = RAND_get0_primary(NULL)) == NULL)
|
||||
return 0;
|
||||
return EVP_RAND_get_state(rand) == EVP_RAND_STATE_READY;
|
||||
+#endif
|
||||
}
|
||||
#else /* !FIPS_MODULE */
|
||||
|
||||
@@ -420,6 +431,12 @@ const RAND_METHOD *RAND_get_rand_method(void)
|
||||
int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
|
||||
unsigned int strength)
|
||||
{
|
||||
+#if defined(__wasi__)
|
||||
+ arc4random_buf(buf, num);
|
||||
+ return 1;
|
||||
+#elif defined(__EMSCRIPTEN__)
|
||||
+ return 1;
|
||||
+#else
|
||||
RAND_GLOBAL *dgbl;
|
||||
EVP_RAND_CTX *rand;
|
||||
#if !defined(OPENSSL_NO_DEPRECATED_3_0) && !defined(FIPS_MODULE)
|
||||
@@ -451,6 +468,7 @@ int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num,
|
||||
return EVP_RAND_generate(rand, buf, num, strength, 0, NULL, 0);
|
||||
|
||||
return 0;
|
||||
+#endif
|
||||
}
|
||||
|
||||
int RAND_priv_bytes(unsigned char *buf, int num)
|
||||
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
|
||||
index 3d21801..e026f8f 100644
|
||||
--- a/ssl/ssl_cert.c
|
||||
+++ b/ssl/ssl_cert.c
|
||||
@@ -941,6 +941,7 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+#ifndef OPENSSL_NO_POSIX_IO
|
||||
int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
|
||||
const char *dir)
|
||||
{
|
||||
@@ -1016,6 +1017,7 @@ err:
|
||||
|
||||
return ret;
|
||||
}
|
||||
+#endif
|
||||
|
||||
static int add_uris_recursive(STACK_OF(X509_NAME) *stack,
|
||||
const char *uri, int depth)
|
||||
+23
-5
@@ -63,6 +63,7 @@ if (YUZU_STATIC_ROOM)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
set(OPENSSL_USE_STATIC_LIBS ON)
|
||||
set(OpenSSL_FORCE_SYSTEM ON)
|
||||
|
||||
set(zstd_FORCE_BUNDLED ON)
|
||||
set(fmt_FORCE_BUNDLED ON)
|
||||
@@ -78,6 +79,7 @@ set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundl
|
||||
cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
|
||||
|
||||
option(ENABLE_DEBUG_TOOLS "Enable debugging tools (maxwell disassembler, SPIRV translator, etc)" OFF)
|
||||
option(ENABLE_WERROR "Enable -Werror diagnostics" OFF)
|
||||
|
||||
# non-linux bundled qt are static
|
||||
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
|
||||
@@ -379,6 +381,15 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
# Prefer the -pthread flag on Linux.
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
# It is absolutely promordial to enable on Emscripten
|
||||
# Not only this allows to use std::thread and std::jthread without exceptions
|
||||
# but it also fixes several issues related to MT operations.
|
||||
# ...and CMake doesn't include it by default even when we specify
|
||||
# that we prefer the pthread flag; why is that? I don't know.
|
||||
if (PLATFORM_EMSCRIPTEN)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-pthread>)
|
||||
add_link_options($<$<COMPILE_LANGUAGE:C,CXX>:-pthread>)
|
||||
endif()
|
||||
|
||||
find_package(RenderDoc MODULE)
|
||||
|
||||
@@ -407,7 +418,12 @@ set(BUILD_TESTING OFF)
|
||||
set(ENABLE_TESTING OFF)
|
||||
|
||||
# boost
|
||||
set(BOOST_INCLUDE_LIBRARIES algorithm icl pool container heap asio headers process filesystem crc variant)
|
||||
if (PLATFORM_EMSCRIPTEN)
|
||||
set(BOOST_INCLUDE_LIBRARIES algorithm icl pool container heap headers filesystem crc variant)
|
||||
set(BOOST_CONTAINER_HEADER_ONLY ON)
|
||||
else()
|
||||
set(BOOST_INCLUDE_LIBRARIES algorithm icl pool container heap asio headers process filesystem crc variant)
|
||||
endif()
|
||||
|
||||
AddJsonPackage(boost)
|
||||
|
||||
@@ -428,10 +444,12 @@ if (Boost_ADDED)
|
||||
|
||||
target_compile_options(boost_heap INTERFACE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>)
|
||||
target_compile_options(boost_icl INTERFACE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>)
|
||||
target_compile_options(boost_asio INTERFACE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-implicit-fallthrough>
|
||||
)
|
||||
# May not exist (i.e emscripten)
|
||||
if (TARGET boost_asio)
|
||||
target_compile_options(boost_asio INTERFACE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-implicit-fallthrough>)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
+165
-180
@@ -1,7 +1,7 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2026 crueter
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
set(CPM_SOURCE_CACHE "${PROJECT_SOURCE_DIR}/.cache/cpm" CACHE STRING "" FORCE)
|
||||
cmake_minimum_required(VERSION 3.31)
|
||||
|
||||
if(MSVC OR ANDROID OR IOS)
|
||||
set(BUNDLED_DEFAULT ON)
|
||||
@@ -9,15 +9,40 @@ else()
|
||||
set(BUNDLED_DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
set(CPM_SOURCE_CACHE "${PROJECT_SOURCE_DIR}/.cache/cpm" CACHE STRING "" FORCE)
|
||||
|
||||
option(CPMUTIL_FORCE_BUNDLED
|
||||
"Force bundled packages for all CPM depdendencies" ${BUNDLED_DEFAULT})
|
||||
|
||||
option(CPMUTIL_FORCE_SYSTEM
|
||||
"Force system packages for all CPM dependencies (NOT RECOMMENDED)" OFF)
|
||||
"Force system packages for all CPM dependencies" OFF)
|
||||
|
||||
set(CPMUTIL_PATCH_DIR "${PROJECT_SOURCE_DIR}/.patch" CACHE STRING
|
||||
"Directory containing patches for packages")
|
||||
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
include(CPM)
|
||||
|
||||
# Rudimentary target architecture detection
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} processor)
|
||||
if (processor MATCHES "x86|amd64")
|
||||
set(CPMUTIL_AMD64 ON)
|
||||
elseif(processor MATCHES "^aarch64|^arm64|^armv8\.*")
|
||||
set(CPMUTIL_ARM64 ON)
|
||||
elseif(processor MATCHES "riscv")
|
||||
set(CPMUTIL_RISCV64 ON)
|
||||
endif()
|
||||
else()
|
||||
# This block exists for compatibility with my own DetectArchitecture.cmake.
|
||||
if (ARCHITECTURE_x86_64)
|
||||
set(CPMUTIL_AMD64 ON)
|
||||
elseif(ARCHITECTURE_arm64)
|
||||
set(CPMUTIL_ARM64 ON)
|
||||
elseif(ARCHITECTURE_riscv64)
|
||||
set(CPMUTIL_RISCV64 ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# cpmfile parsing
|
||||
set(CPMUTIL_JSON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json")
|
||||
|
||||
@@ -70,7 +95,6 @@ function(get_json_element object out member default)
|
||||
|
||||
if(out_type STREQUAL "ARRAY")
|
||||
string(JSON _len LENGTH "${object}" ${member})
|
||||
# array_to_list("${outvar}" ${_len} outvar)
|
||||
set("${out}_LENGTH" "${_len}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
@@ -148,11 +172,12 @@ macro(parse_object object)
|
||||
get_json_element("${object}" repo repo "")
|
||||
get_json_element("${object}" ci ci OFF)
|
||||
get_json_element("${object}" version version "")
|
||||
get_json_element("${object}" min_version min_version "")
|
||||
get_json_element("${object}" git_host git_host "github.com")
|
||||
|
||||
if(ci)
|
||||
get_json_element("${object}" name name "${JSON_NAME}")
|
||||
get_json_element("${object}" extension extension "tar.zst")
|
||||
get_json_element("${object}" min_version min_version "")
|
||||
get_json_element("${object}" raw_disabled disabled_platforms "")
|
||||
|
||||
if(raw_disabled)
|
||||
@@ -163,14 +188,10 @@ macro(parse_object object)
|
||||
endif()
|
||||
else()
|
||||
get_json_element("${object}" hash hash "")
|
||||
get_json_element("${object}" hash_suffix hash_suffix "")
|
||||
get_json_element("${object}" sha sha "")
|
||||
get_json_element("${object}" url url "")
|
||||
get_json_element("${object}" key key "")
|
||||
get_json_element("${object}" tag tag "")
|
||||
get_json_element("${object}" artifact artifact "")
|
||||
get_json_element("${object}" git_version git_version "")
|
||||
get_json_element("${object}" git_host git_host "")
|
||||
get_json_element("${object}" source_subdir source_subdir "")
|
||||
get_json_element("${object}" bundled bundled "unset")
|
||||
get_json_element("${object}" find_args find_args "")
|
||||
@@ -178,23 +199,17 @@ macro(parse_object object)
|
||||
|
||||
# okay here comes the fun part: REPLACEMENTS!
|
||||
# first: tag gets %VERSION% replaced if applicable,
|
||||
# with either git_version (preferred) or version
|
||||
# with version
|
||||
# second: artifact gets %VERSION% and %TAG% replaced
|
||||
# accordingly (same rules for VERSION)
|
||||
|
||||
if(git_version)
|
||||
set(version_replace ${git_version})
|
||||
else()
|
||||
set(version_replace ${version})
|
||||
endif()
|
||||
|
||||
# TODO(crueter): fmt module for cmake
|
||||
if(tag)
|
||||
string(REPLACE "%VERSION%" "${version_replace}" tag ${tag})
|
||||
string(REPLACE "%VERSION%" "${version}" tag ${tag})
|
||||
endif()
|
||||
|
||||
if(artifact)
|
||||
string(REPLACE "%VERSION%" "${version_replace}"
|
||||
string(REPLACE "%VERSION%" "${version}"
|
||||
artifact ${artifact})
|
||||
string(REPLACE "%TAG%" "${tag}" artifact ${artifact})
|
||||
endif()
|
||||
@@ -207,7 +222,7 @@ macro(parse_object object)
|
||||
string(JSON _patch GET "${raw_patches}" "${IDX}")
|
||||
|
||||
set(full_patch
|
||||
"${PROJECT_SOURCE_DIR}/.patch/${JSON_NAME}/${_patch}")
|
||||
"${CPMUTIL_PATCH_DIR}/${JSON_NAME}/${_patch}")
|
||||
if(NOT EXISTS ${full_patch})
|
||||
cpm_utils_message(FATAL_ERROR ${JSON_NAME}
|
||||
"specifies patch ${full_patch} which does not exist")
|
||||
@@ -242,14 +257,16 @@ function(AddJsonPackage)
|
||||
|
||||
# these are overrides that can be generated at runtime,
|
||||
# so can be defined separately from the json
|
||||
BUNDLED_PACKAGE
|
||||
FORCE_BUNDLED_PACKAGE)
|
||||
|
||||
set(multiValueArgs OPTIONS)
|
||||
|
||||
set(optionArgs MODULE_PATH DOWNLOAD_ONLY)
|
||||
|
||||
cmake_parse_arguments(JSON "${optionArgs}" "${oneValueArgs}" "${multiValueArgs}"
|
||||
cmake_parse_arguments(JSON
|
||||
"${optionArgs}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
"${ARGN}")
|
||||
|
||||
list(LENGTH ARGN argnLength)
|
||||
@@ -260,8 +277,8 @@ function(AddJsonPackage)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CPMFILE_CONTENT)
|
||||
cpm_utils_message(WARNING ${name}
|
||||
"No cpmfile, AddJsonPackage is a no-op")
|
||||
cpm_utils_message(FATAL_ERROR ${name}
|
||||
"No cpmfile present")
|
||||
return()
|
||||
endif()
|
||||
|
||||
@@ -288,13 +305,16 @@ function(AddJsonPackage)
|
||||
|
||||
if(ci)
|
||||
AddCIPackage(
|
||||
VERSION ${version}
|
||||
NAME ${name}
|
||||
REPO ${repo}
|
||||
PACKAGE ${package}
|
||||
EXTENSION ${extension}
|
||||
MIN_VERSION ${min_version}
|
||||
DISABLED_PLATFORMS ${disabled_platforms}
|
||||
VERSION "${version}"
|
||||
NAME "${name}"
|
||||
REPO "${repo}"
|
||||
PACKAGE "${package}"
|
||||
EXTENSION "${extension}"
|
||||
MIN_VERSION "${min_version}"
|
||||
DISABLED_PLATFORMS "${disabled_platforms}"
|
||||
|
||||
GIT_HOST "${git_host}"
|
||||
|
||||
${EXTRA_ARGS})
|
||||
else()
|
||||
if (NOT DEFINED JSON_FORCE_BUNDLED_PACKAGE)
|
||||
@@ -304,12 +324,11 @@ function(AddJsonPackage)
|
||||
AddPackage(
|
||||
NAME "${package}"
|
||||
VERSION "${version}"
|
||||
MIN_VERSION "${min_version}"
|
||||
URL "${url}"
|
||||
HASH "${hash}"
|
||||
HASH_SUFFIX "${hash_suffix}"
|
||||
SHA "${sha}"
|
||||
REPO "${repo}"
|
||||
KEY "${key}"
|
||||
PATCHES "${patches}"
|
||||
OPTIONS "${options}"
|
||||
FIND_PACKAGE_ARGUMENTS "${find_args}"
|
||||
@@ -317,11 +336,11 @@ function(AddJsonPackage)
|
||||
FORCE_BUNDLED_PACKAGE "${JSON_FORCE_BUNDLED_PACKAGE}"
|
||||
SOURCE_SUBDIR "${source_subdir}"
|
||||
|
||||
GIT_VERSION "${git_version}"
|
||||
GIT_HOST "${git_host}"
|
||||
|
||||
ARTIFACT "${artifact}"
|
||||
TAG "${tag}"
|
||||
|
||||
${EXTRA_ARGS})
|
||||
endif()
|
||||
|
||||
@@ -339,25 +358,19 @@ function(AddPackage)
|
||||
set(oneValueArgs
|
||||
NAME
|
||||
VERSION
|
||||
GIT_VERSION
|
||||
MIN_VERSION
|
||||
GIT_HOST
|
||||
|
||||
REPO
|
||||
TAG
|
||||
ARTIFACT
|
||||
SHA
|
||||
BRANCH
|
||||
|
||||
HASH
|
||||
HASH_SUFFIX
|
||||
HASH_URL
|
||||
HASH_ALGO
|
||||
|
||||
URL
|
||||
GIT_URL
|
||||
SOURCE_SUBDIR
|
||||
|
||||
KEY
|
||||
SOURCE_SUBDIR
|
||||
BUNDLED_PACKAGE
|
||||
FORCE_BUNDLED_PACKAGE
|
||||
FIND_PACKAGE_ARGUMENTS)
|
||||
@@ -366,7 +379,10 @@ function(AddPackage)
|
||||
|
||||
set(optionArgs MODULE_PATH DOWNLOAD_ONLY)
|
||||
|
||||
cmake_parse_arguments(PKG_ARGS "${optionArgs}" "${oneValueArgs}" "${multiValueArgs}"
|
||||
cmake_parse_arguments(PKG_ARGS
|
||||
"${optionArgs}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
"${ARGN}")
|
||||
|
||||
if(NOT DEFINED PKG_ARGS_NAME)
|
||||
@@ -385,6 +401,7 @@ function(AddPackage)
|
||||
set(CPM_${PKG_ARGS_NAME}_SOURCE ${${PKG_ARGS_NAME}_CUSTOM_DIR})
|
||||
endif()
|
||||
|
||||
# TODO: See if this can be delegated to subshells
|
||||
if(NOT DEFINED PKG_ARGS_GIT_HOST)
|
||||
set(git_host github.com)
|
||||
else()
|
||||
@@ -393,42 +410,22 @@ function(AddPackage)
|
||||
|
||||
if(DEFINED PKG_ARGS_URL)
|
||||
set(pkg_url ${PKG_ARGS_URL})
|
||||
|
||||
if(DEFINED PKG_ARGS_REPO)
|
||||
set(pkg_git_url https://${git_host}/${PKG_ARGS_REPO})
|
||||
else()
|
||||
if(DEFINED PKG_ARGS_GIT_URL)
|
||||
set(pkg_git_url ${PKG_ARGS_GIT_URL})
|
||||
else()
|
||||
set(pkg_git_url ${pkg_url})
|
||||
endif()
|
||||
endif()
|
||||
set(pkg_git_url ${pkg_url})
|
||||
elseif(DEFINED PKG_ARGS_REPO)
|
||||
set(pkg_git_url https://${git_host}/${PKG_ARGS_REPO})
|
||||
|
||||
if(DEFINED PKG_ARGS_TAG)
|
||||
set(pkg_key ${PKG_ARGS_TAG})
|
||||
|
||||
if(DEFINED PKG_ARGS_ARTIFACT)
|
||||
set(pkg_url
|
||||
"${pkg_git_url}/releases/download/${PKG_ARGS_TAG}/${PKG_ARGS_ARTIFACT}")
|
||||
else()
|
||||
set(pkg_url
|
||||
${pkg_git_url}/archive/refs/tags/${PKG_ARGS_TAG}.tar.gz)
|
||||
endif()
|
||||
elseif(DEFINED PKG_ARGS_SHA)
|
||||
if(DEFINED PKG_ARGS_SHA)
|
||||
set(pkg_url "${pkg_git_url}/archive/${PKG_ARGS_SHA}.tar.gz")
|
||||
else()
|
||||
if(DEFINED PKG_ARGS_BRANCH)
|
||||
set(PKG_BRANCH ${PKG_ARGS_BRANCH})
|
||||
elseif(DEFINED PKG_ARGS_TAG)
|
||||
set(tag "${PKG_ARGS_TAG}")
|
||||
if(DEFINED PKG_ARGS_ARTIFACT)
|
||||
set(artifact "${PKG_ARGS_ARTIFACT}")
|
||||
set(pkg_url
|
||||
"${pkg_git_url}/releases/download/${tag}/${artifact}")
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"REPO defined but no TAG, SHA, BRANCH, or URL"
|
||||
"specified, defaulting to master")
|
||||
set(PKG_BRANCH master)
|
||||
set(pkg_url
|
||||
"${pkg_git_url}/archive/refs/tags/${tag}.tar.gz")
|
||||
endif()
|
||||
|
||||
set(pkg_url ${pkg_git_url}/archive/refs/heads/${PKG_BRANCH}.tar.gz)
|
||||
endif()
|
||||
else()
|
||||
cpm_utils_message(FATAL_ERROR ${PKG_ARGS_NAME}
|
||||
@@ -437,75 +434,24 @@ function(AddPackage)
|
||||
|
||||
cpm_utils_message(DEBUG ${PKG_ARGS_NAME} "Download URL is ${pkg_url}")
|
||||
|
||||
if(NOT DEFINED PKG_ARGS_KEY)
|
||||
if(DEFINED PKG_ARGS_SHA)
|
||||
string(SUBSTRING ${PKG_ARGS_SHA} 0 4 pkg_key)
|
||||
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
|
||||
"No custom key defined, using ${pkg_key} from sha")
|
||||
elseif(DEFINED PKG_ARGS_GIT_VERSION)
|
||||
set(pkg_key ${PKG_ARGS_GIT_VERSION})
|
||||
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
|
||||
"No custom key defined, using ${pkg_key}")
|
||||
elseif(DEFINED PKG_ARGS_TAG)
|
||||
set(pkg_key ${PKG_ARGS_TAG})
|
||||
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
|
||||
"No custom key defined, using ${pkg_key}")
|
||||
elseif(DEFINED PKG_ARGS_VERSION)
|
||||
set(pkg_key ${PKG_ARGS_VERSION})
|
||||
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
|
||||
"No custom key defined, using ${pkg_key}")
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"Could not determine cache key, using CPM defaults")
|
||||
endif()
|
||||
if(DEFINED PKG_ARGS_SHA)
|
||||
string(SUBSTRING ${PKG_ARGS_SHA} 0 4 pkg_key)
|
||||
elseif(DEFINED PKG_ARGS_VERSION)
|
||||
set(pkg_key ${PKG_ARGS_VERSION})
|
||||
elseif(DEFINED PKG_ARGS_TAG)
|
||||
set(pkg_key ${PKG_ARGS_TAG})
|
||||
elseif(DEFINED PKG_ARGS_MIN_VERSION)
|
||||
set(pkg_key ${PKG_ARGS_MIN_VERSION})
|
||||
else()
|
||||
set(pkg_key ${PKG_ARGS_KEY})
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_HASH_ALGO)
|
||||
set(hash_algo ${PKG_ARGS_HASH_ALGO})
|
||||
else()
|
||||
set(hash_algo SHA512)
|
||||
cpm_utils_message(FATAL_ERROR ${PKG_ARGS_NAME}
|
||||
"Could not determine cache key")
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_HASH)
|
||||
set(pkg_hash "${hash_algo}=${PKG_ARGS_HASH}")
|
||||
elseif(DEFINED PKG_ARGS_HASH_SUFFIX)
|
||||
# funny sanity check
|
||||
string(TOLOWER ${hash_algo} hash_algo_lower)
|
||||
string(TOLOWER ${PKG_ARGS_HASH_SUFFIX} suffix_lower)
|
||||
if(NOT ${suffix_lower} MATCHES ${hash_algo_lower})
|
||||
cpm_utils_message(WARNING
|
||||
"Hash algorithm and hash suffix do not match, errors may occur")
|
||||
endif()
|
||||
|
||||
set(hash_url ${pkg_url}.${PKG_ARGS_HASH_SUFFIX})
|
||||
elseif(DEFINED PKG_ARGS_HASH_URL)
|
||||
set(hash_url ${PKG_ARGS_HASH_URL})
|
||||
set(pkg_hash "SHA512=${PKG_ARGS_HASH}")
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"No hash or hash URL found")
|
||||
endif()
|
||||
|
||||
if(DEFINED hash_url)
|
||||
set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${PKG_ARGS_NAME}.hash)
|
||||
|
||||
# TODO(crueter): This is kind of a bad solution
|
||||
# because "technically" the hash is invalidated each week
|
||||
# but it works for now kjsdnfkjdnfjksdn
|
||||
string(TOLOWER ${PKG_ARGS_NAME} lowername)
|
||||
if(NOT EXISTS ${outfile} AND NOT EXISTS
|
||||
${CPM_SOURCE_CACHE}/${lowername}/${pkg_key})
|
||||
file(DOWNLOAD ${hash_url} ${outfile})
|
||||
endif()
|
||||
|
||||
if(EXISTS ${outfile})
|
||||
file(READ ${outfile} pkg_hash_tmp)
|
||||
endif()
|
||||
|
||||
if(DEFINED ${pkg_hash_tmp})
|
||||
set(pkg_hash "${hash_algo}=${pkg_hash_tmp}")
|
||||
endif()
|
||||
cpm_utils_message(FATAL_ERROR ${PKG_ARGS_NAME}
|
||||
"No hash defined")
|
||||
endif()
|
||||
|
||||
macro(set_precedence local force)
|
||||
@@ -545,9 +491,9 @@ function(AddPackage)
|
||||
set_precedence(ON OFF)
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_VERSION)
|
||||
if(DEFINED PKG_ARGS_MIN_VERSION)
|
||||
list(APPEND EXTRA_ARGS
|
||||
VERSION ${PKG_ARGS_VERSION})
|
||||
VERSION ${PKG_ARGS_MIN_VERSION})
|
||||
endif()
|
||||
|
||||
if (PKG_ARGS_FIND_PACKAGE_ARGUMENTS)
|
||||
@@ -575,10 +521,10 @@ function(AddPackage)
|
||||
endif()
|
||||
|
||||
CPMAddPackage(
|
||||
NAME "${PKG_ARGS_NAME}"
|
||||
URL "${pkg_url}"
|
||||
URL_HASH "${pkg_hash}"
|
||||
CUSTOM_CACHE_KEY "${pkg_key}"
|
||||
NAME ${PKG_ARGS_NAME}
|
||||
URL ${pkg_url}
|
||||
URL_HASH ${pkg_hash}
|
||||
CUSTOM_CACHE_KEY ${pkg_key}
|
||||
|
||||
EXCLUDE_FROM_ALL ON
|
||||
|
||||
@@ -593,15 +539,15 @@ function(AddPackage)
|
||||
if(DEFINED PKG_ARGS_SHA)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_SHA})
|
||||
elseif(DEFINED PKG_ARGS_GIT_VERSION)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_GIT_VERSION})
|
||||
elseif(DEFINED PKG_ARGS_TAG)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_TAG})
|
||||
elseif(DEFINED PKG_ARGS_VERSION)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_VERSION})
|
||||
elseif(DEFINED PKG_ARGS_TAG)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_TAG})
|
||||
elseif(DEFINED PKG_ARGS_MIN_VERSION)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_MIN_VERSION})
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"Package has no specified sha, tag, or version")
|
||||
@@ -638,7 +584,8 @@ function(AddCIPackage)
|
||||
REPO
|
||||
PACKAGE
|
||||
EXTENSION
|
||||
MIN_VERSION)
|
||||
MIN_VERSION
|
||||
GIT_HOST)
|
||||
|
||||
set(multiValueArgs DISABLED_PLATFORMS)
|
||||
|
||||
@@ -650,6 +597,7 @@ function(AddCIPackage)
|
||||
"${multiValueArgs}"
|
||||
${ARGN})
|
||||
|
||||
# TODO: use cpm_utils_message
|
||||
if(NOT DEFINED PKG_ARGS_VERSION)
|
||||
message(FATAL_ERROR "[CPMUtil] VERSION is required")
|
||||
endif()
|
||||
@@ -675,6 +623,12 @@ function(AddCIPackage)
|
||||
set(ARTIFACT_EXT ${PKG_ARGS_EXTENSION})
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED PKG_ARGS_GIT_HOST)
|
||||
set(ARTIFACT_GIT_HOST "github.com")
|
||||
else()
|
||||
set(ARTIFACT_GIT_HOST "${PKG_ARGS_GIT_HOST}")
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_MIN_VERSION)
|
||||
set(ARTIFACT_MIN_VERSION ${PKG_ARGS_MIN_VERSION})
|
||||
endif()
|
||||
@@ -689,49 +643,81 @@ function(AddCIPackage)
|
||||
set(ARTIFACT_REPO ${PKG_ARGS_REPO})
|
||||
set(ARTIFACT_PACKAGE ${PKG_ARGS_PACKAGE})
|
||||
|
||||
if(MSVC AND ARCHITECTURE_x86_64)
|
||||
set(pkgname windows-amd64)
|
||||
elseif(MSVC AND ARCHITECTURE_arm64)
|
||||
set(pkgname windows-arm64)
|
||||
elseif(MINGW AND ARCHITECTURE_x86_64)
|
||||
set(pkgname mingw-amd64)
|
||||
elseif(MINGW AND ARCHITECTURE_arm64)
|
||||
set(pkgname mingw-arm64)
|
||||
elseif(ANDROID AND ARCHITECTURE_x86_64)
|
||||
set(pkgname android-x86_64)
|
||||
elseif(ANDROID AND ARCHITECTURE_arm64)
|
||||
set(pkgname android-aarch64)
|
||||
elseif(PLATFORM_SUN)
|
||||
set(pkgname solaris-amd64)
|
||||
elseif(PLATFORM_FREEBSD)
|
||||
set(pkgname freebsd-amd64)
|
||||
elseif(PLATFORM_LINUX AND ARCHITECTURE_x86_64)
|
||||
set(pkgname linux-amd64)
|
||||
elseif(PLATFORM_LINUX AND ARCHITECTURE_arm64)
|
||||
set(pkgname linux-aarch64)
|
||||
elseif(APPLE AND NOT IOS)
|
||||
set(pkgname macos-universal)
|
||||
elseif(IOS AND ARCHITECTURE_arm64)
|
||||
set(pkgname ios-aarch64)
|
||||
# TODO: Use amd64/aarch64 naming for everything.
|
||||
# Also drop macos universal
|
||||
|
||||
if (MSVC)
|
||||
set(platname windows)
|
||||
elseif(MINGW)
|
||||
set(platname mingw)
|
||||
elseif(ANDROID)
|
||||
set(platname android)
|
||||
elseif(LINUX)
|
||||
set(platname linux)
|
||||
elseif(IOS)
|
||||
set(platname ios)
|
||||
elseif(APPLE)
|
||||
set(platname macos)
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"Unsupported platform ${CMAKE_SYSTEM_NAME} for CI packages")
|
||||
endif()
|
||||
|
||||
if (DEFINED pkgname AND NOT "${pkgname}" IN_LIST DISABLED_PLATFORMS)
|
||||
if (APPLE AND NOT IOS)
|
||||
set(archname universal)
|
||||
elseif((WIN32 OR LINUX) AND CPMUTIL_AMD64)
|
||||
set(archname amd64)
|
||||
elseif(WIN32 AND CPMUTIL_ARM64)
|
||||
set(archname arm64)
|
||||
elseif((IOS OR LINUX OR ANDROID) AND CPMUTIL_ARM64)
|
||||
set(archname aarch64)
|
||||
elseif(ANDROID AND CPMUTIL_AMD64)
|
||||
set(archname x86_64)
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"Unsupported platform/arch combo for CI packages")
|
||||
endif()
|
||||
|
||||
if (DEFINED platname AND DEFINED archname)
|
||||
set(pkgname ${platname}-${archname})
|
||||
endif()
|
||||
|
||||
if (DEFINED pkgname
|
||||
AND NOT "${pkgname}" IN_LIST DISABLED_PLATFORMS)
|
||||
set(ARTIFACT
|
||||
"${ARTIFACT_NAME}-${pkgname}-${ARTIFACT_VERSION}.${ARTIFACT_EXT}")
|
||||
|
||||
if (PKG_ARGS_MODULE_PATH)
|
||||
list(APPEND EXTRA_ARGS MODULE_PATH)
|
||||
set(EXTRA_ARGS MODULE_PATH)
|
||||
endif()
|
||||
|
||||
# download sha512sum file
|
||||
# TODO:
|
||||
set(sha512sum_url
|
||||
"https://${ARTIFACT_GIT_HOST}/${ARTIFACT_REPO}/releases/download/v${ARTIFACT_VERSION}/${ARTIFACT}.sha512sum")
|
||||
set(sha512sum_file
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/.cpmutil_${ARTIFACT}_sha512sum")
|
||||
|
||||
file(DOWNLOAD "${sha512sum_url}" "${sha512sum_file}"
|
||||
STATUS sha512sum_status)
|
||||
list(GET sha512sum_status 0 sha512sum_error)
|
||||
|
||||
if(sha512sum_error)
|
||||
message(FATAL_ERROR "[CPMUtil] Failed to download sha512sum "
|
||||
"for ${ARTIFACT_NAME} from ${sha512sum_url}")
|
||||
endif()
|
||||
|
||||
file(READ "${sha512sum_file}" sha512sum_hash)
|
||||
string(STRIP "${sha512sum_hash}" sha512sum_hash)
|
||||
file(REMOVE "${sha512sum_file}")
|
||||
|
||||
AddPackage(
|
||||
NAME ${ARTIFACT_PACKAGE}
|
||||
REPO ${ARTIFACT_REPO}
|
||||
TAG "v${ARTIFACT_VERSION}"
|
||||
GIT_VERSION ${ARTIFACT_VERSION}
|
||||
MIN_VERSION ${ARTIFACT_VERSION}
|
||||
ARTIFACT ${ARTIFACT}
|
||||
|
||||
KEY "${pkgname}-${ARTIFACT_VERSION}"
|
||||
HASH_SUFFIX sha512sum
|
||||
HASH ${sha512sum_hash}
|
||||
FORCE_BUNDLED_PACKAGE ON
|
||||
${EXTRA_ARGS})
|
||||
|
||||
@@ -761,7 +747,6 @@ function(AddQt repo version)
|
||||
REPO ${repo}
|
||||
DISABLED_PLATFORMS
|
||||
android-x86_64 android-aarch64
|
||||
freebsd-amd64 solaris-amd64 openbsd-amd64
|
||||
MODULE_PATH)
|
||||
|
||||
find_package(Qt6 REQUIRED PATHS ${Qt6_SOURCE_DIR} NO_DEFAULT_PATH)
|
||||
|
||||
+371
-112
@@ -1,18 +1,230 @@
|
||||
{
|
||||
"biscuit": {
|
||||
"hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a",
|
||||
"min_version": "0.9.1",
|
||||
"repo": "lioncash/biscuit",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "0.19.0"
|
||||
},
|
||||
"boost": {
|
||||
"artifact": "%TAG%-cmake.tar.xz",
|
||||
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
||||
"hash": "6ae6e94664fe7f2fb01976b59b276ac5df8085c7503fa829d810fbfe495960cfec44fa2c36e2cb23480bc19c956ed199d4952b02639a00a6c07625d4e7130c2d",
|
||||
"min_version": "1.57",
|
||||
"package": "Boost",
|
||||
"patches": [
|
||||
"0001-clang-cl.patch"
|
||||
],
|
||||
"repo": "boostorg/boost",
|
||||
"tag": "boost-%VERSION%",
|
||||
"version": "1.90.0"
|
||||
},
|
||||
"boost_headers": {
|
||||
"bundled": true,
|
||||
"hash": "4ef845775e2277a8104ded6ddf749aa262ce52cf8438042869a048f9a0156dd772fbbcfa74efa1378fecef339b7286f6fe4b4feb5c45d49966b35d08e3e83507",
|
||||
"repo": "boostorg/headers",
|
||||
"tag": "boost-%VERSION%",
|
||||
"version": "1.90.0"
|
||||
},
|
||||
"catch2": {
|
||||
"hash": "7eea385d79d88a5690cde131fe7ccda97d5c54ea09d6f515000d7bf07c828809d61c1ac99912c1ee507cf933f61c1c47ecdcc45df7850ffa82714034b0fccf35",
|
||||
"min_version": "3.0.1",
|
||||
"package": "Catch2",
|
||||
"patches": [
|
||||
"0001-solaris-isnan-fix.patch"
|
||||
],
|
||||
"repo": "catchorg/Catch2",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "3.13.0"
|
||||
},
|
||||
"cpp-jwt": {
|
||||
"find_args": "CONFIG",
|
||||
"hash": "d11cbd5ddb3197b4c5ca15679bcd76a49963e7b530b7dd132db91e042925efa20dfb2c24ccfbe7ef82a7012af80deff0f72ee25851312ae80381a462df8534b8",
|
||||
"min_version": "1.4",
|
||||
"options": [
|
||||
"CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF"
|
||||
],
|
||||
"patches": [
|
||||
"0001-fix-missing-decl.patch"
|
||||
],
|
||||
"repo": "arun11299/cpp-jwt",
|
||||
"sha": "7f24eb4c32",
|
||||
"version": "1.5.1"
|
||||
},
|
||||
"cubeb": {
|
||||
"find_args": "CONFIG",
|
||||
"hash": "8a4bcb2f83ba590f52c66626e895304a73eb61928dbc57777e1822e55378e3568366f17f9da4b80036cc2ef4ea9723c32abf6e7d9bbe00fb03654f0991596ab0",
|
||||
"options": [
|
||||
"USE_SANITIZERS OFF",
|
||||
"BUILD_TESTS OFF",
|
||||
"BUILD_TOOLS OFF",
|
||||
"BUNDLE_SPEEX ON"
|
||||
],
|
||||
"repo": "mozilla/cubeb",
|
||||
"sha": "fa02160712",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
"discord-rpc": {
|
||||
"find_args": "MODULE",
|
||||
"hash": "8213c43dcb0f7d479f5861091d111ed12fbdec1e62e6d729d65a4bc181d82f48a35d5fd3cd5c291f2393ac7c9681eabc6b76609755f55376284c8a8d67e148f3",
|
||||
"package": "DiscordRPC",
|
||||
"repo": "eden-emulator/discord-rpc",
|
||||
"sha": "0d8b2d6a37",
|
||||
"version": "3.4.1"
|
||||
},
|
||||
"enet": {
|
||||
"find_args": "MODULE",
|
||||
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
|
||||
"min_version": "1.3",
|
||||
"repo": "lsalzman/enet",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "1.3.18"
|
||||
},
|
||||
"ffmpeg": {
|
||||
"bundled": true,
|
||||
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
|
||||
"repo": "FFmpeg/FFmpeg",
|
||||
"sha": "c7b5f1537d",
|
||||
"version": "8.0.1"
|
||||
},
|
||||
"ffmpeg-ci": {
|
||||
"ci": true,
|
||||
"min_version": "4.1",
|
||||
"name": "ffmpeg",
|
||||
"package": "FFmpeg",
|
||||
"repo": "crueter-ci/FFmpeg",
|
||||
"version": "8.0.1-c7b5f1537d"
|
||||
},
|
||||
"fmt": {
|
||||
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
|
||||
"min_version": "8",
|
||||
"repo": "fmtlib/fmt",
|
||||
"tag": "%VERSION%",
|
||||
"version": "12.1.0"
|
||||
},
|
||||
"frozen": {
|
||||
"hash": "b8dfe741c82bc178dfc9749d4ab5a130cee718d9ee7b71d9b547cf5f7f23027ed0152ad250012a8546399fcc1e12187efc68d89d6731256c4d2df7d04eef8d5c",
|
||||
"package": "frozen",
|
||||
"repo": "serge-sans-paille/frozen",
|
||||
"sha": "61dce5ae18",
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"gamemode": {
|
||||
"find_args": "MODULE",
|
||||
"hash": "e87ec14ed3e826d578ebf095c41580069dda603792ba91efa84f45f4571a28f4d91889675055fd6f042d7dc25b0b9443daf70963ae463e38b11bcba95f4c65a9",
|
||||
"min_version": "1.7",
|
||||
"repo": "FeralInteractive/gamemode",
|
||||
"sha": "ce6fe122f3",
|
||||
"version": "1.8.2"
|
||||
},
|
||||
"httplib": {
|
||||
"find_args": "MODULE GLOBAL",
|
||||
"hash": "159ed94965018f2a371d45a3bfc1961e5fb1549e501ded70a6b4532d7fe99d0579c18b5195aff6e35f96f399b426cea2650ec9fb75ef80d4c9edeccb51f2e6c9",
|
||||
"options": [
|
||||
"HTTPLIB_REQUIRE_OPENSSL OFF",
|
||||
"HTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES ON"
|
||||
],
|
||||
"patches": [
|
||||
"0001-mingw.patch"
|
||||
],
|
||||
"repo": "yhirose/cpp-httplib",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "0.46.0"
|
||||
},
|
||||
"lagoon": {
|
||||
"hash": "b9380f99c6effaeccc6d8f81d4942e852c11ad28613df637e155451556ae5826f93765bee57a5c87a9740d2bd1db463ad0f55a947772fe9d57eeabae3efa373e",
|
||||
"repo": "loongson-community/lagoon",
|
||||
"tag": "%VERSION%",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"libadrenotools": {
|
||||
"hash": "f6526620cb752876edc5ed4c0925d57b873a8218ee09ad10859ee476e9333259784f61c1dcc55a2bcba597352d18aff22cd2e4c1925ec2ae94074e09d7da2265",
|
||||
"patches": [
|
||||
"0001-linkerns-cpm.patch"
|
||||
],
|
||||
"repo": "eden-emulator/libadrenotools",
|
||||
"sha": "8ba23b42d7",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"libusb": {
|
||||
"find_args": "MODULE",
|
||||
"hash": "98c5f7940ff06b25c9aa65aa98e23de4c79a4c1067595f4c73cc145af23a1c286639e1ba11185cd91bab702081f307b973f08a4c9746576dc8d01b3620a3aeb5",
|
||||
"patches": [
|
||||
"0001-netbsd-gettime.patch"
|
||||
],
|
||||
"repo": "libusb/libusb",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "1.0.29"
|
||||
},
|
||||
"llvm-mingw": {
|
||||
"artifact": "clang-rt-builtins.tar.zst",
|
||||
"git_host": "git.eden-emu.dev",
|
||||
"hash": "d902392caf94e84f223766e2cc51ca5fab6cae36ab8dc6ef9ef6a683ab1c483bfcfe291ef0bd38ab16a4ecc4078344fa8af72da2f225ab4c378dee23f6186181",
|
||||
"repo": "eden-emu/llvm-mingw",
|
||||
"tag": "%VERSION%",
|
||||
"version": "20250828"
|
||||
},
|
||||
"lz4": {
|
||||
"hash": "35c21a5d9cfb5bbf314a5321d02b36819491d2ee3cf8007030ca09d13ca4dae672247b7aeab553e973093604fc48221cb03dc92197c6efe8fc3746891363fdab",
|
||||
"name": "lz4",
|
||||
"repo": "lz4/lz4",
|
||||
"sha": "ebb370ca83",
|
||||
"source_subdir": "build/cmake",
|
||||
"version": "1.10.0"
|
||||
},
|
||||
"moltenvk": {
|
||||
"artifact": "MoltenVK-macOS.tar",
|
||||
"bundled": true,
|
||||
"hash": "5695b36ca5775819a71791557fcb40a4a5ee4495be6b8442e0b666d0c436bec02aae68cc6210183f7a5c986bdbec0e117aecfad5396e496e9c2fd5c89133a347",
|
||||
"repo": "V380-Ori/Ryujinx.MoltenVK",
|
||||
"tag": "v%VERSION%-ryujinx",
|
||||
"version": "1.4.1"
|
||||
},
|
||||
"nlohmann": {
|
||||
"hash": "6cc1e86261f8fac21cc17a33da3b6b3c3cd5c116755651642af3c9e99bb3538fd42c1bd50397a77c8fb6821bc62d90e6b91bcdde77a78f58f2416c62fc53b97d",
|
||||
"min_version": "3.8",
|
||||
"package": "nlohmann_json",
|
||||
"repo": "nlohmann/json",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "3.12.0"
|
||||
},
|
||||
"oaknut": {
|
||||
"hash": "9697e80a7d5d9bcb3ce51051a9a24962fb90ca79d215f1f03ae6b58da8ba13a63b5dda1b4dde3d26ac6445029696b8ef2883f4e5a777b342bba01283ed293856",
|
||||
"min_version": "2.0.1",
|
||||
"repo": "eden-emulator/oaknut",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "2.0.3"
|
||||
},
|
||||
"oboe": {
|
||||
"bundled": true,
|
||||
"hash": "ce4011afe7345370d4ead3b891cd69a5ef224b129535783586c0ca75051d303ed446e6c7f10bde8da31fff58d6e307f1732a3ffd03b249f9ef1fd48fd4132715",
|
||||
"repo": "google/oboe",
|
||||
"tag": "%VERSION%",
|
||||
"version": "1.10.0"
|
||||
},
|
||||
"openssl": {
|
||||
"hash": "29002ce50cb95a4f4f1d0e9d3f684401fbd4eac34203dc2eef3b6334af5d44aa46bf788b63a6f5c139c383eafb7269ae87a58a9a3ad5912903b9773e545ccc0a",
|
||||
"min_version": "3.0.0",
|
||||
"package": "OpenSSL",
|
||||
"patches": [
|
||||
"0001-add-bundled-cert.patch",
|
||||
"0002-wasm-support.patch"
|
||||
],
|
||||
"repo": "openssl/openssl",
|
||||
"tag": "openssl-%VERSION%",
|
||||
"version": "3.6.2"
|
||||
},
|
||||
"openssl-ci": {
|
||||
"ci": true,
|
||||
"package": "OpenSSL",
|
||||
"min_version": "3.0.0",
|
||||
"name": "openssl",
|
||||
"package": "OpenSSL",
|
||||
"repo": "crueter-ci/OpenSSL",
|
||||
"version": "4.0.0-11b7b6ea3b",
|
||||
"min_version": "3"
|
||||
"version": "4.0.0-11b7b6ea3b"
|
||||
},
|
||||
"openssl-cmake": {
|
||||
"repo": "jimmy-park/openssl-cmake",
|
||||
"hash": "2cc185c924fd70e7d886257ca0caa42b3b8f7f712f2052b4f94dde74759e27022de76178460e18c9bdfc57c366583999e198fbb6052d4e7d91c099d15a0ca63e",
|
||||
"git_version": "3.6.2",
|
||||
"tag": "%VERSION%",
|
||||
"bundled": true,
|
||||
"hash": "2cc185c924fd70e7d886257ca0caa42b3b8f7f712f2052b4f94dde74759e27022de76178460e18c9bdfc57c366583999e198fbb6052d4e7d91c099d15a0ca63e",
|
||||
"options": [
|
||||
"OPENSSL_CONFIGURE_OPTIONS threads"
|
||||
],
|
||||
@@ -20,128 +232,175 @@
|
||||
"0001-cpmutil-compat.patch",
|
||||
"0002-use-ccache.patch",
|
||||
"0003-use-cmake-compiler-flags.patch",
|
||||
"0004-use-shell-wrapper.patch"
|
||||
]
|
||||
},
|
||||
"openssl": {
|
||||
"repo": "openssl/openssl",
|
||||
"package": "OpenSSL",
|
||||
"min_version": "3",
|
||||
"version": "3",
|
||||
"hash": "29002ce50cb95a4f4f1d0e9d3f684401fbd4eac34203dc2eef3b6334af5d44aa46bf788b63a6f5c139c383eafb7269ae87a58a9a3ad5912903b9773e545ccc0a",
|
||||
"git_version": "3.6.2",
|
||||
"tag": "openssl-%VERSION%",
|
||||
"patches": [
|
||||
"0001-add-bundled-cert.patch"
|
||||
]
|
||||
},
|
||||
"boost": {
|
||||
"package": "Boost",
|
||||
"repo": "boostorg/boost",
|
||||
"tag": "boost-%VERSION%",
|
||||
"artifact": "%TAG%-cmake.tar.xz",
|
||||
"hash": "6ae6e94664fe7f2fb01976b59b276ac5df8085c7503fa829d810fbfe495960cfec44fa2c36e2cb23480bc19c956ed199d4952b02639a00a6c07625d4e7130c2d",
|
||||
"git_version": "1.90.0",
|
||||
"version": "1.57",
|
||||
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
||||
"patches": [
|
||||
"0001-clang-cl.patch"
|
||||
]
|
||||
},
|
||||
"fmt": {
|
||||
"repo": "fmtlib/fmt",
|
||||
"0004-use-shell-wrapper.patch",
|
||||
"0005-wasm-support.patch"
|
||||
],
|
||||
"repo": "jimmy-park/openssl-cmake",
|
||||
"tag": "%VERSION%",
|
||||
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
|
||||
"version": "8",
|
||||
"git_version": "12.1.0"
|
||||
},
|
||||
"lz4": {
|
||||
"name": "lz4",
|
||||
"repo": "lz4/lz4",
|
||||
"sha": "ebb370ca83",
|
||||
"hash": "35c21a5d9cfb5bbf314a5321d02b36819491d2ee3cf8007030ca09d13ca4dae672247b7aeab553e973093604fc48221cb03dc92197c6efe8fc3746891363fdab",
|
||||
"source_subdir": "build/cmake"
|
||||
},
|
||||
"nlohmann": {
|
||||
"package": "nlohmann_json",
|
||||
"repo": "nlohmann/json",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "6cc1e86261f8fac21cc17a33da3b6b3c3cd5c116755651642af3c9e99bb3538fd42c1bd50397a77c8fb6821bc62d90e6b91bcdde77a78f58f2416c62fc53b97d",
|
||||
"version": "3.8",
|
||||
"git_version": "3.12.0"
|
||||
},
|
||||
"zlib": {
|
||||
"package": "ZLIB",
|
||||
"repo": "madler/zlib",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
|
||||
"version": "1.2",
|
||||
"git_version": "1.3.2",
|
||||
"options": [
|
||||
"ZLIB_BUILD_SHARED OFF",
|
||||
"ZLIB_INSTALL OFF"
|
||||
]
|
||||
},
|
||||
"zstd": {
|
||||
"repo": "facebook/zstd",
|
||||
"sha": "b8d6101fba",
|
||||
"hash": "cc5ad4b119a9c2ea57f0b71eeff01113bb506e0d17000159c5409cb8236d22e38c52d5e9e97e7947a4bf1b2dfc44b6c503ab2d9aedbd59458435c6a2849cb029",
|
||||
"version": "1.5",
|
||||
"source_subdir": "build/cmake",
|
||||
"find_args": "MODULE",
|
||||
"options": [
|
||||
"ZSTD_BUILD_SHARED OFF"
|
||||
]
|
||||
"version": "3.6.2"
|
||||
},
|
||||
"opus": {
|
||||
"package": "Opus",
|
||||
"repo": "xiph/opus",
|
||||
"sha": "a3f0ec02b3",
|
||||
"hash": "9506147b0de35befda8633ff272981cc2575c860874791bd455b752f797fd7dbd1079f0ba42ccdd7bb1fe6773fa5e84b3d75667c2883dd1fb2d0e4a5fa4f8387",
|
||||
"version": "1.3",
|
||||
"find_args": "MODULE",
|
||||
"hash": "9506147b0de35befda8633ff272981cc2575c860874791bd455b752f797fd7dbd1079f0ba42ccdd7bb1fe6773fa5e84b3d75667c2883dd1fb2d0e4a5fa4f8387",
|
||||
"min_version": "1.3",
|
||||
"options": [
|
||||
"OPUS_PRESUME_NEON ON"
|
||||
],
|
||||
"package": "Opus",
|
||||
"patches": [
|
||||
"0001-disable-clang-runtime-neon.patch",
|
||||
"0002-no-install.patch"
|
||||
]
|
||||
},
|
||||
"boost_headers": {
|
||||
"repo": "boostorg/headers",
|
||||
"sha": "95930ca8f5",
|
||||
"hash": "8a07d7a6f0065587d3005a83481a794704ae22e773b9f336fbd89ed230aaa7b4c86c03edcbae30bba8b3e20839c3131eaa2dceac037ef811533ef4eadc53b15b",
|
||||
"bundled": true
|
||||
},
|
||||
"llvm-mingw": {
|
||||
"repo": "eden-emu/llvm-mingw",
|
||||
"git_host": "git.eden-emu.dev",
|
||||
"tag": "%VERSION%",
|
||||
"version": "20250828",
|
||||
"artifact": "clang-rt-builtins.tar.zst",
|
||||
"hash": "d902392caf94e84f223766e2cc51ca5fab6cae36ab8dc6ef9ef6a683ab1c483bfcfe291ef0bd38ab16a4ecc4078344fa8af72da2f225ab4c378dee23f6186181"
|
||||
},
|
||||
"vulkan-validation-layers": {
|
||||
"package": "VVL",
|
||||
"repo": "KhronosGroup/Vulkan-ValidationLayers",
|
||||
"tag": "vulkan-sdk-%VERSION%",
|
||||
"git_version": "1.4.341.0",
|
||||
"artifact": "android-binaries-%VERSION%.zip",
|
||||
"hash": "8812ae84cbe49e6a3418ade9c458d3be6d74a3dffd319d4502007b564d580998056e8190414368ec11b27bc83993c7a0dad713c31bcc3d9553b51243efee3753"
|
||||
],
|
||||
"repo": "xiph/opus",
|
||||
"sha": "a3f0ec02b3",
|
||||
"version": "1.5.2"
|
||||
},
|
||||
"quazip": {
|
||||
"package": "QuaZip-Qt6",
|
||||
"repo": "stachenov/quazip",
|
||||
"sha": "2e95c9001b",
|
||||
"hash": "609c240c7f029ac26a37d8fbab51bc16284e05e128b78b9b9c0e95d083538c36047a67d682759ac990e4adb0eeb90f04f1ea7fe2253bbda7e7e3bcce32e53dd8",
|
||||
"version": "1.3",
|
||||
"git_version": "1.5",
|
||||
"min_version": "1.3",
|
||||
"options": [
|
||||
"QUAZIP_QT_MAJOR_VERSION 6",
|
||||
"QUAZIP_INSTALL OFF",
|
||||
"QUAZIP_ENABLE_QTEXTCODEC OFF",
|
||||
"QUAZIP_BZIP2 OFF"
|
||||
]
|
||||
],
|
||||
"package": "QuaZip-Qt6",
|
||||
"repo": "stachenov/quazip",
|
||||
"sha": "2e95c9001b",
|
||||
"version": "1.5"
|
||||
},
|
||||
"sdl3": {
|
||||
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
|
||||
"min_version": "3.2.10",
|
||||
"package": "SDL3",
|
||||
"repo": "libsdl-org/SDL",
|
||||
"tag": "release-%VERSION%",
|
||||
"version": "3.4.8"
|
||||
},
|
||||
"sdl3-ci": {
|
||||
"ci": true,
|
||||
"min_version": "3.2.10",
|
||||
"name": "SDL3",
|
||||
"package": "SDL3",
|
||||
"repo": "crueter-ci/SDL3",
|
||||
"version": "3.4.8-d57c3b685c"
|
||||
},
|
||||
"simpleini": {
|
||||
"find_args": "MODULE",
|
||||
"hash": "b937c18a7b6277d77ca7ebfb216af4984810f77af4c32d101b7685369a4bd5eb61406223f82698e167e6311a728d07415ab59639fdf19eff71ad6dc2abfda989",
|
||||
"package": "SimpleIni",
|
||||
"repo": "brofield/simpleini",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "4.25"
|
||||
},
|
||||
"sirit": {
|
||||
"artifact": "sirit-source-%VERSION%.tar.zst",
|
||||
"find_args": "CONFIG",
|
||||
"options": [
|
||||
"SIRIT_USE_SYSTEM_SPIRV_HEADERS ON"
|
||||
],
|
||||
"repo": "eden-emulator/sirit",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "1.0.5",
|
||||
"hash": "10b3ff60bdcad428bb4f54360ff749212333a1d24c0b3ed99e466b1bfcf99d2db6cf596c0f965854a2095dfef9b7ce4e045edb070fa9f76eb3b295ab03a4a293"
|
||||
},
|
||||
"sirit-ci": {
|
||||
"ci": true,
|
||||
"name": "sirit",
|
||||
"package": "sirit",
|
||||
"repo": "eden-emulator/sirit",
|
||||
"version": "1.0.5"
|
||||
},
|
||||
"spirv-headers": {
|
||||
"hash": "cae8cd179c9013068876908fecc1d158168310ad6ac250398a41f0f5206ceff6469e2aaeab9c820bce9d1b08950c725c89c46e94b89a692be9805432cf749396",
|
||||
"options": [
|
||||
"SPIRV_WERROR OFF"
|
||||
],
|
||||
"package": "SPIRV-Headers",
|
||||
"repo": "KhronosGroup/SPIRV-Headers",
|
||||
"sha": "04f10f650d"
|
||||
},
|
||||
"tzdb": {
|
||||
"artifact": "%VERSION%.tar.gz",
|
||||
"git_host": "git.eden-emu.dev",
|
||||
"hash": "cce65a12bf90f4ead43b24a0b95dfad77ac3d9bfbaaf66c55e6701346e7a1e44ca5d2f23f47ee35ee02271eb1082bf1762af207aad9fb236f1c8476812d008ed",
|
||||
"package": "nx_tzdb",
|
||||
"repo": "eden-emu/tzdb_to_nx",
|
||||
"tag": "%VERSION%",
|
||||
"version": "230326"
|
||||
},
|
||||
"unordered-dense": {
|
||||
"bundled": true,
|
||||
"find_args": "CONFIG",
|
||||
"hash": "d2106f6640f6bfb81755e4b8bfb64982e46ec4a507cacdb38f940123212ccf35a20b43c70c6f01d7bfb8c246d1a16f7845d8052971949cea9def1475e3fa02c8",
|
||||
"package": "unordered_dense",
|
||||
"patches": [
|
||||
"0001-avoid-memset-when-clearing-an-empty-table.patch"
|
||||
],
|
||||
"repo": "martinus/unordered_dense",
|
||||
"sha": "7b55cab841",
|
||||
"version": "4.8.1"
|
||||
},
|
||||
"vulkan-headers": {
|
||||
"hash": "d2846ea228415772645eea4b52a9efd33e6a563043dd3de059e798be6391a8f0ca089f455ae420ff22574939ed0f48ed7c6ff3d5a9987d5231dbf3b3f89b484b",
|
||||
"min_version": "1.4.317",
|
||||
"package": "VulkanHeaders",
|
||||
"repo": "KhronosGroup/Vulkan-Headers",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "1.4.345"
|
||||
},
|
||||
"vulkan-memory-allocator": {
|
||||
"find_args": "CONFIG",
|
||||
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
|
||||
"package": "VulkanMemoryAllocator",
|
||||
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "3.3.0"
|
||||
},
|
||||
"vulkan-utility-libraries": {
|
||||
"hash": "114f6b237a6dcba923ccc576befb5dea3f1c9b3a30de7dc741f234a831d1c2d52d8a224afb37dd57dffca67ac0df461eaaab6a5ab5e503b393f91c166680c3e1",
|
||||
"package": "VulkanUtilityLibraries",
|
||||
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "1.4.345"
|
||||
},
|
||||
"vulkan-validation-layers": {
|
||||
"artifact": "android-binaries-%VERSION%.zip",
|
||||
"hash": "8812ae84cbe49e6a3418ade9c458d3be6d74a3dffd319d4502007b564d580998056e8190414368ec11b27bc83993c7a0dad713c31bcc3d9553b51243efee3753",
|
||||
"package": "VVL",
|
||||
"repo": "KhronosGroup/Vulkan-ValidationLayers",
|
||||
"tag": "vulkan-sdk-%VERSION%",
|
||||
"version": "1.4.341.0"
|
||||
},
|
||||
"xbyak": {
|
||||
"hash": "b6475276b2faaeb315734ea8f4f8bd87ededcee768961b39679bee547e7f3e98884d8b7851e176d861dab30a80a76e6ea302f8c111483607dde969b4797ea95a",
|
||||
"package": "xbyak",
|
||||
"repo": "herumi/xbyak",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "7.35.2"
|
||||
},
|
||||
"zlib": {
|
||||
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
|
||||
"min_version": "1.2",
|
||||
"options": [
|
||||
"ZLIB_BUILD_SHARED OFF",
|
||||
"ZLIB_INSTALL OFF"
|
||||
],
|
||||
"package": "ZLIB",
|
||||
"repo": "madler/zlib",
|
||||
"tag": "v%VERSION%",
|
||||
"version": "1.3.2"
|
||||
},
|
||||
"zstd": {
|
||||
"find_args": "MODULE",
|
||||
"hash": "cc5ad4b119a9c2ea57f0b71eeff01113bb506e0d17000159c5409cb8236d22e38c52d5e9e97e7947a4bf1b2dfc44b6c503ab2d9aedbd59458435c6a2849cb029",
|
||||
"min_version": "1.5",
|
||||
"options": [
|
||||
"ZSTD_BUILD_SHARED OFF"
|
||||
],
|
||||
"repo": "facebook/zstd",
|
||||
"sha": "b8d6101fba",
|
||||
"source_subdir": "build/cmake",
|
||||
"version": "1.5.7"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+620
-603
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+320
-314
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
Vendored
+302
-297
File diff suppressed because it is too large
Load Diff
+320
@@ -0,0 +1,320 @@
|
||||
# CPMUtil
|
||||
|
||||
CPMUtil is a wrapper around CPM that aims to reduce boilerplate and add useful utility functions to make dependency management a piece of cake.
|
||||
|
||||
- [CPMUtil](#cpmutil)
|
||||
- [Global Options](#global-options)
|
||||
- [About](#about)
|
||||
- [Common Properties](#common-properties)
|
||||
- [Standard Packages](#standard-packages)
|
||||
- [Versioning](#versioning)
|
||||
- [Patches](#patches)
|
||||
- [Pre-built CI Packages](#pre-built-ci-packages)
|
||||
- [Usage](#usage)
|
||||
- [Addendum: Cache Storage](#addendum-cache-storage)
|
||||
- [Addendum: Making Patches](#addendum-making-patches)
|
||||
- [Addendum: Package Identification Lists](#addendum-package-identification-lists)
|
||||
- [Addendum: Notes for Packagers](#addendum-notes-for-packagers)
|
||||
- [Network Sandbox](#network-sandbox)
|
||||
- [Unsandboxed](#unsandboxed)
|
||||
- [Addendum: Dependent Packages](#addendum-dependent-packages)
|
||||
- [Example: Vulkan](#example-vulkan)
|
||||
- [Addendum: Module Path Packages](#addendum-module-path-packages)
|
||||
- [Example: OpenSSL](#example-openssl)
|
||||
- [Addendum: Adding Qt](#addendum-adding-qt)
|
||||
|
||||
## Global Options
|
||||
|
||||
- `CPMUTIL_FORCE_SYSTEM` (default `OFF`): Require all CPM dependencies to use system packages. NOT RECOMMENDED!
|
||||
- You may optionally override this (section)
|
||||
- `CPMUTIL_FORCE_BUNDLED` (default `ON` on MSVC and Android, `OFF` elsewhere): Require all CPM dependencies to use bundled packages.
|
||||
- `CPMUTIL_PATCH_DIR` (default `${PROJECT_SOURCE_DIR}/.patch`): Path to patches used in packages. Stored as `<PATCH DIR>/json-package-name/0001-patch-name.patch`, etc.
|
||||
- `CPM_SOURCE_CACHE` (default `${PROJECT_SOURCE_DIR}/.cache/cpm`): Where downloaded dependencies get stored.
|
||||
|
||||
## About
|
||||
|
||||
CPMUtil works by defining dependencies in a JSON file, `cpmfile.json`, and calling `AddJsonPackage`. These dependencies generally must define, at minimum:
|
||||
|
||||
- The repository and Git host
|
||||
- A release artifact, commit, or tag archive to download
|
||||
- A SHA512 sum for the downloaded artifact
|
||||
|
||||
And may optionally define other properties like:
|
||||
|
||||
- The minimum version for system packages
|
||||
- The package name used for system packages (this defaults to the json key if undefined)
|
||||
- In-tree source patches
|
||||
- Options passed to CMake
|
||||
- Options passed to find_package
|
||||
|
||||
For instance:
|
||||
|
||||
```json
|
||||
"fmt": {
|
||||
"repo": "fmtlib/fmt",
|
||||
"tag": "12.1.0",
|
||||
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
|
||||
"min_version": "8",
|
||||
"options": [
|
||||
"FMT_TEST ON"
|
||||
],
|
||||
"patches": [
|
||||
"0001-disable-reference-copy.patch"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Calling `AddJsonPackage(fmt)`:
|
||||
|
||||
- Searches for a system package named `fmt` of version 8 or higher
|
||||
- If found, uses the system package and caches it for future use
|
||||
- If not found:
|
||||
- Downloads fmt 12.1.0 from the GitHub Archive into `.cache/cpm/fmt/12.1.0`
|
||||
- Verifies the hash
|
||||
- Applies the `0001-disable-reference-copy.patch` patch to the source tree
|
||||
- Sets `FMT_TEST` to `ON`
|
||||
- Adds the downloaded directory to CMake
|
||||
- Now, future `find_package(fmt)` calls will use the downloaded package
|
||||
|
||||
There are two types of packages CPMUtil can define: standard and prebuilt CI packages. Some properties are common to both types, however.
|
||||
|
||||
## Common Properties
|
||||
|
||||
These JSON properties are used by standard and CI packages alike.
|
||||
|
||||
- `package`: The package name used by `find_package` to check for the existence of a system package.
|
||||
- If unset, defaults to the JSON key
|
||||
- `repo`: The Git repository the package is stored in, if applicable.
|
||||
- `version`: The version of the package to download. This is required.
|
||||
- `min_version`: The minimum required version of the package, if a system package is desired.
|
||||
- `git_host`: The Git host the package is stored in, if applicable. Defaults to `github.com`.
|
||||
|
||||
## Standard Packages
|
||||
|
||||
Normal packages, like the prior `fmt` example, *must* also define:
|
||||
|
||||
- `hash`: The SHA512 hash of the downloaded artifact. CPMUtil generally computes this for you.
|
||||
- A valid version/URL identifier:
|
||||
- `url`: Download from a raw URL.
|
||||
- `sha`: A short or fully-qualified Git commit sha. CPMUtil recommends using 10-character wide shas.
|
||||
- `tag`: A Git tag. See [Versioning](#versioning) for its relation to `version`.
|
||||
- `artifact`: A GitHub/Forgejo/Gitea release artifact (requires `tag`). See [Versioning](#versioning) for its relation to `tag` and `version`.
|
||||
|
||||
The following are optional to define:
|
||||
|
||||
- `source_subdir`: A subdirectory containing the `CMakeLists.txt` to configure a project. Useful for projects like `zstd`.
|
||||
- `bundled`: Force the usage of a bundled package. Useful for packages where the system package is broken or nonexistent; e.g. including external fragment shaders.
|
||||
- `find_args`: Additional arguments passed to `find_package`, e.g. `MODULE`
|
||||
- `patches`: Array of in-tree patches to apply to the downloaded source code. See [#Patches](TODO).
|
||||
- `options`: Array of CMake options to apply before configuring the package, e.g. `"FMT_TEST ON"`.
|
||||
|
||||
### Versioning
|
||||
|
||||
When using tags or artifacts, it may be cumbersome to repeat the version multiple times; especially if it's constantly changing. For this purpose, `tag` and `artifact` both support basic version text replacement.
|
||||
|
||||
`tag` can use `%VERSION%` to have its version replaced with the `version` defined for the package, e.g. for OpenSSL; when downloading, `tag` will evaluate to `openssl-3.6.2`:
|
||||
|
||||
```json
|
||||
"openssl": {
|
||||
"repo": "openssl/openssl",
|
||||
"version": "3.6.2",
|
||||
"tag": "openssl-%VERSION%"
|
||||
}
|
||||
```
|
||||
|
||||
`artifact` also supports `%VERSION%` replacement, and can also use `%TAG%` to be replaced by the computed tag. Take this Boost definition:
|
||||
|
||||
```json
|
||||
"boost": {
|
||||
"repo": "boostorg/boost",
|
||||
"tag": "boost-%VERSION%",
|
||||
"version": "1.90.0"
|
||||
}
|
||||
```
|
||||
|
||||
Boost's artifact for this version is stored in `boost-1.90.0-cmake.tar.xz`. Notice that the computed tag,`boost-1.90.0`, is in the name of the artifact! Thus, `artifact` can be either:
|
||||
|
||||
- `boost-%VERSION%-cmake.tar.xz`
|
||||
- Or, even simpler: `%TAG%-cmake.tar.xz`
|
||||
|
||||
Future updates need only change the `version` identifier, and the artifact and tag will automatically be updated!
|
||||
|
||||
### Patches
|
||||
|
||||
CPMUtil is able to apply in-place source tree patches to downloaded packages. These are defined in JSON as an array of names, preferably using `git-format-patch`'s scheme of `<4 digit number>-patch-name.patch`. These are stored in `<CPMUTIL_PATCH_DIR>/<json-key>` (remember that `CPMUTIL_PATCH_DIR` defaults to `$ROOT/.patch`); e.g. `boost` patches would be in `.patch/boost`. Let's say we've made three patches and want to add them; in the Boost JSON definition, we would add:
|
||||
|
||||
```json
|
||||
"patches": [
|
||||
"0001-fix-clang-cl-compilation.patch",
|
||||
"0002-fix-msvc-arm64-compilation.patch",
|
||||
"0003-fix-bsd-linking.patch"
|
||||
]
|
||||
```
|
||||
|
||||
Then, when Boost is downloaded, it will apply these patches in order to the source tree.
|
||||
|
||||
To learn how to make patches, see [Addendum: Making Patches](#addendum-making-patches).
|
||||
|
||||
## Pre-built CI Packages
|
||||
|
||||
The definition and usage of CI packages is subject to change in the very near future.
|
||||
|
||||
CI packages are, in essence, prebuilt binary distributions for libraries. They exist for a few reasons:
|
||||
|
||||
- Creating static libraries for system packages that normally lack them, e.g. Qt/SDL
|
||||
- Reducing duplicated compilation effort on rarely-changing externals, e.g. SDL
|
||||
- Creating debloated prebuilt packages specifically for your project to reduce binary size, e.g. FFmpeg
|
||||
|
||||
CPMUtil is specifically designed to work with a small subset of prebuilt CI packages; namely, those that follow the format of the [crueter-ci spec](https://github.com/crueter-ci/spec/blob/master/README.md).
|
||||
|
||||
To use them, you must add `ci: true` to your package definition. Alongside the common properties, CI packages define the following:
|
||||
|
||||
- `name`: The artifacts' name prefix (required), e.g. `openssl`
|
||||
- `extension`: The artifacts' extension (default `tar.zst`)
|
||||
- `disabled_platforms`: CPMUtil-supported platforms that are not built into this repository.
|
||||
- This is subject to change.
|
||||
|
||||
**Note that `package` is subject to removal here.**
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
"sdl2": {
|
||||
"repo": "crueter-ci/SDL2",
|
||||
"package": "SDL2",
|
||||
"min_version": "2.26.4",
|
||||
"ci": true,
|
||||
"version": "2.32.10-a65111bd2d",
|
||||
"artifact": "SDL2"
|
||||
},
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Once you've defined your package in `cpmfile.json`, simply call `AddJsonPackage(<JSON key>)` and go from there! Specific instructions differ between individual packages, so you're on your own from here.
|
||||
|
||||
If you're only concerned with basic usage, you can stop reading. For more advanced use cases and package management, read these addenda.
|
||||
|
||||
## Addendum: Cache Storage
|
||||
|
||||
CPMUtil stores downloaded packages within `.cache/cpm` by default (see `CPM_SOURCE_CACHE`). Subdirectories stored within are lowercase representations of the `find_package` name for the package; for instance, a `vulkan-headers` definition with `package: "VulkanHeaders"` would be stored in `.cache/cpm/vulkanheaders`.
|
||||
|
||||
Within these subdirectories, additional directories are created for each individual version:
|
||||
|
||||
- A four-character shorthand of `sha`, if defined
|
||||
- If `sha` is not defined, the fully qualified `version` is used
|
||||
|
||||
CI packages use `<platform>-<architecture>-<version>` unconditionally.
|
||||
|
||||
## Addendum: Making Patches
|
||||
|
||||
CPMUtil has a dedicated command for making patches. You're recommended to have Git and a command line editor installed, but CPMUtil is able to work without either. To do so, follow these steps, noting your package's JSON key:
|
||||
|
||||
- Clean-fetch your package: `tools/cpmutil.sh package reset <package>`
|
||||
- Make any necessary modifications to the package source.
|
||||
- You can access the package source directory via `tools/cpmutil.sh package dir <package>`.
|
||||
- Create the patch: `tools/cpmutil.sh package patch <package>`
|
||||
- Follow the on-screen prompts. If you have Git installed, an editor will be opened so you can type your commit message. If not, just type a one-line description.
|
||||
|
||||
And you're done! CPMUtil will automatically create and name the patch, and add it to the list of patches in the JSON definition.
|
||||
|
||||
## Addendum: Package Identification Lists
|
||||
|
||||
CPMUtil will create three lists of dependencies where `AddPackage` or similar was used. Each is in order of addition.
|
||||
|
||||
- `CPM_PACKAGE_NAMES`: The names of packages included by CPMUtil
|
||||
- `CPM_PACKAGE_URLS`: The URLs to project/repo pages of packages
|
||||
- `CPM_PACKAGE_SHAS`: Short version identifiers for each package
|
||||
- If the package was included as a system package, `(system)` is appended thereafter
|
||||
- Packages whose versions can't be deduced will be left as `unknown`.
|
||||
|
||||
For an example of how this might be implemented in an application, see Eden's implementation:
|
||||
|
||||
- [`dep_hashes.h.in`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/dep_hashes.h.in)
|
||||
- [`GenerateDepHashes.cmake`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CMakeModules/GenerateDepHashes.cmake)
|
||||
- [`deps_dialog.cpp`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/yuzu/deps_dialog.cpp)
|
||||
|
||||
## Addendum: Notes for Packagers
|
||||
|
||||
If you are packaging a project that uses CPMUtil, read this!
|
||||
|
||||
### Network Sandbox
|
||||
|
||||
For sandboxed environments (e.g. Gentoo, nixOS) you must install all dependencies to the system beforehand and set `-DCPMUTIL_FORCE_SYSTEM=ON`. If a dependency is missing, get creating!
|
||||
|
||||
Alternatively, if CPMUtil pulls in a package that has no suitable way to install or use a system version, download it separately and pass `-DPackageName_DIR=/path/to/downloaded/dir` (e.g. shaders)
|
||||
|
||||
### Unsandboxed
|
||||
|
||||
For others (AUR, MPR, etc). CPMUtil will handle everything for you, including if some of the project's dependencies are missing from your distribution's repositories. See [`eden-git`](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=eden-git) for an example.
|
||||
|
||||
## Addendum: Dependent Packages
|
||||
|
||||
Consider the following scenario: the Vulkan Headers and Vulkan Utility libraries are both pulled in by my project. In order for both to compile cleanly, their versions *must* match. However, a user may have the Vulkan Headers installed, but *not* the Vulkan Utility Libraries! This can cause a version mismatch where the Utility Libraries expect a much newer version of the Vulkan Headers than the user has installed.
|
||||
|
||||
To solve this, CPMUtil has an `AddDependentPackages` command. This takes a list of JSON package keys that *must* either ALL be installed to the system, or ALL be bundled.
|
||||
|
||||
### Example: Vulkan
|
||||
|
||||
Using the prior Vulkan example:
|
||||
|
||||
```json
|
||||
"vulkan-headers": {
|
||||
"repo": "KhronosGroup/Vulkan-Headers",
|
||||
"package": "VulkanHeaders",
|
||||
"min_version": "1.4.317",
|
||||
"version": "1.4.342",
|
||||
"tag": "v%VERSION%"
|
||||
},
|
||||
"vulkan-utility-libraries": {
|
||||
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
|
||||
"package": "VulkanUtilityLibraries",
|
||||
"version": "1.4.342",
|
||||
"tag": "v%VERSION%"
|
||||
}
|
||||
```
|
||||
|
||||
In CMake:
|
||||
|
||||
```cmake
|
||||
AddDependentPackages(vulkan-headers vulkan-utility-libraries)
|
||||
```
|
||||
|
||||
Possible scenarios:
|
||||
|
||||
- The user has both Vulkan Headers and Vulkan Utility Libraries installed to the system, and both are new enough.
|
||||
- Configuration proceeds without issue.
|
||||
- The user has neither installed, or has a too-old version of Vulkan Headers installed
|
||||
- Configuration proceeds without issue.
|
||||
- The user has a valid Vulkan Headers installed, but not Vulkan Utility Libraries.
|
||||
- CPMUtil instructs the user to either force bundled Vulkan Headers, or install Vulkan Utility Libraries.
|
||||
- The user has both installed, but Vulkan Headers are too old.
|
||||
- CPMUtil instructs the user to install a valid version of Vulkan Headers, or force bundled Vulkan Utility Libraries.
|
||||
|
||||
## Addendum: Module Path Packages
|
||||
|
||||
Sometimes, a prebuilt CI package may be packed in such a way that it's meant to be used in the context of a system install (e.g. pkgconfig or CMakeConfig files). In this case, CPMUtil normally will be unable to configure the downloaded subdirectory. To solve this, you can use `AddJsonPackage`'s `MODULE_PATH` mode, which adds the downloaded source directory to the `CMAKE_MODULE_PATH`.
|
||||
|
||||
### Example: OpenSSL
|
||||
|
||||
Say an OpenSSL CI package is packed to contain its CMake config files rather than a root `CMakeLists.txt`; in this case, you would call:
|
||||
|
||||
```cmake
|
||||
AddJsonPackage(NAME openssl MODULE_PATH)
|
||||
```
|
||||
|
||||
The `NAME` argument is also required, as the parsing is different from the standard single-argument function signature.
|
||||
|
||||
From here, calling `find_package(OpenSSL)` will use the bundled OpenSSL.
|
||||
|
||||
## Addendum: Adding Qt
|
||||
|
||||
If you'd like to use customized Qt builds, CPMUtil provides a convenience function that allows you to add Qt builds. This usage and setup is subject to change.
|
||||
|
||||
See [crueter-ci/Qt](https://github.com/crueter-ci/Qt) for an example of how one might build customized Qt. To add a Qt build to your project, use `AddQt(<repository> <version>)`, e.g.:
|
||||
|
||||
```cmake
|
||||
AddQt(QDash-CI/Qt 6.11.1)
|
||||
```
|
||||
|
||||
Then, call `find_package(Qt6 ...)` and it will pull Qt from your downloaded source.
|
||||
@@ -1,21 +0,0 @@
|
||||
# AddPackage
|
||||
|
||||
- `VERSION` (required): The version to get (the tag will be `v${VERSION}`)
|
||||
- `NAME` (required): Name used within the artifacts
|
||||
- `REPO` (required): CI repository, e.g. `crueter-ci/OpenSSL`
|
||||
- `PACKAGE` (required): `find_package` package name
|
||||
- `EXTENSION`: Artifact extension (default `tar.zst`)
|
||||
- `MIN_VERSION`: Minimum version for `find_package`. Only used if platform does not support this package as a bundled artifact
|
||||
- `DISABLED_PLATFORMS`: List of platforms that lack artifacts for this package. Options:
|
||||
- `windows-amd64`
|
||||
- `windows-arm64`
|
||||
- `mingw-amd64`
|
||||
- `mingw-arm64`
|
||||
- `android-x86_64`
|
||||
- `android-aarch64`
|
||||
- `solaris-amd64`
|
||||
- `freebsd-amd64`
|
||||
- `linux-amd64`
|
||||
- `linux-aarch64`
|
||||
- `macos-universal`
|
||||
- `ios-aarch64`
|
||||
@@ -1,41 +0,0 @@
|
||||
# AddDependentPackage
|
||||
|
||||
Use `AddDependentPackage` when you have multiple packages that are required to all be from the system, OR bundled. This is useful in cases where e.g. versions must absolutely match.
|
||||
|
||||
## Versioning
|
||||
|
||||
Versioning must be handled by the package itself.
|
||||
|
||||
## Examples
|
||||
|
||||
### Vulkan
|
||||
|
||||
`cpmfile.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"vulkan-headers": {
|
||||
"repo": "KhronosGroup/Vulkan-Headers",
|
||||
"package": "VulkanHeaders",
|
||||
"version": "1.4.317",
|
||||
"hash": "26e0ad8fa34ab65a91ca62ddc54cc4410d209a94f64f2817dcdb8061dc621539a4262eab6387e9b9aa421db3dbf2cf8e2a4b041b696d0d03746bae1f25191272",
|
||||
"git_version": "1.4.342",
|
||||
"tag": "v%VERSION%"
|
||||
},
|
||||
"vulkan-utility-libraries": {
|
||||
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
|
||||
"package": "VulkanUtilityLibraries",
|
||||
"hash": "8147370f964fd82c315d6bb89adeda30186098427bf3efaa641d36282d42a263f31e96e4586bfd7ae0410ff015379c19aa4512ba160630444d3d8553afd1ec14",
|
||||
"git_version": "1.4.342",
|
||||
"tag": "v%VERSION%"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`CMakeLists.txt`:
|
||||
|
||||
```cmake
|
||||
AddDependentPackages(vulkan-headers vulkan-utility-libraries)
|
||||
```
|
||||
|
||||
If Vulkan Headers are installed, but NOT Vulkan Utility Libraries, then CPMUtil will throw an error.
|
||||
@@ -1,105 +0,0 @@
|
||||
# AddJsonPackage
|
||||
|
||||
In each directory that utilizes `CPMUtil`, there must be a `cpmfile.json` that defines dependencies in a similar manner to the individual calls.
|
||||
|
||||
The cpmfile is an object of objects, with each sub-object being named according to the package's identifier, e.g. `openssl`, which can then be fetched with `AddJsonPackage(<identifier>)`. Options are designed to map closely to the argument names, and are always strings unless otherwise specified.
|
||||
<!-- TOC -->
|
||||
- [Options](#options)
|
||||
- [Examples](#examples)
|
||||
<!-- /TOC -->
|
||||
|
||||
## Options
|
||||
|
||||
- `package` -> `NAME` (`PACKAGE` for CI), defaults to the object key
|
||||
- `repo` -> `REPO`
|
||||
- `version` -> `VERSION`
|
||||
- `ci` (bool)
|
||||
|
||||
If `ci` is `false`:
|
||||
|
||||
- `hash` -> `HASH`
|
||||
- `hash_suffix` -> `HASH_SUFFIX`
|
||||
- `sha` -> `SHA`
|
||||
- `key` -> `KEY`
|
||||
- `tag` -> `TAG`
|
||||
- If the tag contains `%VERSION%`, that part will be replaced by the `git_version`, OR `version` if `git_version` is not specified
|
||||
- `url` -> `URL`
|
||||
- `artifact` -> `ARTIFACT`
|
||||
- If the artifact contains `%VERSION%`, that part will be replaced by the `git_version`, OR `version` if `git_version` is not specified
|
||||
- If the artifact contains `%TAG%`, that part will be replaced by the `tag` (with its replacement already done)
|
||||
- `git_version` -> `GIT_VERSION`
|
||||
- `git_host` -> `GIT_HOST`
|
||||
- `source_subdir` -> `SOURCE_SUBDIR`
|
||||
- `bundled` -> `BUNDLED_PACKAGE`
|
||||
- `find_args` -> `FIND_PACKAGE_ARGUMENTS`
|
||||
- `download_only` -> `DOWNLOAD_ONLY`
|
||||
- `patches` -> `PATCHES` (array)
|
||||
- `options` -> `OPTIONS` (array)
|
||||
- `skip_updates`: Tells `check-updates.sh` to not check for new updates on this package.
|
||||
|
||||
Other arguments aren't currently supported. If you wish to add them, see the `AddJsonPackage` function in `CMakeModules/CPMUtil.cmake`.
|
||||
|
||||
If `ci` is `true`:
|
||||
|
||||
- `name` -> `NAME`, defaults to the object key
|
||||
- `extension` -> `EXTENSION`, defaults to `tar.zst`
|
||||
- `min_version` -> `MIN_VERSION`
|
||||
- `extension` -> `EXTENSION`
|
||||
- `disabled_platforms` -> `DISABLED_PLATFORMS` (array)
|
||||
|
||||
## Examples
|
||||
|
||||
In order: OpenSSL CI, Boost (tag + artifact), Opus (options + find_args), discord-rpc (sha + options + patches).
|
||||
|
||||
```json
|
||||
{
|
||||
"openssl": {
|
||||
"ci": true,
|
||||
"package": "OpenSSL",
|
||||
"name": "openssl",
|
||||
"repo": "crueter-ci/OpenSSL",
|
||||
"version": "3.6.0",
|
||||
"min_version": "1.1.1",
|
||||
"disabled_platforms": [
|
||||
"macos-universal",
|
||||
"ios-aarch64"
|
||||
]
|
||||
},
|
||||
"boost": {
|
||||
"package": "Boost",
|
||||
"repo": "boostorg/boost",
|
||||
"tag": "boost-%VERSION%",
|
||||
"artifact": "%TAG%-cmake.7z",
|
||||
"hash": "e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01",
|
||||
"git_version": "1.88.0",
|
||||
"version": "1.57"
|
||||
},
|
||||
"opus": {
|
||||
"package": "Opus",
|
||||
"repo": "xiph/opus",
|
||||
"sha": "5ded705cf4",
|
||||
"hash": "0dc89e58ddda1f3bc6a7037963994770c5806c10e66f5cc55c59286fc76d0544fe4eca7626772b888fd719f434bc8a92f792bdb350c807968b2ac14cfc04b203",
|
||||
"version": "1.3",
|
||||
"find_args": "MODULE",
|
||||
"options": [
|
||||
"OPUS_BUILD_TESTING OFF",
|
||||
"OPUS_BUILD_PROGRAMS OFF",
|
||||
"OPUS_INSTALL_PKG_CONFIG_MODULE OFF",
|
||||
"OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF"
|
||||
]
|
||||
},
|
||||
"discord-rpc": {
|
||||
"repo": "discord/discord-rpc",
|
||||
"sha": "963aa9f3e5",
|
||||
"hash": "386e1344e9a666d730f2d335ee3aef1fd05b1039febefd51aa751b705009cc764411397f3ca08dffd46205c72f75b235c870c737b2091a4ed0c3b061f5919bde",
|
||||
"options": [
|
||||
"BUILD_EXAMPLES OFF"
|
||||
],
|
||||
"patches": [
|
||||
"0001-cmake-version.patch",
|
||||
"0002-no-clang-format.patch",
|
||||
"0003-fix-cpp17.patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,118 +0,0 @@
|
||||
# `AddPackage`
|
||||
|
||||
<!-- TOC -->
|
||||
- [Identification/Fetching](#identificationfetching)
|
||||
- [Hashing](#hashing)
|
||||
- [Other Options](#other-options)
|
||||
- [Extra Variables](#extra-variables)
|
||||
- [System/Bundled Packages](#systembundled-packages)
|
||||
- [Identification](#identification)
|
||||
<!-- /TOC -->
|
||||
|
||||
## Identification/Fetching
|
||||
|
||||
- `NAME` (required): The package name (must be the same as the `find_package` name if applicable)
|
||||
- `VERSION`: The minimum version of this package that can be used on the system
|
||||
- `GIT_VERSION`: The "version" found within git
|
||||
- `URL`: The URL to fetch.
|
||||
- `REPO`: The repo to use (`owner/repo`).
|
||||
- `GIT_HOST`: The Git host to use
|
||||
- Defaults to `github.com`. Do not include the protocol, as HTTPS is enforced.
|
||||
- `TAG`: The tag to fetch, if applicable.
|
||||
- `ARTIFACT`: The name of the artifact, if applicable.
|
||||
- `SHA`: Commit sha to fetch, if applicable.
|
||||
- `BRANCH`: Branch to fetch, if applicable.
|
||||
|
||||
The following configurations are supported, in descending order of precedence:
|
||||
|
||||
- `URL`: Bare URL download, useful for custom artifacts
|
||||
- If this is set, `GIT_URL` or `REPO` should be set to allow the dependency viewer to link to the project's Git repository.
|
||||
- If this is NOT set, `REPO` must be defined.
|
||||
- `REPO + TAG + ARTIFACT`: GitHub release artifact
|
||||
- The final download URL will be `https://github.com/${REPO}/releases/download/${TAG}/${ARTIFACT}`
|
||||
- Useful for prebuilt libraries and prefetched archives
|
||||
- `REPO + TAG`: GitHub tag archive
|
||||
- The final download URL will be `https://github.com/${REPO}/archive/refs/tags/${TAG}.tar.gz`
|
||||
- Useful for pinning to a specific tag, better for build identification
|
||||
- `REPO + SHA`: GitHub commit archive
|
||||
- The final download URL will be `https://github.com/${REPO}/archive/${SHA}.zip`
|
||||
- Useful for pinning to a specific commit
|
||||
- `REPO + BRANCH`: GitHub branch archive
|
||||
- The final download URL will be `https://github.com/${REPO}/archive/refs/heads/${BRANCH}.zip`
|
||||
- Generally not recommended unless the branch is frozen
|
||||
- `REPO`: GitHub master archive
|
||||
- The final download URL will be `https://github.com/${REPO}/archive/refs/heads/master.zip`
|
||||
- Generally not recommended unless the project is dead
|
||||
|
||||
## Hashing
|
||||
|
||||
Hashing is used for verifying downloads. It's highly recommended to use these.
|
||||
|
||||
- `HASH_ALGO` (default `SHA512`): Hash algorithm to use
|
||||
|
||||
Hashing strategies, descending order of precedence:
|
||||
|
||||
- `HASH`: Bare hash verification, useful for static downloads e.g. commit archives
|
||||
- `HASH_SUFFIX`: Download the hash as `${DOWNLOAD_URL}.${HASH_SUFFIX}`
|
||||
- The downloaded hash *must* match the hash algorithm and contain nothing but the hash; no filenames or extra content.
|
||||
- `HASH_URL`: Download the hash from a separate URL
|
||||
|
||||
## Other Options
|
||||
|
||||
- `KEY`: Custom cache key to use (stored as `.cache/cpm/${packagename_lower}/${key}`)
|
||||
- Default is based on, in descending order of precedence:
|
||||
- First 4 characters of the sha
|
||||
- `GIT_VERSION`
|
||||
- Tag
|
||||
- `VERSION`
|
||||
- Otherwise, CPM defaults will be used. This is not recommended as it doesn't produce reproducible caches
|
||||
- `DOWNLOAD_ONLY`: Whether or not to configure the downloaded package via CMake
|
||||
- Useful to turn `OFF` if the project doesn't use CMake
|
||||
- `SOURCE_SUBDIR`: Subdirectory of the project containing a CMakeLists.txt file
|
||||
- `FIND_PACKAGE_ARGUMENTS`: Arguments to pass to the `find_package` call
|
||||
- `BUNDLED_PACKAGE`: Set to `ON` to default to the bundled package
|
||||
- `FORCE_BUNDLED_PACKAGE`: Set to `ON` to force the usage of the bundled package, regardless of CPMUTIL_FORCE_SYSTEM or `<package>_FORCE_SYSTEM`
|
||||
- `OPTIONS`: Options to pass to the configuration of the package
|
||||
- `PATCHES`: Patches to apply to the package, stored in `.patch/${packagename_lower}/0001-patch-name.patch` and so on
|
||||
- Other arguments can be passed to CPM as well
|
||||
|
||||
## Extra Variables
|
||||
|
||||
For each added package, users may additionally force usage of the system/bundled package.
|
||||
|
||||
- `${package}_DIR`: Path to a separately-downloaded copy of the package. Note that versioning is not checked!
|
||||
- `${package}_FORCE_SYSTEM`: Require the package to be installed on the system
|
||||
- `${package}_FORCE_BUNDLED`: Force the package to be fetched and use the bundled version
|
||||
|
||||
## System/Bundled Packages
|
||||
|
||||
Descending order of precedence:
|
||||
|
||||
- If `${package}_FORCE_SYSTEM` is true, requires the package to be on the system
|
||||
- If `${package}_FORCE_BUNDLED` is true, forcefully uses the bundled package
|
||||
- If `CPMUTIL_FORCE_SYSTEM` is true, requires the package to be on the system
|
||||
- If `CPMUTIL_FORCE_BUNDLED` is true, forcefully uses the bundled package
|
||||
- If the `BUNDLED_PACKAGE` argument is true, forcefully uses the bundled package
|
||||
- Otherwise, CPM will search for the package first, and if not found, will use the bundled package
|
||||
|
||||
## Identification
|
||||
|
||||
All dependencies must be identifiable in some way for usage in the dependency viewer. Lists are provided in descending order of precedence.
|
||||
|
||||
URLs:
|
||||
|
||||
- `GIT_URL`
|
||||
- `REPO` as a Git repository
|
||||
- You may optionally specify `GIT_HOST` to use a custom host, e.g. `GIT_HOST git.crueter.xyz`. Note that the git host MUST be GitHub-like in its artifact/archive downloads, e.g. Forgejo
|
||||
- If `GIT_HOST` is unspecified, defaults to `github.com`
|
||||
- `URL`
|
||||
|
||||
Versions (bundled):
|
||||
|
||||
- `SHA`
|
||||
- `GIT_VERSION`
|
||||
- `VERSION`
|
||||
- `TAG`
|
||||
- "unknown"
|
||||
|
||||
If the package is a system package, AddPackage will attempt to determine the package version and append `(system)` to the identifier. Otherwise, it will be marked as `unknown (system)`
|
||||
@@ -1,28 +0,0 @@
|
||||
# AddQt
|
||||
|
||||
Simply call `AddQt(<Qt Version>)` before any Qt `find_package` calls and everything will be set up for you. On Linux, the bundled Qt library is built as a shared library, and provided you have OpenSSL and X11, everything should just work.
|
||||
|
||||
On Windows, MinGW, and MacOS, Qt is bundled as a static library. No further action is needed, as the provided libraries automatically integrate the Windows/Cocoa plugins, alongside the corresponding Multimedia and Network plugins.
|
||||
|
||||
## Modules
|
||||
|
||||
The following modules are bundled into these Qt builds:
|
||||
|
||||
- Base (Gui, Core, Widgets, Network)
|
||||
- Multimedia
|
||||
- Declarative (Quick, QML)
|
||||
- Linux: Wayland client
|
||||
|
||||
Each platform has the corresponding QPA built in and set as the default as well. This means you don't need to add `Q_IMPORT_PLUGIN`!
|
||||
|
||||
## Example
|
||||
|
||||
See an example in the [`tests/qt`](https://git.crueter.xyz/CMake/CPMUtil/src/branch/master/tests/qt/CMakeLists.txt) directory.
|
||||
|
||||
## Versions
|
||||
|
||||
The following versions have available builds:
|
||||
|
||||
- 6.9.3
|
||||
|
||||
See [`crueter-ci/Qt`](https://github.com/crueter-ci/Qt) for an updated list at any time.
|
||||
@@ -1,70 +0,0 @@
|
||||
# CPMUtil
|
||||
|
||||
CPMUtil is a wrapper around CPM that aims to reduce boilerplate and add useful utility functions to make dependency management a piece of cake.
|
||||
|
||||
Global Options:
|
||||
|
||||
- `CPMUTIL_FORCE_SYSTEM` (default `OFF`): Require all CPM dependencies to use system packages. NOT RECOMMENDED!
|
||||
- You may optionally override this (section)
|
||||
- `CPMUTIL_FORCE_BUNDLED` (default `ON` on MSVC and Android, `OFF` elsewhere): Require all CPM dependencies to use bundled packages.
|
||||
|
||||
You are highly encouraged to read AddPackage first, even if you plan to only interact with CPMUtil via `AddJsonPackage`.
|
||||
|
||||
- [AddPackage](#addpackage)
|
||||
- [AddCIPackage](#addcipackage)
|
||||
- [AddJsonPackage](#addjsonpackage)
|
||||
- [AddQt](#addqt)
|
||||
- [Lists](#lists)
|
||||
- [For Packagers](#for-packagers)
|
||||
- [Network Sandbox](#network-sandbox)
|
||||
- [Unsandboxed](#unsandboxed)
|
||||
|
||||
## AddPackage
|
||||
|
||||
The core of CPMUtil is the [`AddPackage`](./AddPackage.md) function. [`AddPackage`](./AddPackage.md) itself is fully CMake-based, and largely serves as an interface between CPM and the rest of CPMUtil.
|
||||
|
||||
## AddCIPackage
|
||||
|
||||
[`AddCIPackage`](./AddCIPackage.md) adds a package that follows [crueter's CI repository spec](https://github.com/crueter-ci).
|
||||
|
||||
## AddJsonPackage
|
||||
|
||||
[`AddJsonPackage`](./AddJsonPackage.md) is the recommended method of usage for CPMUtil.
|
||||
|
||||
## AddDependentPackage
|
||||
|
||||
[`AddDependentPackage`](./AddDependentPackage.md) allows you to add multiple packages such that all of them must be from the system OR bundled.
|
||||
|
||||
## AddQt
|
||||
|
||||
[`AddQt`](./AddQt.md) adds a specific version of Qt to your project.
|
||||
|
||||
## Lists
|
||||
|
||||
CPMUtil will create three lists of dependencies where `AddPackage` or similar was used. Each is in order of addition.
|
||||
|
||||
- `CPM_PACKAGE_NAMES`: The names of packages included by CPMUtil
|
||||
- `CPM_PACKAGE_URLS`: The URLs to project/repo pages of packages
|
||||
- `CPM_PACKAGE_SHAS`: Short version identifiers for each package
|
||||
- If the package was included as a system package, `(system)` is appended thereafter
|
||||
- Packages whose versions can't be deduced will be left as `unknown`.
|
||||
|
||||
For an example of how this might be implemented in an application, see Eden's implementation:
|
||||
|
||||
- [`dep_hashes.h.in`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/dep_hashes.h.in)
|
||||
- [`GenerateDepHashes.cmake`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CMakeModules/GenerateDepHashes.cmake)
|
||||
- [`deps_dialog.cpp`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/yuzu/deps_dialog.cpp)
|
||||
|
||||
## For Packagers
|
||||
|
||||
If you are packaging a project that uses CPMUtil, read this!
|
||||
|
||||
### Network Sandbox
|
||||
|
||||
For sandboxed environments (e.g. Gentoo, nixOS) you must install all dependencies to the system beforehand and set `-DCPMUTIL_FORCE_SYSTEM=ON`. If a dependency is missing, get creating!
|
||||
|
||||
Alternatively, if CPMUtil pulls in a package that has no suitable way to install or use a system version, download it separately and pass `-DPackageName_DIR=/path/to/downloaded/dir` (e.g. shaders)
|
||||
|
||||
### Unsandboxed
|
||||
|
||||
For others (AUR, MPR, etc). CPMUtil will handle everything for you, including if some of the project's dependencies are missing from your distribution's repositories. That is pretty much half the reason I created this behemoth, after all.
|
||||
@@ -12,6 +12,7 @@
|
||||
- [NetBSD](#netbsd)
|
||||
- [MSYS2](#msys2)
|
||||
- [RedoxOS](#redoxos)
|
||||
- [WebAssembly](#webassembly)
|
||||
- [Windows](#windows)
|
||||
- [Windows 7, Windows 8 and Windows 8.1](#windows-7-windows-8-and-windows-81)
|
||||
- [Windows Vista and below](#windows-vista-and-below)
|
||||
@@ -245,6 +246,22 @@ The package install may randomly hang at times, in which case it has to be resta
|
||||
|
||||
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
|
||||
|
||||
## WebAssembly
|
||||
|
||||
**It doesn't run on a browser yet.**
|
||||
|
||||
WebAssembly or "WASM" for short is a *mainly 32-bit* virtual "architecture" which we only bootstrap on 64-bit only. This means not only the program runs 2x slower than it would due to using JS BigInt, it also means we need to go out of our way to enable proper 64-bit support via `-sMEMORY64=1`, however once again, some Emscripten quirks force us to specify `-s MEMORY64` and `-sMEMORY64=1` at the same time: see the [CI build script](../.ci/wasm/build.sh).
|
||||
|
||||
The WebAssembly target is very heavy on resources and requires at least 4 times the normal amount of resources that a native build would. Additionally, the only supported environment is Firefox at the moment, node.js and `wasmtime are not supported (PRs welcome!)
|
||||
|
||||
If running under Firefox and you hit "out of memory" on dev console, close the entire tab, then open it back again, see [this issue](https://github.com/emscripten-core/emscripten/issues/8126).
|
||||
|
||||
To run the binary (after building) you should be fine with `node ./eden-cli.js`. For obvious reasons no Qt frontend is available on WASM, support for Vulkan is done charily via [llvmpipe2wasm](https://github.com/Devsh-Graphics-Programming/llvmpipe2wasm).
|
||||
|
||||
If you run into the error "acorn.js can't be found" check [this associated issue](https://github.com/emscripten-core/emscripten/issues/13368), the fix in short is `npm --global install acorn`. On FreeBSD you could run `npm` under root, or you could do the sane thing and do `sudo chown -R $USER /usr/local/lib/node_modules/ /usr/local/bin/` (remember to restore permissions afterwards!) unless you wish to run `npm` under root which is generally a bad idea.
|
||||
|
||||
2026-06-09: As of writing, no Dynarmic-based JIT is possible on this target, full interpreted emulation is the only reasonable option. While there is some efforts on making a JIT like [here](https://github.com/wingo/wasm-jit) or [here](https://wingolog.org/archives/2022/08/18/just-in-time-code-generation-within-webassembly), the result is so latency expensive we're better off using an interpreter instead.
|
||||
|
||||
## Windows
|
||||
|
||||
### Windows 7, Windows 8 and Windows 8.1
|
||||
|
||||
@@ -359,6 +359,14 @@ pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel b
|
||||
|
||||
[Caveats](./Caveats.md#haikuos).
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>WebAssembly</summary>
|
||||
|
||||
Emscripten: The default installation should provide enough.
|
||||
|
||||
[Caveats](./Caveats.md#wasm).
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>RedoxOS</summary>
|
||||
|
||||
@@ -27,3 +27,6 @@ There are two main applications, an SDL-based app (`eden-cli`) and a Qt based ap
|
||||
- `--user/-u`: Specify the user index.
|
||||
- `--version/-v`: Display version and quit.
|
||||
- `--input-profile/-i`: Specifies input profile name to use (for player #0 only).
|
||||
- `--null-render/-n`: Forces the usage of the "Null" render backend irrespective of settings.
|
||||
- `--filter/-x`: Sets the debug log filter irrespective of settings.
|
||||
- `--singlecore/-s`: Forces single-core regardless of settings.
|
||||
|
||||
Vendored
+1
-2
@@ -6,8 +6,7 @@
|
||||
|
||||
# TODO(crueter): A lot of this should be moved to the root.
|
||||
# otherwise we have to do weird shenanigans with library linking and stuff
|
||||
|
||||
include(CPMUtil)
|
||||
# Or just add a CPMUtil thing to propagate packages
|
||||
|
||||
# Explicitly declare this option here to propagate to the oaknut CPM call
|
||||
option(DYNARMIC_TESTS "Build tests" ${BUILD_TESTING})
|
||||
|
||||
+9
-5
@@ -94,6 +94,10 @@ function(detect_architecture_symbols)
|
||||
endfunction()
|
||||
|
||||
# arches here are put in a sane default order of importance
|
||||
# EXCEPT FOR WASM, which must be probed for FIRST, because some genius
|
||||
# decided to also allow the host architecture to be defined when building
|
||||
# for the emscripten target, absolutely lovely detail.
|
||||
#
|
||||
# notably, amd64, arm64, and riscv (in order) are BY FAR the most common
|
||||
# mips is pretty popular in embedded
|
||||
# ppc64 is pretty popular in supercomputing
|
||||
@@ -101,6 +105,11 @@ endfunction()
|
||||
# ia64 exists
|
||||
# the rest exist, but are probably less popular than ia64
|
||||
|
||||
detect_architecture_symbols(
|
||||
ARCH wasm
|
||||
SYMBOLS
|
||||
"__EMSCRIPTEN__")
|
||||
|
||||
detect_architecture_symbols(
|
||||
ARCH arm64
|
||||
SYMBOLS
|
||||
@@ -203,11 +212,6 @@ detect_architecture_symbols(
|
||||
"__loongarch__"
|
||||
"__loongarch64")
|
||||
|
||||
detect_architecture_symbols(
|
||||
ARCH wasm
|
||||
SYMBOLS
|
||||
"__EMSCRIPTEN__")
|
||||
|
||||
# "generic" target
|
||||
# If you have reached this point, you're on some as-of-yet unsupported architecture.
|
||||
# See the docs up above for known unsupported architectures
|
||||
|
||||
+4
-2
@@ -33,6 +33,9 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Haiku")
|
||||
set(PLATFORM_HAIKU ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(PLATFORM_LINUX ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
|
||||
set(PLATFORM_EMSCRIPTEN ON)
|
||||
message(WARNING "${CMAKE_LIBRARY_ARCHITECTURE} support is highly experimental!!!")
|
||||
endif()
|
||||
|
||||
# dumb heuristic to detect msys2
|
||||
@@ -151,6 +154,5 @@ endif()
|
||||
|
||||
# awesome
|
||||
if (PLATFORM_FREEBSD OR PLATFORM_DRAGONFLYBSD)
|
||||
set(CMAKE_EXE_LINKER_FLAGS
|
||||
"${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/local/lib")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/local/lib")
|
||||
endif()
|
||||
|
||||
Vendored
-249
@@ -1,249 +0,0 @@
|
||||
{
|
||||
"vulkan-memory-allocator": {
|
||||
"package": "VulkanMemoryAllocator",
|
||||
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
|
||||
"find_args": "CONFIG",
|
||||
"git_version": "3.3.0"
|
||||
},
|
||||
"sirit": {
|
||||
"repo": "eden-emulator/sirit",
|
||||
"git_version": "1.0.5",
|
||||
"tag": "v%VERSION%",
|
||||
"artifact": "sirit-source-%VERSION%.tar.zst",
|
||||
"hash_suffix": "sha512sum",
|
||||
"find_args": "CONFIG",
|
||||
"options": [
|
||||
"SIRIT_USE_SYSTEM_SPIRV_HEADERS ON"
|
||||
]
|
||||
},
|
||||
"sirit-ci": {
|
||||
"ci": true,
|
||||
"package": "sirit",
|
||||
"name": "sirit",
|
||||
"repo": "eden-emulator/sirit",
|
||||
"version": "1.0.5"
|
||||
},
|
||||
"httplib": {
|
||||
"repo": "yhirose/cpp-httplib",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "159ed94965018f2a371d45a3bfc1961e5fb1549e501ded70a6b4532d7fe99d0579c18b5195aff6e35f96f399b426cea2650ec9fb75ef80d4c9edeccb51f2e6c9",
|
||||
"git_version": "0.46.0",
|
||||
"find_args": "MODULE GLOBAL",
|
||||
"patches": [
|
||||
"0001-mingw.patch"
|
||||
],
|
||||
"options": [
|
||||
"HTTPLIB_REQUIRE_OPENSSL ON",
|
||||
"HTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES ON"
|
||||
]
|
||||
},
|
||||
"cpp-jwt": {
|
||||
"version": "1.4",
|
||||
"repo": "arun11299/cpp-jwt",
|
||||
"sha": "7f24eb4c32",
|
||||
"hash": "d11cbd5ddb3197b4c5ca15679bcd76a49963e7b530b7dd132db91e042925efa20dfb2c24ccfbe7ef82a7012af80deff0f72ee25851312ae80381a462df8534b8",
|
||||
"find_args": "CONFIG",
|
||||
"options": [
|
||||
"CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF"
|
||||
],
|
||||
"patches": [
|
||||
"0001-fix-missing-decl.patch"
|
||||
]
|
||||
},
|
||||
"xbyak": {
|
||||
"package": "xbyak",
|
||||
"repo": "herumi/xbyak",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "b6475276b2faaeb315734ea8f4f8bd87ededcee768961b39679bee547e7f3e98884d8b7851e176d861dab30a80a76e6ea302f8c111483607dde969b4797ea95a",
|
||||
"git_version": "7.35.2"
|
||||
},
|
||||
"oaknut": {
|
||||
"repo": "eden-emulator/oaknut",
|
||||
"version": "2.0.1",
|
||||
"git_version": "2.0.3",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "9697e80a7d5d9bcb3ce51051a9a24962fb90ca79d215f1f03ae6b58da8ba13a63b5dda1b4dde3d26ac6445029696b8ef2883f4e5a777b342bba01283ed293856"
|
||||
},
|
||||
"lagoon": {
|
||||
"repo": "loongson-community/lagoon",
|
||||
"tag": "%VERSION%",
|
||||
"version": "1.0.0",
|
||||
"hash": "b9380f99c6effaeccc6d8f81d4942e852c11ad28613df637e155451556ae5826f93765bee57a5c87a9740d2bd1db463ad0f55a947772fe9d57eeabae3efa373e"
|
||||
},
|
||||
"libadrenotools": {
|
||||
"repo": "eden-emulator/libadrenotools",
|
||||
"sha": "8ba23b42d7",
|
||||
"hash": "f6526620cb752876edc5ed4c0925d57b873a8218ee09ad10859ee476e9333259784f61c1dcc55a2bcba597352d18aff22cd2e4c1925ec2ae94074e09d7da2265",
|
||||
"patches": [
|
||||
"0001-linkerns-cpm.patch"
|
||||
]
|
||||
},
|
||||
"oboe": {
|
||||
"repo": "google/oboe",
|
||||
"tag": "%VERSION%",
|
||||
"hash": "ce4011afe7345370d4ead3b891cd69a5ef224b129535783586c0ca75051d303ed446e6c7f10bde8da31fff58d6e307f1732a3ffd03b249f9ef1fd48fd4132715",
|
||||
"git_version": "1.10.0",
|
||||
"bundled": true
|
||||
},
|
||||
"unordered-dense": {
|
||||
"package": "unordered_dense",
|
||||
"repo": "martinus/unordered_dense",
|
||||
"sha": "7b55cab841",
|
||||
"hash": "d2106f6640f6bfb81755e4b8bfb64982e46ec4a507cacdb38f940123212ccf35a20b43c70c6f01d7bfb8c246d1a16f7845d8052971949cea9def1475e3fa02c8",
|
||||
"find_args": "CONFIG",
|
||||
"bundled": true,
|
||||
"patches": [
|
||||
"0001-avoid-memset-when-clearing-an-empty-table.patch"
|
||||
]
|
||||
},
|
||||
"enet": {
|
||||
"repo": "lsalzman/enet",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
|
||||
"version": "1.3",
|
||||
"git_version": "1.3.18",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"spirv-headers": {
|
||||
"package": "SPIRV-Headers",
|
||||
"repo": "KhronosGroup/SPIRV-Headers",
|
||||
"sha": "04f10f650d",
|
||||
"hash": "cae8cd179c9013068876908fecc1d158168310ad6ac250398a41f0f5206ceff6469e2aaeab9c820bce9d1b08950c725c89c46e94b89a692be9805432cf749396",
|
||||
"options": [
|
||||
"SPIRV_WERROR OFF"
|
||||
]
|
||||
},
|
||||
"cubeb": {
|
||||
"repo": "mozilla/cubeb",
|
||||
"sha": "fa02160712",
|
||||
"hash": "8a4bcb2f83ba590f52c66626e895304a73eb61928dbc57777e1822e55378e3568366f17f9da4b80036cc2ef4ea9723c32abf6e7d9bbe00fb03654f0991596ab0",
|
||||
"find_args": "CONFIG",
|
||||
"options": [
|
||||
"USE_SANITIZERS OFF",
|
||||
"BUILD_TESTS OFF",
|
||||
"BUILD_TOOLS OFF",
|
||||
"BUNDLE_SPEEX ON"
|
||||
]
|
||||
},
|
||||
"sdl3-ci": {
|
||||
"ci": true,
|
||||
"package": "SDL3",
|
||||
"name": "SDL3",
|
||||
"repo": "crueter-ci/SDL3",
|
||||
"version": "3.4.8-d57c3b685c",
|
||||
"min_version": "3.2.10"
|
||||
},
|
||||
"catch2": {
|
||||
"package": "Catch2",
|
||||
"repo": "catchorg/Catch2",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "7eea385d79d88a5690cde131fe7ccda97d5c54ea09d6f515000d7bf07c828809d61c1ac99912c1ee507cf933f61c1c47ecdcc45df7850ffa82714034b0fccf35",
|
||||
"version": "3.0.1",
|
||||
"git_version": "3.13.0",
|
||||
"patches": [
|
||||
"0001-solaris-isnan-fix.patch"
|
||||
]
|
||||
},
|
||||
"discord-rpc": {
|
||||
"package": "DiscordRPC",
|
||||
"repo": "eden-emulator/discord-rpc",
|
||||
"sha": "0d8b2d6a37",
|
||||
"hash": "8213c43dcb0f7d479f5861091d111ed12fbdec1e62e6d729d65a4bc181d82f48a35d5fd3cd5c291f2393ac7c9681eabc6b76609755f55376284c8a8d67e148f3",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"simpleini": {
|
||||
"package": "SimpleIni",
|
||||
"repo": "brofield/simpleini",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "b937c18a7b6277d77ca7ebfb216af4984810f77af4c32d101b7685369a4bd5eb61406223f82698e167e6311a728d07415ab59639fdf19eff71ad6dc2abfda989",
|
||||
"find_args": "MODULE",
|
||||
"git_version": "4.25"
|
||||
},
|
||||
"sdl3": {
|
||||
"package": "SDL3",
|
||||
"repo": "libsdl-org/SDL",
|
||||
"tag": "release-%VERSION%",
|
||||
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
|
||||
"git_version": "3.4.8",
|
||||
"version": "3.2.10"
|
||||
},
|
||||
"moltenvk": {
|
||||
"repo": "V380-Ori/Ryujinx.MoltenVK",
|
||||
"tag": "v%VERSION%-ryujinx",
|
||||
"git_version": "1.4.1",
|
||||
"artifact": "MoltenVK-macOS.tar",
|
||||
"hash": "5695b36ca5775819a71791557fcb40a4a5ee4495be6b8442e0b666d0c436bec02aae68cc6210183f7a5c986bdbec0e117aecfad5396e496e9c2fd5c89133a347",
|
||||
"bundled": true
|
||||
},
|
||||
"gamemode": {
|
||||
"repo": "FeralInteractive/gamemode",
|
||||
"sha": "ce6fe122f3",
|
||||
"hash": "e87ec14ed3e826d578ebf095c41580069dda603792ba91efa84f45f4571a28f4d91889675055fd6f042d7dc25b0b9443daf70963ae463e38b11bcba95f4c65a9",
|
||||
"version": "1.7",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"biscuit": {
|
||||
"repo": "lioncash/biscuit",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a",
|
||||
"version": "0.9.1",
|
||||
"git_version": "0.19.0"
|
||||
},
|
||||
"libusb": {
|
||||
"repo": "libusb/libusb",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "98c5f7940ff06b25c9aa65aa98e23de4c79a4c1067595f4c73cc145af23a1c286639e1ba11185cd91bab702081f307b973f08a4c9746576dc8d01b3620a3aeb5",
|
||||
"find_args": "MODULE",
|
||||
"git_version": "1.0.29",
|
||||
"patches": [
|
||||
"0001-netbsd-gettime.patch"
|
||||
]
|
||||
},
|
||||
"ffmpeg": {
|
||||
"repo": "FFmpeg/FFmpeg",
|
||||
"sha": "c7b5f1537d",
|
||||
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
|
||||
"bundled": true
|
||||
},
|
||||
"ffmpeg-ci": {
|
||||
"ci": true,
|
||||
"package": "FFmpeg",
|
||||
"name": "ffmpeg",
|
||||
"repo": "crueter-ci/FFmpeg",
|
||||
"version": "8.0.1-c7b5f1537d",
|
||||
"min_version": "4.1"
|
||||
},
|
||||
"tzdb": {
|
||||
"package": "nx_tzdb",
|
||||
"repo": "eden-emu/tzdb_to_nx",
|
||||
"git_host": "git.eden-emu.dev",
|
||||
"artifact": "%VERSION%.tar.gz",
|
||||
"tag": "%VERSION%",
|
||||
"hash": "cce65a12bf90f4ead43b24a0b95dfad77ac3d9bfbaaf66c55e6701346e7a1e44ca5d2f23f47ee35ee02271eb1082bf1762af207aad9fb236f1c8476812d008ed",
|
||||
"version": "121125",
|
||||
"git_version": "230326"
|
||||
},
|
||||
"vulkan-headers": {
|
||||
"repo": "KhronosGroup/Vulkan-Headers",
|
||||
"package": "VulkanHeaders",
|
||||
"version": "1.4.317",
|
||||
"hash": "d2846ea228415772645eea4b52a9efd33e6a563043dd3de059e798be6391a8f0ca089f455ae420ff22574939ed0f48ed7c6ff3d5a9987d5231dbf3b3f89b484b",
|
||||
"git_version": "1.4.345",
|
||||
"tag": "v%VERSION%"
|
||||
},
|
||||
"vulkan-utility-libraries": {
|
||||
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
|
||||
"package": "VulkanUtilityLibraries",
|
||||
"hash": "114f6b237a6dcba923ccc576befb5dea3f1c9b3a30de7dc741f234a831d1c2d52d8a224afb37dd57dffca67ac0df461eaaab6a5ab5e503b393f91c166680c3e1",
|
||||
"git_version": "1.4.345",
|
||||
"tag": "v%VERSION%"
|
||||
},
|
||||
"frozen": {
|
||||
"package": "frozen",
|
||||
"repo": "serge-sans-paille/frozen",
|
||||
"sha": "61dce5ae18",
|
||||
"hash": "b8dfe741c82bc178dfc9749d4ab5a130cee718d9ee7b71d9b547cf5f7f23027ed0152ad250012a8546399fcc1e12187efc68d89d6731256c4d2df7d04eef8d5c"
|
||||
}
|
||||
}
|
||||
Vendored
+58
-26
@@ -37,26 +37,39 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
elseif (NOT (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES CMAKE_SYSTEM_PROCESSOR
|
||||
AND CMAKE_HOST_SYSTEM_NAME MATCHES CMAKE_SYSTEM_NAME))
|
||||
string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME)
|
||||
if (FFmpeg_SYSTEM_NAME STREQUAL "openorbis" OR FFmpeg_SYSTEM_NAME STREQUAL "managarm")
|
||||
# All of these platforms are supported by ffmpeg as native build OSes
|
||||
# anything else (like Redox or Managarm or PS4) is NOT natively supported
|
||||
# hence, assume the "unix like" is just "none" for the sake of OUR sanity.
|
||||
# If YOUR OS/platform has actual native support:
|
||||
# 1. fucking congrats
|
||||
# 2. feel free to add it on the condition below
|
||||
if (NOT (PLATFORM_NETBSD OR PLATFORM_SUN OR PLATFORM_FREEBSD
|
||||
OR PLATFORM_OPENBSD OR PLATFORM_DRAGONFLYBSD OR PLATFORM_HAIKU
|
||||
OR PLATFORM_LINUX OR PLATFORM_MSYS OR WIN32 OR ANDROID OR APPLE))
|
||||
set(FFmpeg_SYSTEM_NAME "none")
|
||||
endif()
|
||||
# TODO: Can we really do better? Auto-detection? Something clever?
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
|
||||
--enable-cross-compile
|
||||
--arch="${CMAKE_SYSTEM_PROCESSOR}"
|
||||
--target-os="${FFmpeg_SYSTEM_NAME}"
|
||||
--sysroot="${CMAKE_SYSROOT}"
|
||||
)
|
||||
--target-os="${FFmpeg_SYSTEM_NAME}")
|
||||
if (PLATFORM_EMSCRIPTEN)
|
||||
# funniest trolling from emscripten, such a classic!
|
||||
# maybe I should PR so they use CMAKE_SYSROOT... y'know?
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --sysroot="${EMSCRIPTEN_SYSROOT}")
|
||||
else()
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --sysroot="${CMAKE_SYSROOT}")
|
||||
endif()
|
||||
if (DEFINED FFmpeg_CROSS_PREFIX)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --cross-prefix="${FFmpeg_CROSS_PREFIX}")
|
||||
else()
|
||||
message(WARNING "Please set FFmpeg_CROSS_PREFIX to your cross toolchain prefix, for example: \${CMAKE_STAGING_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}-")
|
||||
message(WARNING "Please set FFmpeg_CROSS_PREFIX to your cross toolchain prefix, for example: ${CMAKE_STAGING_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}")
|
||||
endif()
|
||||
set(FFmpeg_IS_CROSS_COMPILING TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (PLATFORM_PS4 OR PLATFORM_MANAGARM)
|
||||
if (PLATFORM_PS4 OR PLATFORM_MANAGARM OR PLATFORM_EMSCRIPTEN)
|
||||
# Doesn't support VA-API, don't go thru the embarrassment of trying to enable it
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
|
||||
elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
@@ -159,20 +172,28 @@ if (PLATFORM_PS4)
|
||||
-lSceUserService
|
||||
-lSceSysmodule
|
||||
-lSceNet
|
||||
-lSceLibcInternal
|
||||
)
|
||||
-lSceLibcInternal)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
|
||||
--disable-pthreads
|
||||
--extra-cflags=${CMAKE_SYSROOT}/usr/include
|
||||
--extra-cxxflags=${CMAKE_SYSROOT}/usr/include
|
||||
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}"
|
||||
)
|
||||
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}")
|
||||
elseif (PLATFORM_MANAGARM)
|
||||
# Required for proper stuff
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
|
||||
--disable-pthreads
|
||||
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}"
|
||||
)
|
||||
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}")
|
||||
endif()
|
||||
|
||||
# Usually used by Emscripten
|
||||
if (DEFINED CMAKE_AR)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --ar=${CMAKE_AR})
|
||||
endif()
|
||||
if (DEFINED CMAKE_NM)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --nm=${CMAKE_NM})
|
||||
endif()
|
||||
if (DEFINED CMAKE_RANLIB)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --ranlib=${CMAKE_RANLIB})
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
@@ -202,6 +223,7 @@ else()
|
||||
# Build FFmpeg from externals
|
||||
message(STATUS "Using FFmpeg from externals")
|
||||
|
||||
set(FFmpeg_LD ${CMAKE_LINKER})
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)")
|
||||
# FFmpeg has source that requires one of nasm or yasm to assemble it.
|
||||
# REQUIRED throws an error if not found here during configuration rather than during compilation.
|
||||
@@ -210,6 +232,12 @@ else()
|
||||
message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.")
|
||||
endif()
|
||||
endif()
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
||||
# TODO: this is 100% redundant but we need it because CMAKE_LINKER can resolve to ld.lld
|
||||
# which is NOT compatible
|
||||
find_program(EMCC NAMES emcc REQUIRED)
|
||||
set(FFmpeg_LD ${EMCC})
|
||||
endif()
|
||||
|
||||
find_program(AUTOCONF autoconf)
|
||||
if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND")
|
||||
@@ -243,7 +271,13 @@ else()
|
||||
CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
endforeach()
|
||||
|
||||
find_program(BASH_PROGRAM bash REQUIRED)
|
||||
# Some SDKs (especially wasm) require us, actually, WANT us to use their "emconfigure"
|
||||
# otherwise they will cry a billion tears
|
||||
if (PLATFORM_EMSCRIPTEN)
|
||||
find_program(FFmpeg_CONFIGURE_WRAPPER emconfigure REQUIRED)
|
||||
else()
|
||||
find_program(FFmpeg_CONFIGURE_WRAPPER bash REQUIRED)
|
||||
endif()
|
||||
|
||||
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
|
||||
# `--disable-vdpau` is needed to avoid linking issues
|
||||
@@ -253,7 +287,7 @@ else()
|
||||
OUTPUT
|
||||
${FFmpeg_MAKEFILE}
|
||||
COMMAND
|
||||
${BASH_PROGRAM} ${FFmpeg_PREFIX}/configure
|
||||
${FFmpeg_CONFIGURE_WRAPPER} ${FFmpeg_PREFIX}/configure
|
||||
--disable-avdevice
|
||||
--disable-avformat
|
||||
--disable-doc
|
||||
@@ -262,6 +296,10 @@ else()
|
||||
--disable-ffprobe
|
||||
--disable-network
|
||||
--disable-swresample
|
||||
--disable-autodetect
|
||||
--disable-runtime-cpudetect
|
||||
--disable-debug
|
||||
--disable-programs
|
||||
--enable-decoder=h264
|
||||
--enable-decoder=vp8
|
||||
--enable-decoder=vp9
|
||||
@@ -269,7 +307,7 @@ else()
|
||||
--enable-pic
|
||||
--cc=${FFmpeg_CC}
|
||||
--cxx=${FFmpeg_CXX}
|
||||
--ld=${CMAKE_LINKER}
|
||||
--ld=${FFmpeg_LD}
|
||||
--extra-cflags=${CMAKE_C_FLAGS}
|
||||
--extra-cxxflags=${CMAKE_CXX_FLAGS}
|
||||
--extra-ldflags=${CMAKE_C_LINK_FLAGS}
|
||||
@@ -285,26 +323,20 @@ else()
|
||||
|
||||
# Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
|
||||
# with context of the jobserver. Also helps ninja users.
|
||||
execute_process(
|
||||
COMMAND
|
||||
nproc
|
||||
OUTPUT_VARIABLE
|
||||
SYSTEM_THREADS)
|
||||
cmake_host_system_information(RESULT SYSTEM_THREADS QUERY NUMBER_OF_LOGICAL_CORES)
|
||||
|
||||
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
|
||||
|
||||
# BSD make or Solaris make don't support ffmpeg make-j8
|
||||
if (PLATFORM_LINUX OR ANDROID OR APPLE OR WIN32 OR PLATFORM_FREEBSD)
|
||||
set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS})
|
||||
else()
|
||||
set(FFmpeg_MAKE_ARGS "")
|
||||
find_program(MAKE NAMES gmake make REQUIRED)
|
||||
if (SYSTEM_THREADS GREATER 1)
|
||||
set(FFmpeg_MAKE_ARGS -j ${SYSTEM_THREADS})
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_BUILD_LIBRARIES}
|
||||
COMMAND
|
||||
gmake ${FFmpeg_MAKE_ARGS}
|
||||
${MAKE} ${FFmpeg_MAKE_ARGS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
Vendored
+2
@@ -14,7 +14,9 @@
|
||||
namespace Tz {
|
||||
|
||||
namespace {
|
||||
#ifndef EINVAL
|
||||
#define EINVAL 22
|
||||
#endif
|
||||
|
||||
static Rule gmtmem{};
|
||||
static Rule* const gmtptr = &gmtmem;
|
||||
|
||||
+16
-10
@@ -155,23 +155,25 @@ else()
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WERROR)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-Werror>)
|
||||
endif()
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=all>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=extra>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=missing-declarations>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=shadow>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=unused>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wall>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wextra>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wmissing-declarations>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wshadow>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wunused>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-attributes>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-invalid-offsetof>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-parameter>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-missing-field-initializers>)
|
||||
|
||||
if (CXX_CLANG OR CXX_ICC OR CXX_APPLE) # Clang, AppleClang, or Intel C++
|
||||
if (NOT MSVC)
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=shadow-uncaptured-local>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=implicit-fallthrough>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=type-limits>)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wshadow-uncaptured-local>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wimplicit-fallthrough>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wtype-limits>)
|
||||
endif()
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-braced-scalar-init>
|
||||
@@ -179,7 +181,11 @@ else()
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-nullability-completeness>)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64)
|
||||
if (ARCHITECTURE_wasm)
|
||||
# we are evil but fmt is even more evil
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shorten-64-to-32>)
|
||||
elseif (ARCHITECTURE_x86_64)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-mcx16>)
|
||||
if (PLATFORM_LINUX OR PLATFORM_FREEBSD)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-mtls-dialect=gnu2>)
|
||||
|
||||
+2
-1
@@ -83,9 +83,10 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
ENABLE_OVERLAY("enable_overlay"),
|
||||
|
||||
// GPU Logging
|
||||
GPU_LOGGING_ENABLED("gpu_logging_enabled"),
|
||||
GPU_LOG_VULKAN_CALLS("gpu_log_vulkan_calls"),
|
||||
GPU_LOG_SHADER_DUMPS("gpu_log_shader_dumps"),
|
||||
DUMP_GUEST_SHADERS("dump_guest_shaders"),
|
||||
DUMP_MACROS("dump_macros"),
|
||||
GPU_LOG_MEMORY_TRACKING("gpu_log_memory_tracking"),
|
||||
GPU_LOG_DRIVER_DEBUG("gpu_log_driver_debug"),
|
||||
|
||||
|
||||
+14
-7
@@ -931,13 +931,6 @@ abstract class SettingsItem(
|
||||
)
|
||||
|
||||
// GPU Logging settings
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.GPU_LOGGING_ENABLED,
|
||||
titleId = R.string.gpu_logging_enabled,
|
||||
descriptionId = R.string.gpu_logging_enabled_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
ByteSetting.GPU_LOG_LEVEL,
|
||||
@@ -954,6 +947,13 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.gpu_log_vulkan_calls_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.DUMP_GUEST_SHADERS,
|
||||
titleId = R.string.dump_guest_shaders,
|
||||
descriptionId = R.string.dump_guest_shaders_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.GPU_LOG_SHADER_DUMPS,
|
||||
@@ -961,6 +961,13 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.gpu_log_shader_dumps_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.DUMP_MACROS,
|
||||
titleId = R.string.dump_macros,
|
||||
descriptionId = R.string.dump_macros_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.GPU_LOG_MEMORY_TRACKING,
|
||||
|
||||
+11
-8
@@ -1288,14 +1288,17 @@ class SettingsFragmentPresenter(
|
||||
add(ShortSetting.DEBUG_KNOBS.key)
|
||||
add(StringSetting.PROGRAM_ARGS.key)
|
||||
|
||||
add(HeaderSetting(R.string.gpu_logging_header))
|
||||
add(BooleanSetting.GPU_LOGGING_ENABLED.key)
|
||||
add(ByteSetting.GPU_LOG_LEVEL.key)
|
||||
add(BooleanSetting.GPU_LOG_VULKAN_CALLS.key)
|
||||
add(BooleanSetting.GPU_LOG_SHADER_DUMPS.key)
|
||||
add(BooleanSetting.GPU_LOG_MEMORY_TRACKING.key)
|
||||
add(BooleanSetting.GPU_LOG_DRIVER_DEBUG.key)
|
||||
add(IntSetting.GPU_LOG_RING_BUFFER_SIZE.key)
|
||||
if (!NativeConfig.isPerGameConfigLoaded()) {
|
||||
add(HeaderSetting(R.string.gpu_logging_header))
|
||||
add(ByteSetting.GPU_LOG_LEVEL.key)
|
||||
add(BooleanSetting.GPU_LOG_VULKAN_CALLS.key)
|
||||
add(BooleanSetting.DUMP_GUEST_SHADERS.key)
|
||||
add(BooleanSetting.GPU_LOG_SHADER_DUMPS.key)
|
||||
add(BooleanSetting.DUMP_MACROS.key)
|
||||
add(BooleanSetting.GPU_LOG_MEMORY_TRACKING.key)
|
||||
add(BooleanSetting.GPU_LOG_DRIVER_DEBUG.key)
|
||||
add(IntSetting.GPU_LOG_RING_BUFFER_SIZE.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -569,8 +569,6 @@
|
||||
|
||||
<!-- GPU Logging strings -->
|
||||
<string name="gpu_logging_header">تسجيل وحدة معالجة الرسومات</string>
|
||||
<string name="gpu_logging_enabled">تمكين تسجيل وحدة معالجة الرسومات</string>
|
||||
<string name="gpu_logging_enabled_description">تسجيل عمليات وحدة معالجة الرسومات في ملف eden_gpu.log لتصحيح أخطاء برامج تشغيل Adreno</string>
|
||||
<string name="gpu_log_level">مستوى السجل</string>
|
||||
<string name="gpu_log_level_description">مستوى التفاصيل لسجلات وحدة معالجة الرسومات (كلما زاد المستوى، زادت التفاصيل وزادت التكاليف الإضافية)</string>
|
||||
<string name="gpu_log_vulkan_calls">تسجيل استدعاءات واجهة برمجة تطبيقات Vulkan</string>
|
||||
|
||||
@@ -563,8 +563,6 @@
|
||||
|
||||
<!-- GPU Logging strings -->
|
||||
<string name="gpu_logging_header">Registros de la GPU</string>
|
||||
<string name="gpu_logging_enabled">Activar los registros de la GPU</string>
|
||||
<string name="gpu_logging_enabled_description">Registra las operaciones de la GPU en eden_gpu.log para la depuración de los controladores de Adreno</string>
|
||||
<string name="gpu_log_level">Nivel de registros</string>
|
||||
<string name="gpu_log_level_description">Nivel de detalle de los registros de la GPU (más alto = más detalles, más sobrecarga)</string>
|
||||
<string name="gpu_log_vulkan_calls">Registros de llamadas del API de Vulkan</string>
|
||||
|
||||
@@ -525,7 +525,6 @@
|
||||
|
||||
<!-- GPU Logging strings -->
|
||||
<string name="gpu_logging_header">Journalisation GPU</string>
|
||||
<string name="gpu_logging_enabled">Activer la journalisation GPU</string>
|
||||
<string name="gpu_log_level">Niveau de journalisation</string>
|
||||
<string name="gpu_log_vulkan_calls">Journaliser les appels API Vulkan</string>
|
||||
<string name="gpu_log_shader_dumps">Extraire les shaders</string>
|
||||
|
||||
@@ -562,8 +562,6 @@
|
||||
|
||||
<!-- GPU Logging strings -->
|
||||
<string name="gpu_logging_header">Ведение журнала ГПУ</string>
|
||||
<string name="gpu_logging_enabled">Включить ведение журнала ГПУ</string>
|
||||
<string name="gpu_logging_enabled_description">Записывать операции ГПУ в файл eden_gpu.log для отладки драйверов Adreno</string>
|
||||
<string name="gpu_log_level">Уровень журналирования</string>
|
||||
<string name="gpu_log_level_description">Уровень детализации логов ГПУ (больше значение = больше деталей, выше нагрузка)</string>
|
||||
<string name="gpu_log_vulkan_calls">Записывать вызовы Vulkan API</string>
|
||||
|
||||
@@ -565,8 +565,6 @@
|
||||
|
||||
<!-- GPU Logging strings -->
|
||||
<string name="gpu_logging_header">Журналювання ГП</string>
|
||||
<string name="gpu_logging_enabled">Увімкнути журналювання ГП</string>
|
||||
<string name="gpu_logging_enabled_description">Журналювати операції ГП до eden_gpu.log для зневадження драйверів Adreno</string>
|
||||
<string name="gpu_log_level">Рівень журналювання</string>
|
||||
<string name="gpu_log_level_description">Рівень подробиць у журналі ГП (вищий = більше подробиць, більший вплив на швидкодію)</string>
|
||||
<string name="gpu_log_vulkan_calls">Записувати виклики API Vulkan</string>
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
<string name="buffer_reorder_disable_description">勾选时,禁用映射内存上传的重排序功能,允许将上传与特定绘制关联。在某些情况下可能会降低性能。</string>
|
||||
|
||||
<string name="use_sync_core">同步核心速度</string>
|
||||
<string name="use_sync_core_description">将核心速度与最大速度百分比同步,在不改变游戏实际速度的情况下提高性能。</string>
|
||||
<string name="use_sync_core_description">将核心时钟周期速度与最大速度百分比同步,从而在不改变游戏实际速度的情况下提升性能。</string>
|
||||
<string name="cpuopt_unsafe_host_mmu">启用主机 MMU 模拟</string>
|
||||
<string name="cpuopt_unsafe_host_mmu_description">此优化可加速来宾程序的内存访问。启用后,来宾内存读取/写入将直接在内存中执行并利用主机的 MMU。禁用此功能将强制所有内存访问使用软件 MMU 模拟。</string>
|
||||
<string name="debug_knobs">调试开关</string>
|
||||
@@ -248,7 +248,7 @@
|
||||
<string name="install_prod_keys">安装 prod.keys 文件</string>
|
||||
<string name="install_prod_keys_description">需要密钥文件来解密游戏</string>
|
||||
<string name="install_prod_keys_warning">跳过添加密钥文件?</string>
|
||||
<string name="install_prod_keys_warning_description">对于商业游戏,需要有效的密钥文件才能运行。如果没有密钥文件,将只能运行自制软件。</string>
|
||||
<string name="install_prod_keys_warning_description">模拟零售版游戏需要有效的密钥。如果选择继续,仅有自制软件可以正常运行。</string>
|
||||
<string name="install_prod_keys_warning_help">https://yuzu-mirror.github.io/help/quickstart/#guide-introduction</string>
|
||||
<string name="install_firmware_warning">跳过添加固件?</string>
|
||||
<string name="emulator_data">设置模拟器数据</string>
|
||||
@@ -291,7 +291,7 @@
|
||||
<string name="gpu_driver_fetcher">GPU驱动获取器</string>
|
||||
<string name="gpu_driver_manager">GPU 驱动管理器</string>
|
||||
<string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string>
|
||||
<string name="advanced_settings">高级选项</string>
|
||||
<string name="advanced_settings">高级设置</string>
|
||||
<string name="settings_description">更改模拟器设置</string>
|
||||
<string name="search_recently_played">最近游玩</string>
|
||||
<string name="search_recently_added">最近添加</string>
|
||||
@@ -418,6 +418,9 @@
|
||||
<string name="cpu_accuracy">CPU 精度</string>
|
||||
<string name="value_with_units">%1$s%2$s</string>
|
||||
|
||||
<string name="program_args">自制软件参数</string>
|
||||
<string name="program_args_description">启动时传递给自制软件的命令行参数(例如 -noglsl)。</string>
|
||||
|
||||
<!-- System settings strings -->
|
||||
<string name="device_name">设备名称</string>
|
||||
<string name="use_docked_mode">主机模式</string>
|
||||
@@ -433,9 +436,9 @@
|
||||
<!-- CPU -->
|
||||
<string name="fast_cpu_time">CPU 超频</string>
|
||||
<string name="fast_cpu_time_description">强制模拟的 CPU 以更高的时钟频率运行,从而消除某些帧率限制。使用“升频”(1700MHz)以在 Switch 的最高原生时钟频率运行,或使用“快速”(2000MHz)以 2 倍时钟频率运行。</string>
|
||||
<string name="custom_cpu_ticks">自定义CPU时钟</string>
|
||||
<string name="custom_cpu_ticks_description">设置自定义的CPU时钟值。更高的值可能提高性能,但也可能导致游戏卡顿。建议范围为77-21000。</string>
|
||||
<string name="cpu_ticks">时钟</string>
|
||||
<string name="custom_cpu_ticks">自定义 CPU 时钟周期</string>
|
||||
<string name="custom_cpu_ticks_description">设定自定义的 CPU 时钟周期值。更高的值可以提升性能,但也可能导致游戏冻结卡死。建议的赋值范围为77-21000。</string>
|
||||
<string name="cpu_ticks">时钟周期</string>
|
||||
<string name="memory_layout">内存布局</string>
|
||||
<string name="memory_layout_description">(实验性) 更改模拟内存布局。此项设置并不会提升性能,但可能有助于游戏通过 mods 来利用高分辨率。请不要在内存不大于 8GB 的手机上使用。仅适用于 Dynamic(JIT)后端。</string>
|
||||
|
||||
@@ -466,7 +469,7 @@
|
||||
<string name="anisotropic_filtering">各向异性过滤</string>
|
||||
<string name="anisotropic_filtering_description">提高斜角的纹理质量</string>
|
||||
<string name="vram_usage_mode">显存使用模式</string>
|
||||
<string name="vram_usage_mode_description">控制显存分配策略</string>
|
||||
<string name="vram_usage_mode_description">控制显存分配与释放策略</string>
|
||||
<string name="accelerate_astc">ASTC解码方式</string>
|
||||
<string name="accelerate_astc_description">选择渲染时使用的 ASTC 压缩纹理解码方式:CPU(缓慢,安全),GPU(快速,推荐),或 CPU 异步(无卡顿,但可能导致问题)</string>
|
||||
|
||||
@@ -494,7 +497,7 @@
|
||||
<string name="skip_cpu_inner_invalidation">跳过CPU内部无效化</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">在更新内存时跳过某些 CPU 端的缓存失效操作,从而降低 CPU 占用率并提升性能。可能会在某些游戏中引发故障点或崩溃。</string>
|
||||
<string name="antiflicker">防闪烁</string>
|
||||
<string name="antiflicker_description">强制 GPU 围栏回调等待已提交的 GPU 任务。配合“快速 GPU 模式”一起使用,以避免画面闪烁现象,仅会牺牲少量性能。</string>
|
||||
<string name="antiflicker_description">强制 GPU 围栏回调等待已提交的 GPU 任务。配合“快速 GPU 模式”一起使用,以牺牲少量性能为代价来避免画面闪烁现象。</string>
|
||||
<string name="fix_bloom_effects">修复 Bloom 效果</string>
|
||||
<string name="fix_bloom_effects_description">减少《智慧的再现》和《众神的三角力量2》(Adreno A6XX - A7XX/ Turnip)中的 bloom 模糊,并移除《Burnout》中的 bloom 效果。警告:可能会导致在其他游戏中出现图形异常。</string>
|
||||
<string name="emulate_bgr565">模拟 BGR565</string>
|
||||
@@ -539,8 +542,8 @@
|
||||
|
||||
<!-- Debug settings strings -->
|
||||
<string name="cpu">CPU</string>
|
||||
<string name="use_auto_stub">使用自动存根</string>
|
||||
<string name="use_auto_stub_description">自动补全缺失的服务和功能。可提高兼容性但可能导致崩溃和稳定性问题。</string>
|
||||
<string name="use_auto_stub">使用自动占位处理</string>
|
||||
<string name="use_auto_stub_description">自动为缺失的服务和功能生成占位代码。这可能会提高兼容性,但也可能导致崩溃和稳定性问题</string>
|
||||
|
||||
<string name="gpu">GPU</string>
|
||||
<string name="renderer_api">API</string>
|
||||
@@ -556,8 +559,6 @@
|
||||
|
||||
<!-- GPU Logging strings -->
|
||||
<string name="gpu_logging_header">GPU 日志</string>
|
||||
<string name="gpu_logging_enabled">启用 GPU 日志</string>
|
||||
<string name="gpu_logging_enabled_description">将 GPU 操作记录至 eden_gpu.log 以供调试 Adreno 驱动</string>
|
||||
<string name="gpu_log_level">日志等级</string>
|
||||
<string name="gpu_log_level_description">GPU 日志的详细级别(数值越高 = 细节越多,开销越大)</string>
|
||||
<string name="gpu_log_vulkan_calls">记录 Vulkan API 调用</string>
|
||||
@@ -661,9 +662,9 @@
|
||||
<string name="shutting_down">正在关闭…</string>
|
||||
<string name="reset_setting_confirmation">您要将此设定重置为默认值吗?</string>
|
||||
<string name="reset_to_default">恢复默认</string>
|
||||
<string name="reset_to_default_description">重置所有高级选项</string>
|
||||
<string name="reset_to_default_description">重置所有高级设置</string>
|
||||
<string name="reset_all_settings">重置所有设置项?</string>
|
||||
<string name="reset_all_settings_description">所有高级选项都将被重置,此动作无法还原。</string>
|
||||
<string name="reset_all_settings_description">所有高级设置都将重置为默认。此操作无法撤销。</string>
|
||||
<string name="settings_reset">重置设置项</string>
|
||||
<string name="close">关闭</string>
|
||||
<string name="learn_more">了解更多</string>
|
||||
@@ -790,7 +791,7 @@
|
||||
<string name="clear_shader_cache_warning_description">由于着色器缓存需要重新生成,您将遇到更多卡顿</string>
|
||||
<string name="cleared_shaders_successfully">着色器缓存清除成功</string>
|
||||
<string name="driver_shader_wipe_dialog_title">已清理着色器</string>
|
||||
<string name="driver_shader_wipe_dialog_message">Eden 已自动清除所有着色器缓存以维护 Vulkan 管线验证。这在切换 GPU 驱动程序时是必需的,以防止崩溃和图形损坏。在着色器重建期间您可能会遇到一些卡顿。</string>
|
||||
<string name="driver_shader_wipe_dialog_message">Eden 已自动清空所有着色器缓存,以维持 Vulkan 管线验证流程。在切换 GPU 驱动程序时,此操作是必要的,可防止崩溃和画面异常。在着色器重构期间,您可能会感受到些许卡顿。</string>
|
||||
<string name="addons_game">附加项: %1$s</string>
|
||||
<string name="save_data">保存数据</string>
|
||||
<string name="save_data_description">管理此游戏的保存数据</string>
|
||||
@@ -991,8 +992,8 @@
|
||||
<string name="dma_accuracy_unsafe">不安全</string>
|
||||
<string name="dma_accuracy_safe">安全</string>
|
||||
|
||||
<string name="vram_usage_conservative">保守模式</string>
|
||||
<string name="vram_usage_aggressive">激进模式</string>
|
||||
<string name="vram_usage_conservative">保守式</string>
|
||||
<string name="vram_usage_aggressive">主动式</string>
|
||||
|
||||
<!-- Renderer VSync -->
|
||||
<string name="renderer_vsync_immediate">即时 (关闭)</string>
|
||||
@@ -1014,9 +1015,9 @@
|
||||
<string name="ratio_stretch">拉伸窗口</string>
|
||||
|
||||
<!-- CPU Accuracy -->
|
||||
<string name="cpu_accuracy_accurate">高精度</string>
|
||||
<string name="cpu_accuracy_unsafe">低精度</string>
|
||||
<string name="cpu_accuracy_paranoid">偏执模式</string>
|
||||
<string name="cpu_accuracy_accurate">精准</string>
|
||||
<string name="cpu_accuracy_unsafe">不安全</string>
|
||||
<string name="cpu_accuracy_paranoid">极致</string>
|
||||
<string name="cpu_accuracy_debugging">调试</string>
|
||||
|
||||
<!-- Freedreno Settings -->
|
||||
|
||||
@@ -575,14 +575,16 @@
|
||||
|
||||
<!-- GPU Logging strings -->
|
||||
<string name="gpu_logging_header">GPU Logging</string>
|
||||
<string name="gpu_logging_enabled">Enable GPU Logging</string>
|
||||
<string name="gpu_logging_enabled_description">Log GPU operations to eden_gpu.log for debugging Adreno drivers</string>
|
||||
<string name="gpu_log_level">Log Level</string>
|
||||
<string name="gpu_log_level_description">Detail level for GPU logs (higher = more detail, more overhead)</string>
|
||||
<string name="gpu_log_vulkan_calls">Log Vulkan API Calls</string>
|
||||
<string name="gpu_log_vulkan_calls_description">Track all Vulkan API calls in ring buffer</string>
|
||||
<string name="gpu_log_shader_dumps">Dump Shaders</string>
|
||||
<string name="gpu_log_shader_dumps_description">Save compiled shader SPIR-V to files</string>
|
||||
<string name="gpu_log_shader_dumps">Dump SPIR-V Shaders</string>
|
||||
<string name="gpu_log_shader_dumps_description">Save recompiled SPIR-V binaries (.spv) to dump folder. Inspect with spirv-dis/spirv-cross/spirv-val.</string>
|
||||
<string name="dump_guest_shaders">Dump Guest (Maxwell) Shaders</string>
|
||||
<string name="dump_guest_shaders_description">Save Maxwell guest shader bytecode files (*.ash) to dump folder. Inspect with nvdisasm.</string>
|
||||
<string name="dump_macros">Dump Maxwell Macros</string>
|
||||
<string name="dump_macros_description">Save Maxwell macro program files (*.macro) to dump folder. Inspect with envydis.</string>
|
||||
<string name="gpu_log_memory_tracking">Track GPU Memory</string>
|
||||
<string name="gpu_log_memory_tracking_description">Monitor GPU memory allocations and deallocations</string>
|
||||
<string name="gpu_log_driver_debug">Driver Debug Info</string>
|
||||
|
||||
@@ -222,7 +222,7 @@ if (MSVC)
|
||||
)
|
||||
else()
|
||||
target_compile_options(audio_core PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-sign-conversion>)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -8,10 +11,11 @@
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
AudioCore::AudioCore(Core::System& system) : audio_manager{std::make_unique<AudioManager>()} {
|
||||
AudioCore::AudioCore(Core::System& system) {
|
||||
audio_manager.emplace();
|
||||
CreateSinks();
|
||||
// Must be created after the sinks
|
||||
adsp = std::make_unique<ADSP::ADSP>(system, *output_sink);
|
||||
adsp.emplace(system, *output_sink);
|
||||
}
|
||||
|
||||
AudioCore ::~AudioCore() {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -15,10 +18,7 @@ class System;
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
class AudioManager;
|
||||
/**
|
||||
* Main audio class, stored inside the core, and holding the audio manager, all sinks, and the ADSP.
|
||||
*/
|
||||
/// @brief Main audio class, stored inside the core, and holding the audio manager, all sinks, and the ADSP.
|
||||
class AudioCore {
|
||||
public:
|
||||
explicit AudioCore(Core::System& system);
|
||||
@@ -50,27 +50,22 @@ public:
|
||||
*/
|
||||
Sink::Sink& GetInputSink();
|
||||
|
||||
/**
|
||||
* Get the ADSP.
|
||||
*
|
||||
* @return Ref to the ADSP.
|
||||
*/
|
||||
/// @brief Get the ADSP.
|
||||
/// @return Ref to the ADSP.
|
||||
ADSP::ADSP& ADSP();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Create the sinks on startup.
|
||||
*/
|
||||
/// @brief Create the sinks on startup.
|
||||
void CreateSinks();
|
||||
|
||||
/// Main audio manager for audio in/out
|
||||
std::unique_ptr<AudioManager> audio_manager;
|
||||
std::optional<AudioManager> audio_manager;
|
||||
/// Sink used for audio renderer and audio out
|
||||
std::unique_ptr<Sink::Sink> output_sink;
|
||||
/// Sink used for audio input
|
||||
std::unique_ptr<Sink::Sink> input_sink;
|
||||
/// The ADSP in the sysmodule
|
||||
std::unique_ptr<ADSP::ADSP> adsp;
|
||||
std::optional<ADSP::ADSP> adsp;
|
||||
};
|
||||
|
||||
} // namespace AudioCore
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -41,8 +44,7 @@ void Manager::ReleaseSessionId(const size_t session_id) {
|
||||
Result Manager::LinkToManager() {
|
||||
std::scoped_lock l{mutex};
|
||||
if (!linked_to_manager) {
|
||||
AudioManager& manager{system.AudioCore().GetAudioManager()};
|
||||
manager.SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
|
||||
system.AudioCore().GetAudioManager().SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
|
||||
linked_to_manager = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,81 +1,77 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/audio_manager.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/audio/errors.h"
|
||||
|
||||
namespace AudioCore {
|
||||
|
||||
AudioManager::AudioManager() {
|
||||
thread = std::jthread([this]() { ThreadFunc(); });
|
||||
thread = std::jthread([this](std::stop_token stop_token) {
|
||||
Common::SetCurrentThreadName("AudioManager");
|
||||
std::unique_lock l{events.GetAudioEventLock()};
|
||||
events.ClearEvents();
|
||||
while (!stop_token.stop_requested()) {
|
||||
const auto timed_out{events.Wait(l, std::chrono::seconds(2))};
|
||||
if (events.CheckAudioEventSet(Event::Type::Max)) {
|
||||
break;
|
||||
}
|
||||
for (size_t i = 0; i < buffer_events.size(); i++) {
|
||||
const auto event_type = Event::Type(i);
|
||||
if (events.CheckAudioEventSet(event_type) || timed_out) {
|
||||
if (buffer_events[i]) {
|
||||
buffer_events[i]();
|
||||
}
|
||||
}
|
||||
events.SetAudioEvent(event_type, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AudioManager::Shutdown() {
|
||||
running = false;
|
||||
events.SetAudioEvent(Event::Type::Max, true);
|
||||
thread.join();
|
||||
if (thread.joinable()) {
|
||||
thread.request_stop();
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
Result AudioManager::SetOutManager(BufferEventFunc buffer_func) {
|
||||
if (!running) {
|
||||
return Service::Audio::ResultOperationFailed;
|
||||
if (thread.joinable()) {
|
||||
std::scoped_lock l{lock};
|
||||
const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)};
|
||||
if (buffer_events[index] == nullptr) {
|
||||
buffer_events[index] = std::move(buffer_func);
|
||||
needs_update = true;
|
||||
events.SetAudioEvent(Event::Type::AudioOutManager, true);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
std::scoped_lock l{lock};
|
||||
|
||||
const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)};
|
||||
if (buffer_events[index] == nullptr) {
|
||||
buffer_events[index] = std::move(buffer_func);
|
||||
needs_update = true;
|
||||
events.SetAudioEvent(Event::Type::AudioOutManager, true);
|
||||
}
|
||||
return ResultSuccess;
|
||||
return Service::Audio::ResultOperationFailed;
|
||||
}
|
||||
|
||||
Result AudioManager::SetInManager(BufferEventFunc buffer_func) {
|
||||
if (!running) {
|
||||
return Service::Audio::ResultOperationFailed;
|
||||
if (thread.joinable()) {
|
||||
std::scoped_lock l{lock};
|
||||
const auto index{events.GetManagerIndex(Event::Type::AudioInManager)};
|
||||
if (buffer_events[index] == nullptr) {
|
||||
buffer_events[index] = std::move(buffer_func);
|
||||
needs_update = true;
|
||||
events.SetAudioEvent(Event::Type::AudioInManager, true);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
std::scoped_lock l{lock};
|
||||
|
||||
const auto index{events.GetManagerIndex(Event::Type::AudioInManager)};
|
||||
if (buffer_events[index] == nullptr) {
|
||||
buffer_events[index] = std::move(buffer_func);
|
||||
needs_update = true;
|
||||
events.SetAudioEvent(Event::Type::AudioInManager, true);
|
||||
}
|
||||
return ResultSuccess;
|
||||
return Service::Audio::ResultOperationFailed;
|
||||
}
|
||||
|
||||
void AudioManager::SetEvent(const Event::Type type, const bool signalled) {
|
||||
events.SetAudioEvent(type, signalled);
|
||||
}
|
||||
|
||||
void AudioManager::ThreadFunc() {
|
||||
std::unique_lock l{events.GetAudioEventLock()};
|
||||
events.ClearEvents();
|
||||
running = true;
|
||||
|
||||
while (running) {
|
||||
const auto timed_out{events.Wait(l, std::chrono::seconds(2))};
|
||||
|
||||
if (events.CheckAudioEventSet(Event::Type::Max)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < buffer_events.size(); i++) {
|
||||
const auto event_type = static_cast<Event::Type>(i);
|
||||
|
||||
if (events.CheckAudioEventSet(event_type) || timed_out) {
|
||||
if (buffer_events[i]) {
|
||||
buffer_events[i]();
|
||||
}
|
||||
}
|
||||
events.SetAudioEvent(event_type, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AudioCore
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -66,13 +69,6 @@ public:
|
||||
void SetEvent(Event::Type type, bool signalled);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Main thread, waiting on a manager signal and calling the registered function.
|
||||
*/
|
||||
void ThreadFunc();
|
||||
|
||||
/// Is the main thread running?
|
||||
std::atomic<bool> running{};
|
||||
/// Unused
|
||||
bool needs_update{};
|
||||
/// Events to be set and signalled
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -40,8 +43,7 @@ void Manager::ReleaseSessionId(const size_t session_id) {
|
||||
Result Manager::LinkToManager() {
|
||||
std::scoped_lock l{mutex};
|
||||
if (!linked_to_manager) {
|
||||
AudioManager& manager{system.AudioCore().GetAudioManager()};
|
||||
manager.SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
|
||||
system.AudioCore().GetAudioManager().SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
|
||||
linked_to_manager = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -39,7 +42,7 @@ Result DeviceSession::Initialize(std::string_view name_, SampleFormat sample_for
|
||||
channel_count = channel_count_;
|
||||
session_id = session_id_;
|
||||
handle = handle_;
|
||||
handle->Open();
|
||||
handle->Open(system.Kernel());
|
||||
applet_resource_user_id = applet_resource_user_id_;
|
||||
|
||||
if (type == Sink::StreamType::In) {
|
||||
@@ -60,7 +63,7 @@ void DeviceSession::Finalize() {
|
||||
}
|
||||
|
||||
if (handle) {
|
||||
handle->Close();
|
||||
handle->Close(system.Kernel());
|
||||
handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ Result System::Stop() {
|
||||
session->SetVolume(0.0f);
|
||||
session->ClearBuffers();
|
||||
if (buffers.ReleaseBuffers(system.CoreTiming(), *session, true)) {
|
||||
buffer_event->Signal();
|
||||
buffer_event->Signal(system.Kernel());
|
||||
}
|
||||
state = State::Stopped;
|
||||
}
|
||||
@@ -164,7 +164,7 @@ void System::ReleaseBuffers() {
|
||||
|
||||
if (signal) {
|
||||
// Signal if any buffer was released, or if none are registered, we need more.
|
||||
buffer_event->Signal();
|
||||
buffer_event->Signal(system.Kernel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ bool System::FlushAudioInBuffers() {
|
||||
buffers.FlushBuffers(buffers_released);
|
||||
|
||||
if (buffers_released > 0) {
|
||||
buffer_event->Signal();
|
||||
buffer_event->Signal(system.Kernel());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ Result System::Stop() {
|
||||
session->SetVolume(0.0f);
|
||||
session->ClearBuffers();
|
||||
if (buffers.ReleaseBuffers(system.CoreTiming(), *session, true)) {
|
||||
buffer_event->Signal();
|
||||
buffer_event->Signal(system.Kernel());
|
||||
}
|
||||
state = State::Stopped;
|
||||
}
|
||||
@@ -162,7 +162,7 @@ void System::ReleaseBuffers() {
|
||||
bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session, false)};
|
||||
if (signal) {
|
||||
// Signal if any buffer was released, or if none are registered, we need more.
|
||||
buffer_event->Signal();
|
||||
buffer_event->Signal(system.Kernel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ bool System::FlushAudioOutBuffers() {
|
||||
buffers.FlushBuffers(buffers_released);
|
||||
|
||||
if (buffers_released > 0) {
|
||||
buffer_event->Signal();
|
||||
buffer_event->Signal(system.Kernel());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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 2022 yuzu Emulator Project
|
||||
@@ -540,7 +540,7 @@ Result System::Update(std::span<const u8> input, std::span<u8> performance, std:
|
||||
return result;
|
||||
}
|
||||
|
||||
adsp_rendered_event->Clear();
|
||||
adsp_rendered_event->Clear(core.Kernel());
|
||||
num_times_updated++;
|
||||
|
||||
const auto end_time{core.CoreTiming().GetGlobalTimeNs().count()};
|
||||
@@ -624,7 +624,7 @@ void System::SendCommandToDsp() {
|
||||
reset_command_buffers = false;
|
||||
command_buffer_size = command_size;
|
||||
if (remaining_command_count == 0) {
|
||||
adsp_rendered_event->Signal();
|
||||
adsp_rendered_event->Signal(core.Kernel());
|
||||
}
|
||||
} else {
|
||||
audio_renderer.ClearRemainCommandCount(session_id);
|
||||
|
||||
@@ -50,7 +50,6 @@ add_library(
|
||||
elf.h
|
||||
error.cpp
|
||||
error.h
|
||||
expected.h
|
||||
fiber.cpp
|
||||
fiber.h
|
||||
fixed_point.h
|
||||
@@ -221,7 +220,7 @@ endif()
|
||||
if(CXX_CLANG)
|
||||
target_compile_options(common PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-fsized-deallocation>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=unreachable-code-aggressive>)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wunreachable-code-aggressive>)
|
||||
target_compile_definitions(
|
||||
common
|
||||
PRIVATE
|
||||
@@ -236,7 +235,11 @@ else()
|
||||
target_link_libraries(common PUBLIC Boost::headers)
|
||||
endif()
|
||||
target_link_libraries(common PRIVATE OpenSSL::SSL)
|
||||
target_link_libraries(common PUBLIC Boost::filesystem Boost::context httplib::httplib nlohmann_json::nlohmann_json)
|
||||
target_link_libraries(common PUBLIC Boost::filesystem httplib::httplib nlohmann_json::nlohmann_json)
|
||||
if (NOT PLATFORM_EMSCRIPTEN)
|
||||
# Emscripten is: "bring your own implementation", boost doesn't add upstream support sadly
|
||||
target_link_libraries(common PRIVATE Boost::context)
|
||||
endif()
|
||||
|
||||
if (lz4_ADDED)
|
||||
target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib)
|
||||
|
||||
@@ -1,986 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// This is based on the proposed implementation of std::expected (P0323)
|
||||
// https://github.com/TartanLlama/expected/blob/master/include/tl/expected.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Common {
|
||||
|
||||
template <typename T, typename E>
|
||||
class Expected;
|
||||
|
||||
template <typename E>
|
||||
class Unexpected {
|
||||
public:
|
||||
Unexpected() = delete;
|
||||
|
||||
constexpr explicit Unexpected(const E& e) : m_val{e} {}
|
||||
|
||||
constexpr explicit Unexpected(E&& e) : m_val{std::move(e)} {}
|
||||
|
||||
constexpr E& value() & {
|
||||
return m_val;
|
||||
}
|
||||
|
||||
constexpr const E& value() const& {
|
||||
return m_val;
|
||||
}
|
||||
|
||||
constexpr E&& value() && {
|
||||
return std::move(m_val);
|
||||
}
|
||||
|
||||
constexpr const E&& value() const&& {
|
||||
return std::move(m_val);
|
||||
}
|
||||
|
||||
private:
|
||||
E m_val;
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
constexpr auto operator<=>(const Unexpected<E>& lhs, const Unexpected<E>& rhs) {
|
||||
return lhs.value() <=> rhs.value();
|
||||
}
|
||||
|
||||
struct unexpect_t {
|
||||
constexpr explicit unexpect_t() = default;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct no_init_t {
|
||||
constexpr explicit no_init_t() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* This specialization is for when T is not trivially destructible,
|
||||
* so the destructor must be called on destruction of `expected'
|
||||
* Additionally, this requires E to be trivially destructible
|
||||
*/
|
||||
template <typename T, typename E, bool = std::is_trivially_destructible_v<T>>
|
||||
requires std::is_trivially_destructible_v<E>
|
||||
struct expected_storage_base {
|
||||
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
|
||||
|
||||
constexpr expected_storage_base(no_init_t) : m_has_val{false} {}
|
||||
|
||||
template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
|
||||
constexpr expected_storage_base(std::in_place_t, Args&&... args)
|
||||
: m_val{std::forward<Args>(args)...}, m_has_val{true} {}
|
||||
|
||||
template <typename U, typename... Args,
|
||||
std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
|
||||
nullptr>
|
||||
constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il, Args&&... args)
|
||||
: m_val{il, std::forward<Args>(args)...}, m_has_val{true} {}
|
||||
|
||||
template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args&&... args)
|
||||
: m_unexpect{std::forward<Args>(args)...}, m_has_val{false} {}
|
||||
|
||||
template <typename U, typename... Args,
|
||||
std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il,
|
||||
Args&&... args)
|
||||
: m_unexpect{il, std::forward<Args>(args)...}, m_has_val{false} {}
|
||||
|
||||
~expected_storage_base() {
|
||||
if (m_has_val) {
|
||||
m_val.~T();
|
||||
}
|
||||
}
|
||||
|
||||
union {
|
||||
T m_val;
|
||||
Unexpected<E> m_unexpect;
|
||||
};
|
||||
|
||||
bool m_has_val;
|
||||
};
|
||||
|
||||
/**
|
||||
* This specialization is for when T is trivially destructible,
|
||||
* so the destructor of `expected` can be trivial
|
||||
* Additionally, this requires E to be trivially destructible
|
||||
*/
|
||||
template <typename T, typename E>
|
||||
requires std::is_trivially_destructible_v<E>
|
||||
struct expected_storage_base<T, E, true> {
|
||||
constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
|
||||
|
||||
constexpr expected_storage_base(no_init_t) : m_has_val{false} {}
|
||||
|
||||
template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
|
||||
constexpr expected_storage_base(std::in_place_t, Args&&... args)
|
||||
: m_val{std::forward<Args>(args)...}, m_has_val{true} {}
|
||||
|
||||
template <typename U, typename... Args,
|
||||
std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
|
||||
nullptr>
|
||||
constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il, Args&&... args)
|
||||
: m_val{il, std::forward<Args>(args)...}, m_has_val{true} {}
|
||||
|
||||
template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, Args&&... args)
|
||||
: m_unexpect{std::forward<Args>(args)...}, m_has_val{false} {}
|
||||
|
||||
template <typename U, typename... Args,
|
||||
std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
|
||||
nullptr>
|
||||
constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il,
|
||||
Args&&... args)
|
||||
: m_unexpect{il, std::forward<Args>(args)...}, m_has_val{false} {}
|
||||
|
||||
~expected_storage_base() = default;
|
||||
|
||||
union {
|
||||
T m_val;
|
||||
Unexpected<E> m_unexpect;
|
||||
};
|
||||
|
||||
bool m_has_val;
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
struct expected_operations_base : expected_storage_base<T, E> {
|
||||
using expected_storage_base<T, E>::expected_storage_base;
|
||||
|
||||
template <typename... Args>
|
||||
void construct(Args&&... args) noexcept {
|
||||
new (std::addressof(this->m_val)) T{std::forward<Args>(args)...};
|
||||
this->m_has_val = true;
|
||||
}
|
||||
|
||||
template <typename Rhs>
|
||||
void construct_with(Rhs&& rhs) noexcept {
|
||||
new (std::addressof(this->m_val)) T{std::forward<Rhs>(rhs).get()};
|
||||
this->m_has_val = true;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void construct_error(Args&&... args) noexcept {
|
||||
new (std::addressof(this->m_unexpect)) Unexpected<E>{std::forward<Args>(args)...};
|
||||
this->m_has_val = false;
|
||||
}
|
||||
|
||||
void assign(const expected_operations_base& rhs) noexcept {
|
||||
if (!this->m_has_val && rhs.m_has_val) {
|
||||
geterr().~Unexpected<E>();
|
||||
construct(rhs.get());
|
||||
} else {
|
||||
assign_common(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
void assign(expected_operations_base&& rhs) noexcept {
|
||||
if (!this->m_has_val && rhs.m_has_val) {
|
||||
geterr().~Unexpected<E>();
|
||||
construct(std::move(rhs).get());
|
||||
} else {
|
||||
assign_common(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Rhs>
|
||||
void assign_common(Rhs&& rhs) {
|
||||
if (this->m_has_val) {
|
||||
if (rhs.m_has_val) {
|
||||
get() = std::forward<Rhs>(rhs).get();
|
||||
} else {
|
||||
destroy_val();
|
||||
construct_error(std::forward<Rhs>(rhs).geterr());
|
||||
}
|
||||
} else {
|
||||
if (!rhs.m_has_val) {
|
||||
geterr() = std::forward<Rhs>(rhs).geterr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool has_value() const {
|
||||
return this->m_has_val;
|
||||
}
|
||||
|
||||
constexpr T& get() & {
|
||||
return this->m_val;
|
||||
}
|
||||
|
||||
constexpr const T& get() const& {
|
||||
return this->m_val;
|
||||
}
|
||||
|
||||
constexpr T&& get() && {
|
||||
return std::move(this->m_val);
|
||||
}
|
||||
|
||||
constexpr const T&& get() const&& {
|
||||
return std::move(this->m_val);
|
||||
}
|
||||
|
||||
constexpr Unexpected<E>& geterr() & {
|
||||
return this->m_unexpect;
|
||||
}
|
||||
|
||||
constexpr const Unexpected<E>& geterr() const& {
|
||||
return this->m_unexpect;
|
||||
}
|
||||
|
||||
constexpr Unexpected<E>&& geterr() && {
|
||||
return std::move(this->m_unexpect);
|
||||
}
|
||||
|
||||
constexpr const Unexpected<E>&& geterr() const&& {
|
||||
return std::move(this->m_unexpect);
|
||||
}
|
||||
|
||||
constexpr void destroy_val() {
|
||||
get().~T();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This manages conditionally having a trivial copy constructor
|
||||
* This specialization is for when T is trivially copy constructible
|
||||
* Additionally, this requires E to be trivially copy constructible
|
||||
*/
|
||||
template <typename T, typename E, bool = std::is_trivially_copy_constructible_v<T>>
|
||||
requires std::is_trivially_copy_constructible_v<E>
|
||||
struct expected_copy_base : expected_operations_base<T, E> {
|
||||
using expected_operations_base<T, E>::expected_operations_base;
|
||||
};
|
||||
|
||||
/**
|
||||
* This specialization is for when T is not trivially copy constructible
|
||||
* Additionally, this requires E to be trivially copy constructible
|
||||
*/
|
||||
template <typename T, typename E>
|
||||
requires std::is_trivially_copy_constructible_v<E>
|
||||
struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
|
||||
using expected_operations_base<T, E>::expected_operations_base;
|
||||
|
||||
expected_copy_base() = default;
|
||||
|
||||
expected_copy_base(const expected_copy_base& rhs)
|
||||
: expected_operations_base<T, E>{no_init_t{}} {
|
||||
if (rhs.has_value()) {
|
||||
this->construct_with(rhs);
|
||||
} else {
|
||||
this->construct_error(rhs.geterr());
|
||||
}
|
||||
}
|
||||
|
||||
expected_copy_base(expected_copy_base&&) = default;
|
||||
|
||||
expected_copy_base& operator=(const expected_copy_base&) = default;
|
||||
|
||||
expected_copy_base& operator=(expected_copy_base&&) = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* This manages conditionally having a trivial move constructor
|
||||
* This specialization is for when T is trivially move constructible
|
||||
* Additionally, this requires E to be trivially move constructible
|
||||
*/
|
||||
template <typename T, typename E, bool = std::is_trivially_move_constructible_v<T>>
|
||||
requires std::is_trivially_move_constructible_v<E>
|
||||
struct expected_move_base : expected_copy_base<T, E> {
|
||||
using expected_copy_base<T, E>::expected_copy_base;
|
||||
};
|
||||
|
||||
/**
|
||||
* This specialization is for when T is not trivially move constructible
|
||||
* Additionally, this requires E to be trivially move constructible
|
||||
*/
|
||||
template <typename T, typename E>
|
||||
requires std::is_trivially_move_constructible_v<E>
|
||||
struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
|
||||
using expected_copy_base<T, E>::expected_copy_base;
|
||||
|
||||
expected_move_base() = default;
|
||||
|
||||
expected_move_base(const expected_move_base&) = default;
|
||||
|
||||
expected_move_base(expected_move_base&& rhs) noexcept(std::is_nothrow_move_constructible_v<T>)
|
||||
: expected_copy_base<T, E>{no_init_t{}} {
|
||||
if (rhs.has_value()) {
|
||||
this->construct_with(std::move(rhs));
|
||||
} else {
|
||||
this->construct_error(std::move(rhs.geterr()));
|
||||
}
|
||||
}
|
||||
|
||||
expected_move_base& operator=(const expected_move_base&) = default;
|
||||
|
||||
expected_move_base& operator=(expected_move_base&&) = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* This manages conditionally having a trivial copy assignment operator
|
||||
* This specialization is for when T is trivially copy assignable
|
||||
* Additionally, this requires E to be trivially copy assignable
|
||||
*/
|
||||
template <typename T, typename E,
|
||||
bool = std::conjunction_v<std::is_trivially_copy_assignable<T>,
|
||||
std::is_trivially_copy_constructible<T>,
|
||||
std::is_trivially_destructible<T>>>
|
||||
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
|
||||
std::is_trivially_copy_constructible<E>,
|
||||
std::is_trivially_destructible<E>>
|
||||
struct expected_copy_assign_base : expected_move_base<T, E> {
|
||||
using expected_move_base<T, E>::expected_move_base;
|
||||
};
|
||||
|
||||
/**
|
||||
* This specialization is for when T is not trivially copy assignable
|
||||
* Additionally, this requires E to be trivially copy assignable
|
||||
*/
|
||||
template <typename T, typename E>
|
||||
requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
|
||||
std::is_trivially_copy_constructible<E>,
|
||||
std::is_trivially_destructible<E>>
|
||||
struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
|
||||
using expected_move_base<T, E>::expected_move_base;
|
||||
|
||||
expected_copy_assign_base() = default;
|
||||
|
||||
expected_copy_assign_base(const expected_copy_assign_base&) = default;
|
||||
|
||||
expected_copy_assign_base(expected_copy_assign_base&&) = default;
|
||||
|
||||
expected_copy_assign_base& operator=(const expected_copy_assign_base& rhs) {
|
||||
this->assign(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
expected_copy_assign_base& operator=(expected_copy_assign_base&&) = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* This manages conditionally having a trivial move assignment operator
|
||||
* This specialization is for when T is trivially move assignable
|
||||
* Additionally, this requires E to be trivially move assignable
|
||||
*/
|
||||
template <typename T, typename E,
|
||||
bool = std::conjunction_v<std::is_trivially_move_assignable<T>,
|
||||
std::is_trivially_move_constructible<T>,
|
||||
std::is_trivially_destructible<T>>>
|
||||
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
|
||||
std::is_trivially_move_constructible<E>,
|
||||
std::is_trivially_destructible<E>>
|
||||
struct expected_move_assign_base : expected_copy_assign_base<T, E> {
|
||||
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
|
||||
};
|
||||
|
||||
/**
|
||||
* This specialization is for when T is not trivially move assignable
|
||||
* Additionally, this requires E to be trivially move assignable
|
||||
*/
|
||||
template <typename T, typename E>
|
||||
requires std::conjunction_v<std::is_trivially_move_assignable<E>,
|
||||
std::is_trivially_move_constructible<E>,
|
||||
std::is_trivially_destructible<E>>
|
||||
struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E> {
|
||||
using expected_copy_assign_base<T, E>::expected_copy_assign_base;
|
||||
|
||||
expected_move_assign_base() = default;
|
||||
|
||||
expected_move_assign_base(const expected_move_assign_base&) = default;
|
||||
|
||||
expected_move_assign_base(expected_move_assign_base&&) = default;
|
||||
|
||||
expected_move_assign_base& operator=(const expected_move_assign_base&) = default;
|
||||
|
||||
expected_move_assign_base& operator=(expected_move_assign_base&& rhs) noexcept(
|
||||
std::conjunction_v<std::is_nothrow_move_constructible<T>,
|
||||
std::is_nothrow_move_assignable<T>>) {
|
||||
this->assign(std::move(rhs));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* expected_delete_ctor_base will conditionally delete copy and move constructors
|
||||
* depending on whether T is copy/move constructible
|
||||
* Additionally, this requires E to be copy/move constructible
|
||||
*/
|
||||
template <typename T, typename E, bool EnableCopy = std::is_copy_constructible_v<T>,
|
||||
bool EnableMove = std::is_move_constructible_v<T>>
|
||||
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
|
||||
struct expected_delete_ctor_base {
|
||||
expected_delete_ctor_base() = default;
|
||||
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
|
||||
expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default;
|
||||
expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
|
||||
expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
|
||||
struct expected_delete_ctor_base<T, E, true, false> {
|
||||
expected_delete_ctor_base() = default;
|
||||
expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
|
||||
expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete;
|
||||
expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
|
||||
expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
|
||||
struct expected_delete_ctor_base<T, E, false, true> {
|
||||
expected_delete_ctor_base() = default;
|
||||
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
|
||||
expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default;
|
||||
expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
|
||||
expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
|
||||
struct expected_delete_ctor_base<T, E, false, false> {
|
||||
expected_delete_ctor_base() = default;
|
||||
expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
|
||||
expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete;
|
||||
expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
|
||||
expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* expected_delete_assign_base will conditionally delete copy and move assignment operators
|
||||
* depending on whether T is copy/move constructible + assignable
|
||||
* Additionally, this requires E to be copy/move constructible + assignable
|
||||
*/
|
||||
template <
|
||||
typename T, typename E,
|
||||
bool EnableCopy = std::conjunction_v<std::is_copy_constructible<T>, std::is_copy_assignable<T>>,
|
||||
bool EnableMove = std::conjunction_v<std::is_move_constructible<T>, std::is_move_assignable<T>>>
|
||||
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
|
||||
std::is_copy_assignable<E>, std::is_move_assignable<E>>
|
||||
struct expected_delete_assign_base {
|
||||
expected_delete_assign_base() = default;
|
||||
expected_delete_assign_base(const expected_delete_assign_base&) = default;
|
||||
expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
|
||||
expected_delete_assign_base& operator=(const expected_delete_assign_base&) = default;
|
||||
expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = default;
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
|
||||
std::is_copy_assignable<E>, std::is_move_assignable<E>>
|
||||
struct expected_delete_assign_base<T, E, true, false> {
|
||||
expected_delete_assign_base() = default;
|
||||
expected_delete_assign_base(const expected_delete_assign_base&) = default;
|
||||
expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
|
||||
expected_delete_assign_base& operator=(const expected_delete_assign_base&) = default;
|
||||
expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = delete;
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
|
||||
std::is_copy_assignable<E>, std::is_move_assignable<E>>
|
||||
struct expected_delete_assign_base<T, E, false, true> {
|
||||
expected_delete_assign_base() = default;
|
||||
expected_delete_assign_base(const expected_delete_assign_base&) = default;
|
||||
expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
|
||||
expected_delete_assign_base& operator=(const expected_delete_assign_base&) = delete;
|
||||
expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = default;
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
|
||||
std::is_copy_assignable<E>, std::is_move_assignable<E>>
|
||||
struct expected_delete_assign_base<T, E, false, false> {
|
||||
expected_delete_assign_base() = default;
|
||||
expected_delete_assign_base(const expected_delete_assign_base&) = default;
|
||||
expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
|
||||
expected_delete_assign_base& operator=(const expected_delete_assign_base&) = delete;
|
||||
expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is needed to be able to construct the expected_default_ctor_base which follows,
|
||||
* while still conditionally deleting the default constructor.
|
||||
*/
|
||||
struct default_constructor_tag {
|
||||
constexpr explicit default_constructor_tag() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* expected_default_ctor_base will ensure that expected
|
||||
* has a deleted default constructor if T is not default constructible
|
||||
* This specialization is for when T is default constructible
|
||||
*/
|
||||
template <typename T, typename E, bool Enable = std::is_default_constructible_v<T>>
|
||||
struct expected_default_ctor_base {
|
||||
constexpr expected_default_ctor_base() noexcept = default;
|
||||
constexpr expected_default_ctor_base(expected_default_ctor_base const&) noexcept = default;
|
||||
constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = default;
|
||||
expected_default_ctor_base& operator=(expected_default_ctor_base const&) noexcept = default;
|
||||
expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = default;
|
||||
|
||||
constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
struct expected_default_ctor_base<T, E, false> {
|
||||
constexpr expected_default_ctor_base() noexcept = delete;
|
||||
constexpr expected_default_ctor_base(expected_default_ctor_base const&) noexcept = default;
|
||||
constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = default;
|
||||
expected_default_ctor_base& operator=(expected_default_ctor_base const&) noexcept = default;
|
||||
expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = default;
|
||||
|
||||
constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
|
||||
};
|
||||
|
||||
template <typename T, typename E, typename U>
|
||||
using expected_enable_forward_value =
|
||||
std::enable_if_t<std::is_constructible_v<T, U&&> &&
|
||||
!std::is_same_v<std::remove_cvref_t<U>, std::in_place_t> &&
|
||||
!std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
|
||||
!std::is_same_v<Unexpected<E>, std::remove_cvref_t<U>>>;
|
||||
|
||||
template <typename T, typename E, typename U, typename G, typename UR, typename GR>
|
||||
using expected_enable_from_other = std::enable_if_t<
|
||||
std::is_constructible_v<T, UR> && std::is_constructible_v<E, GR> &&
|
||||
!std::is_constructible_v<T, Expected<U, G>&> && !std::is_constructible_v<T, Expected<U, G>&&> &&
|
||||
!std::is_constructible_v<T, const Expected<U, G>&> &&
|
||||
!std::is_constructible_v<T, const Expected<U, G>&&> &&
|
||||
!std::is_convertible_v<Expected<U, G>&, T> && !std::is_convertible_v<Expected<U, G>&&, T> &&
|
||||
!std::is_convertible_v<const Expected<U, G>&, T> &&
|
||||
!std::is_convertible_v<const Expected<U, G>&&, T>>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename E>
|
||||
class Expected : private detail::expected_move_assign_base<T, E>,
|
||||
private detail::expected_delete_ctor_base<T, E>,
|
||||
private detail::expected_delete_assign_base<T, E>,
|
||||
private detail::expected_default_ctor_base<T, E> {
|
||||
public:
|
||||
using value_type = T;
|
||||
using error_type = E;
|
||||
using unexpected_type = Unexpected<E>;
|
||||
|
||||
constexpr Expected() = default;
|
||||
constexpr Expected(const Expected&) = default;
|
||||
constexpr Expected(Expected&&) = default;
|
||||
Expected& operator=(const Expected&) = default;
|
||||
Expected& operator=(Expected&&) = default;
|
||||
|
||||
template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
|
||||
constexpr Expected(std::in_place_t, Args&&... args)
|
||||
: impl_base{std::in_place, std::forward<Args>(args)...},
|
||||
ctor_base{detail::default_constructor_tag{}} {}
|
||||
|
||||
template <typename U, typename... Args,
|
||||
std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
|
||||
nullptr>
|
||||
constexpr Expected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
|
||||
: impl_base{std::in_place, il, std::forward<Args>(args)...},
|
||||
ctor_base{detail::default_constructor_tag{}} {}
|
||||
|
||||
template <typename G = E, std::enable_if_t<std::is_constructible_v<E, const G&>>* = nullptr,
|
||||
std::enable_if_t<!std::is_convertible_v<const G&, E>>* = nullptr>
|
||||
constexpr explicit Expected(const Unexpected<G>& e)
|
||||
: impl_base{unexpect_t{}, e.value()}, ctor_base{detail::default_constructor_tag{}} {}
|
||||
|
||||
template <typename G = E, std::enable_if_t<std::is_constructible_v<E, const G&>>* = nullptr,
|
||||
std::enable_if_t<std::is_convertible_v<const G&, E>>* = nullptr>
|
||||
constexpr Expected(Unexpected<G> const& e)
|
||||
: impl_base{unexpect_t{}, e.value()}, ctor_base{detail::default_constructor_tag{}} {}
|
||||
|
||||
template <typename G = E, std::enable_if_t<std::is_constructible_v<E, G&&>>* = nullptr,
|
||||
std::enable_if_t<!std::is_convertible_v<G&&, E>>* = nullptr>
|
||||
constexpr explicit Expected(Unexpected<G>&& e) noexcept(std::is_nothrow_constructible_v<E, G&&>)
|
||||
: impl_base{unexpect_t{}, std::move(e.value())}, ctor_base{
|
||||
detail::default_constructor_tag{}} {}
|
||||
|
||||
template <typename G = E, std::enable_if_t<std::is_constructible_v<E, G&&>>* = nullptr,
|
||||
std::enable_if_t<std::is_convertible_v<G&&, E>>* = nullptr>
|
||||
constexpr Expected(Unexpected<G>&& e) noexcept(std::is_nothrow_constructible_v<E, G&&>)
|
||||
: impl_base{unexpect_t{}, std::move(e.value())}, ctor_base{
|
||||
detail::default_constructor_tag{}} {}
|
||||
|
||||
template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
|
||||
constexpr explicit Expected(unexpect_t, Args&&... args)
|
||||
: impl_base{unexpect_t{}, std::forward<Args>(args)...},
|
||||
ctor_base{detail::default_constructor_tag{}} {}
|
||||
|
||||
template <typename U, typename... Args,
|
||||
std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
|
||||
nullptr>
|
||||
constexpr explicit Expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
|
||||
: impl_base{unexpect_t{}, il, std::forward<Args>(args)...},
|
||||
ctor_base{detail::default_constructor_tag{}} {}
|
||||
|
||||
template <typename U, typename G,
|
||||
std::enable_if_t<!(std::is_convertible_v<U const&, T> &&
|
||||
std::is_convertible_v<G const&, E>)>* = nullptr,
|
||||
detail::expected_enable_from_other<T, E, U, G, const U&, const G&>* = nullptr>
|
||||
constexpr explicit Expected(const Expected<U, G>& rhs)
|
||||
: ctor_base{detail::default_constructor_tag{}} {
|
||||
if (rhs.has_value()) {
|
||||
this->construct(*rhs);
|
||||
} else {
|
||||
this->construct_error(rhs.error());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, typename G,
|
||||
std::enable_if_t<(std::is_convertible_v<U const&, T> &&
|
||||
std::is_convertible_v<G const&, E>)>* = nullptr,
|
||||
detail::expected_enable_from_other<T, E, U, G, const U&, const G&>* = nullptr>
|
||||
constexpr Expected(const Expected<U, G>& rhs) : ctor_base{detail::default_constructor_tag{}} {
|
||||
if (rhs.has_value()) {
|
||||
this->construct(*rhs);
|
||||
} else {
|
||||
this->construct_error(rhs.error());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, typename G,
|
||||
std::enable_if_t<!(std::is_convertible_v<U&&, T> && std::is_convertible_v<G&&, E>)>* =
|
||||
nullptr,
|
||||
detail::expected_enable_from_other<T, E, U, G, U&&, G&&>* = nullptr>
|
||||
constexpr explicit Expected(Expected<U, G>&& rhs)
|
||||
: ctor_base{detail::default_constructor_tag{}} {
|
||||
if (rhs.has_value()) {
|
||||
this->construct(std::move(*rhs));
|
||||
} else {
|
||||
this->construct_error(std::move(rhs.error()));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, typename G,
|
||||
std::enable_if_t<(std::is_convertible_v<U&&, T> && std::is_convertible_v<G&&, E>)>* =
|
||||
nullptr,
|
||||
detail::expected_enable_from_other<T, E, U, G, U&&, G&&>* = nullptr>
|
||||
constexpr Expected(Expected<U, G>&& rhs) : ctor_base{detail::default_constructor_tag{}} {
|
||||
if (rhs.has_value()) {
|
||||
this->construct(std::move(*rhs));
|
||||
} else {
|
||||
this->construct_error(std::move(rhs.error()));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U = T, std::enable_if_t<!std::is_convertible_v<U&&, T>>* = nullptr,
|
||||
detail::expected_enable_forward_value<T, E, U>* = nullptr>
|
||||
constexpr explicit Expected(U&& v) : Expected{std::in_place, std::forward<U>(v)} {}
|
||||
|
||||
template <typename U = T, std::enable_if_t<std::is_convertible_v<U&&, T>>* = nullptr,
|
||||
detail::expected_enable_forward_value<T, E, U>* = nullptr>
|
||||
constexpr Expected(U&& v) : Expected{std::in_place, std::forward<U>(v)} {}
|
||||
|
||||
template <typename U = T, typename G = T,
|
||||
std::enable_if_t<std::is_nothrow_constructible_v<T, U&&>>* = nullptr,
|
||||
std::enable_if_t<(
|
||||
!std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
|
||||
!std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::remove_cvref_t<U>>> &&
|
||||
std::is_constructible_v<T, U> && std::is_assignable_v<G&, U> &&
|
||||
std::is_nothrow_move_constructible_v<E>)>* = nullptr>
|
||||
Expected& operator=(U&& v) {
|
||||
if (has_value()) {
|
||||
val() = std::forward<U>(v);
|
||||
} else {
|
||||
err().~Unexpected<E>();
|
||||
new (valptr()) T{std::forward<U>(v)};
|
||||
this->m_has_val = true;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U = T, typename G = T,
|
||||
std::enable_if_t<!std::is_nothrow_constructible_v<T, U&&>>* = nullptr,
|
||||
std::enable_if_t<(
|
||||
!std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
|
||||
!std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::remove_cvref_t<U>>> &&
|
||||
std::is_constructible_v<T, U> && std::is_assignable_v<G&, U> &&
|
||||
std::is_nothrow_move_constructible_v<E>)>* = nullptr>
|
||||
Expected& operator=(U&& v) {
|
||||
if (has_value()) {
|
||||
val() = std::forward<U>(v);
|
||||
} else {
|
||||
auto tmp = std::move(err());
|
||||
err().~Unexpected<E>();
|
||||
new (valptr()) T{std::forward<U>(v)};
|
||||
this->m_has_val = true;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename G = E, std::enable_if_t<std::is_nothrow_copy_constructible_v<G> &&
|
||||
std::is_assignable_v<G&, G>>* = nullptr>
|
||||
Expected& operator=(const Unexpected<G>& rhs) {
|
||||
if (!has_value()) {
|
||||
err() = rhs;
|
||||
} else {
|
||||
this->destroy_val();
|
||||
new (errptr()) Unexpected<E>{rhs};
|
||||
this->m_has_val = false;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename G = E, std::enable_if_t<std::is_nothrow_move_constructible_v<G> &&
|
||||
std::is_move_assignable_v<G>>* = nullptr>
|
||||
Expected& operator=(Unexpected<G>&& rhs) noexcept {
|
||||
if (!has_value()) {
|
||||
err() = std::move(rhs);
|
||||
} else {
|
||||
this->destroy_val();
|
||||
new (errptr()) Unexpected<E>{std::move(rhs)};
|
||||
this->m_has_val = false;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... Args,
|
||||
std::enable_if_t<std::is_nothrow_constructible_v<T, Args&&...>>* = nullptr>
|
||||
void emplace(Args&&... args) {
|
||||
if (has_value()) {
|
||||
val() = T{std::forward<Args>(args)...};
|
||||
} else {
|
||||
err().~Unexpected<E>();
|
||||
new (valptr()) T{std::forward<Args>(args)...};
|
||||
this->m_has_val = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args,
|
||||
std::enable_if_t<!std::is_nothrow_constructible_v<T, Args&&...>>* = nullptr>
|
||||
void emplace(Args&&... args) {
|
||||
if (has_value()) {
|
||||
val() = T{std::forward<Args>(args)...};
|
||||
} else {
|
||||
auto tmp = std::move(err());
|
||||
err().~Unexpected<E>();
|
||||
new (valptr()) T{std::forward<Args>(args)...};
|
||||
this->m_has_val = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, typename... Args,
|
||||
std::enable_if_t<std::is_nothrow_constructible_v<T, std::initializer_list<U>&,
|
||||
Args&&...>>* = nullptr>
|
||||
void emplace(std::initializer_list<U> il, Args&&... args) {
|
||||
if (has_value()) {
|
||||
T t{il, std::forward<Args>(args)...};
|
||||
val() = std::move(t);
|
||||
} else {
|
||||
err().~Unexpected<E>();
|
||||
new (valptr()) T{il, std::forward<Args>(args)...};
|
||||
this->m_has_val = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U, typename... Args,
|
||||
std::enable_if_t<!std::is_nothrow_constructible_v<T, std::initializer_list<U>&,
|
||||
Args&&...>>* = nullptr>
|
||||
void emplace(std::initializer_list<U> il, Args&&... args) {
|
||||
if (has_value()) {
|
||||
T t{il, std::forward<Args>(args)...};
|
||||
val() = std::move(t);
|
||||
} else {
|
||||
auto tmp = std::move(err());
|
||||
err().~Unexpected<E>();
|
||||
new (valptr()) T{il, std::forward<Args>(args)...};
|
||||
this->m_has_val = true;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr T* operator->() {
|
||||
return valptr();
|
||||
}
|
||||
|
||||
constexpr const T* operator->() const {
|
||||
return valptr();
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr U& operator*() & {
|
||||
return val();
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr const U& operator*() const& {
|
||||
return val();
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr U&& operator*() && {
|
||||
return std::move(val());
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr const U&& operator*() const&& {
|
||||
return std::move(val());
|
||||
}
|
||||
|
||||
constexpr bool has_value() const noexcept {
|
||||
return this->m_has_val;
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return this->m_has_val;
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr U& value() & {
|
||||
return val();
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr const U& value() const& {
|
||||
return val();
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr U&& value() && {
|
||||
return std::move(val());
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr const U&& value() const&& {
|
||||
return std::move(val());
|
||||
}
|
||||
|
||||
constexpr E& error() & {
|
||||
return err().value();
|
||||
}
|
||||
|
||||
constexpr const E& error() const& {
|
||||
return err().value();
|
||||
}
|
||||
|
||||
constexpr E&& error() && {
|
||||
return std::move(err().value());
|
||||
}
|
||||
|
||||
constexpr const E&& error() const&& {
|
||||
return std::move(err().value());
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
constexpr T value_or(U&& v) const& {
|
||||
static_assert(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>,
|
||||
"T must be copy-constructible and convertible from U&&");
|
||||
return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
constexpr T value_or(U&& v) && {
|
||||
static_assert(std::is_move_constructible_v<T> && std::is_convertible_v<U&&, T>,
|
||||
"T must be move-constructible and convertible from U&&");
|
||||
return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
|
||||
}
|
||||
|
||||
private:
|
||||
static_assert(!std::is_reference_v<T>, "T must not be a reference");
|
||||
static_assert(!std::is_same_v<T, std::remove_cv_t<std::in_place_t>>,
|
||||
"T must not be std::in_place_t");
|
||||
static_assert(!std::is_same_v<T, std::remove_cv_t<unexpect_t>>, "T must not be unexpect_t");
|
||||
static_assert(!std::is_same_v<T, std::remove_cv_t<Unexpected<E>>>,
|
||||
"T must not be Unexpected<E>");
|
||||
static_assert(!std::is_reference_v<E>, "E must not be a reference");
|
||||
|
||||
T* valptr() {
|
||||
return std::addressof(this->m_val);
|
||||
}
|
||||
|
||||
const T* valptr() const {
|
||||
return std::addressof(this->m_val);
|
||||
}
|
||||
|
||||
Unexpected<E>* errptr() {
|
||||
return std::addressof(this->m_unexpect);
|
||||
}
|
||||
|
||||
const Unexpected<E>* errptr() const {
|
||||
return std::addressof(this->m_unexpect);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr U& val() {
|
||||
return this->m_val;
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
constexpr const U& val() const {
|
||||
return this->m_val;
|
||||
}
|
||||
|
||||
constexpr Unexpected<E>& err() {
|
||||
return this->m_unexpect;
|
||||
}
|
||||
|
||||
constexpr const Unexpected<E>& err() const {
|
||||
return this->m_unexpect;
|
||||
}
|
||||
|
||||
using impl_base = detail::expected_move_assign_base<T, E>;
|
||||
using ctor_base = detail::expected_default_ctor_base<T, E>;
|
||||
};
|
||||
|
||||
template <typename T, typename E, typename U, typename F>
|
||||
constexpr bool operator==(const Expected<T, E>& lhs, const Expected<U, F>& rhs) {
|
||||
return (lhs.has_value() != rhs.has_value())
|
||||
? false
|
||||
: (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename U, typename F>
|
||||
constexpr bool operator!=(const Expected<T, E>& lhs, const Expected<U, F>& rhs) {
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename U>
|
||||
constexpr bool operator==(const Expected<T, E>& x, const U& v) {
|
||||
return x.has_value() ? *x == v : false;
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename U>
|
||||
constexpr bool operator==(const U& v, const Expected<T, E>& x) {
|
||||
return x.has_value() ? *x == v : false;
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename U>
|
||||
constexpr bool operator!=(const Expected<T, E>& x, const U& v) {
|
||||
return !operator==(x, v);
|
||||
}
|
||||
|
||||
template <typename T, typename E, typename U>
|
||||
constexpr bool operator!=(const U& v, const Expected<T, E>& x) {
|
||||
return !operator==(v, x);
|
||||
}
|
||||
|
||||
template <typename T, typename E>
|
||||
constexpr bool operator==(const Expected<T, E>& x, const Unexpected<E>& e) {
|
||||
return x.has_value() ? false : x.error() == e.value();
|
||||
}
|
||||
|
||||
template <typename T, typename E>
|
||||
constexpr bool operator==(const Unexpected<E>& e, const Expected<T, E>& x) {
|
||||
return x.has_value() ? false : x.error() == e.value();
|
||||
}
|
||||
|
||||
template <typename T, typename E>
|
||||
constexpr bool operator!=(const Expected<T, E>& x, const Unexpected<E>& e) {
|
||||
return !operator==(x, e);
|
||||
}
|
||||
|
||||
template <typename T, typename E>
|
||||
constexpr bool operator!=(const Unexpected<E>& e, const Expected<T, E>& x) {
|
||||
return !operator==(e, x);
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
+85
-12
@@ -11,7 +11,12 @@
|
||||
#include "common/fiber.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/fiber.h>
|
||||
#else
|
||||
#include <boost/context/detail/fcontext.hpp>
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
@@ -22,36 +27,103 @@ constexpr size_t DEFAULT_STACK_SIZE = 512 * 4096;
|
||||
#endif
|
||||
constexpr u32 CANARY_VALUE = 0xDEADBEEF;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
struct Fiber::FiberImpl {
|
||||
FiberImpl() {}
|
||||
|
||||
u32 canary_1 = CANARY_VALUE;
|
||||
std::array<u8, DEFAULT_STACK_SIZE> stack{};
|
||||
std::array<u8, DEFAULT_STACK_SIZE> rewind_stack{};
|
||||
std::array<u8, DEFAULT_STACK_SIZE> astack{};
|
||||
u32 canary_2 = CANARY_VALUE;
|
||||
|
||||
boost::context::detail::fcontext_t context{};
|
||||
boost::context::detail::fcontext_t rewind_context{};
|
||||
emscripten_fiber_t* context{nullptr};
|
||||
|
||||
std::mutex guard;
|
||||
std::function<void()> entry_point;
|
||||
std::function<void()> rewind_point;
|
||||
std::shared_ptr<Fiber> previous_fiber;
|
||||
|
||||
u8* stack_limit = nullptr;
|
||||
u8* rewind_stack_limit = nullptr;
|
||||
bool is_thread_fiber = false;
|
||||
bool released = false;
|
||||
};
|
||||
|
||||
void Fiber::SetRewindPoint(std::function<void()>&& rewind_func) {
|
||||
impl->rewind_point = std::move(rewind_func);
|
||||
Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
|
||||
impl->entry_point = std::move(entry_point_func);
|
||||
emscripten_fiber_init(impl->context, [](void *user_data) -> void {
|
||||
auto* fiber = static_cast<Fiber*>(user_data);
|
||||
ASSERT(fiber && fiber->impl && fiber->impl->previous_fiber && fiber->impl->previous_fiber->impl);
|
||||
ASSERT(fiber->impl->canary_1 == CANARY_VALUE);
|
||||
ASSERT(fiber->impl->canary_2 == CANARY_VALUE);
|
||||
fiber->impl->previous_fiber->impl->context = fiber->impl->context;
|
||||
fiber->impl->previous_fiber->impl->guard.unlock();
|
||||
fiber->impl->previous_fiber.reset();
|
||||
fiber->impl->entry_point();
|
||||
UNREACHABLE();
|
||||
}, impl.get(), impl->stack.data(), impl->stack.size(), impl->astack.data(), impl->astack.size());
|
||||
}
|
||||
|
||||
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
|
||||
|
||||
Fiber::~Fiber() {
|
||||
if (!impl->released) {
|
||||
// Make sure the Fiber is not being used
|
||||
const bool locked = impl->guard.try_lock();
|
||||
ASSERT(locked && "Destroying a fiber that's still running");
|
||||
if (locked) {
|
||||
impl->guard.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fiber::Exit() {
|
||||
ASSERT(impl->is_thread_fiber && "Exiting non main thread fiber");
|
||||
if (impl->is_thread_fiber) {
|
||||
impl->guard.unlock();
|
||||
impl->released = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Fiber::YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to) {
|
||||
to.impl->guard.lock();
|
||||
to.impl->previous_fiber = weak_from.lock();
|
||||
emscripten_fiber_swap(to.impl->context, to.impl->previous_fiber->impl->context);
|
||||
// "from" might no longer be valid if the thread was killed
|
||||
if (auto from = weak_from.lock()) {
|
||||
if (from->impl->previous_fiber == nullptr) {
|
||||
ASSERT(false && "previous_fiber is nullptr!");
|
||||
} else {
|
||||
from->impl->previous_fiber->impl->guard.unlock();
|
||||
from->impl->previous_fiber.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
||||
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
|
||||
fiber->impl->guard.lock();
|
||||
fiber->impl->is_thread_fiber = true;
|
||||
return fiber;
|
||||
}
|
||||
#else
|
||||
struct Fiber::FiberImpl {
|
||||
FiberImpl() {}
|
||||
|
||||
u32 canary_1 = CANARY_VALUE;
|
||||
std::array<u8, DEFAULT_STACK_SIZE> stack{};
|
||||
u32 canary_2 = CANARY_VALUE;
|
||||
|
||||
boost::context::detail::fcontext_t context{};
|
||||
|
||||
std::mutex guard;
|
||||
std::function<void()> entry_point;
|
||||
std::shared_ptr<Fiber> previous_fiber;
|
||||
|
||||
u8* stack_limit = nullptr;
|
||||
bool is_thread_fiber = false;
|
||||
bool released = false;
|
||||
};
|
||||
|
||||
Fiber::Fiber(std::function<void()>&& entry_point_func) : impl{std::make_unique<FiberImpl>()} {
|
||||
impl->entry_point = std::move(entry_point_func);
|
||||
impl->stack_limit = impl->stack.data();
|
||||
impl->rewind_stack_limit = impl->rewind_stack.data();
|
||||
u8* stack_base = impl->stack_limit + DEFAULT_STACK_SIZE;
|
||||
impl->context = boost::context::detail::make_fcontext(stack_base, impl->stack.size(), [](boost::context::detail::transfer_t transfer) -> void {
|
||||
auto* fiber = static_cast<Fiber*>(transfer.data);
|
||||
@@ -72,7 +144,7 @@ Fiber::~Fiber() {
|
||||
if (!impl->released) {
|
||||
// Make sure the Fiber is not being used
|
||||
const bool locked = impl->guard.try_lock();
|
||||
ASSERT_MSG(locked, "Destroying a fiber that's still running");
|
||||
ASSERT(locked && "Destroying a fiber that's still running");
|
||||
if (locked) {
|
||||
impl->guard.unlock();
|
||||
}
|
||||
@@ -80,7 +152,7 @@ Fiber::~Fiber() {
|
||||
}
|
||||
|
||||
void Fiber::Exit() {
|
||||
ASSERT_MSG(impl->is_thread_fiber, "Exiting non main thread fiber");
|
||||
ASSERT(impl->is_thread_fiber && "Exiting non main thread fiber");
|
||||
if (impl->is_thread_fiber) {
|
||||
impl->guard.unlock();
|
||||
impl->released = true;
|
||||
@@ -110,5 +182,6 @@ std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
|
||||
fiber->impl->is_thread_fiber = true;
|
||||
return fiber;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Common
|
||||
|
||||
+1
-2
@@ -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 2020 yuzu Emulator Project
|
||||
@@ -45,7 +45,6 @@ public:
|
||||
/// Fiber 'from' must be the currently running fiber.
|
||||
static void YieldTo(std::weak_ptr<Fiber> weak_from, Fiber& to);
|
||||
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
|
||||
void SetRewindPoint(std::function<void()>&& rewind_func);
|
||||
/// Only call from main thread's fiber
|
||||
void Exit();
|
||||
private:
|
||||
|
||||
@@ -136,6 +136,11 @@ public:
|
||||
eden_path = GetDataDirectory("XDG_DATA_HOME") / EDEN_DIR;
|
||||
eden_path_cache = GetDataDirectory("XDG_CACHE_HOME") / EDEN_DIR;
|
||||
eden_path_config = GetDataDirectory("XDG_CONFIG_HOME") / EDEN_DIR;
|
||||
#if defined(__EMSCRIPTEN__) || defined(__wasi__) || defined(__managarm__)
|
||||
// folders MAY not exist in this distrobution/OS
|
||||
CreateParentDir(GetDataDirectory("XDG_CONFIG_HOME"));
|
||||
CreateParentDir(GetDataDirectory("XDG_CACHE_HOME"));
|
||||
#endif
|
||||
} else {
|
||||
eden_path_cache = eden_path / CACHE_DIR;
|
||||
eden_path_config = eden_path / CONFIG_DIR;
|
||||
|
||||
@@ -394,7 +394,7 @@ private:
|
||||
ankerl::unordered_dense::map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset
|
||||
};
|
||||
|
||||
#elif defined(__OPENORBIS__) || defined(__managarm__)
|
||||
#elif defined(__OPENORBIS__) || defined(__managarm__) || defined(__wasi__) || defined(__EMSCRIPTEN__)
|
||||
// None of the luxuries of POSIX, all of the suffering
|
||||
// For managarm: see https://github.com/managarm/managarm/issues/1370
|
||||
#else // ^^^ Windows ^^^ vvv POSIX vvv
|
||||
@@ -689,7 +689,7 @@ HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size(backing_size_)
|
||||
, virtual_size(virtual_size_)
|
||||
{
|
||||
#if defined(__OPENORBIS__) || defined(__managarm__)
|
||||
#if defined(__OPENORBIS__) || defined(__managarm__) || defined(__wasi__) || defined(__EMSCRIPTEN__)
|
||||
LOG_WARNING(HW_Memory, "Platform doesn't support fastmem");
|
||||
fallback_buffer.emplace(backing_size);
|
||||
backing_base = fallback_buffer->data();
|
||||
@@ -723,7 +723,7 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default;
|
||||
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
|
||||
|
||||
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms, bool separate_heap) {
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__) || defined(__wasi__) || defined(__EMSCRIPTEN__))
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(host_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
@@ -737,7 +737,7 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, M
|
||||
}
|
||||
|
||||
void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__) || defined(__wasi__) || defined(__EMSCRIPTEN__))
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
@@ -749,7 +749,7 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap)
|
||||
}
|
||||
|
||||
void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) {
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__) || defined(__wasi__) || defined(__EMSCRIPTEN__))
|
||||
ASSERT(virtual_offset % PageAlignment == 0);
|
||||
ASSERT(length % PageAlignment == 0);
|
||||
ASSERT(virtual_offset + length <= virtual_size);
|
||||
@@ -768,7 +768,7 @@ void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 f
|
||||
}
|
||||
|
||||
void HostMemory::EnableDirectMappedAddress() {
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__) || defined(__wasi__) || defined(__EMSCRIPTEN__))
|
||||
if (impl) {
|
||||
impl->EnableDirectMappedAddress();
|
||||
virtual_size += reinterpret_cast<uintptr_t>(virtual_base);
|
||||
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
size_t backing_size{};
|
||||
size_t virtual_size{};
|
||||
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__) || defined(__wasi__) || defined(__EMSCRIPTEN__))
|
||||
// Low level handler for the platform dependent memory routines
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
|
||||
+10
-1
@@ -54,7 +54,6 @@ SWITCHABLE(CpuBackend, true);
|
||||
SWITCHABLE(CpuAccuracy, true);
|
||||
SWITCHABLE(FullscreenMode, true);
|
||||
SWITCHABLE(GpuAccuracy, true);
|
||||
SWITCHABLE(GpuLogLevel, true);
|
||||
SWITCHABLE(Language, true);
|
||||
SWITCHABLE(MemoryLayout, true);
|
||||
SWITCHABLE(NvdecEmulation, false);
|
||||
@@ -213,6 +212,16 @@ bool IsNceEnabled() {
|
||||
return is_nce_enabled;
|
||||
}
|
||||
|
||||
static u64 current_program_id = 0;
|
||||
|
||||
void SetCurrentProgramID(u64 program_id) {
|
||||
current_program_id = program_id;
|
||||
}
|
||||
|
||||
u64 GetCurrentProgramID() {
|
||||
return current_program_id;
|
||||
}
|
||||
|
||||
bool IsDockedMode() {
|
||||
return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked;
|
||||
}
|
||||
|
||||
+14
-5
@@ -573,6 +573,13 @@ struct Values {
|
||||
false,
|
||||
#endif
|
||||
"rescale_hack", Category::RendererHacks};
|
||||
SwitchableSetting<bool> enable_gpu_buffer_readback{linkage,
|
||||
false,
|
||||
"enable_gpu_buffer_readback",
|
||||
Category::RendererAdvanced,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
|
||||
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
||||
Category::RendererHacks};
|
||||
@@ -788,8 +795,8 @@ struct Values {
|
||||
false}; // runtime_modifiable_ — startup-only
|
||||
Setting<bool> dump_exefs{linkage, false, "dump_exefs", Category::Debugging};
|
||||
Setting<bool> dump_nso{linkage, false, "dump_nso", Category::Debugging};
|
||||
Setting<bool> dump_shaders{
|
||||
linkage, false, "dump_shaders", Category::DebuggingGraphics, Specialization::Default,
|
||||
Setting<bool> dump_guest_shaders{
|
||||
linkage, false, "dump_guest_shaders", Category::DebuggingGraphics, Specialization::Default,
|
||||
false};
|
||||
Setting<bool> dump_macros{
|
||||
linkage, false, "dump_macros", Category::DebuggingGraphics, Specialization::Default, false};
|
||||
@@ -813,9 +820,8 @@ struct Values {
|
||||
Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Debugging};
|
||||
|
||||
// GPU Logging
|
||||
Setting<bool> gpu_logging_enabled{linkage, false, "gpu_logging_enabled", Category::Debugging};
|
||||
SwitchableSetting<GpuLogLevel> gpu_log_level{linkage, GpuLogLevel::Standard, "gpu_log_level",
|
||||
Category::Debugging};
|
||||
Setting<GpuLogLevel> gpu_log_level{linkage, GpuLogLevel::Off, "gpu_log_level",
|
||||
Category::Debugging};
|
||||
Setting<bool> gpu_log_vulkan_calls{linkage, true, "gpu_log_vulkan_calls", Category::Debugging};
|
||||
Setting<bool> gpu_log_shader_dumps{linkage, false, "gpu_log_shader_dumps", Category::Debugging};
|
||||
Setting<bool> gpu_log_memory_tracking{linkage, true, "gpu_log_memory_tracking",
|
||||
@@ -876,6 +882,9 @@ bool IsFastmemEnabled();
|
||||
void SetNceEnabled(bool is_64bit);
|
||||
bool IsNceEnabled();
|
||||
|
||||
void SetCurrentProgramID(u64 program_id);
|
||||
u64 GetCurrentProgramID();
|
||||
|
||||
bool IsOpenGL();
|
||||
|
||||
bool IsDockedMode();
|
||||
|
||||
@@ -78,6 +78,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
|
||||
}
|
||||
}();
|
||||
set_thread_priority(find_thread(NULL), priority);
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
// TODO: set priority?
|
||||
#else
|
||||
pthread_t this_thread = pthread_self();
|
||||
const auto scheduling_type = SCHED_OTHER;
|
||||
@@ -127,6 +129,8 @@ void SetCurrentThreadName(const char* name) {
|
||||
// See for reference
|
||||
// https://gitlab.freedesktop.org/mesa/mesa/-/blame/main/src/util/u_thread.c?ref_type=heads#L75
|
||||
(void)name;
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
// TODO: set thread name?
|
||||
#else
|
||||
pthread_setname_np(pthread_self(), name);
|
||||
#endif
|
||||
|
||||
@@ -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 2020 yuzu Emulator Project
|
||||
@@ -17,7 +17,11 @@ namespace Common {
|
||||
|
||||
void* AllocateMemoryPages(std::size_t size) noexcept {
|
||||
#ifdef _WIN32
|
||||
void* base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
void* base = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if (base == nullptr) {
|
||||
// Probably failing to reserve is less likely than failing to commit
|
||||
base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
#else
|
||||
void* base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
if (base == MAP_FAILED)
|
||||
|
||||
+13
-6
@@ -38,10 +38,6 @@ add_library(core STATIC
|
||||
debugger/debugger.cpp
|
||||
debugger/debugger.h
|
||||
debugger/debugger_interface.h
|
||||
debugger/gdbstub.cpp
|
||||
debugger/gdbstub.h
|
||||
debugger/gdbstub_arch.cpp
|
||||
debugger/gdbstub_arch.h
|
||||
device_memory.cpp
|
||||
device_memory.h
|
||||
device_memory_manager.h
|
||||
@@ -1170,6 +1166,14 @@ add_library(core STATIC
|
||||
tools/freezer.h
|
||||
tools/renderdoc.cpp
|
||||
tools/renderdoc.h)
|
||||
if (NOT PLATFORM_EMSCRIPTEN)
|
||||
# incompatible with wasm's async model
|
||||
target_sources(core PRIVATE
|
||||
debugger/gdbstub.cpp
|
||||
debugger/gdbstub.h
|
||||
debugger/gdbstub_arch.cpp
|
||||
debugger/gdbstub_arch.h)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WIFI_SCAN)
|
||||
target_sources(core PRIVATE internal_network/wifi_scanner.cpp)
|
||||
@@ -1199,7 +1203,7 @@ if (MSVC)
|
||||
)
|
||||
else()
|
||||
target_compile_options(core PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-sign-conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-cast-function-type>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>)
|
||||
@@ -1213,7 +1217,10 @@ target_include_directories(core PRIVATE ${OPUS_INCLUDE_DIRS})
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz)
|
||||
|
||||
if (BOOST_NO_HEADERS)
|
||||
target_link_libraries(core PUBLIC Boost::container Boost::heap Boost::asio Boost::process Boost::crc)
|
||||
target_link_libraries(core PUBLIC Boost::container Boost::heap Boost::crc)
|
||||
if (NOT PLATFORM_EMSCRIPTEN)
|
||||
target_link_libraries(core PUBLIC Boost::asio Boost::process)
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(core PUBLIC Boost::headers)
|
||||
endif()
|
||||
|
||||
@@ -6,19 +6,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#include <dynarmic/interface/halt_reason.h>
|
||||
|
||||
#endif
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
constexpr Dynarmic::HaltReason StepThread = Dynarmic::HaltReason::Step;
|
||||
constexpr Dynarmic::HaltReason DataAbort = Dynarmic::HaltReason::MemoryAbort;
|
||||
constexpr Dynarmic::HaltReason BreakLoop = Dynarmic::HaltReason::UserDefined2;
|
||||
constexpr Dynarmic::HaltReason SupervisorCall = Dynarmic::HaltReason::UserDefined3;
|
||||
constexpr Dynarmic::HaltReason InstructionBreakpoint = Dynarmic::HaltReason::UserDefined4;
|
||||
constexpr Dynarmic::HaltReason PrefetchAbort = Dynarmic::HaltReason::UserDefined6;
|
||||
|
||||
constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
||||
static_assert(u64(HaltReason::StepThread) == u64(StepThread));
|
||||
static_assert(u64(HaltReason::DataAbort) == u64(DataAbort));
|
||||
@@ -28,5 +29,6 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
||||
static_assert(u64(HaltReason::PrefetchAbort) == u64(PrefetchAbort));
|
||||
return HaltReason(hr);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Core
|
||||
|
||||
+10
-9
@@ -108,7 +108,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
|
||||
struct System::Impl {
|
||||
explicit Impl(System& system)
|
||||
: kernel{system}, fs_controller{system}, hid_core{}, cpu_manager{system},
|
||||
: kernel{system}, fs_controller{system}, hid_core{system.Kernel()}, cpu_manager{system},
|
||||
reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {}
|
||||
|
||||
u64 program_id;
|
||||
@@ -271,7 +271,7 @@ struct System::Impl {
|
||||
|
||||
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
|
||||
host1x_core.emplace(system);
|
||||
gpu_core = VideoCore::CreateGPU(emu_window, system);
|
||||
VideoCore::CreateGPU(gpu_core, emu_window, system);
|
||||
if (!gpu_core)
|
||||
return SystemResultStatus::ErrorVideoCore;
|
||||
|
||||
@@ -326,6 +326,9 @@ struct System::Impl {
|
||||
|
||||
LOG_INFO(Core, "Loading {} ({:016X}) ...", name, params.program_id);
|
||||
|
||||
// Expose program id to dump sites and other global readers.
|
||||
Settings::SetCurrentProgramID(params.program_id);
|
||||
|
||||
// Track launch time for frontend launches
|
||||
LaunchTimestampCache::SaveLaunchTimestamp(params.program_id);
|
||||
|
||||
@@ -347,7 +350,7 @@ struct System::Impl {
|
||||
|
||||
// Register with applet manager
|
||||
// All threads are started, begin main process execution, now that we're in the clear
|
||||
applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params);
|
||||
applet_manager.CreateAndInsertByFrontendAppletParameters(std::make_unique<Service::Process>(*std::move(process)), params);
|
||||
|
||||
if (Settings::values.gamecard_inserted) {
|
||||
if (Settings::values.gamecard_current_game) {
|
||||
@@ -391,10 +394,8 @@ struct System::Impl {
|
||||
is_powered_on = false;
|
||||
exit_locked = false;
|
||||
exit_requested = false;
|
||||
|
||||
if (gpu_core != nullptr) {
|
||||
if (gpu_core)
|
||||
gpu_core->NotifyShutdown();
|
||||
}
|
||||
|
||||
stop_event.request_stop();
|
||||
core_timing.SyncPause(false);
|
||||
@@ -478,6 +479,7 @@ struct System::Impl {
|
||||
std::optional<Memory::CheatEngine> cheat_engine;
|
||||
std::optional<Tools::Freezer> memory_freezer;
|
||||
std::optional<Tools::RenderdocAPI> renderdoc_api;
|
||||
std::optional<Tegra::GPU> gpu_core;
|
||||
|
||||
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> gpu_dirty_memory_managers;
|
||||
std::vector<std::vector<u8>> user_channel;
|
||||
@@ -492,7 +494,6 @@ struct System::Impl {
|
||||
std::unique_ptr<FileSys::ContentProviderUnion> content_provider;
|
||||
/// AppLoader used to load the current executing application
|
||||
std::unique_ptr<Loader::AppLoader> app_loader;
|
||||
std::unique_ptr<Tegra::GPU> gpu_core;
|
||||
std::stop_source stop_event;
|
||||
|
||||
mutable std::mutex suspend_guard;
|
||||
@@ -925,7 +926,7 @@ void System::PushGeneralChannelData(std::vector<u8>&& data) {
|
||||
const bool was_empty = impl->general_channel.empty();
|
||||
impl->general_channel.push_back(std::move(data));
|
||||
if (was_empty) {
|
||||
impl->general_channel_event->Signal();
|
||||
impl->general_channel_event->Signal(impl->kernel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,7 +938,7 @@ bool System::TryPopGeneralChannel(std::vector<u8>& out_data) {
|
||||
out_data = std::move(impl->general_channel.back());
|
||||
impl->general_channel.pop_back();
|
||||
if (impl->general_channel.empty()) {
|
||||
impl->general_channel_event->Clear();
|
||||
impl->general_channel_event->Clear(impl->kernel);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -438,7 +438,6 @@ public:
|
||||
/// Applies any changes to settings to this core instance.
|
||||
void ApplySettings();
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
+35
-50
@@ -25,9 +25,11 @@ CpuManager::~CpuManager() = default;
|
||||
|
||||
void CpuManager::Initialize() {
|
||||
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
|
||||
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
|
||||
gpu_barrier.emplace(num_cores + 1);
|
||||
for (std::size_t core = 0; core < num_cores; core++)
|
||||
core_data[core].host_thread = std::jthread([this, core](std::stop_token token) { RunThread(token, core); });
|
||||
core_data[core].host_thread = std::jthread([this, core](std::stop_token token) {
|
||||
RunThread(token, core);
|
||||
});
|
||||
}
|
||||
|
||||
void CpuManager::Shutdown() {
|
||||
@@ -39,69 +41,61 @@ void CpuManager::Shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::GuestThreadFunction() {
|
||||
void CpuManager::GuestThreadFunction(Kernel::KernelCore& kernel) {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunGuestThread();
|
||||
MultiCoreRunGuestThread(kernel);
|
||||
} else {
|
||||
SingleCoreRunGuestThread();
|
||||
SingleCoreRunGuestThread(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::IdleThreadFunction() {
|
||||
void CpuManager::IdleThreadFunction(Kernel::KernelCore& kernel) {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunIdleThread();
|
||||
MultiCoreRunIdleThread(kernel);
|
||||
} else {
|
||||
SingleCoreRunIdleThread();
|
||||
SingleCoreRunIdleThread(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::ShutdownThreadFunction() {
|
||||
ShutdownThread();
|
||||
void CpuManager::ShutdownThreadFunction(Kernel::KernelCore& kernel) {
|
||||
ShutdownThread(kernel);
|
||||
}
|
||||
|
||||
void CpuManager::HandleInterrupt() {
|
||||
auto& kernel = system.Kernel();
|
||||
void CpuManager::HandleInterrupt(Kernel::KernelCore& kernel) {
|
||||
auto core_index = kernel.CurrentPhysicalCoreIndex();
|
||||
|
||||
Kernel::KInterruptManager::HandleInterrupt(kernel, static_cast<s32>(core_index));
|
||||
Kernel::KInterruptManager::HandleInterrupt(kernel, s32(core_index));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// MultiCore ///
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CpuManager::MultiCoreRunGuestThread() {
|
||||
void CpuManager::MultiCoreRunGuestThread(Kernel::KernelCore& kernel) {
|
||||
// Similar to UserModeThreadStarter in HOS
|
||||
auto& kernel = system.Kernel();
|
||||
auto* thread = Kernel::GetCurrentThreadPointer(kernel);
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
kernel.CurrentScheduler()->OnThreadStart(kernel);
|
||||
|
||||
while (true) {
|
||||
auto* physical_core = &kernel.CurrentPhysicalCore();
|
||||
while (!physical_core->IsInterrupted()) {
|
||||
physical_core->RunThread(thread);
|
||||
physical_core->RunThread(kernel, thread);
|
||||
physical_core = &kernel.CurrentPhysicalCore();
|
||||
}
|
||||
|
||||
HandleInterrupt();
|
||||
HandleInterrupt(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::MultiCoreRunIdleThread() {
|
||||
void CpuManager::MultiCoreRunIdleThread(Kernel::KernelCore& kernel) {
|
||||
// Not accurate to HOS. Remove this entire method when singlecore is removed.
|
||||
// See notes in KScheduler::ScheduleImpl for more information about why this
|
||||
// is inaccurate.
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
|
||||
kernel.CurrentScheduler()->OnThreadStart(kernel);
|
||||
while (true) {
|
||||
auto& physical_core = kernel.CurrentPhysicalCore();
|
||||
if (!physical_core.IsInterrupted()) {
|
||||
physical_core.Idle();
|
||||
}
|
||||
|
||||
HandleInterrupt();
|
||||
HandleInterrupt(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,15 +103,14 @@ void CpuManager::MultiCoreRunIdleThread() {
|
||||
/// SingleCore ///
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CpuManager::SingleCoreRunGuestThread() {
|
||||
auto& kernel = system.Kernel();
|
||||
void CpuManager::SingleCoreRunGuestThread(Kernel::KernelCore& kernel) {
|
||||
auto* thread = Kernel::GetCurrentThreadPointer(kernel);
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
kernel.CurrentScheduler()->OnThreadStart(kernel);
|
||||
|
||||
while (true) {
|
||||
auto* physical_core = &kernel.CurrentPhysicalCore();
|
||||
if (!physical_core->IsInterrupted()) {
|
||||
physical_core->RunThread(thread);
|
||||
physical_core->RunThread(kernel, thread);
|
||||
physical_core = &kernel.CurrentPhysicalCore();
|
||||
}
|
||||
|
||||
@@ -125,26 +118,22 @@ void CpuManager::SingleCoreRunGuestThread() {
|
||||
system.CoreTiming().Advance();
|
||||
kernel.SetIsPhantomModeForSingleCore(false);
|
||||
|
||||
PreemptSingleCore();
|
||||
HandleInterrupt();
|
||||
PreemptSingleCore(kernel);
|
||||
HandleInterrupt(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::SingleCoreRunIdleThread() {
|
||||
auto& kernel = system.Kernel();
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
|
||||
void CpuManager::SingleCoreRunIdleThread(Kernel::KernelCore& kernel) {
|
||||
kernel.CurrentScheduler()->OnThreadStart(kernel);
|
||||
while (true) {
|
||||
PreemptSingleCore(false);
|
||||
PreemptSingleCore(kernel, false);
|
||||
system.CoreTiming().AddTicks(1000U);
|
||||
idle_count++;
|
||||
HandleInterrupt();
|
||||
HandleInterrupt(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::PreemptSingleCore(bool from_running_environment) {
|
||||
auto& kernel = system.Kernel();
|
||||
|
||||
void CpuManager::PreemptSingleCore(Kernel::KernelCore& kernel, bool from_running_environment) {
|
||||
if (idle_count >= 4 || from_running_environment) {
|
||||
if (!from_running_environment) {
|
||||
system.CoreTiming().Idle();
|
||||
@@ -156,7 +145,7 @@ void CpuManager::PreemptSingleCore(bool from_running_environment) {
|
||||
}
|
||||
current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
|
||||
system.CoreTiming().ResetTicks();
|
||||
kernel.Scheduler(current_core).PreemptSingleCore();
|
||||
kernel.Scheduler(current_core).PreemptSingleCore(kernel);
|
||||
|
||||
// We've now been scheduled again, and we may have exchanged schedulers.
|
||||
// Reload the scheduler in case it's different.
|
||||
@@ -165,20 +154,16 @@ void CpuManager::PreemptSingleCore(bool from_running_environment) {
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::GuestActivate() {
|
||||
void CpuManager::GuestActivate(Kernel::KernelCore& kernel) {
|
||||
// Similar to the HorizonKernelMain callback in HOS
|
||||
auto& kernel = system.Kernel();
|
||||
auto* scheduler = kernel.CurrentScheduler();
|
||||
|
||||
scheduler->Activate();
|
||||
scheduler->Activate(kernel);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void CpuManager::ShutdownThread() {
|
||||
auto& kernel = system.Kernel();
|
||||
void CpuManager::ShutdownThread(Kernel::KernelCore& kernel) {
|
||||
auto* thread = kernel.GetCurrentEmuThread();
|
||||
auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0;
|
||||
|
||||
Common::Fiber::YieldTo(thread->GetHostContext(), *core_data[core].host_context);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
+32
-27
@@ -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
|
||||
|
||||
@@ -14,6 +17,10 @@
|
||||
#include "common/thread.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
class Event;
|
||||
class Fiber;
|
||||
@@ -51,57 +58,55 @@ public:
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
std::function<void()> GetGuestActivateFunc() {
|
||||
return [this] { GuestActivate(); };
|
||||
std::function<void()> GetGuestActivateFunc(Kernel::KernelCore& kernel) {
|
||||
return [this, &kernel] { GuestActivate(kernel); };
|
||||
}
|
||||
std::function<void()> GetGuestThreadFunc() {
|
||||
return [this] { GuestThreadFunction(); };
|
||||
std::function<void()> GetGuestThreadFunc(Kernel::KernelCore& kernel) {
|
||||
return [this, &kernel] { GuestThreadFunction(kernel); };
|
||||
}
|
||||
std::function<void()> GetIdleThreadStartFunc() {
|
||||
return [this] { IdleThreadFunction(); };
|
||||
std::function<void()> GetIdleThreadStartFunc(Kernel::KernelCore& kernel) {
|
||||
return [this, &kernel] { IdleThreadFunction(kernel); };
|
||||
}
|
||||
std::function<void()> GetShutdownThreadStartFunc() {
|
||||
return [this] { ShutdownThreadFunction(); };
|
||||
std::function<void()> GetShutdownThreadStartFunc(Kernel::KernelCore& kernel) {
|
||||
return [this, &kernel] { ShutdownThreadFunction(kernel); };
|
||||
}
|
||||
|
||||
void PreemptSingleCore(bool from_running_environment = true);
|
||||
void PreemptSingleCore(Kernel::KernelCore& kernel, bool from_running_environment = true);
|
||||
|
||||
std::size_t CurrentCore() const {
|
||||
return current_core.load();
|
||||
}
|
||||
|
||||
private:
|
||||
void GuestThreadFunction();
|
||||
void IdleThreadFunction();
|
||||
void ShutdownThreadFunction();
|
||||
void GuestThreadFunction(Kernel::KernelCore& kernel);
|
||||
void IdleThreadFunction(Kernel::KernelCore& kernel);
|
||||
void ShutdownThreadFunction(Kernel::KernelCore& kernel);
|
||||
|
||||
void MultiCoreRunGuestThread();
|
||||
void MultiCoreRunIdleThread();
|
||||
void MultiCoreRunGuestThread(Kernel::KernelCore& kernel);
|
||||
void MultiCoreRunIdleThread(Kernel::KernelCore& kernel);
|
||||
|
||||
void SingleCoreRunGuestThread();
|
||||
void SingleCoreRunIdleThread();
|
||||
void SingleCoreRunGuestThread(Kernel::KernelCore& kernel);
|
||||
void SingleCoreRunIdleThread(Kernel::KernelCore& kernel);
|
||||
|
||||
void GuestActivate();
|
||||
void HandleInterrupt();
|
||||
void ShutdownThread();
|
||||
void GuestActivate(Kernel::KernelCore& kernel);
|
||||
void HandleInterrupt(Kernel::KernelCore& kernel);
|
||||
void ShutdownThread(Kernel::KernelCore& kernel);
|
||||
void RunThread(std::stop_token stop_token, std::size_t core);
|
||||
|
||||
static constexpr std::size_t max_cycle_runs = 5;
|
||||
|
||||
std::optional<Common::Barrier> gpu_barrier{};
|
||||
struct CoreData {
|
||||
std::shared_ptr<Common::Fiber> host_context;
|
||||
std::jthread host_thread;
|
||||
};
|
||||
|
||||
std::unique_ptr<Common::Barrier> gpu_barrier{};
|
||||
std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
|
||||
|
||||
bool is_async_gpu{};
|
||||
bool is_multicore{};
|
||||
Core::System& system;
|
||||
std::atomic<std::size_t> current_core{};
|
||||
std::size_t idle_count{};
|
||||
std::size_t num_cores{};
|
||||
static constexpr std::size_t max_cycle_runs = 5;
|
||||
|
||||
System& system;
|
||||
bool is_async_gpu{};
|
||||
bool is_multicore{};
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -6,30 +6,54 @@
|
||||
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
#if defined(__EMSCRIPTEN__) || defined(__wasi__)
|
||||
// TODO: gdb stub compat with emscripten?
|
||||
#else
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION > 108400 && (!defined(_WINDOWS) && !defined(__ANDROID__)) || defined(YUZU_BOOST_v1)
|
||||
#define USE_BOOST_v1
|
||||
#endif
|
||||
|
||||
#ifdef USE_BOOST_v1
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
#else
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/core.h"
|
||||
#include "core/debugger/debugger.h"
|
||||
#if defined(__EMSCRIPTEN__) || defined(__wasi__)
|
||||
// TODO: gdbstub with emscripten?
|
||||
#else
|
||||
#include "core/debugger/debugger_interface.h"
|
||||
#include "core/debugger/gdbstub.h"
|
||||
#endif
|
||||
#include "core/hle/kernel/global_scheduler_context.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
|
||||
#if defined(__EMSCRIPTEN__) || defined(__wasi__)
|
||||
namespace Core {
|
||||
// Dummy
|
||||
class DebuggerImpl {
|
||||
char pad;
|
||||
};
|
||||
Debugger::Debugger(Core::System& system, u16 port) {}
|
||||
Debugger::~Debugger() = default;
|
||||
bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) {
|
||||
return false;
|
||||
}
|
||||
bool Debugger::NotifyThreadWatchpoint(Kernel::KThread* thread, const Kernel::DebugWatchpoint& watch) {
|
||||
return false;
|
||||
}
|
||||
void Debugger::NotifyShutdown() {}
|
||||
} // namespace Core
|
||||
#else
|
||||
template <typename Readable, typename Buffer, typename Callback>
|
||||
static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
|
||||
static_assert(std::is_trivial_v<Buffer>);
|
||||
@@ -81,7 +105,10 @@ namespace Core {
|
||||
|
||||
class DebuggerImpl : public DebuggerBackend {
|
||||
public:
|
||||
explicit DebuggerImpl(Core::System& system_, u16 port) : system{system_} {
|
||||
explicit DebuggerImpl(Core::System& system_, u16 port)
|
||||
: system{system_}
|
||||
, debug_process{system_.Kernel()}
|
||||
{
|
||||
InitializeServer(port);
|
||||
}
|
||||
|
||||
@@ -121,7 +148,7 @@ public:
|
||||
}
|
||||
|
||||
void SetActiveThread(Kernel::KThread* thread) override {
|
||||
state->active_thread = thread;
|
||||
state->active_thread = {system.Kernel(), thread};
|
||||
}
|
||||
|
||||
Kernel::KThread* GetActiveThread() override {
|
||||
@@ -168,14 +195,7 @@ private:
|
||||
frontend = std::make_unique<GDBStub>(*this, system, debug_process.GetPointerUnsafe());
|
||||
|
||||
// Set the new state. This will tear down any existing state.
|
||||
state = ConnectionState{
|
||||
.client_socket{std::move(peer)},
|
||||
.signal_pipe{io_context},
|
||||
.info{},
|
||||
.active_thread{},
|
||||
.client_data{},
|
||||
.pipe_data{},
|
||||
};
|
||||
state.emplace(std::move(peer), io_context, system.Kernel());
|
||||
|
||||
// Set up the client signals for new data.
|
||||
AsyncReceiveInto(state->signal_pipe, state->pipe_data, [&](auto d) { PipeData(d); });
|
||||
@@ -204,7 +224,7 @@ private:
|
||||
PauseEmulation();
|
||||
|
||||
// Notify the client.
|
||||
state->active_thread = state->info.thread;
|
||||
state->active_thread = {system.Kernel(), state->info.thread};
|
||||
UpdateActiveThread();
|
||||
|
||||
if (state->info.type == SignalType::Watchpoint) {
|
||||
@@ -258,7 +278,7 @@ private:
|
||||
auto* gdb = static_cast<GDBStub*>(frontend.get());
|
||||
MarkResumed([this, threads = std::move(gdb->resume_threads)] {
|
||||
state->active_thread->SetStepState(Kernel::StepState::StepPending);
|
||||
state->active_thread->Resume(Kernel::SuspendType::Debug);
|
||||
state->active_thread->Resume(system.Kernel(), Kernel::SuspendType::Debug);
|
||||
ResumeThreads(threads, state->active_thread.GetPointerUnsafe());
|
||||
});
|
||||
break;
|
||||
@@ -281,7 +301,7 @@ private:
|
||||
|
||||
// Put all threads to sleep on next scheduler round.
|
||||
for (auto& thread : ThreadList()) {
|
||||
thread.RequestSuspend(Kernel::SuspendType::Debug);
|
||||
thread.RequestSuspend(system.Kernel(), Kernel::SuspendType::Debug);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +316,7 @@ private:
|
||||
}
|
||||
|
||||
thread.SetStepState(Kernel::StepState::NotStepping);
|
||||
thread.Resume(Kernel::SuspendType::Debug);
|
||||
thread.Resume(system.Kernel(), Kernel::SuspendType::Debug);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +332,7 @@ private:
|
||||
}
|
||||
|
||||
thread->SetStepState(Kernel::StepState::NotStepping);
|
||||
thread->Resume(Kernel::SuspendType::Debug);
|
||||
thread->Resume(system.Kernel(), Kernel::SuspendType::Debug);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,7 +352,7 @@ private:
|
||||
return;
|
||||
}
|
||||
}
|
||||
state->active_thread = std::addressof(threads.front());
|
||||
state->active_thread = {system.Kernel(), std::addressof(threads.front())};
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -354,13 +374,20 @@ private:
|
||||
std::mutex connection_lock;
|
||||
|
||||
struct ConnectionState {
|
||||
boost::asio::ip::tcp::socket client_socket;
|
||||
#ifdef USE_BOOST_v1
|
||||
boost::process::v1::async_pipe signal_pipe;
|
||||
using async_pipe = boost::process::v1::async_pipe;
|
||||
#else
|
||||
boost::process::async_pipe signal_pipe;
|
||||
using async_pipe = boost::process::async_pipe;
|
||||
#endif
|
||||
|
||||
ConnectionState(boost::asio::ip::tcp::socket&& client_socket_, async_pipe signal_pipe_, Kernel::KernelCore& kernel)
|
||||
: client_socket{std::move(client_socket_)}
|
||||
, signal_pipe{signal_pipe_}
|
||||
, active_thread{kernel, nullptr}
|
||||
{}
|
||||
|
||||
boost::asio::ip::tcp::socket client_socket;
|
||||
async_pipe signal_pipe;
|
||||
SignalInfo info;
|
||||
Kernel::KScopedAutoObject<Kernel::KThread> active_thread;
|
||||
std::array<u8, 4096> client_data;
|
||||
@@ -397,3 +424,4 @@ void Debugger::NotifyShutdown() {
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
#endif
|
||||
|
||||
@@ -323,13 +323,13 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) {
|
||||
success = true;
|
||||
break;
|
||||
case BreakpointType::WriteWatch:
|
||||
success = debug_process->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Write);
|
||||
success = debug_process->InsertWatchpoint(system.Kernel(), addr, size, Kernel::DebugWatchpointType::Write);
|
||||
break;
|
||||
case BreakpointType::ReadWatch:
|
||||
success = debug_process->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Read);
|
||||
success = debug_process->InsertWatchpoint(system.Kernel(), addr, size, Kernel::DebugWatchpointType::Read);
|
||||
break;
|
||||
case BreakpointType::AccessWatch:
|
||||
success = debug_process->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
|
||||
success = debug_process->InsertWatchpoint(system.Kernel(), addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
|
||||
break;
|
||||
case BreakpointType::Hardware:
|
||||
default:
|
||||
@@ -368,13 +368,13 @@ void GDBStub::HandleBreakpointRemove(std::string_view sv) {
|
||||
break;
|
||||
}
|
||||
case BreakpointType::WriteWatch:
|
||||
success = debug_process->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Write);
|
||||
success = debug_process->RemoveWatchpoint(system.Kernel(), addr, size, Kernel::DebugWatchpointType::Write);
|
||||
break;
|
||||
case BreakpointType::ReadWatch:
|
||||
success = debug_process->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Read);
|
||||
success = debug_process->RemoveWatchpoint(system.Kernel(), addr, size, Kernel::DebugWatchpointType::Read);
|
||||
break;
|
||||
case BreakpointType::AccessWatch:
|
||||
success = debug_process->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
|
||||
success = debug_process->RemoveWatchpoint(system.Kernel(), addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
|
||||
break;
|
||||
case BreakpointType::Hardware:
|
||||
default:
|
||||
|
||||
@@ -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 2020 yuzu Emulator Project
|
||||
@@ -17,7 +17,8 @@
|
||||
namespace Kernel {
|
||||
|
||||
GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
|
||||
: m_kernel{kernel}, m_scheduler_lock{kernel} {}
|
||||
: m_scheduler_lock{kernel}
|
||||
{}
|
||||
|
||||
GlobalSchedulerContext::~GlobalSchedulerContext() = default;
|
||||
|
||||
@@ -37,7 +38,7 @@ void GlobalSchedulerContext::RemoveThread(KThread* thread) noexcept {
|
||||
/// and then does some core rebalancing. Preemption priorities can be found
|
||||
/// in the array 'preemption_priorities'.
|
||||
/// @note This operation happens every 10ms.
|
||||
void GlobalSchedulerContext::PreemptThreads() noexcept {
|
||||
void GlobalSchedulerContext::PreemptThreads(KernelCore& kernel) noexcept {
|
||||
// The priority levels at which the global scheduler preempts threads every 10 ms. They are
|
||||
// ordered from Core 0 to Core 3.
|
||||
static constexpr std::array<u32, Core::Hardware::NUM_CPU_CORES> per_core{
|
||||
@@ -46,9 +47,9 @@ void GlobalSchedulerContext::PreemptThreads() noexcept {
|
||||
59,
|
||||
63,
|
||||
};
|
||||
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
|
||||
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
|
||||
for (u32 core_id = 0; core_id < per_core.size(); core_id++)
|
||||
KScheduler::RotateScheduledQueue(m_kernel, core_id, per_core[core_id]);
|
||||
KScheduler::RotateScheduledQueue(kernel, core_id, per_core[core_id]);
|
||||
}
|
||||
|
||||
/// @brief Returns true if the global scheduler lock is acquired
|
||||
@@ -69,11 +70,11 @@ void GlobalSchedulerContext::UnregisterDummyThreadForWakeup(KThread* thread) noe
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalSchedulerContext::WakeupWaitingDummyThreads() noexcept {
|
||||
void GlobalSchedulerContext::WakeupWaitingDummyThreads(KernelCore& kernel) noexcept {
|
||||
ASSERT(this->IsLocked());
|
||||
if (m_woken_dummy_threads.size() > 0) {
|
||||
for (auto* thread : m_woken_dummy_threads)
|
||||
thread->DummyThreadEndWait();
|
||||
thread->DummyThreadEndWait(kernel);
|
||||
m_woken_dummy_threads.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 2020 yuzu Emulator Project
|
||||
@@ -50,17 +50,16 @@ public:
|
||||
}
|
||||
void AddThread(KThread* thread) noexcept;
|
||||
void RemoveThread(KThread* thread) noexcept;
|
||||
void PreemptThreads() noexcept;
|
||||
void PreemptThreads(KernelCore& kernel) noexcept;
|
||||
bool IsLocked() const noexcept;
|
||||
void UnregisterDummyThreadForWakeup(KThread* thread) noexcept;
|
||||
void RegisterDummyThreadForWakeup(KThread* thread) noexcept;
|
||||
void WakeupWaitingDummyThreads() noexcept;
|
||||
void WakeupWaitingDummyThreads(KernelCore& kernel) noexcept;
|
||||
|
||||
private:
|
||||
friend class KScopedSchedulerLock;
|
||||
friend class KScopedSchedulerLockAndSleep;
|
||||
|
||||
KernelCore& m_kernel;
|
||||
std::atomic_bool m_scheduler_update_needed{};
|
||||
KSchedulerPriorityQueue m_priority_queue;
|
||||
LockType m_scheduler_lock;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -281,7 +284,7 @@ void KPageBufferSlabHeap::Initialize(Core::System& system) {
|
||||
|
||||
// Reserve memory from the system resource limit.
|
||||
ASSERT(
|
||||
kernel.GetSystemResourceLimit()->Reserve(LimitableResource::PhysicalMemoryMax, slab_size));
|
||||
kernel.GetSystemResourceLimit()->Reserve(kernel, LimitableResource::PhysicalMemoryMax, slab_size));
|
||||
|
||||
// Allocate memory for the slab.
|
||||
constexpr auto AllocateOption = KMemoryManager::EncodeOption(
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -16,8 +19,9 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
KAddressArbiter::KAddressArbiter(Core::System& system)
|
||||
: m_system{system}, m_kernel{system.Kernel()} {}
|
||||
KAddressArbiter::KAddressArbiter(Core::System& system_)
|
||||
: system{system_}
|
||||
{}
|
||||
KAddressArbiter::~KAddressArbiter() = default;
|
||||
|
||||
namespace {
|
||||
@@ -112,7 +116,7 @@ public:
|
||||
explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel, KAddressArbiter::ThreadTree* t)
|
||||
: KThreadQueue(kernel), m_tree(t) {}
|
||||
|
||||
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
||||
void CancelWait(KernelCore& kernel, KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
|
||||
// If the thread is waiting on an address arbiter, remove it from the tree.
|
||||
if (waiting_thread->IsWaitingForAddressArbiter()) {
|
||||
m_tree->erase(m_tree->iterator_to(*waiting_thread));
|
||||
@@ -120,7 +124,7 @@ public:
|
||||
}
|
||||
|
||||
// Invoke the base cancel wait handler.
|
||||
KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
|
||||
KThreadQueue::CancelWait(kernel, waiting_thread, wait_result, cancel_timer_task);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -133,14 +137,14 @@ Result KAddressArbiter::Signal(uint64_t addr, s32 count) {
|
||||
// Perform signaling.
|
||||
s32 num_waiters{};
|
||||
{
|
||||
KScopedSchedulerLock sl(m_kernel);
|
||||
KScopedSchedulerLock sl(system.Kernel());
|
||||
|
||||
auto it = m_tree.nfind_key({addr, -1});
|
||||
while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
|
||||
(it->GetAddressArbiterKey() == addr)) {
|
||||
// End the thread's wait.
|
||||
KThread* target_thread = std::addressof(*it);
|
||||
target_thread->EndWait(ResultSuccess);
|
||||
target_thread->EndWait(system.Kernel(), ResultSuccess);
|
||||
|
||||
ASSERT(target_thread->IsWaitingForAddressArbiter());
|
||||
target_thread->ClearAddressArbiter();
|
||||
@@ -156,11 +160,11 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32
|
||||
// Perform signaling.
|
||||
s32 num_waiters{};
|
||||
{
|
||||
KScopedSchedulerLock sl(m_kernel);
|
||||
KScopedSchedulerLock sl(system.Kernel());
|
||||
|
||||
// Check the userspace value.
|
||||
s32 user_value{};
|
||||
R_UNLESS(UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, value + 1),
|
||||
R_UNLESS(UpdateIfEqual(system.Kernel(), std::addressof(user_value), addr, value, value + 1),
|
||||
ResultInvalidCurrentMemory);
|
||||
R_UNLESS(user_value == value, ResultInvalidState);
|
||||
|
||||
@@ -169,7 +173,7 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32
|
||||
(it->GetAddressArbiterKey() == addr)) {
|
||||
// End the thread's wait.
|
||||
KThread* target_thread = std::addressof(*it);
|
||||
target_thread->EndWait(ResultSuccess);
|
||||
target_thread->EndWait(system.Kernel(), ResultSuccess);
|
||||
|
||||
ASSERT(target_thread->IsWaitingForAddressArbiter());
|
||||
target_thread->ClearAddressArbiter();
|
||||
@@ -185,7 +189,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32
|
||||
// Perform signaling.
|
||||
s32 num_waiters{};
|
||||
{
|
||||
KScopedSchedulerLock sl(m_kernel);
|
||||
KScopedSchedulerLock sl(system.Kernel());
|
||||
|
||||
auto it = m_tree.nfind_key({addr, -1});
|
||||
// Determine the updated value.
|
||||
@@ -220,9 +224,9 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32
|
||||
s32 user_value{};
|
||||
bool succeeded{};
|
||||
if (value != new_value) {
|
||||
succeeded = UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, new_value);
|
||||
succeeded = UpdateIfEqual(system.Kernel(), std::addressof(user_value), addr, value, new_value);
|
||||
} else {
|
||||
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
|
||||
succeeded = ReadFromUser(system.Kernel(), std::addressof(user_value), addr);
|
||||
}
|
||||
|
||||
R_UNLESS(succeeded, ResultInvalidCurrentMemory);
|
||||
@@ -232,7 +236,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32
|
||||
(it->GetAddressArbiterKey() == addr)) {
|
||||
// End the thread's wait.
|
||||
KThread* target_thread = std::addressof(*it);
|
||||
target_thread->EndWait(ResultSuccess);
|
||||
target_thread->EndWait(system.Kernel(), ResultSuccess);
|
||||
|
||||
ASSERT(target_thread->IsWaitingForAddressArbiter());
|
||||
target_thread->ClearAddressArbiter();
|
||||
@@ -246,12 +250,12 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32
|
||||
|
||||
Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement, s64 timeout) {
|
||||
// Prepare to wait.
|
||||
KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
|
||||
KThread* cur_thread = GetCurrentThreadPointer(system.Kernel());
|
||||
KHardwareTimer* timer{};
|
||||
ThreadQueueImplForKAddressArbiter wait_queue(m_kernel, std::addressof(m_tree));
|
||||
ThreadQueueImplForKAddressArbiter wait_queue(system.Kernel(), std::addressof(m_tree));
|
||||
|
||||
{
|
||||
KScopedSchedulerLockAndSleep slp{m_kernel, std::addressof(timer), cur_thread, timeout};
|
||||
KScopedSchedulerLockAndSleep slp{system.Kernel(), std::addressof(timer), cur_thread, timeout};
|
||||
|
||||
// Check that the thread isn't terminating.
|
||||
if (cur_thread->IsTerminationRequested()) {
|
||||
@@ -263,9 +267,9 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement,
|
||||
s32 user_value{};
|
||||
bool succeeded{};
|
||||
if (decrement) {
|
||||
succeeded = DecrementIfLessThan(m_kernel, std::addressof(user_value), addr, value);
|
||||
succeeded = DecrementIfLessThan(system.Kernel(), std::addressof(user_value), addr, value);
|
||||
} else {
|
||||
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
|
||||
succeeded = ReadFromUser(system.Kernel(), std::addressof(user_value), addr);
|
||||
}
|
||||
|
||||
if (!succeeded) {
|
||||
@@ -291,7 +295,7 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement,
|
||||
|
||||
// Wait for the thread to finish.
|
||||
wait_queue.SetHardwareTimer(timer);
|
||||
cur_thread->BeginWait(std::addressof(wait_queue));
|
||||
cur_thread->BeginWait(system.Kernel(), std::addressof(wait_queue));
|
||||
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
|
||||
}
|
||||
|
||||
@@ -301,12 +305,12 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement,
|
||||
|
||||
Result KAddressArbiter::WaitIfEqual(uint64_t addr, s32 value, s64 timeout) {
|
||||
// Prepare to wait.
|
||||
KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
|
||||
KThread* cur_thread = GetCurrentThreadPointer(system.Kernel());
|
||||
KHardwareTimer* timer{};
|
||||
ThreadQueueImplForKAddressArbiter wait_queue(m_kernel, std::addressof(m_tree));
|
||||
ThreadQueueImplForKAddressArbiter wait_queue(system.Kernel(), std::addressof(m_tree));
|
||||
|
||||
{
|
||||
KScopedSchedulerLockAndSleep slp{m_kernel, std::addressof(timer), cur_thread, timeout};
|
||||
KScopedSchedulerLockAndSleep slp{system.Kernel(), std::addressof(timer), cur_thread, timeout};
|
||||
|
||||
// Check that the thread isn't terminating.
|
||||
if (cur_thread->IsTerminationRequested()) {
|
||||
@@ -316,7 +320,7 @@ Result KAddressArbiter::WaitIfEqual(uint64_t addr, s32 value, s64 timeout) {
|
||||
|
||||
// Read the value from userspace.
|
||||
s32 user_value{};
|
||||
if (!ReadFromUser(m_kernel, std::addressof(user_value), addr)) {
|
||||
if (!ReadFromUser(system.Kernel(), std::addressof(user_value), addr)) {
|
||||
slp.CancelSleep();
|
||||
R_THROW(ResultInvalidCurrentMemory);
|
||||
}
|
||||
@@ -339,7 +343,7 @@ Result KAddressArbiter::WaitIfEqual(uint64_t addr, s32 value, s64 timeout) {
|
||||
|
||||
// Wait for the thread to finish.
|
||||
wait_queue.SetHardwareTimer(timer);
|
||||
cur_thread->BeginWait(std::addressof(wait_queue));
|
||||
cur_thread->BeginWait(system.Kernel(), std::addressof(wait_queue));
|
||||
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -60,8 +63,7 @@ private:
|
||||
|
||||
private:
|
||||
ThreadTree m_tree;
|
||||
Core::System& m_system;
|
||||
KernelCore& m_kernel;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -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 2021 yuzu Emulator Project
|
||||
@@ -15,8 +15,8 @@ KAutoObject* KAutoObject::Create(KAutoObject* obj) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
void KAutoObject::RegisterWithKernel() {
|
||||
m_kernel.RegisterKernelObject(this);
|
||||
void KAutoObject::RegisterWithKernel(KernelCore& kernel) {
|
||||
kernel.RegisterKernelObject(this);
|
||||
}
|
||||
|
||||
void KAutoObject::UnregisterWithKernel(KernelCore& kernel, KAutoObject* self) {
|
||||
|
||||
@@ -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 2022 yuzu Emulator Project
|
||||
@@ -87,21 +87,21 @@ private:
|
||||
KERNEL_AUTOOBJECT_TRAITS_IMPL(KAutoObject, KAutoObject, const);
|
||||
|
||||
public:
|
||||
explicit KAutoObject(KernelCore& kernel) : m_kernel(kernel) {
|
||||
explicit KAutoObject(KernelCore& kernel) {
|
||||
m_class_token = GetStaticTypeObj().GetClassToken();
|
||||
RegisterWithKernel();
|
||||
RegisterWithKernel(kernel);
|
||||
}
|
||||
virtual ~KAutoObject() = default;
|
||||
|
||||
static KAutoObject* Create(KAutoObject* ptr);
|
||||
|
||||
// Destroy is responsible for destroying the auto object's resources when ref_count hits zero.
|
||||
virtual void Destroy() {
|
||||
virtual void Destroy(KernelCore& kernel) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
// Finalize is responsible for cleaning up resource, but does not destroy the object.
|
||||
virtual void Finalize() {}
|
||||
virtual void Finalize(KernelCore& kernel) {}
|
||||
|
||||
virtual KProcess* GetOwner() const {
|
||||
return nullptr;
|
||||
@@ -123,67 +123,50 @@ public:
|
||||
Derived DynamicCast() {
|
||||
static_assert(std::is_pointer_v<Derived>);
|
||||
using DerivedType = std::remove_pointer_t<Derived>;
|
||||
|
||||
if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) {
|
||||
return static_cast<Derived>(this);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj()))
|
||||
return Derived(this);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
const Derived DynamicCast() const {
|
||||
static_assert(std::is_pointer_v<Derived>);
|
||||
using DerivedType = std::remove_pointer_t<Derived>;
|
||||
|
||||
if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) {
|
||||
return static_cast<Derived>(this);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj()))
|
||||
return Derived(this);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Open() {
|
||||
bool Open(KernelCore& kernel) {
|
||||
// Atomically increment the reference count, only if it's positive.
|
||||
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
|
||||
do {
|
||||
if (cur_ref_count == 0) {
|
||||
if (cur_ref_count == 0)
|
||||
return false;
|
||||
}
|
||||
ASSERT(cur_ref_count < cur_ref_count + 1);
|
||||
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count + 1,
|
||||
std::memory_order_relaxed));
|
||||
|
||||
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count + 1, std::memory_order_relaxed));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Close() {
|
||||
void Close(KernelCore& kernel) {
|
||||
// Atomically decrement the reference count, not allowing it to become negative.
|
||||
u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
|
||||
do {
|
||||
if (cur_ref_count == 0) {
|
||||
if (cur_ref_count == 0)
|
||||
return;
|
||||
}
|
||||
ASSERT(cur_ref_count > 0);
|
||||
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1,
|
||||
std::memory_order_acq_rel));
|
||||
|
||||
} while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1, std::memory_order_acq_rel));
|
||||
// If ref count hits 1, destroy the object.
|
||||
if (cur_ref_count == 1) {
|
||||
KernelCore& kernel = m_kernel;
|
||||
this->Destroy();
|
||||
this->Destroy(kernel);
|
||||
KAutoObject::UnregisterWithKernel(kernel, this);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void RegisterWithKernel();
|
||||
void RegisterWithKernel(KernelCore& kernel);
|
||||
static void UnregisterWithKernel(KernelCore& kernel, KAutoObject* self);
|
||||
|
||||
protected:
|
||||
KernelCore& m_kernel;
|
||||
|
||||
private:
|
||||
std::atomic<u32> m_ref_count{};
|
||||
ClassTokenType m_class_token{};
|
||||
};
|
||||
@@ -225,17 +208,22 @@ class KScopedAutoObject {
|
||||
public:
|
||||
YUZU_NON_COPYABLE(KScopedAutoObject);
|
||||
|
||||
constexpr KScopedAutoObject() = default;
|
||||
constexpr KScopedAutoObject(KernelCore& kernel_)
|
||||
: kernel{kernel_}
|
||||
{}
|
||||
|
||||
constexpr KScopedAutoObject(T* o) : m_obj(o) {
|
||||
constexpr KScopedAutoObject(KernelCore& kernel_, T* o)
|
||||
: kernel{kernel_}
|
||||
, m_obj(o)
|
||||
{
|
||||
if (m_obj != nullptr) {
|
||||
m_obj->Open();
|
||||
m_obj->Open(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
~KScopedAutoObject() {
|
||||
if (m_obj != nullptr) {
|
||||
m_obj->Close();
|
||||
m_obj->Close(kernel);
|
||||
}
|
||||
m_obj = nullptr;
|
||||
}
|
||||
@@ -253,7 +241,7 @@ public:
|
||||
if (rhs.m_obj != nullptr) {
|
||||
derived = rhs.m_obj->template DynamicCast<T*>();
|
||||
if (derived == nullptr) {
|
||||
rhs.m_obj->Close();
|
||||
rhs.m_obj->Close(rhs.kernel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,8 +262,16 @@ public:
|
||||
return *m_obj;
|
||||
}
|
||||
|
||||
constexpr void SetObject(T* o) {
|
||||
if (m_obj)
|
||||
m_obj->Close(kernel);
|
||||
m_obj = o;
|
||||
if (m_obj)
|
||||
m_obj->Open(kernel);
|
||||
}
|
||||
|
||||
constexpr void Reset(T* o) {
|
||||
KScopedAutoObject(o).Swap(*this);
|
||||
KScopedAutoObject(kernel, o).Swap(*this);
|
||||
}
|
||||
|
||||
constexpr T* GetPointerUnsafe() {
|
||||
@@ -304,6 +300,7 @@ private:
|
||||
friend class KScopedAutoObject;
|
||||
|
||||
private:
|
||||
KernelCore& kernel;
|
||||
T* m_obj{};
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2021 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -15,7 +18,7 @@ namespace Kernel {
|
||||
KClientPort::KClientPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
|
||||
KClientPort::~KClientPort() = default;
|
||||
|
||||
void KClientPort::Initialize(KPort* parent, s32 max_sessions) {
|
||||
void KClientPort::Initialize(KernelCore& kernel, KPort* parent, s32 max_sessions) {
|
||||
// Set member variables.
|
||||
m_num_sessions = 0;
|
||||
m_peak_sessions = 0;
|
||||
@@ -23,48 +26,48 @@ void KClientPort::Initialize(KPort* parent, s32 max_sessions) {
|
||||
m_max_sessions = max_sessions;
|
||||
}
|
||||
|
||||
void KClientPort::OnSessionFinalized() {
|
||||
KScopedSchedulerLock sl{m_kernel};
|
||||
void KClientPort::OnSessionFinalized(KernelCore& kernel) {
|
||||
KScopedSchedulerLock sl{kernel};
|
||||
|
||||
if (const auto prev = m_num_sessions--; prev == m_max_sessions) {
|
||||
this->NotifyAvailable();
|
||||
this->NotifyAvailable(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void KClientPort::OnServerClosed() {}
|
||||
void KClientPort::OnServerClosed(KernelCore& kernel) {}
|
||||
|
||||
bool KClientPort::IsLight() const {
|
||||
bool KClientPort::IsLight(KernelCore& kernel) const {
|
||||
return this->GetParent()->IsLight();
|
||||
}
|
||||
|
||||
bool KClientPort::IsServerClosed() const {
|
||||
return this->GetParent()->IsServerClosed();
|
||||
bool KClientPort::IsServerClosed(KernelCore& kernel) const {
|
||||
return this->GetParent()->IsServerClosed(kernel);
|
||||
}
|
||||
|
||||
void KClientPort::Destroy() {
|
||||
void KClientPort::Destroy(KernelCore& kernel) {
|
||||
// Note with our parent that we're closed.
|
||||
m_parent->OnClientClosed();
|
||||
m_parent->OnClientClosed(kernel);
|
||||
|
||||
// Close our reference to our parent.
|
||||
m_parent->Close();
|
||||
m_parent->Close(kernel);
|
||||
}
|
||||
|
||||
bool KClientPort::IsSignaled() const {
|
||||
bool KClientPort::IsSignaled(KernelCore& kernel) const {
|
||||
return m_num_sessions.load() < m_max_sessions;
|
||||
}
|
||||
|
||||
Result KClientPort::CreateSession(KClientSession** out) {
|
||||
Result KClientPort::CreateSession(KernelCore& kernel, KClientSession** out) {
|
||||
// Declare the session we're going to allocate.
|
||||
KSession* session{};
|
||||
|
||||
// Reserve a new session from the resource limit.
|
||||
KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel),
|
||||
KScopedResourceReservation session_reservation(kernel, GetCurrentProcessPointer(kernel),
|
||||
LimitableResource::SessionCountMax);
|
||||
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
|
||||
|
||||
// Allocate a session normally.
|
||||
// TODO: Dynamic resource limits
|
||||
session = KSession::Create(m_kernel);
|
||||
session = KSession::Create(kernel);
|
||||
|
||||
// Check that we successfully created a session.
|
||||
R_UNLESS(session != nullptr, ResultOutOfResource);
|
||||
@@ -72,7 +75,7 @@ Result KClientPort::CreateSession(KClientSession** out) {
|
||||
// Update the session counts.
|
||||
{
|
||||
ON_RESULT_FAILURE {
|
||||
session->Close();
|
||||
session->Close(kernel);
|
||||
};
|
||||
|
||||
// Atomically increment the number of sessions.
|
||||
@@ -100,38 +103,37 @@ Result KClientPort::CreateSession(KClientSession** out) {
|
||||
}
|
||||
|
||||
// Initialize the session.
|
||||
session->Initialize(this, m_parent->GetName());
|
||||
session->Initialize(kernel, this, m_parent->GetName());
|
||||
|
||||
// Commit the session reservation.
|
||||
session_reservation.Commit();
|
||||
|
||||
// Register the session.
|
||||
KSession::Register(m_kernel, session);
|
||||
KSession::Register(kernel, session);
|
||||
ON_RESULT_FAILURE {
|
||||
session->GetClientSession().Close();
|
||||
session->GetServerSession().Close();
|
||||
session->GetClientSession().Close(kernel);
|
||||
session->GetServerSession().Close(kernel);
|
||||
};
|
||||
|
||||
// Enqueue the session with our parent.
|
||||
R_TRY(m_parent->EnqueueSession(std::addressof(session->GetServerSession())));
|
||||
R_TRY(m_parent->EnqueueSession(kernel, std::addressof(session->GetServerSession())));
|
||||
|
||||
// We succeeded, so set the output.
|
||||
*out = std::addressof(session->GetClientSession());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KClientPort::CreateLightSession(KLightClientSession** out) {
|
||||
Result KClientPort::CreateLightSession(KernelCore& kernel, KLightClientSession** out) {
|
||||
// Declare the session we're going to allocate.
|
||||
KLightSession* session{};
|
||||
|
||||
// Reserve a new session from the resource limit.
|
||||
KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel),
|
||||
Svc::LimitableResource::SessionCountMax);
|
||||
KScopedResourceReservation session_reservation(kernel, GetCurrentProcessPointer(kernel), Svc::LimitableResource::SessionCountMax);
|
||||
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
|
||||
|
||||
// Allocate a session normally.
|
||||
// TODO: Dynamic resource limits
|
||||
session = KLightSession::Create(m_kernel);
|
||||
session = KLightSession::Create(kernel);
|
||||
|
||||
// Check that we successfully created a session.
|
||||
R_UNLESS(session != nullptr, ResultOutOfResource);
|
||||
@@ -139,7 +141,7 @@ Result KClientPort::CreateLightSession(KLightClientSession** out) {
|
||||
// Update the session counts.
|
||||
{
|
||||
ON_RESULT_FAILURE {
|
||||
session->Close();
|
||||
session->Close(kernel);
|
||||
};
|
||||
|
||||
// Atomically increment the number of sessions.
|
||||
@@ -167,20 +169,20 @@ Result KClientPort::CreateLightSession(KLightClientSession** out) {
|
||||
}
|
||||
|
||||
// Initialize the session.
|
||||
session->Initialize(this, m_parent->GetName());
|
||||
session->Initialize(kernel, this, m_parent->GetName());
|
||||
|
||||
// Commit the session reservation.
|
||||
session_reservation.Commit();
|
||||
|
||||
// Register the session.
|
||||
KLightSession::Register(m_kernel, session);
|
||||
KLightSession::Register(kernel, session);
|
||||
ON_RESULT_FAILURE {
|
||||
session->GetClientSession().Close();
|
||||
session->GetServerSession().Close();
|
||||
session->GetClientSession().Close(kernel);
|
||||
session->GetServerSession().Close(kernel);
|
||||
};
|
||||
|
||||
// Enqueue the session with our parent.
|
||||
R_TRY(m_parent->EnqueueSession(std::addressof(session->GetServerSession())));
|
||||
R_TRY(m_parent->EnqueueSession(kernel, std::addressof(session->GetServerSession())));
|
||||
|
||||
// We succeeded, so set the output.
|
||||
*out = std::addressof(session->GetClientSession());
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -23,9 +26,9 @@ public:
|
||||
explicit KClientPort(KernelCore& kernel);
|
||||
~KClientPort() override;
|
||||
|
||||
void Initialize(KPort* parent, s32 max_sessions);
|
||||
void OnSessionFinalized();
|
||||
void OnServerClosed();
|
||||
void Initialize(KernelCore& kernel, KPort* parent, s32 max_sessions);
|
||||
void OnSessionFinalized(KernelCore& kernel);
|
||||
void OnServerClosed(KernelCore& kernel);
|
||||
|
||||
const KPort* GetParent() const {
|
||||
return m_parent;
|
||||
@@ -44,15 +47,15 @@ public:
|
||||
return m_max_sessions;
|
||||
}
|
||||
|
||||
bool IsLight() const;
|
||||
bool IsServerClosed() const;
|
||||
bool IsLight(KernelCore& kernel) const;
|
||||
bool IsServerClosed(KernelCore& kernel) const;
|
||||
|
||||
// Overridden virtual functions.
|
||||
void Destroy() override;
|
||||
bool IsSignaled() const override;
|
||||
void Destroy(KernelCore& kernel) override;
|
||||
bool IsSignaled(KernelCore& kernel) const override;
|
||||
|
||||
Result CreateSession(KClientSession** out);
|
||||
Result CreateLightSession(KLightClientSession** out);
|
||||
Result CreateSession(KernelCore& kernel, KClientSession** out);
|
||||
Result CreateLightSession(KernelCore& kernel, KLightClientSession** out);
|
||||
|
||||
private:
|
||||
std::atomic<s32> m_num_sessions{};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user