mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-27 01:17:40 +00:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 237fb283f8 | |||
| a098e17e5c | |||
| b3e4033ce9 | |||
| 26cb153f14 | |||
| ce8ec956bc | |||
| 56ea54c380 | |||
| e0facbe8a7 | |||
| 9c395241ca | |||
| e00e9faf12 | |||
| 526a367ffa | |||
| 7bd119a5b1 | |||
| cc3f8cc4ca | |||
| b6fb3300b0 | |||
| 2d8ee311dc | |||
| 2b7fac48cd | |||
| 411809818b | |||
| 67b3730059 | |||
| 4a96cc9694 | |||
| b3bc1d8a40 | |||
| 2da1418d77 | |||
| a74d16a8fa | |||
| 60943e8b9e | |||
| 911bab04f7 | |||
| cc04e1c536 | |||
| e7a931d06b | |||
| 8648c27cbb | |||
| def76946f0 | |||
| 13d39f39aa | |||
| 7731b5bc86 | |||
| c4ab2f6b9e | |||
| dd12266c26 | |||
| a3d32a18b8 | |||
| c0ffc900cd |
@@ -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
|
||||
@@ -1,9 +1,9 @@
|
||||
name: tx-pull
|
||||
|
||||
on:
|
||||
# tuesday, saturday at 2pm
|
||||
# monday at 4pm
|
||||
schedule:
|
||||
- cron: '0 14 * * 2,6'
|
||||
- cron: '0 16 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -3,7 +3,7 @@ description: File a bug report
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with yuzu.
|
||||
value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with Eden.
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
@@ -43,7 +43,7 @@ body:
|
||||
id: log
|
||||
attributes:
|
||||
label: Log File
|
||||
description: A log file will help our developers to better diagnose and fix the issue. Instructions can be found [here](https://yuzu-emu.org/help/reference/log-files).
|
||||
description: A log file will help our developers to better diagnose and fix the issue. Instructions can be found [here](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md).
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
@@ -4,7 +4,7 @@ labels: "request"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Tech support does not belong here. You should only file an issue here if you are requesting a feature you believe would make yuzu better.
|
||||
value: Tech support does not belong here. You should only file an issue here if you are requesting a feature you believe would make Eden better.
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
@@ -23,6 +23,6 @@ body:
|
||||
id: why-feature
|
||||
attributes:
|
||||
label: Why would this feature be useful?
|
||||
description: A brief description of why this feature would make yuzu better.
|
||||
description: A brief description of why this feature would make Eden better.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -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)
|
||||
+50
-20
@@ -28,23 +28,23 @@ if (NOT DEFINED ARCHITECTURE)
|
||||
endif()
|
||||
|
||||
# Needed for FFmpeg w/ VAAPI and DRM
|
||||
if (PLATFORM_OPENBSD)
|
||||
if (OPENBSD)
|
||||
# OpenBSD 7.8 broke libcxx when upgrading, so we must define the PSTL backend manually
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R6/lib")
|
||||
elseif (PLATFORM_NETBSD)
|
||||
elseif (NETBSD)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R7/lib")
|
||||
endif()
|
||||
|
||||
# NetBSD: Fun for the whole family!
|
||||
if (PLATFORM_NETBSD)
|
||||
if (NETBSD)
|
||||
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig")
|
||||
endif()
|
||||
|
||||
cmake_dependent_option(YUZU_STATIC_ROOM "Build a static room executable only (CI only)" OFF "PLATFORM_LINUX" OFF)
|
||||
cmake_dependent_option(YUZU_STATIC_ROOM "Build a static room executable only (CI only)" OFF "LINUX" OFF)
|
||||
if (YUZU_STATIC_ROOM)
|
||||
set(YUZU_ROOM ON)
|
||||
set(YUZU_ROOM_STANDALONE ON)
|
||||
@@ -79,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" ON)
|
||||
|
||||
# non-linux bundled qt are static
|
||||
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
|
||||
@@ -157,6 +158,19 @@ if (CXX_CLANG_CL)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-reserved-identifier>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-deprecated-declarations>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-cast-function-type-mismatch>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c99-extensions>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++17-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++11-compat-reserved-user-defined-literal>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++11-compat-deprecated-writable-strings>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++11-compat-pedantic>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++11-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++0x-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++98-c++11-compat-binary-literal>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++98-compat-pedantic>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++98-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c99-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c98-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c99-extensions>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:/EHsc>)
|
||||
# REQUIRED CPU features IN Windows-amd64
|
||||
if (ARCHITECTURE_x86_64)
|
||||
@@ -210,7 +224,7 @@ endif()
|
||||
|
||||
# ffmpeg
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${SOLARIS}" "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
|
||||
# sirit
|
||||
set(BUNDLED_SIRIT_DEFAULT OFF)
|
||||
@@ -221,7 +235,7 @@ endif()
|
||||
option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT})
|
||||
|
||||
# FreeBSD 15+ has libusb, versions below should disable it
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR PLATFORM_LINUX OR PLATFORM_FREEBSD OR APPLE" OFF)
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
|
||||
|
||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE" OFF)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
@@ -235,7 +249,7 @@ option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
|
||||
|
||||
# Install udev rules on Linux (mainly for gyros)
|
||||
# Only acts on joysticks and nothing else.
|
||||
cmake_dependent_option(YUZU_INSTALL_UDEV_RULES "Install udev rules for gyro access" OFF "PLATFORM_LINUX" OFF)
|
||||
cmake_dependent_option(YUZU_INSTALL_UDEV_RULES "Install udev rules for gyro access" OFF "LINUX" OFF)
|
||||
|
||||
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
|
||||
|
||||
@@ -248,7 +262,7 @@ cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable"
|
||||
|
||||
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROID" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR PLATFORM_LINUX" OFF)
|
||||
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||
|
||||
option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" ON)
|
||||
set(YUZU_TZDB_PATH "" CACHE STRING "Path to a pre-downloaded timezone database")
|
||||
@@ -258,7 +272,7 @@ cmake_dependent_option(YUZU_USE_BUNDLED_MOLTENVK "Download bundled MoltenVK lib"
|
||||
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
|
||||
|
||||
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL OFF)
|
||||
if (EXT_DEFAULT OR PLATFORM_SUN OR PLATFORM_OPENBSD)
|
||||
if (EXT_DEFAULT OR SOLARIS OR OPENBSD)
|
||||
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL ON)
|
||||
endif()
|
||||
|
||||
@@ -281,7 +295,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/hooks/pre-commit AND NOT EXISTS ${PROJECT_SOURCE
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX))
|
||||
if (ARCHITECTURE_arm64 AND (ANDROID OR LINUX))
|
||||
set(HAS_NCE 1)
|
||||
add_compile_definitions(HAS_NCE=1)
|
||||
endif()
|
||||
@@ -290,7 +304,7 @@ if (YUZU_ROOM)
|
||||
add_compile_definitions(YUZU_ROOM)
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT (PLATFORM_LINUX OR WIN32))
|
||||
if (UNIX AND NOT (LINUX OR WIN32))
|
||||
if(CXX_APPLE OR CXX_CLANG)
|
||||
# libc++ has stop_token and jthread as experimental
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
|
||||
@@ -361,6 +375,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)
|
||||
|
||||
@@ -389,7 +412,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)
|
||||
|
||||
@@ -404,16 +432,18 @@ if (Boost_ADDED)
|
||||
|
||||
if (NOT MSVC OR CXX_CLANG)
|
||||
# boost sucks
|
||||
if (PLATFORM_SUN)
|
||||
if (SOLARIS)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-pthreads>)
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
@@ -508,9 +538,9 @@ elseif (WIN32)
|
||||
# PSAPI is the Process Status API
|
||||
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version crypt32 rpcrt4 gdi32 wldap32 mswsock)
|
||||
endif()
|
||||
elseif (PLATFORM_MANAGARM)
|
||||
elseif (MANAGARM)
|
||||
set(PLATFORM_LIBRARIES iconv intl)
|
||||
elseif (PLATFORM_HAIKU)
|
||||
elseif (HAIKUOS)
|
||||
# Haiku is so special :)
|
||||
set(PLATFORM_LIBRARIES bsd /boot/system/lib/libnetwork.so)
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
|
||||
@@ -604,7 +634,7 @@ if (ENABLE_QT)
|
||||
|
||||
# Best practice is to ask for all components at once, so they are from the same version
|
||||
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent Gui)
|
||||
if (PLATFORM_LINUX OR PLATFORM_FREEBSD)
|
||||
if (LINUX OR FREEBSD)
|
||||
list(APPEND YUZU_QT_COMPONENTS DBus)
|
||||
# yes Qt, we get it
|
||||
set(QT_NO_PRIVATE_MODULE_WARNING ON)
|
||||
|
||||
@@ -13,7 +13,7 @@ find_package_handle_standard_args(Opus
|
||||
VERSION_VAR OPUS_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::OPUS)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ find_package_handle_standard_args(enet
|
||||
VERSION_VAR ENET_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::ENET)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ find_package_handle_standard_args(libusb
|
||||
VERSION_VAR LIBUSB_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::LIBUSB)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::LZ4)
|
||||
endif()
|
||||
|
||||
|
||||
+5
-1
@@ -22,9 +22,13 @@ Eden is free, open-source, copyleft software, licensed under the terms of the [G
|
||||
|
||||
- No LLM or AI usage, *period*, for patches, pull requests, issues, comments, debugging, brainstorming, etc.
|
||||
- For details on why, see the [detailed AI policy](docs/policies/AI.md).
|
||||
- Usage of any form of profanity or otherwise unsavory language is generally discouraged.
|
||||
- This is primarily because it rarely helps to actually understand what's going on.
|
||||
- Remember that your comments should be focused and actually address what's happening. With very few exceptions, expletives are actively detrimental at best.
|
||||
- New code must follow the same general style as the surrounding codebase. Exceptions may be granted in certain cases.
|
||||
- Maintainers reserve the right to change your patches and pull requests at will. We will try to avoid this.
|
||||
- You should respect all decisions made by the [code owners](docs/CODEOWNERS) in your particular subsystem. If you feel they are overstepping or are incorrect, don't be afraid to stand your ground!
|
||||
- You should generally respect all decisions made by the [code owners](docs/CODEOWNERS) in your particular subsystem.
|
||||
- However, if you feel they are overstepping or are incorrect, don't be afraid to stand your ground! Maintainers are not always correct.
|
||||
- While we do *not* adhere to the terms of a formal code of conduct, you will generally be expected to respect other developers, contributors, and community members.
|
||||
- You **must** have basic knowledge of [Git](https://git-scm.com/learn). Knowing how to manage your branches and follow proper fork policies is a necessity.
|
||||
|
||||
|
||||
+5
-3
@@ -108,7 +108,7 @@
|
||||
"find_args": "MODULE GLOBAL",
|
||||
"hash": "159ed94965018f2a371d45a3bfc1961e5fb1549e501ded70a6b4532d7fe99d0579c18b5195aff6e35f96f399b426cea2650ec9fb75ef80d4c9edeccb51f2e6c9",
|
||||
"options": [
|
||||
"HTTPLIB_REQUIRE_OPENSSL ON",
|
||||
"HTTPLIB_REQUIRE_OPENSSL OFF",
|
||||
"HTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES ON"
|
||||
],
|
||||
"patches": [
|
||||
@@ -190,7 +190,8 @@
|
||||
"min_version": "3.0.0",
|
||||
"package": "OpenSSL",
|
||||
"patches": [
|
||||
"0001-add-bundled-cert.patch"
|
||||
"0001-add-bundled-cert.patch",
|
||||
"0002-wasm-support.patch"
|
||||
],
|
||||
"repo": "openssl/openssl",
|
||||
"version": "openssl-3.6.2"
|
||||
@@ -213,7 +214,8 @@
|
||||
"0001-cpmutil-compat.patch",
|
||||
"0002-use-ccache.patch",
|
||||
"0003-use-cmake-compiler-flags.patch",
|
||||
"0004-use-shell-wrapper.patch"
|
||||
"0004-use-shell-wrapper.patch",
|
||||
"0005-wasm-support.patch"
|
||||
],
|
||||
"repo": "jimmy-park/openssl-cmake",
|
||||
"version": "3.6.2"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -46,6 +46,8 @@ These options control dependencies.
|
||||
- `YUZU_INSTALL_UDEV_RULES` (OFF) Install udev rules to enable hidraw access
|
||||
- Needed for gyroscopes
|
||||
- Only available on Linux
|
||||
- `ENABLE_DEBUG_TOOLS` (OFF) Enables debugging and development tools, see [tools](../tools/README.md).
|
||||
- `ENABLE_WERROR` (ON) Enables warnings as errors (-Werror).
|
||||
|
||||
### Flavors
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ Everyone has their own way of viewing good/bad C++ practices, my general outline
|
||||
- The reason is because the project has `-fno-rtti` disabled by default, due to the costs of dynamic polymorphism.
|
||||
- Always copy-on-value for objects with `sizeof(void *) >= sizeof(T) * 2`, i.e objects sized as 2 pointers or less, for bigger objects you can use ref/pointer as usual.
|
||||
- Try using move semantics instead of references, whenever possible.
|
||||
- Remember function parameters are extremelly cheap as fuck, don't be afraid to place upto 8 parameters on a given function.
|
||||
- Function parameters are cheap. Don't be afraid to use as many as needed (API usability permitting).
|
||||
- Don't save a reference in structures of a parent object, i.e:
|
||||
|
||||
```c++
|
||||
|
||||
Vendored
+1
-1
@@ -164,7 +164,7 @@ if (NOT ANDROID)
|
||||
AddJsonPackage(sdl3)
|
||||
else()
|
||||
message(STATUS "Using bundled SDL3")
|
||||
if (PLATFORM_FREEBSD)
|
||||
if (FREEBSD)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
AddJsonPackage(sdl3-ci)
|
||||
|
||||
+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
|
||||
|
||||
+44
-76
@@ -1,45 +1,49 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 crueter
|
||||
# SPDX-FileCopyrightText: Copyright 2026 crueter
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
## DetectPlatform ##
|
||||
|
||||
# This is a small helper that sets PLATFORM_<platform> variables for various
|
||||
# This is a small helper that sets platform variables for various
|
||||
# operating systems and distributions. Note that Apple, Windows, Android, etc.
|
||||
# are not covered, as CMake already does that for us.
|
||||
|
||||
# It also sets CXX_<compiler> for the C++ compiler.
|
||||
|
||||
# Furthermore, some platforms have really silly requirements/quirks, so this
|
||||
# also does a few of those.
|
||||
|
||||
# This module contains contributions from the Eden Emulator Project,
|
||||
# notably from crueter and Lizzie.
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "SunOS")
|
||||
set(PLATFORM_SUN ON)
|
||||
set(SOLARIS ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenOrbis")
|
||||
set(PLATFORM_PS4 ON)
|
||||
set(OPENORBIS ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "managarm")
|
||||
set(PLATFORM_MANAGARM ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
set(PLATFORM_FREEBSD ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
||||
set(PLATFORM_OPENBSD ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
|
||||
set(PLATFORM_NETBSD ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "DragonFly")
|
||||
set(PLATFORM_DRAGONFLYBSD ON)
|
||||
set(MANAGARM ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Haiku")
|
||||
set(PLATFORM_HAIKU ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(PLATFORM_LINUX ON)
|
||||
set(HAIKUOS ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
|
||||
set(EMSCRIPTEN ON)
|
||||
message(WARNING "${CMAKE_LIBRARY_ARCHITECTURE} support is highly experimental!!!")
|
||||
endif()
|
||||
|
||||
# BSD
|
||||
if (DEFINED BSD)
|
||||
if ("${BSD}" STREQUAL "DragonFlyBSD")
|
||||
set(DRAGONFLYBSD ON)
|
||||
elseif ("${BSD}" STREQUAL "FreeBSD")
|
||||
set(FREEBSD ON)
|
||||
elseif ("${BSD}" STREQUAL "OpenBSD")
|
||||
set(OPENBSD ON)
|
||||
elseif ("${BSD}" STREQUAL "NetBSD")
|
||||
set(NETBSD ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# dumb heuristic to detect msys2
|
||||
if (CMAKE_COMMAND MATCHES "msys64")
|
||||
set(PLATFORM_MSYS ON)
|
||||
set(MSYS2 ON)
|
||||
endif()
|
||||
|
||||
# compiler checks
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(CXX_CLANG ON)
|
||||
if (MSVC)
|
||||
@@ -47,8 +51,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
endif()
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(CXX_GCC ON)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
set(CXX_CL ON)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
||||
set(CXX_ICC ON)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
@@ -61,37 +63,13 @@ if(MINGW AND CXX_CLANG)
|
||||
set(CMAKE_SYSTEM_VERSION 10.0.0)
|
||||
endif()
|
||||
|
||||
# NB: this does not account for SPARC
|
||||
if (PLATFORM_SUN)
|
||||
# Terrific OpenIndiana pkg shenanigans
|
||||
list(APPEND CMAKE_PREFIX_PATH
|
||||
"${CMAKE_SYSROOT}/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${CMAKE_SYSROOT}/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
|
||||
# Amazing - absolutely incredible
|
||||
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SYSROOT}/usr/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SYSROOT}/usr/lib/amd64/cmake")
|
||||
|
||||
# For some mighty reason, doing a normal release build sometimes
|
||||
# may not trigger the proper -O3 switch to materialize
|
||||
if (CMAKE_BUILD_TYPE MATCHES "Release")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
endif()
|
||||
if (CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# MSYS2 utilities
|
||||
|
||||
# Sometimes, PkgConfig modules will incorrectly reference / when CMake
|
||||
# wants you to reference it as C:/msys64/. This function corrects that.
|
||||
# Example in a Find module:
|
||||
#[[
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::OPUS)
|
||||
endif()
|
||||
]]
|
||||
@@ -116,41 +94,31 @@ function(FixMsysPath target)
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${include_dir})
|
||||
endfunction()
|
||||
|
||||
# MSYSTEM handling + program_path
|
||||
if (PLATFORM_MSYS)
|
||||
# really, really dumb heuristic to detect what environment we are in
|
||||
macro(system var)
|
||||
if (CMAKE_COMMAND MATCHES ${var})
|
||||
set(MSYSTEM ${var})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
system(mingw64)
|
||||
system(clang64)
|
||||
system(clangarm64)
|
||||
system(ucrt64)
|
||||
|
||||
if (NOT DEFINED MSYSTEM)
|
||||
set(MSYSTEM msys2)
|
||||
endif()
|
||||
|
||||
# We generally want to prioritize environment-specific binaries if possible
|
||||
# some, like autoconf, are not present on environments besides msys2 though
|
||||
set(CMAKE_PROGRAM_PATH C:/msys64/${MSYSTEM}/bin C:/msys64/usr/bin)
|
||||
set(ENV{PKG_CONFIG_PATH} C:/msys64/${MSYSTEM}/lib/pkgconfig)
|
||||
endif()
|
||||
|
||||
# This saves a truly ridiculous amount of time during linking
|
||||
# In my tests, without this, Eden takes 2 mins, with this, it takes 3-5 seconds
|
||||
# or on GitHub Actions, 10 minutes -> 3 seconds
|
||||
# Saves linking time
|
||||
if (MINGW)
|
||||
set(MINGW_FLAGS "-Wl,--strip-all -Wl,--gc-sections")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE
|
||||
"${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${MINGW_FLAGS}")
|
||||
endif()
|
||||
|
||||
if (PLATFORM_EMSCRIPTEN)
|
||||
set(EMSCRIPTEN_C_FLAGS "-s MEMORY64 -m64 -pipe -sMEMORY64=1")
|
||||
set(EMSCRIPTEN_LINK_FLAGS "-sMEMORY64=1 -m64 -Wl,-mwasm64 -sASYNCIFY=1")
|
||||
|
||||
# This prevents FFmpeg and other libraries from assuming it's the host's CPU
|
||||
# Additionally some Emscripten installs may not be very good... generally
|
||||
set(EMSCRIPTEN_SYSTEM_PROCESSOR wasm)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EMSCRIPTEN_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${EMSCRIPTEN_C_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EMSCRIPTEN_LINK_FLAGS}")
|
||||
set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} ${EMSCRIPTEN_LINK_FLAGS}")
|
||||
set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} ${EMSCRIPTEN_LINK_FLAGS}")
|
||||
|
||||
unset(EMSCRIPTEN_C_FLAGS)
|
||||
unset(EMSCRIPTEN_LINK_FLAGS)
|
||||
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
+60
-23
@@ -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 (OPENORBIS OR MANAGARM OR 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 (ANDROID)
|
||||
@@ -75,7 +88,7 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
if(X11_FOUND)
|
||||
if (NOT APPLE)
|
||||
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
|
||||
if(PLATFORM_SUN)
|
||||
if(SOLARIS)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
X11
|
||||
"${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so")
|
||||
@@ -158,26 +171,35 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (PLATFORM_PS4)
|
||||
if (OPENORBIS)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_LIBS
|
||||
-lkernel
|
||||
-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}"
|
||||
)
|
||||
elseif (PLATFORM_MANAGARM)
|
||||
elseif (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)
|
||||
@@ -207,6 +229,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.
|
||||
@@ -215,6 +238,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")
|
||||
@@ -248,7 +277,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
|
||||
@@ -258,7 +293,7 @@ else()
|
||||
OUTPUT
|
||||
${FFmpeg_MAKEFILE}
|
||||
COMMAND
|
||||
${BASH_PROGRAM} ${FFmpeg_PREFIX}/configure
|
||||
${FFmpeg_CONFIGURE_WRAPPER} ${FFmpeg_PREFIX}/configure
|
||||
--disable-avdevice
|
||||
--disable-avformat
|
||||
--disable-doc
|
||||
@@ -267,6 +302,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
|
||||
@@ -274,7 +313,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}
|
||||
@@ -290,18 +329,16 @@ 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)
|
||||
if (LINUX OR ANDROID OR APPLE OR WIN32 OR FREEBSD)
|
||||
set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS})
|
||||
else()
|
||||
# No GNU make implies that this system may be highly non-GNU
|
||||
find_program(MAKE make required)
|
||||
set(FFmpeg_MAKE_ARGS "")
|
||||
endif()
|
||||
|
||||
@@ -309,7 +346,7 @@ else()
|
||||
OUTPUT
|
||||
${FFmpeg_BUILD_LIBRARIES}
|
||||
COMMAND
|
||||
gmake ${FFmpeg_MAKE_ARGS}
|
||||
${MAKE} ${FFmpeg_MAKE_ARGS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
Vendored
+1
-1
@@ -11,7 +11,7 @@ if (NOT libusb_ADDED)
|
||||
endif()
|
||||
|
||||
# TODO: *BSD fails to compile--may need different configs/symbols
|
||||
if (MINGW OR PLATFORM_LINUX OR APPLE)
|
||||
if (MINGW OR LINUX OR APPLE)
|
||||
set(LIBUSB_FOUND ON CACHE BOOL "libusb is present" FORCE)
|
||||
set(LIBUSB_VERSION "1.0.24" CACHE STRING "libusb version string" FORCE)
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -1177,7 +1177,7 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_TGA
|
||||
// test tga last because it's a crappy test!
|
||||
// test tga last because it's a bad test!
|
||||
if (stbi__tga_test(s))
|
||||
return stbi__tga_load(s,x,y,comp,req_comp, ri);
|
||||
#endif
|
||||
@@ -7662,7 +7662,7 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
|
||||
if (stbi__hdr_info(s, x, y, comp)) return 1;
|
||||
#endif
|
||||
|
||||
// test tga last because it's a crappy test!
|
||||
// test tga last because it's a bad test!
|
||||
#ifndef STBI_NO_TGA
|
||||
if (stbi__tga_info(s, x, y, comp))
|
||||
return 1;
|
||||
|
||||
Vendored
+2
@@ -14,7 +14,9 @@
|
||||
namespace Tz {
|
||||
|
||||
namespace {
|
||||
#ifndef EINVAL
|
||||
#define EINVAL 22
|
||||
#endif
|
||||
|
||||
static Rule gmtmem{};
|
||||
static Rule* const gmtptr = &gmtmem;
|
||||
|
||||
+26
-11
@@ -155,23 +155,34 @@ else()
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WERROR)
|
||||
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>)
|
||||
else()
|
||||
add_compile_options(
|
||||
$<$<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>
|
||||
# Some compilers could particularly misbehave :)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-error-all>)
|
||||
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>:-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,9 +190,13 @@ 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)
|
||||
if (LINUX OR FREEBSD)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-mtls-dialect=gnu2>)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
-1
@@ -27,7 +27,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
RENDERER_ASYNCHRONOUS_GPU_EMULATION("use_asynchronous_gpu_emulation"),
|
||||
RENDERER_ASYNC_PRESENTATION("async_presentation"),
|
||||
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
|
||||
RENDERER_UNIFIED_MEMORY("use_unified_memory"),
|
||||
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
||||
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
|
||||
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
|
||||
|
||||
-7
@@ -685,13 +685,6 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.renderer_asynchronous_shaders_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.RENDERER_UNIFIED_MEMORY,
|
||||
titleId = R.string.renderer_unified_memory,
|
||||
descriptionId = R.string.renderer_unified_memory_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.FAST_GPU_TIME,
|
||||
|
||||
-1
@@ -304,7 +304,6 @@ class SettingsFragmentPresenter(
|
||||
add(BooleanSetting.EMULATE_BGR565.key)
|
||||
add(BooleanSetting.RESCALE_HACK.key)
|
||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||
add(BooleanSetting.RENDERER_UNIFIED_MEMORY.key)
|
||||
add(IntSetting.ANDROID_PIPELINE_WORKERS.key)
|
||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key)
|
||||
add(BooleanSetting.RENDERER_ASYNC_PRESENTATION.key)
|
||||
|
||||
@@ -524,8 +524,6 @@
|
||||
<string name="rescale_hack_description">Enables a legacy handling for the rescale configuration pass for games by using a quick rescale path</string>
|
||||
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
||||
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
|
||||
<string name="renderer_unified_memory">Unified memory access</string>
|
||||
<string name="renderer_unified_memory_description">Allows GPU write buffer readbacks directly into guest memory, skipping the CPU staging copy.</string>
|
||||
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
|
||||
<string name="gpu_unswizzle_settings_description">Configure GPU-based texture unswizzling parameters or disable it entirely. Adjust these settings to balance performance and texture loading quality.</string>
|
||||
<string name="gpu_unswizzle_enable">Enable GPU Unswizzle</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()
|
||||
|
||||
|
||||
@@ -220,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
|
||||
@@ -235,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)
|
||||
|
||||
+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;
|
||||
|
||||
@@ -31,9 +31,7 @@ s64 GetMaxPermissibleResidentMapCount() {
|
||||
} // namespace
|
||||
|
||||
HeapTracker::HeapTracker(Common::HostMemory& buffer)
|
||||
: m_buffer(buffer),
|
||||
m_has_hardware_buffer_backing(!buffer.BackingHardwareBuffers().empty()),
|
||||
m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {}
|
||||
: m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {}
|
||||
HeapTracker::~HeapTracker() = default;
|
||||
|
||||
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
@@ -87,8 +85,7 @@ void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_hea
|
||||
|
||||
// If resident, erase from resident map.
|
||||
if (item->is_resident) {
|
||||
m_resident_map_count -= this->HostMapCount(item->paddr, item->size);
|
||||
ASSERT(m_resident_map_count >= 0);
|
||||
ASSERT(--m_resident_map_count >= 0);
|
||||
m_resident_mappings.erase(m_resident_mappings.iterator_to(*item));
|
||||
}
|
||||
|
||||
@@ -194,7 +191,7 @@ bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
|
||||
|
||||
// This map is now resident.
|
||||
it->is_resident = true;
|
||||
m_resident_map_count += this->HostMapCount(it->paddr, it->size);
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*it);
|
||||
}
|
||||
|
||||
@@ -216,17 +213,17 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
||||
// Despite being worse in theory, this has proven to be better in practice than more
|
||||
// regularly dumping a smaller amount, because it significantly reduces average case
|
||||
// lock contention.
|
||||
s64 const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
std::size_t const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
std::size_t const evict_count = m_resident_map_count - desired_count;
|
||||
auto it = m_resident_mappings.begin();
|
||||
|
||||
while (m_resident_map_count > desired_count && it != m_resident_mappings.end()) {
|
||||
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
|
||||
// Unmark and unmap.
|
||||
it->is_resident = false;
|
||||
m_buffer.Unmap(it->vaddr, it->size, false);
|
||||
|
||||
// Advance.
|
||||
m_resident_map_count -= this->HostMapCount(it->paddr, it->size);
|
||||
ASSERT(m_resident_map_count >= 0);
|
||||
ASSERT(--m_resident_map_count >= 0);
|
||||
it = m_resident_mappings.erase(it);
|
||||
}
|
||||
}
|
||||
@@ -248,7 +245,6 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) {
|
||||
// Cache the original values.
|
||||
auto* const left = std::addressof(*it);
|
||||
const size_t orig_size = left->size;
|
||||
const s64 orig_host_map_count = this->HostMapCount(left->paddr, orig_size);
|
||||
|
||||
// Adjust the left map.
|
||||
const size_t left_size = offset - left->vaddr;
|
||||
@@ -270,20 +266,11 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) {
|
||||
|
||||
// If resident, also insert into resident map.
|
||||
if (right->is_resident) {
|
||||
m_resident_map_count += this->HostMapCount(left->paddr, left->size) +
|
||||
this->HostMapCount(right->paddr, right->size) -
|
||||
orig_host_map_count;
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*right);
|
||||
}
|
||||
}
|
||||
|
||||
s64 HeapTracker::HostMapCount(PAddr paddr, size_t size) const {
|
||||
if (!m_has_hardware_buffer_backing) {
|
||||
return size != 0 ? 1 : 0;
|
||||
}
|
||||
return static_cast<s64>(m_buffer.BackingMapCount(paddr, size));
|
||||
}
|
||||
|
||||
HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) {
|
||||
const SeparateHeapMap key{
|
||||
.vaddr = offset,
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -85,13 +82,10 @@ private:
|
||||
|
||||
AddrTree::iterator GetNearestHeapMapLocked(VAddr offset);
|
||||
|
||||
s64 HostMapCount(PAddr paddr, size_t size) const;
|
||||
|
||||
void RebuildSeparateHeapAddressSpace();
|
||||
|
||||
private:
|
||||
Common::HostMemory& m_buffer;
|
||||
const bool m_has_hardware_buffer_backing;
|
||||
const s64 m_max_resident_map_count;
|
||||
|
||||
std::shared_mutex m_rebuild_lock{};
|
||||
|
||||
+12
-374
@@ -51,45 +51,14 @@
|
||||
|
||||
#endif // ^^^ POSIX ^^^
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/free_region_manager.h"
|
||||
#include "common/host_memory.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/memory_detect.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <dlfcn.h>
|
||||
#include <android/hardware_buffer.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct NativeHandle {
|
||||
int version;
|
||||
int numFds;
|
||||
int numInts;
|
||||
int data[1];
|
||||
};
|
||||
|
||||
using PFN_AHardwareBuffer_getNativeHandle = const NativeHandle* (*)(const AHardwareBuffer*);
|
||||
|
||||
PFN_AHardwareBuffer_getNativeHandle ResolveGetNativeHandle() {
|
||||
void* const lib = dlopen("libnativewindow.so", RTLD_NOW);
|
||||
if (lib == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<PFN_AHardwareBuffer_getNativeHandle>(
|
||||
dlsym(lib, "AHardwareBuffer_getNativeHandle"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) && __ANDROID_API__ < 30
|
||||
#include <sys/syscall.h>
|
||||
@@ -106,12 +75,6 @@ namespace Common {
|
||||
[[maybe_unused]] constexpr size_t PageAlignment = 0x1000;
|
||||
[[maybe_unused]] constexpr size_t HugePageSize = 0x200000;
|
||||
|
||||
static std::atomic<u64> committed_backing_size{};
|
||||
|
||||
u64 GetCommittedBackingSize() noexcept {
|
||||
return committed_backing_size.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Manually imported for MinGW compatibility
|
||||
@@ -160,7 +123,7 @@ static void GetFuncAddress(Common::DynamicLibrary& dll, const char* name, T& pfn
|
||||
|
||||
class HostMemory::Impl {
|
||||
public:
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_, size_t)
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size{backing_size_}
|
||||
, virtual_size{virtual_size_}
|
||||
, process{GetCurrentProcess()}
|
||||
@@ -266,10 +229,6 @@ public:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool IsBackingShared() const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t backing_size; ///< Size of the backing memory in bytes
|
||||
const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
|
||||
|
||||
@@ -435,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
|
||||
@@ -542,10 +501,9 @@ static int shm_open_anon(int flags, mode_t mode) {
|
||||
|
||||
class HostMemory::Impl {
|
||||
public:
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_, size_t preferred_offset_)
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size{backing_size_}
|
||||
, virtual_size{virtual_size_}
|
||||
, preferred_offset{preferred_offset_}
|
||||
{}
|
||||
|
||||
bool Init() {
|
||||
@@ -585,15 +543,10 @@ public:
|
||||
LOG_WARNING(Common_Memory, "Using private mappings instead of shared ones");
|
||||
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
||||
if (fd > 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
}
|
||||
fd = -1;
|
||||
} else {
|
||||
#ifdef __ANDROID__
|
||||
if (InitAhbBacking()) {
|
||||
return InitVirtual();
|
||||
}
|
||||
#endif
|
||||
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
}
|
||||
if (backing_base == MAP_FAILED) {
|
||||
@@ -601,10 +554,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
return InitVirtual();
|
||||
}
|
||||
|
||||
bool InitVirtual() {
|
||||
// Virtual memory initialization
|
||||
virtual_base = virtual_map_base = static_cast<u8*>(ChooseVirtualBase(virtual_size));
|
||||
if (virtual_base == MAP_FAILED) {
|
||||
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
|
||||
@@ -617,242 +567,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static AHardwareBuffer_Desc MakeBlobDesc(size_t len) {
|
||||
return AHardwareBuffer_Desc{
|
||||
.width = static_cast<u32>(len),
|
||||
.height = 1,
|
||||
.layers = 1,
|
||||
.format = AHARDWAREBUFFER_FORMAT_BLOB,
|
||||
.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
|
||||
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
|
||||
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER,
|
||||
.stride = 0,
|
||||
.rfu0 = 0,
|
||||
.rfu1 = 0,
|
||||
};
|
||||
}
|
||||
|
||||
static bool ProbeAhbBacking(PFN_AHardwareBuffer_getNativeHandle get_native_handle) {
|
||||
const AHardwareBuffer_Desc desc = MakeBlobDesc(PageAlignment * 2);
|
||||
AHardwareBuffer* buffer{};
|
||||
if (AHardwareBuffer_allocate(&desc, &buffer) != 0 || buffer == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const NativeHandle* const handle = get_native_handle(buffer);
|
||||
if (handle == nullptr || handle->numFds < 1) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
return false;
|
||||
}
|
||||
const int probe_fd = handle->data[0];
|
||||
bool ok = true;
|
||||
const auto try_map = [&](int prot, off_t offset, const char* what) {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
void* const ptr = mmap(nullptr, PageAlignment, prot, MAP_SHARED, probe_fd, offset);
|
||||
if (ptr == MAP_FAILED) {
|
||||
ok = false;
|
||||
return;
|
||||
}
|
||||
munmap(ptr, PageAlignment);
|
||||
};
|
||||
try_map(PROT_READ | PROT_WRITE, 0, "shared mappings");
|
||||
try_map(PROT_READ | PROT_WRITE, static_cast<off_t>(PageAlignment), "mappings at an offset");
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
try_map(PROT_READ | PROT_EXEC, 0, "executable mappings");
|
||||
#endif
|
||||
AHardwareBuffer_release(buffer);
|
||||
return ok;
|
||||
}
|
||||
|
||||
size_t ComputeAhbBudget(size_t window_size) const {
|
||||
const u64 total_physical = Common::GetMemInfo().TotalPhysicalMemory;
|
||||
constexpr u64 BaselineFootprint = 6ULL << 30;
|
||||
if (total_physical <= BaselineFootprint) {
|
||||
return 0;
|
||||
}
|
||||
const u64 max_map_count = Common::GetMaxMapCount();
|
||||
constexpr u64 ReservedMaps = 24576;
|
||||
if (max_map_count == 0 || max_map_count <= ReservedMaps) {
|
||||
return 0;
|
||||
}
|
||||
u64 budget = (total_physical - BaselineFootprint) / 2;
|
||||
constexpr u64 MapSlotsPerWindow = 4096;
|
||||
const u64 affordable_windows = (max_map_count - ReservedMaps) / MapSlotsPerWindow;
|
||||
budget = (std::min)(budget, affordable_windows * window_size);
|
||||
const u64 available = Common::GetAvailablePhysicalMemory();
|
||||
if (available != 0) {
|
||||
budget = (std::min)(budget, available / 2);
|
||||
}
|
||||
budget = (std::min)(budget, static_cast<u64>(backing_size));
|
||||
budget = Common::AlignDown(budget, window_size);
|
||||
constexpr u64 MinimumBudget = 256ULL << 20;
|
||||
if (budget < MinimumBudget) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<size_t>(budget);
|
||||
}
|
||||
|
||||
bool InitAhbBacking() {
|
||||
if (!Settings::values.use_unified_memory.GetValue()) {
|
||||
return false;
|
||||
}
|
||||
static const PFN_AHardwareBuffer_getNativeHandle get_native_handle =
|
||||
ResolveGetNativeHandle();
|
||||
if (get_native_handle == nullptr) {
|
||||
return false;
|
||||
}
|
||||
constexpr size_t window_size = 256ULL << 20;
|
||||
const size_t budget = ComputeAhbBudget(window_size);
|
||||
if (budget == 0) {
|
||||
return false;
|
||||
}
|
||||
if (!ProbeAhbBacking(get_native_handle)) {
|
||||
return false;
|
||||
}
|
||||
const size_t aligned_backing = Common::AlignDown(backing_size, window_size);
|
||||
const size_t max_windows = (std::min)(budget, aligned_backing) / window_size;
|
||||
|
||||
std::vector<AHardwareBuffer*> buffers;
|
||||
std::vector<int> buffer_fds;
|
||||
const auto cleanup = [&] {
|
||||
for (AHardwareBuffer* buffer : buffers) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
}
|
||||
buffers.clear();
|
||||
buffer_fds.clear();
|
||||
};
|
||||
for (size_t i = 0; i < max_windows; ++i) {
|
||||
const AHardwareBuffer_Desc desc = MakeBlobDesc(window_size);
|
||||
AHardwareBuffer* buffer{};
|
||||
if (AHardwareBuffer_allocate(&desc, &buffer) != 0 || buffer == nullptr) {
|
||||
break;
|
||||
}
|
||||
const NativeHandle* const handle = get_native_handle(buffer);
|
||||
if (handle == nullptr || handle->numFds < 1) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
break;
|
||||
}
|
||||
const int buffer_fd = handle->data[0];
|
||||
const off_t buffer_len = lseek(buffer_fd, 0, SEEK_END);
|
||||
if (buffer_len < static_cast<off_t>(window_size)) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
break;
|
||||
}
|
||||
buffers.push_back(buffer);
|
||||
buffer_fds.push_back(buffer_fd);
|
||||
}
|
||||
const size_t num_windows = buffers.size();
|
||||
if (num_windows == 0) {
|
||||
return false;
|
||||
}
|
||||
const size_t region_size = num_windows * window_size;
|
||||
const size_t region_base = Common::AlignDown(
|
||||
(std::min)(preferred_offset, aligned_backing - region_size), window_size);
|
||||
u8* const base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0));
|
||||
if (base == MAP_FAILED) {
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
const auto map_over_reservation = [&](size_t offset, size_t len, int map_fd,
|
||||
off_t map_offset) {
|
||||
if (len == 0) {
|
||||
return true;
|
||||
}
|
||||
if (mmap(base + offset, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, map_fd,
|
||||
map_offset) == MAP_FAILED) {
|
||||
munmap(base, backing_size);
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if (!map_over_reservation(0, region_base, fd, 0)) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < num_windows; ++i) {
|
||||
if (!map_over_reservation(region_base + i * window_size, window_size, buffer_fds[i],
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const size_t tail_offset = region_base + region_size;
|
||||
if (!map_over_reservation(tail_offset, backing_size - tail_offset, fd,
|
||||
static_cast<off_t>(tail_offset))) {
|
||||
return false;
|
||||
}
|
||||
backing_base = base;
|
||||
ahb_windows = std::move(buffers);
|
||||
ahb_fds = std::move(buffer_fds);
|
||||
ahb_window_size = window_size;
|
||||
ahb_base = region_base;
|
||||
ahb_bytes = region_size;
|
||||
committed_backing_size.store(region_size, std::memory_order_relaxed);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MapBackingRange(size_t virtual_offset, size_t host_offset, size_t length, int prot_flags) {
|
||||
while (length > 0) {
|
||||
int map_fd = fd;
|
||||
off_t map_offset = static_cast<off_t>(host_offset);
|
||||
size_t chunk = length;
|
||||
if (host_offset < ahb_base) {
|
||||
chunk = (std::min)(chunk, ahb_base - host_offset);
|
||||
} else if (host_offset < ahb_base + ahb_bytes) {
|
||||
const size_t relative = host_offset - ahb_base;
|
||||
const size_t window = relative / ahb_window_size;
|
||||
const size_t local = relative % ahb_window_size;
|
||||
map_fd = ahb_fds[window];
|
||||
map_offset = static_cast<off_t>(local);
|
||||
chunk = (std::min)(chunk, ahb_window_size - local);
|
||||
}
|
||||
void* const ret = mmap(virtual_base + virtual_offset, chunk, prot_flags,
|
||||
MAP_SHARED | MAP_FIXED, map_fd, map_offset);
|
||||
ASSERT_MSG(ret != MAP_FAILED, "mmap: {}", strerror(errno));
|
||||
virtual_offset += chunk;
|
||||
host_offset += chunk;
|
||||
length -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
size_t BackingMapCount(size_t host_offset, size_t length) const noexcept {
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (ahb_bytes == 0) {
|
||||
return 1;
|
||||
}
|
||||
size_t count = 0;
|
||||
while (length > 0) {
|
||||
size_t chunk = length;
|
||||
if (host_offset < ahb_base) {
|
||||
chunk = (std::min)(chunk, ahb_base - host_offset);
|
||||
} else if (host_offset < ahb_base + ahb_bytes) {
|
||||
const size_t local = (host_offset - ahb_base) % ahb_window_size;
|
||||
chunk = (std::min)(chunk, ahb_window_size - local);
|
||||
}
|
||||
host_offset += chunk;
|
||||
length -= chunk;
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
std::span<AHardwareBuffer* const> AhbWindows() const noexcept {
|
||||
return ahb_windows;
|
||||
}
|
||||
|
||||
size_t AhbWindowSize() const noexcept {
|
||||
return ahb_bytes != 0 ? ahb_window_size : 0;
|
||||
}
|
||||
|
||||
size_t AhbBase() const noexcept {
|
||||
return ahb_base;
|
||||
}
|
||||
#endif
|
||||
|
||||
~Impl() {
|
||||
Release();
|
||||
}
|
||||
@@ -873,12 +587,6 @@ public:
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
if (True(perms & MemoryPermission::Execute))
|
||||
prot_flags |= PROT_EXEC;
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
if (ahb_bytes != 0) {
|
||||
MapBackingRange(virtual_offset, host_offset, length, prot_flags);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
int flags = (fd >= 0 ? MAP_SHARED : MAP_PRIVATE) | MAP_FIXED;
|
||||
void* ret = mmap(virtual_base + virtual_offset, length, prot_flags, flags, fd, host_offset);
|
||||
@@ -924,18 +632,8 @@ public:
|
||||
virtual_base = nullptr;
|
||||
}
|
||||
|
||||
bool IsBackingShared() const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
if (ahb_bytes != 0) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return fd >= 0;
|
||||
}
|
||||
|
||||
const size_t backing_size; ///< Size of the backing memory in bytes
|
||||
const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
|
||||
const size_t preferred_offset;
|
||||
|
||||
u8* backing_base{reinterpret_cast<u8*>(MAP_FAILED)};
|
||||
u8* virtual_base{reinterpret_cast<u8*>(MAP_FAILED)};
|
||||
@@ -958,18 +656,6 @@ private:
|
||||
int ret = close(fd);
|
||||
ASSERT_MSG(ret == 0, "close failed: {}", strerror(errno));
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
for (AHardwareBuffer* buffer : ahb_windows) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
}
|
||||
ahb_windows.clear();
|
||||
ahb_fds.clear();
|
||||
if (ahb_bytes != 0) {
|
||||
committed_backing_size.store(0, std::memory_order_relaxed);
|
||||
ahb_bytes = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AdjustMap(size_t* virtual_offset, size_t* length) {
|
||||
@@ -995,23 +681,15 @@ private:
|
||||
|
||||
int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create
|
||||
FreeRegionManager free_manager{};
|
||||
|
||||
#ifdef __ANDROID__
|
||||
std::vector<AHardwareBuffer*> ahb_windows;
|
||||
std::vector<int> ahb_fds;
|
||||
size_t ahb_window_size{};
|
||||
size_t ahb_base{};
|
||||
size_t ahb_bytes{};
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // ^^^ POSIX ^^^
|
||||
|
||||
HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_, size_t preferred_offset_)
|
||||
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();
|
||||
@@ -1019,7 +697,7 @@ HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_, size_t prefer
|
||||
#else
|
||||
// Try to allocate a fastmem arena.
|
||||
// The implementation will fail with std::bad_alloc on errors.
|
||||
impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize, preferred_offset_);
|
||||
impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize);
|
||||
if (impl->Init()) {
|
||||
backing_base = impl->backing_base;
|
||||
virtual_base = impl->virtual_base;
|
||||
@@ -1045,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);
|
||||
@@ -1059,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);
|
||||
@@ -1071,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);
|
||||
@@ -1089,48 +767,8 @@ void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 f
|
||||
std::memset(backing_base + physical_offset, fill_value, length);
|
||||
}
|
||||
|
||||
std::span<AHardwareBuffer* const> HostMemory::BackingHardwareBuffers() const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
return impl ? impl->AhbWindows() : std::span<AHardwareBuffer* const>{};
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t HostMemory::BackingMapCount(size_t host_offset, size_t length) const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
return impl ? impl->BackingMapCount(host_offset, length) : (length != 0 ? 1 : 0);
|
||||
#else
|
||||
return length != 0 ? 1 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t HostMemory::BackingHardwareBufferWindowSize() const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
return impl ? impl->AhbWindowSize() : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool HostMemory::IsBackingShared() const noexcept {
|
||||
#if defined(__OPENORBIS__) || defined(__managarm__)
|
||||
return false;
|
||||
#else
|
||||
return impl && impl->IsBackingShared();
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t HostMemory::BackingHardwareBufferBase() const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
return impl ? impl->AhbBase() : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -8,17 +8,12 @@
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
|
||||
struct AHardwareBuffer;
|
||||
|
||||
namespace Common {
|
||||
|
||||
[[nodiscard]] u64 GetCommittedBackingSize() noexcept;
|
||||
|
||||
enum class MemoryPermission : u32 {
|
||||
Read = 1 << 0,
|
||||
Write = 1 << 1,
|
||||
@@ -33,7 +28,7 @@ DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
|
||||
*/
|
||||
class HostMemory {
|
||||
public:
|
||||
explicit HostMemory(size_t backing_size_, size_t virtual_size_, size_t preferred_offset_ = 0);
|
||||
explicit HostMemory(size_t backing_size_, size_t virtual_size_);
|
||||
~HostMemory();
|
||||
|
||||
/**
|
||||
@@ -67,20 +62,6 @@ public:
|
||||
return backing_base;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t BackingSize() const noexcept {
|
||||
return backing_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t BackingMapCount(size_t host_offset, size_t length) const noexcept;
|
||||
|
||||
[[nodiscard]] std::span<AHardwareBuffer* const> BackingHardwareBuffers() const noexcept;
|
||||
|
||||
[[nodiscard]] size_t BackingHardwareBufferWindowSize() const noexcept;
|
||||
|
||||
[[nodiscard]] size_t BackingHardwareBufferBase() const noexcept;
|
||||
|
||||
[[nodiscard]] bool IsBackingShared() const noexcept;
|
||||
|
||||
[[nodiscard]] u8* VirtualBasePointer() noexcept {
|
||||
return virtual_base;
|
||||
}
|
||||
@@ -96,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;
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -20,10 +17,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/memory_detect.h"
|
||||
|
||||
namespace Common {
|
||||
@@ -76,55 +69,4 @@ const MemoryInfo& GetMemInfo() {
|
||||
return mem_info;
|
||||
}
|
||||
|
||||
u64 GetAvailablePhysicalMemory() {
|
||||
#ifdef _WIN32
|
||||
MEMORYSTATUSEX memorystatus;
|
||||
memorystatus.dwLength = sizeof(memorystatus);
|
||||
if (GlobalMemoryStatusEx(&memorystatus)) {
|
||||
return memorystatus.ullAvailPhys;
|
||||
}
|
||||
return 0;
|
||||
#elif defined(__linux__)
|
||||
if (std::FILE* const file = std::fopen("/proc/meminfo", "re")) {
|
||||
char line[256];
|
||||
u64 available = 0;
|
||||
while (std::fgets(line, sizeof(line), file) != nullptr) {
|
||||
if (std::strncmp(line, "MemAvailable:", 13) == 0) {
|
||||
available = std::strtoull(line + 13, nullptr, 10) * 1024ULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::fclose(file);
|
||||
if (available != 0) {
|
||||
return available;
|
||||
}
|
||||
}
|
||||
struct sysinfo info;
|
||||
if (sysinfo(&info) == 0) {
|
||||
const u64 unit = info.mem_unit != 0 ? info.mem_unit : 1ULL;
|
||||
return (static_cast<u64>(info.freeram) + static_cast<u64>(info.bufferram)) * unit;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 GetMaxMapCount() {
|
||||
#ifdef __linux__
|
||||
if (std::FILE* const file = std::fopen("/proc/sys/vm/max_map_count", "re")) {
|
||||
char line[32];
|
||||
u64 count = 0;
|
||||
if (std::fgets(line, sizeof(line), file) != nullptr) {
|
||||
count = std::strtoull(line, nullptr, 10);
|
||||
}
|
||||
std::fclose(file);
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -21,8 +18,4 @@ struct MemoryInfo {
|
||||
*/
|
||||
[[nodiscard]] const MemoryInfo& GetMemInfo();
|
||||
|
||||
[[nodiscard]] u64 GetAvailablePhysicalMemory();
|
||||
|
||||
[[nodiscard]] u64 GetMaxMapCount();
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -587,9 +587,6 @@ struct Values {
|
||||
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
||||
Category::RendererHacks};
|
||||
|
||||
SwitchableSetting<bool> use_unified_memory{linkage, false, "use_unified_memory",
|
||||
Category::RendererHacks};
|
||||
|
||||
SwitchableSetting<GpuUnswizzleSize> gpu_unswizzle_texture_size{linkage,
|
||||
GpuUnswizzleSize::Large,
|
||||
"gpu_unswizzle_texture_size",
|
||||
@@ -705,7 +702,15 @@ struct Values {
|
||||
|
||||
// Controls
|
||||
InputSetting<std::array<PlayerInput, 10>> players;
|
||||
|
||||
Setting<bool> disable_wgi_xinput{
|
||||
linkage, false, "disable_wgi_xinput", Category::Controls, Specialization::Default,
|
||||
// Only read/write disable_wgi_xinput on Windows platforms
|
||||
#ifdef _WIN32
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
};
|
||||
Setting<bool> enable_raw_input{
|
||||
linkage, false, "enable_raw_input", Category::Controls, Specialization::Default,
|
||||
// Only read/write enable_raw_input on Windows platforms
|
||||
|
||||
@@ -490,6 +490,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
|
||||
LOG_DEBUG(Common, "Could not set thread nice value to {}: {}", nice_value,
|
||||
GetLastErrorMsg());
|
||||
}
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
// TODO: set priority?
|
||||
#else
|
||||
const s32 max_prio = sched_get_priority_max(SCHED_OTHER);
|
||||
const s32 min_prio = sched_get_priority_min(SCHED_OTHER);
|
||||
@@ -534,6 +536,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
|
||||
|
||||
+14
-7
@@ -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,10 +1166,18 @@ 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)
|
||||
if (PLATFORM_LINUX)
|
||||
if (LINUX)
|
||||
target_link_libraries(core PRIVATE iw)
|
||||
endif()
|
||||
else()
|
||||
@@ -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
|
||||
|
||||
+1
-5
@@ -119,7 +119,6 @@ struct System::Impl {
|
||||
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
extended_memory_layout = Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
|
||||
unified_memory = Settings::values.use_unified_memory.GetValue();
|
||||
|
||||
core_timing.SetMulticore(is_multicore);
|
||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||
@@ -147,8 +146,7 @@ struct System::Impl {
|
||||
!device_memory.has_value() ||
|
||||
is_multicore != Settings::values.use_multi_core.GetValue() ||
|
||||
extended_memory_layout != (Settings::values.memory_layout_mode.GetValue() !=
|
||||
Settings::MemoryLayout::Memory_4Gb) ||
|
||||
unified_memory != Settings::values.use_unified_memory.GetValue();
|
||||
Settings::MemoryLayout::Memory_4Gb);
|
||||
|
||||
if (!must_reinitialize) {
|
||||
return;
|
||||
@@ -159,7 +157,6 @@ struct System::Impl {
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
extended_memory_layout =
|
||||
Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
|
||||
unified_memory = Settings::values.use_unified_memory.GetValue();
|
||||
|
||||
Initialize(system);
|
||||
}
|
||||
@@ -506,7 +503,6 @@ struct System::Impl {
|
||||
std::atomic_bool is_powered_on{};
|
||||
bool is_multicore : 1 = false;
|
||||
bool extended_memory_layout : 1 = false;
|
||||
bool unified_memory : 1 = false;
|
||||
bool exit_locked : 1 = false;
|
||||
bool exit_requested : 1 = false;
|
||||
bool nvdec_active : 1 = false;
|
||||
|
||||
@@ -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>);
|
||||
@@ -400,3 +424,4 @@ void Debugger::NotifyShutdown() {
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -15,18 +12,9 @@ constexpr size_t VirtualReserveSize = 1ULL << 38;
|
||||
constexpr size_t VirtualReserveSize = 1ULL << 39;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
size_t ApplicationPoolOffset() {
|
||||
using Init = Kernel::Board::Nintendo::Nx::KSystemControl::Init;
|
||||
const size_t dram_size = Init::GetIntendedMemorySize();
|
||||
const size_t application_pool_size = Init::GetApplicationPoolSize();
|
||||
return dram_size > application_pool_size ? dram_size - application_pool_size : 0;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceMemory::DeviceMemory()
|
||||
: buffer{Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(),
|
||||
VirtualReserveSize, ApplicationPoolOffset()} {}
|
||||
VirtualReserveSize} {}
|
||||
|
||||
DeviceMemory::~DeviceMemory() = default;
|
||||
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
|
||||
struct AHardwareBuffer;
|
||||
|
||||
namespace Core {
|
||||
|
||||
constexpr size_t DEVICE_PAGEBITS = 12ULL;
|
||||
@@ -97,34 +95,6 @@ public:
|
||||
ApplyOpOnPAddr(address, buffer, operation);
|
||||
}
|
||||
|
||||
u8* GetPhysicalBase() noexcept {
|
||||
return reinterpret_cast<u8*>(physical_base);
|
||||
}
|
||||
|
||||
const u8* GetPhysicalBase() const noexcept {
|
||||
return reinterpret_cast<const u8*>(physical_base);
|
||||
}
|
||||
|
||||
size_t GetPhysicalSize() const noexcept {
|
||||
return physical_size;
|
||||
}
|
||||
|
||||
std::span<AHardwareBuffer* const> GetBackingHardwareBuffers() const noexcept {
|
||||
return ahb_windows;
|
||||
}
|
||||
|
||||
size_t GetBackingHardwareBufferWindowSize() const noexcept {
|
||||
return ahb_window_size;
|
||||
}
|
||||
|
||||
size_t GetBackingHardwareBufferBase() const noexcept {
|
||||
return ahb_base;
|
||||
}
|
||||
|
||||
bool IsBackingShared() const noexcept {
|
||||
return backing_is_shared;
|
||||
}
|
||||
|
||||
PAddr GetPhysicalRawAddressFromDAddr(DAddr address) const {
|
||||
PAddr subbits = PAddr(address & page_mask);
|
||||
auto paddr = tracked_entries[(address >> page_bits)].compressed_physical_ptr;
|
||||
@@ -201,11 +171,6 @@ private:
|
||||
std::unique_ptr<DeviceMemoryManagerAllocator<Traits>> impl;
|
||||
|
||||
const uintptr_t physical_base;
|
||||
const size_t physical_size;
|
||||
const std::span<AHardwareBuffer* const> ahb_windows;
|
||||
const size_t ahb_window_size;
|
||||
const size_t ahb_base;
|
||||
const bool backing_is_shared;
|
||||
DeviceInterface* device_inter;
|
||||
|
||||
struct TrackedEntry {
|
||||
|
||||
@@ -171,11 +171,6 @@ struct DeviceMemoryManagerAllocator {
|
||||
template <typename Traits>
|
||||
DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_)
|
||||
: physical_base{uintptr_t(device_memory_.buffer.BackingBasePointer())}
|
||||
, physical_size{device_memory_.buffer.BackingSize()}
|
||||
, ahb_windows{device_memory_.buffer.BackingHardwareBuffers()}
|
||||
, ahb_window_size{device_memory_.buffer.BackingHardwareBufferWindowSize()}
|
||||
, ahb_base{device_memory_.buffer.BackingHardwareBufferBase()}
|
||||
, backing_is_shared{device_memory_.buffer.IsBackingShared()}
|
||||
, device_inter{nullptr}
|
||||
, compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() == Settings::MemoryLayout::Memory_4Gb ? physical_min_bits : physical_max_bits) - Memory::YUZU_PAGEBITS))
|
||||
, tracked_entries(device_as_size >> Memory::YUZU_PAGEBITS)
|
||||
|
||||
@@ -7,8 +7,14 @@
|
||||
#include <random>
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||
#endif
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
||||
@@ -18,8 +24,6 @@
|
||||
#include "core/hle/kernel/k_thread_queue.h"
|
||||
#include "core/hle/kernel/k_worker_task_manager.h"
|
||||
|
||||
#include "core/arm/dynarmic/arm_dynarmic_32.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_64.h"
|
||||
#ifdef HAS_NCE
|
||||
#include "core/arm/nce/arm_nce.h"
|
||||
#endif
|
||||
@@ -1300,9 +1304,11 @@ void KProcess::LoadModule(KernelCore& kernel, CodeSet code_set, KProcessAddress
|
||||
}
|
||||
|
||||
void KProcess::InitializeInterfaces(KernelCore& kernel) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
ASSERT(false && "unimplemented");
|
||||
#else
|
||||
m_exclusive_monitor =
|
||||
Core::MakeExclusiveMonitor(this->GetMemory(), Core::Hardware::NUM_CPU_CORES);
|
||||
|
||||
#ifdef HAS_NCE
|
||||
if (this->IsApplication() && Settings::IsNceEnabled()) {
|
||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++)
|
||||
@@ -1322,6 +1328,7 @@ void KProcess::InitializeInterfaces(KernelCore& kernel) {
|
||||
static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool KProcess::InsertWatchpoint(KernelCore& kernel, KProcessAddress addr, u64 size, DebugWatchpointType type) {
|
||||
|
||||
@@ -28,7 +28,7 @@ Result CloseHandle(Core::System& system, Handle handle) {
|
||||
|
||||
/// Clears the signaled state of an event or process.
|
||||
Result ResetSignal(Core::System& system, Handle handle) {
|
||||
LOG_DEBUG(Kernel_SVC, "called handle {:#08x}", handle);
|
||||
LOG_TRACE(Kernel_SVC, "called handle {:#08x}", handle);
|
||||
|
||||
// Get the current handle table.
|
||||
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
|
||||
|
||||
@@ -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 2024 yuzu Emulator
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
RestrictionSettings restriction_settings{};
|
||||
std::array<char, 8> pin_code{};
|
||||
Capability capability{};
|
||||
// TODO: this is RAW as fuck
|
||||
// TODO: this is raw
|
||||
PlayTimerSettings raw_play_timer_settings{};
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
@@ -86,15 +86,22 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
|
||||
// BEGONE cold clones of lambdas, for I have merged you all into a SINGLE lambda instead of
|
||||
// spamming lambdas like it's some kind of lambda calculus class
|
||||
for (auto const& e : std::vector<std::pair<std::string_view, void (*)(Core::System&)>>{
|
||||
std::vector<std::pair<std::string_view, void (*)(Core::System&)>> rt_services{
|
||||
{"audio", &Audio::LoopProcess},
|
||||
{"FS", &FileSystem::LoopProcess},
|
||||
{"ldn", &LDN::LoopProcess},
|
||||
{"nvservices", &Nvidia::LoopProcess},
|
||||
{"bsdsocket", &Sockets::LoopProcess},
|
||||
})
|
||||
};
|
||||
#if defined(__EMSCRIPTEN__) || defined(__wasi__) || defined(__OPENORBIS__)
|
||||
for (auto const& e : rt_services)
|
||||
kernel.RunOnGuestCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); });
|
||||
kernel.RunOnGuestCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); });
|
||||
#else
|
||||
for (auto const& e : rt_services)
|
||||
kernel.RunOnHostCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); }).detach();
|
||||
kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach();
|
||||
kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach();
|
||||
#endif
|
||||
// Avoid cold clones of lambdas -- succintly
|
||||
for (auto const& e : std::vector<std::pair<std::string_view, void (*)(Core::System&)>>{
|
||||
{"sm", &SM::LoopProcess},
|
||||
@@ -118,7 +125,10 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
{"glue", &Glue::LoopProcess},
|
||||
{"grc", &GRC::LoopProcess},
|
||||
{"hid", &HID::LoopProcess},
|
||||
// Must match with src/core/CMakeLists.txt for target_source of jit.cpp
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) || defined(ARCHITECTURE_riscv64) || defined(ARCHITECTURE_loongarch64)
|
||||
{"jit", &JIT::LoopProcess},
|
||||
#endif
|
||||
{"lbl", &LBL::LoopProcess},
|
||||
{"Loader", &LDR::LoopProcess},
|
||||
{"LogManager.Prod", &LM::LoopProcess},
|
||||
|
||||
@@ -1020,7 +1020,7 @@ Result ISystemSettingsServer::GetBatteryLot(Out<BatteryLot> out_battery_lot) {
|
||||
c.lot_number[1] = 'H';
|
||||
c.lot_number[2] = 'A';
|
||||
c.lot_number[3] = 'C';
|
||||
// TODO: I have no fucking idea what the letters mean
|
||||
// TODO: what do the letters mean?
|
||||
c.lot_number[4] = 'H';
|
||||
c.lot_number[5] = 'Z';
|
||||
c.lot_number[6] = 'Z';
|
||||
|
||||
@@ -531,7 +531,8 @@ int TranslateTypeToNative(Type type) {
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MPLS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PFSYNC)
|
||||
#elif defined(__linux__)
|
||||
// Other platforms get fucked
|
||||
// Other platforms may not support some niche protocols.
|
||||
// This is usually not an issue
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_LIST \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IP) \
|
||||
/*NETWORK_PROTOCOL_TRANSLATE_ELEM(HOPOPTS)*/ \
|
||||
|
||||
@@ -25,7 +25,7 @@ endif()
|
||||
# Dynarmic project options
|
||||
option(DYNARMIC_ENABLE_CPU_FEATURE_DETECTION "Turning this off causes dynarmic to assume the host CPU doesn't support anything later than SSE3" ON)
|
||||
|
||||
if (PLATFORM_OPENBSD OR PLATFORM_DRAGONFLY OR PLATFORM_NETBSD)
|
||||
if (OPENBSD OR DRAGONFLY OR NETBSD)
|
||||
set(REQUIRE_WX ON)
|
||||
else()
|
||||
set(REQUIRE_WX OFF)
|
||||
|
||||
@@ -363,7 +363,7 @@ elseif (APPLE)
|
||||
backend/exception_handler_macos_mig.c
|
||||
)
|
||||
endif()
|
||||
elseif (UNIX AND NOT PLATFORM_HAIKU)
|
||||
elseif (UNIX AND NOT HAIKUOS)
|
||||
# Haiku lacks <ucontext.h>
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
target_link_libraries(dynarmic PRIVATE rt)
|
||||
|
||||
@@ -234,7 +234,7 @@ private:
|
||||
BlockOfCode block_of_code;
|
||||
A32EmitX64 emitter;
|
||||
Optimization::PolyfillOptions polyfill_options;
|
||||
// Keep it here, you don't wanna mess with the fuckery that's initializer lists
|
||||
// Keep it here in order to not mess with initializer lists
|
||||
const A32::UserConfig conf;
|
||||
Jit* jit_interface;
|
||||
|
||||
|
||||
@@ -2160,8 +2160,6 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
ROUNDING_MODE_CASE(CASE, 0x3e) \
|
||||
ROUNDING_MODE_CASE(CASE, 0x3f)
|
||||
|
||||
// FUCK YOU MSVC, FUCKING DEPTH CANT EVEN HANDLE 8+16+32+64 DEPTH OF A ELSE STATMENT YOU FUCKING STUPID
|
||||
// BURN MSVC BURN IT STUPID COMPILER CAN'T EVEN COMPILE THE MOST BASIC C++
|
||||
ROUNDING_MODE_SWITCH(ToNearest_TieEven)
|
||||
ROUNDING_MODE_SWITCH(TowardsPlusInfinity)
|
||||
ROUNDING_MODE_SWITCH(TowardsMinusInfinity)
|
||||
|
||||
@@ -787,7 +787,7 @@ static void FoldCountLeadingZeros(IR::Inst& inst, bool is_32_bit) {
|
||||
/// Folds division operations based on the following:
|
||||
///
|
||||
/// 1. x / 0 -> 0 (NOTE: This is an ARM-specific behavior defined in the architecture reference manual)
|
||||
/// 2a. 0x8000_0000 / 0xFFFF_FFFF -> 0x8000_0000 (NOTE: More ARM bullshit)
|
||||
/// 2a. 0x8000_0000 / 0xFFFF_FFFF -> 0x8000_0000 (NOTE: More ARM errata)
|
||||
/// 2b. 0x8000_0000_0000_0000 / 0xFFFF_FFFF_FFFF_FFFF -> 0x8000_0000_0000_0000
|
||||
/// 3. imm_x / imm_y -> result
|
||||
/// 4. x / 1 -> x
|
||||
|
||||
@@ -151,7 +151,7 @@ if (MSVC)
|
||||
)
|
||||
else()
|
||||
target_compile_options(hid_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>)
|
||||
|
||||
@@ -28,7 +28,10 @@ enum class NpadMcuState : u32 {
|
||||
struct NpadMcuHolder {
|
||||
NpadMcuState state;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
IAbstractedPad* abstracted_pad;
|
||||
union {
|
||||
IAbstractedPad* abstracted_pad;
|
||||
u64 abstracted_pad_raw;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(NpadMcuHolder) == 0x10, "NpadMcuHolder is an invalid size");
|
||||
|
||||
|
||||
@@ -33,9 +33,15 @@ public:
|
||||
bool is_created{};
|
||||
bool is_mapped{};
|
||||
INSERT_PADDING_BYTES(0x5);
|
||||
Kernel::KSharedMemory* shared_memory;
|
||||
union {
|
||||
Kernel::KSharedMemory* shared_memory = nullptr;
|
||||
u64 shared_memory_raw;
|
||||
};
|
||||
INSERT_PADDING_BYTES(0x38);
|
||||
SharedMemoryFormat* address = nullptr;
|
||||
union {
|
||||
SharedMemoryFormat* address = nullptr;
|
||||
u64 address_raw;
|
||||
};
|
||||
};
|
||||
// Correct size is 0x50 bytes
|
||||
static_assert(sizeof(SharedMemoryHolder) == 0x50, "SharedMemoryHolder is an invalid size");
|
||||
|
||||
@@ -15,8 +15,6 @@ add_library(input_common STATIC
|
||||
drivers/tas_input.h
|
||||
drivers/touch_screen.cpp
|
||||
drivers/touch_screen.h
|
||||
drivers/udp_client.cpp
|
||||
drivers/udp_client.h
|
||||
drivers/virtual_amiibo.cpp
|
||||
drivers/virtual_amiibo.h
|
||||
drivers/virtual_gamepad.cpp
|
||||
@@ -34,8 +32,12 @@ add_library(input_common STATIC
|
||||
input_poller.cpp
|
||||
input_poller.h
|
||||
main.cpp
|
||||
main.h
|
||||
)
|
||||
main.h)
|
||||
if (NOT PLATFORM_EMSCRIPTEN)
|
||||
target_sources(input_common PRIVATE
|
||||
drivers/udp_client.cpp
|
||||
drivers/udp_client.h)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(input_common PRIVATE
|
||||
@@ -44,7 +46,7 @@ if (MSVC)
|
||||
/we4800 # Implicit conversion from 'type' to bool. Possible information loss
|
||||
)
|
||||
else()
|
||||
target_compile_options(input_common PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>)
|
||||
target_compile_options(input_common PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -157,8 +160,8 @@ Common::ParamPackage Android::BuildButtonParamPackageForButton(PadIdentifier ide
|
||||
|
||||
bool Android::MatchVID(Common::UUID device, const std::vector<std::string>& vids) const {
|
||||
for (size_t i = 0; i < vids.size(); ++i) {
|
||||
auto fucker = device.RawString();
|
||||
if (fucker.find(vids[i]) != std::string::npos) {
|
||||
auto dev_str = device.RawString();
|
||||
if (dev_str.find(vids[i]) != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,6 +648,13 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
|
||||
// Disable raw input. When enabled this setting causes SDL to die when a web applet opens
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, Settings::values.enable_raw_input ? "1" : "0");
|
||||
|
||||
#ifdef _WIN32
|
||||
if (Settings::values.disable_wgi_xinput) {
|
||||
SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT, "0", SDL_HINT_OVERRIDE);
|
||||
SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_WGI, "0", SDL_HINT_OVERRIDE);
|
||||
}
|
||||
#endif
|
||||
|
||||
// SDL3 defaults Steam Controller Bluetooth HIDAPI support to off, which can disable gyro.
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, "1");
|
||||
SDL_SetHint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION, "1");
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "input_common/drivers/mouse.h"
|
||||
#include "input_common/drivers/tas_input.h"
|
||||
#include "input_common/drivers/touch_screen.h"
|
||||
#include "input_common/drivers/udp_client.h"
|
||||
#include "input_common/drivers/virtual_amiibo.h"
|
||||
#include "input_common/drivers/virtual_gamepad.h"
|
||||
#include "input_common/helpers/stick_from_buttons.h"
|
||||
@@ -21,6 +20,9 @@
|
||||
#include "input_common/input_mapping.h"
|
||||
#include "input_common/input_poller.h"
|
||||
#include "input_common/main.h"
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#include "input_common/drivers/udp_client.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_LIBUSB
|
||||
#include "input_common/drivers/gc_adapter.h"
|
||||
@@ -82,7 +84,9 @@ struct InputSubsystem::Impl {
|
||||
#ifdef ENABLE_LIBUSB
|
||||
RegisterEngine("gcpad", gcadapter);
|
||||
#endif
|
||||
#ifndef __EMSCRIPTEN__
|
||||
RegisterEngine("cemuhookudp", udp_client);
|
||||
#endif
|
||||
RegisterEngine("tas", tas_input);
|
||||
RegisterEngine("camera", camera);
|
||||
#ifdef __ANDROID__
|
||||
@@ -116,7 +120,9 @@ struct InputSubsystem::Impl {
|
||||
#ifdef ENABLE_LIBUSB
|
||||
UnregisterEngine(gcadapter);
|
||||
#endif
|
||||
#ifndef __EMSCRIPTEN__
|
||||
UnregisterEngine(udp_client);
|
||||
#endif
|
||||
UnregisterEngine(tas_input);
|
||||
UnregisterEngine(camera);
|
||||
#ifdef __ANDROID__
|
||||
@@ -152,8 +158,10 @@ struct InputSubsystem::Impl {
|
||||
auto gcadapter_devices = gcadapter->GetInputDevices();
|
||||
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
|
||||
#endif
|
||||
#ifndef __EMSCRIPTEN__
|
||||
auto udp_devices = udp_client->GetInputDevices();
|
||||
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
||||
#endif
|
||||
#ifdef HAVE_SDL3
|
||||
auto joycon_devices = joycon->GetInputDevices();
|
||||
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
||||
@@ -186,9 +194,11 @@ struct InputSubsystem::Impl {
|
||||
return gcadapter;
|
||||
}
|
||||
#endif
|
||||
#ifndef __EMSCRIPTEN__
|
||||
if (engine == udp_client->GetEngineName()) {
|
||||
return udp_client;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SDL3
|
||||
if (engine == sdl->GetEngineName()) {
|
||||
return sdl;
|
||||
@@ -271,9 +281,11 @@ struct InputSubsystem::Impl {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifndef __EMSCRIPTEN__
|
||||
if (engine == udp_client->GetEngineName()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (engine == tas_input->GetEngineName()) {
|
||||
return true;
|
||||
}
|
||||
@@ -300,7 +312,9 @@ struct InputSubsystem::Impl {
|
||||
#ifdef ENABLE_LIBUSB
|
||||
gcadapter->BeginConfiguration();
|
||||
#endif
|
||||
#ifndef __EMSCRIPTEN__
|
||||
udp_client->BeginConfiguration();
|
||||
#endif
|
||||
#ifdef HAVE_SDL3
|
||||
sdl->BeginConfiguration();
|
||||
joycon->BeginConfiguration();
|
||||
@@ -316,7 +330,9 @@ struct InputSubsystem::Impl {
|
||||
#ifdef ENABLE_LIBUSB
|
||||
gcadapter->EndConfiguration();
|
||||
#endif
|
||||
#ifndef __EMSCRIPTEN__
|
||||
udp_client->EndConfiguration();
|
||||
#endif
|
||||
#ifdef HAVE_SDL3
|
||||
sdl->EndConfiguration();
|
||||
joycon->EndConfiguration();
|
||||
@@ -341,7 +357,9 @@ struct InputSubsystem::Impl {
|
||||
std::shared_ptr<Mouse> mouse;
|
||||
std::shared_ptr<TouchScreen> touch_screen;
|
||||
std::shared_ptr<TasInput::Tas> tas_input;
|
||||
#ifndef __EMSCRIPTEN__
|
||||
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
|
||||
#endif
|
||||
std::shared_ptr<Camera> camera;
|
||||
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
|
||||
std::shared_ptr<VirtualGamepad> virtual_gamepad;
|
||||
@@ -470,7 +488,9 @@ bool InputSubsystem::IsStickInverted(const Common::ParamPackage& params) const {
|
||||
}
|
||||
|
||||
void InputSubsystem::ReloadInputDevices() {
|
||||
#ifndef __EMSCRIPTEN__
|
||||
impl->udp_client.get()->ReloadSockets();
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputSubsystem::BeginMapping(Polling::InputType type) {
|
||||
|
||||
@@ -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: 2022 yuzu Emulator Project
|
||||
@@ -28,6 +28,6 @@ if (ENABLE_WEB_SERVICE)
|
||||
endif()
|
||||
|
||||
# Solaris uses /lib/amd64/libsocket.so and /lib/amd64/libnsl.so
|
||||
if (PLATFORM_SUN)
|
||||
if (SOLARIS)
|
||||
target_link_libraries(network PRIVATE socket nsl)
|
||||
endif()
|
||||
|
||||
@@ -227,8 +227,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
||||
tr("Preserves GPU-modified data by reading it back before uploading.\nSome games require this to render certain effects properly."));
|
||||
INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"),
|
||||
tr("May reduce shader stutter."));
|
||||
INSERT(Settings, use_unified_memory, tr("Enable unified memory access"),
|
||||
tr("Lets the GPU write buffer readbacks directly into guest memory."));
|
||||
INSERT(Settings, gpu_clock, tr("GPU Clocks"),
|
||||
tr("Makes the game believe GPU work finishes faster than it does, so it stops lowering "
|
||||
"resolution and render distance to fit the Switch's clocks."));
|
||||
|
||||
@@ -253,12 +253,11 @@ if (MSVC)
|
||||
)
|
||||
else()
|
||||
target_compile_options(shader_recompiler PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>
|
||||
# Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
|
||||
# And this in turns limits the size of a std::array.
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fbracket-depth=1024>
|
||||
$<$<CXX_COMPILER_ID:AppleClang>:-fbracket-depth=1024>
|
||||
)
|
||||
$<$<CXX_COMPILER_ID:AppleClang>:-fbracket-depth=1024>)
|
||||
endif()
|
||||
|
||||
create_target_directory_groups(shader_recompiler)
|
||||
|
||||
@@ -31,7 +31,7 @@ struct CbufWordKey {
|
||||
|
||||
struct CbufWordKeyHash {
|
||||
constexpr size_t operator()(const CbufWordKey& k) const noexcept {
|
||||
return (size_t(k.index) << 32) ^ k.offset;
|
||||
return size_t((u64(k.index) << 32) ^ u64(k.offset));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -157,16 +160,14 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
||||
|
||||
unsigned Swizzle(u64 insn) {
|
||||
const Encoding texs{insn};
|
||||
const size_t encoding{texs.swizzle};
|
||||
u8 const encoding = u8(texs.swizzle);
|
||||
if (texs.dest_reg_b == IR::Reg::RZ) {
|
||||
if (encoding >= RG_LUT.size()) {
|
||||
if (encoding >= RG_LUT.size())
|
||||
throw NotImplementedException("Illegal RG encoding {}", encoding);
|
||||
}
|
||||
return RG_LUT[encoding];
|
||||
} else {
|
||||
if (encoding >= RGBA_LUT.size()) {
|
||||
if (encoding >= RGBA_LUT.size())
|
||||
throw NotImplementedException("Illegal RGBA encoding {}", encoding);
|
||||
}
|
||||
return RGBA_LUT[encoding];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -142,16 +145,14 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) {
|
||||
|
||||
unsigned Swizzle(u64 insn) {
|
||||
const Encoding tlds{insn};
|
||||
const size_t encoding{tlds.swizzle};
|
||||
u8 const encoding = u8(tlds.swizzle);
|
||||
if (tlds.dest_reg_b == IR::Reg::RZ) {
|
||||
if (encoding >= RG_LUT.size()) {
|
||||
if (encoding >= RG_LUT.size())
|
||||
throw NotImplementedException("Illegal RG encoding {}", encoding);
|
||||
}
|
||||
return RG_LUT[encoding];
|
||||
} else {
|
||||
if (encoding >= RGBA_LUT.size()) {
|
||||
if (encoding >= RGBA_LUT.size())
|
||||
throw NotImplementedException("Illegal RGBA encoding {}", encoding);
|
||||
}
|
||||
return RGBA_LUT[encoding];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ else()
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-local-typedef>)
|
||||
else()
|
||||
target_compile_options(video_core PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>)
|
||||
target_compile_options(video_core PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>)
|
||||
endif()
|
||||
|
||||
target_compile_options(video_core PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-sign-conversion>)
|
||||
|
||||
@@ -571,11 +571,7 @@ void BufferCache<P>::AccumulateFlushes() {
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
|
||||
if (async_buffers.empty()) {
|
||||
return false;
|
||||
}
|
||||
return async_buffers.front().has_value() ||
|
||||
!pending_downloads.front().unified_copies.empty();
|
||||
return (!async_buffers.empty() && async_buffers.front().has_value());
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -583,7 +579,6 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
|
||||
AccumulateFlushes();
|
||||
|
||||
if (committed_gpu_modified_ranges.empty()) {
|
||||
pending_downloads.emplace_back();
|
||||
async_buffers.emplace_back(std::optional<Async_Buffer>{});
|
||||
return;
|
||||
}
|
||||
@@ -643,83 +638,27 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
|
||||
}
|
||||
committed_gpu_modified_ranges.clear();
|
||||
if (downloads.empty()) {
|
||||
pending_downloads.emplace_back();
|
||||
async_buffers.emplace_back(std::optional<Async_Buffer>{});
|
||||
return;
|
||||
}
|
||||
|
||||
struct QueuedUnifiedCopy {
|
||||
u64 window;
|
||||
BufferId buffer_id;
|
||||
boost::container::small_vector<BufferCopy, 16> copies;
|
||||
};
|
||||
|
||||
AsyncDownloadBatch batch;
|
||||
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 16> staging_downloads;
|
||||
boost::container::small_vector<QueuedUnifiedCopy, 4> unified_copy_queue;
|
||||
boost::container::small_vector<u64, 4> window_ids;
|
||||
UnifiedWindowGroups groups;
|
||||
u64 staging_size_bytes = 0;
|
||||
for (auto& [copy, buffer_id] : downloads) {
|
||||
Buffer& buffer = slot_buffers[buffer_id];
|
||||
const DAddr orig_device_addr = buffer.CpuAddr() + copy.src_offset;
|
||||
bool unified = false;
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
if (runtime.HasUnifiedMemory()) {
|
||||
window_ids.clear();
|
||||
groups.clear();
|
||||
unified = ResolveUnifiedWindows(orig_device_addr, copy.src_offset, copy.size,
|
||||
window_ids, groups);
|
||||
}
|
||||
}
|
||||
BufferCopy record{copy};
|
||||
record.src_offset = static_cast<size_t>(orig_device_addr);
|
||||
if (unified) {
|
||||
async_downloads.Add(orig_device_addr, copy.size);
|
||||
buffer.MarkUsage(copy.src_offset, copy.size);
|
||||
for (size_t i = 0; i < window_ids.size(); ++i) {
|
||||
unified_copy_queue.push_back(
|
||||
QueuedUnifiedCopy{window_ids[i], buffer_id, std::move(groups[i])});
|
||||
}
|
||||
batch.unified_copies.push_back(record);
|
||||
continue;
|
||||
}
|
||||
copy.dst_offset = staging_size_bytes;
|
||||
constexpr u64 align = 64ULL;
|
||||
staging_size_bytes += (copy.size + align - 1) & ~(align - 1ULL);
|
||||
staging_downloads.push_back({copy, buffer_id});
|
||||
}
|
||||
|
||||
std::optional<Async_Buffer> download_staging;
|
||||
if (!staging_downloads.empty()) {
|
||||
download_staging = runtime.DownloadStagingBuffer(staging_size_bytes, true);
|
||||
}
|
||||
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes, true);
|
||||
boost::container::small_vector<BufferCopy, 4> normalized_copies;
|
||||
runtime.PreCopyBarrier();
|
||||
for (auto& [copy, buffer_id] : staging_downloads) {
|
||||
copy.dst_offset += download_staging->offset;
|
||||
for (auto& [copy, buffer_id] : downloads) {
|
||||
copy.dst_offset += download_staging.offset;
|
||||
const std::array copies{copy};
|
||||
BufferCopy second_copy{copy};
|
||||
Buffer& buffer = slot_buffers[buffer_id];
|
||||
BufferCopy record{copy};
|
||||
record.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset;
|
||||
const DAddr orig_device_addr = static_cast<DAddr>(record.src_offset);
|
||||
second_copy.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset;
|
||||
const DAddr orig_device_addr = static_cast<DAddr>(second_copy.src_offset);
|
||||
async_downloads.Add(orig_device_addr, copy.size);
|
||||
buffer.MarkUsage(copy.src_offset, copy.size);
|
||||
runtime.CopyBuffer(download_staging->buffer, buffer, copies, false);
|
||||
batch.staging_copies.push_back(record);
|
||||
}
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
for (const auto& queued : unified_copy_queue) {
|
||||
const std::span<const BufferCopy> group_span(queued.copies.data(),
|
||||
queued.copies.size());
|
||||
runtime.CopyToUnifiedMemory(queued.window, slot_buffers[queued.buffer_id], group_span);
|
||||
}
|
||||
if (!unified_copy_queue.empty()) {
|
||||
runtime.UnifiedMemoryHostBarrier();
|
||||
}
|
||||
runtime.CopyBuffer(download_staging.buffer, buffer, copies, false);
|
||||
normalized_copies.push_back(second_copy);
|
||||
}
|
||||
runtime.PostCopyBarrier();
|
||||
pending_downloads.emplace_back(std::move(batch));
|
||||
async_buffers.emplace_back(std::move(download_staging));
|
||||
pending_downloads.emplace_back(std::move(normalized_copies));
|
||||
async_buffers.emplace_back(download_staging);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -734,49 +673,32 @@ void BufferCache<P>::PopAsyncFlushes() {
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::PopAsyncBuffers() {
|
||||
struct Writeback {
|
||||
DAddr addr;
|
||||
const u8* src;
|
||||
u64 size;
|
||||
};
|
||||
boost::container::small_vector<Writeback, 8> writebacks;
|
||||
{
|
||||
std::scoped_lock lock{mutex};
|
||||
if (async_buffers.empty()) {
|
||||
return;
|
||||
}
|
||||
auto& batch = pending_downloads.front();
|
||||
auto& async_buffer = async_buffers.front();
|
||||
if (async_buffer.has_value()) {
|
||||
const u8* base = async_buffer->mapped_span.data();
|
||||
const size_t base_offset = async_buffer->offset;
|
||||
for (const auto& copy : batch.staging_copies) {
|
||||
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
|
||||
const u64 dst_offset = copy.dst_offset - base_offset;
|
||||
const u8* read_mapped_memory = base + dst_offset;
|
||||
async_downloads.ForEachInRange(
|
||||
device_addr, copy.size, [&](DAddr start, DAddr end, s32) {
|
||||
writebacks.push_back(
|
||||
{start, &read_mapped_memory[start - device_addr], end - start});
|
||||
});
|
||||
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
|
||||
gpu_modified_ranges.Subtract(start, end - start);
|
||||
});
|
||||
}
|
||||
async_buffers_death_ring.emplace_back(*async_buffer);
|
||||
}
|
||||
for (const auto& copy : batch.unified_copies) {
|
||||
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
|
||||
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
|
||||
gpu_modified_ranges.Subtract(start, end - start);
|
||||
});
|
||||
}
|
||||
if (async_buffers.empty()) {
|
||||
return;
|
||||
}
|
||||
if (!async_buffers.front().has_value()) {
|
||||
async_buffers.pop_front();
|
||||
pending_downloads.pop_front();
|
||||
return;
|
||||
}
|
||||
for (const auto& wb : writebacks) {
|
||||
device_memory.WriteBlockUnsafe(wb.addr, wb.src, wb.size);
|
||||
auto& downloads = pending_downloads.front();
|
||||
auto& async_buffer = async_buffers.front();
|
||||
u8* base = async_buffer->mapped_span.data();
|
||||
const size_t base_offset = async_buffer->offset;
|
||||
for (const auto& copy : downloads) {
|
||||
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
|
||||
const u64 dst_offset = copy.dst_offset - base_offset;
|
||||
const u8* read_mapped_memory = base + dst_offset;
|
||||
async_downloads.ForEachInRange(device_addr, copy.size, [&](DAddr start, DAddr end, s32) {
|
||||
device_memory.WriteBlockUnsafe(start, &read_mapped_memory[start - device_addr],
|
||||
end - start);
|
||||
});
|
||||
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
|
||||
gpu_modified_ranges.Subtract(start, end - start);
|
||||
});
|
||||
}
|
||||
async_buffers_death_ring.emplace_back(*async_buffer);
|
||||
async_buffers.pop_front();
|
||||
pending_downloads.pop_front();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -1741,9 +1663,6 @@ bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
|
||||
template <class P>
|
||||
void BufferCache<P>::UploadMemory(Buffer& buffer, u64 total_size_bytes, u64 largest_copy,
|
||||
std::span<BufferCopy> copies) {
|
||||
if (TryUnifiedUploadMemory(buffer, copies)) {
|
||||
return;
|
||||
}
|
||||
if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
|
||||
MappedUploadMemory(buffer, total_size_bytes, copies);
|
||||
} else {
|
||||
@@ -1780,126 +1699,6 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::ResolveUnifiedWindows(
|
||||
[[maybe_unused]] DAddr device_addr, [[maybe_unused]] u64 buffer_offset,
|
||||
[[maybe_unused]] u64 size, [[maybe_unused]] boost::container::small_vector<u64, 4>& window_ids,
|
||||
[[maybe_unused]] UnifiedWindowGroups& groups) {
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
const u8* const physical_base = device_memory.GetPhysicalBase();
|
||||
const u64 unified_base = runtime.UnifiedMemoryBase();
|
||||
const u64 unified_size = runtime.UnifiedMemorySize();
|
||||
const u64 window_size = runtime.UnifiedMemoryWindowSize();
|
||||
if (window_size == 0) {
|
||||
return false;
|
||||
}
|
||||
const auto group_for = [&](u64 window) -> boost::container::small_vector<BufferCopy, 16>& {
|
||||
for (size_t i = 0; i < window_ids.size(); ++i) {
|
||||
if (window_ids[i] == window) {
|
||||
return groups[i];
|
||||
}
|
||||
}
|
||||
window_ids.push_back(window);
|
||||
groups.emplace_back();
|
||||
return groups.back();
|
||||
};
|
||||
u64 downloaded = 0;
|
||||
while (downloaded < size) {
|
||||
const DAddr page_addr = device_addr + downloaded;
|
||||
const u8* const ptr = device_memory.GetPointer<u8>(page_addr);
|
||||
if (ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const u64 page_offset = page_addr & Core::DEVICE_PAGEMASK;
|
||||
u64 chunk = (std::min)(size - downloaded,
|
||||
static_cast<u64>(Core::DEVICE_PAGESIZE) - page_offset);
|
||||
const u64 phys_offset = static_cast<u64>(ptr - physical_base);
|
||||
if (phys_offset < unified_base || phys_offset - unified_base + chunk > unified_size) {
|
||||
return false;
|
||||
}
|
||||
const u64 relative = phys_offset - unified_base;
|
||||
const u64 window = relative / window_size;
|
||||
const u64 local_offset = relative % window_size;
|
||||
chunk = (std::min)(chunk, window_size - local_offset);
|
||||
auto& group = group_for(window);
|
||||
if (!group.empty()) {
|
||||
BufferCopy& last = group.back();
|
||||
if (last.src_offset + last.size == buffer_offset + downloaded &&
|
||||
last.dst_offset + last.size == local_offset) {
|
||||
last.size += chunk;
|
||||
downloaded += chunk;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
group.push_back(BufferCopy{
|
||||
.src_offset = buffer_offset + downloaded,
|
||||
.dst_offset = local_offset,
|
||||
.size = chunk,
|
||||
});
|
||||
downloaded += chunk;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::TryUnifiedDownloadMemory([[maybe_unused]] Buffer& buffer,
|
||||
[[maybe_unused]] std::span<BufferCopy> copies) {
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
boost::container::small_vector<u64, 4> window_ids;
|
||||
UnifiedWindowGroups groups;
|
||||
for (const BufferCopy& copy : copies) {
|
||||
if (!ResolveUnifiedWindows(buffer.CpuAddr() + copy.src_offset, copy.src_offset,
|
||||
copy.size, window_ids, groups)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const BufferCopy& copy : copies) {
|
||||
buffer.MarkUsage(copy.src_offset, copy.size);
|
||||
}
|
||||
runtime.PreCopyBarrier();
|
||||
for (size_t i = 0; i < window_ids.size(); ++i) {
|
||||
const std::span<const BufferCopy> group_span(groups[i].data(), groups[i].size());
|
||||
runtime.CopyToUnifiedMemory(window_ids[i], buffer, group_span);
|
||||
}
|
||||
runtime.UnifiedMemoryHostBarrier();
|
||||
runtime.Finish();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::TryUnifiedUploadMemory([[maybe_unused]] Buffer& buffer,
|
||||
[[maybe_unused]] std::span<BufferCopy> copies) {
|
||||
if constexpr (USE_UNIFIED_UPLOADS) {
|
||||
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
|
||||
return false;
|
||||
}
|
||||
boost::container::small_vector<u64, 4> window_ids;
|
||||
UnifiedWindowGroups groups;
|
||||
for (const BufferCopy& copy : copies) {
|
||||
if (!ResolveUnifiedWindows(buffer.CpuAddr() + copy.dst_offset, copy.dst_offset,
|
||||
copy.size, window_ids, groups)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
runtime.UnifiedMemoryUploadBarrier();
|
||||
runtime.PreCopyBarrier();
|
||||
for (size_t i = 0; i < window_ids.size(); ++i) {
|
||||
const std::span<const BufferCopy> group_span(groups[i].data(), groups[i].size());
|
||||
runtime.CopyFromUnifiedMemory(window_ids[i], buffer, group_span);
|
||||
}
|
||||
runtime.PostCopyBarrier();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
|
||||
[[maybe_unused]] u64 total_size_bytes,
|
||||
@@ -2003,12 +1802,6 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, DAddr device_addr, u64
|
||||
}
|
||||
|
||||
if constexpr (USE_MEMORY_MAPS) {
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
if (runtime.HasUnifiedMemory() &&
|
||||
TryUnifiedDownloadMemory(buffer, std::span(copies.data(), copies.size()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
|
||||
const u8* const mapped_memory = download_staging.mapped_span.data();
|
||||
const std::span<BufferCopy> copies_span(copies.data(), copies.data() + copies.size());
|
||||
|
||||
@@ -180,8 +180,6 @@ class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInf
|
||||
static constexpr bool USE_MEMORY_MAPS = P::USE_MEMORY_MAPS;
|
||||
static constexpr bool SEPARATE_IMAGE_BUFFERS_BINDINGS = P::SEPARATE_IMAGE_BUFFER_BINDINGS;
|
||||
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = P::USE_MEMORY_MAPS_FOR_UPLOADS;
|
||||
static constexpr bool USE_UNIFIED_MEMORY = P::USE_UNIFIED_MEMORY;
|
||||
static constexpr bool USE_UNIFIED_UPLOADS = P::USE_UNIFIED_UPLOADS;
|
||||
|
||||
#ifdef YUZU_LEGACY
|
||||
static constexpr s64 TARGET_THRESHOLD = 3_GiB;
|
||||
@@ -445,17 +443,6 @@ private:
|
||||
|
||||
void MappedUploadMemory(Buffer& buffer, u64 total_size_bytes, std::span<BufferCopy> copies);
|
||||
|
||||
bool TryUnifiedDownloadMemory(Buffer& buffer, std::span<BufferCopy> copies);
|
||||
|
||||
bool TryUnifiedUploadMemory(Buffer& buffer, std::span<BufferCopy> copies);
|
||||
|
||||
using UnifiedWindowGroups =
|
||||
boost::container::small_vector<boost::container::small_vector<BufferCopy, 16>, 4>;
|
||||
|
||||
bool ResolveUnifiedWindows(DAddr device_addr, u64 buffer_offset, u64 size,
|
||||
boost::container::small_vector<u64, 4>& window_ids,
|
||||
UnifiedWindowGroups& groups);
|
||||
|
||||
void DownloadBufferMemory(Buffer& buffer_id);
|
||||
|
||||
void DownloadBufferMemory(Buffer& buffer_id, DAddr device_addr, u64 size);
|
||||
@@ -511,14 +498,9 @@ private:
|
||||
std::deque<Common::RangeSet<DAddr>> committed_gpu_modified_ranges;
|
||||
|
||||
// Async Buffers
|
||||
struct AsyncDownloadBatch {
|
||||
boost::container::small_vector<BufferCopy, 4> staging_copies;
|
||||
boost::container::small_vector<BufferCopy, 4> unified_copies;
|
||||
};
|
||||
|
||||
Common::OverlapRangeSet<DAddr> async_downloads;
|
||||
std::deque<std::optional<Async_Buffer>> async_buffers;
|
||||
std::deque<AsyncDownloadBatch> pending_downloads;
|
||||
std::deque<boost::container::small_vector<BufferCopy, 4>> pending_downloads;
|
||||
std::optional<Async_Buffer> current_buffer;
|
||||
|
||||
std::deque<Async_Buffer> async_buffers_death_ring;
|
||||
|
||||
@@ -2257,7 +2257,7 @@ public:
|
||||
/// Returns whether the vertex array specified by index is supposed to be
|
||||
/// accessed per instance or not.
|
||||
bool IsInstancingEnabled(std::size_t index) const {
|
||||
return bool(is_instanced[index]); //FUCK YOU MSVC
|
||||
return bool(is_instanced[index]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ public:
|
||||
}
|
||||
|
||||
struct Regs {
|
||||
// No fucking idea
|
||||
INSERT_PADDING_BYTES_NOINIT(0x48);
|
||||
} regs{};
|
||||
private:
|
||||
|
||||
@@ -963,7 +963,7 @@ void Vic::WriteABGR(const OutputSurfaceConfig& output_surface_config, VideoPixel
|
||||
auto pixel1213 = _mm_load_si128((__m128i*)&inp[src + x + 12]);
|
||||
auto pixel1415 = _mm_load_si128((__m128i*)&inp[src + x + 14]);
|
||||
|
||||
// Right-shift the channels by 16 to un-do the left shit on read and bring the range
|
||||
// Right-shift the channels by 16 to un-do the left shift on read and bring the range
|
||||
// back to 8-bit.
|
||||
pixel01 = _mm_srli_epi16(pixel01, 2);
|
||||
pixel23 = _mm_srli_epi16(pixel23, 2);
|
||||
|
||||
@@ -88,7 +88,7 @@ set(SHADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sgsr1_shader_mobile_edge_direction.frag
|
||||
)
|
||||
|
||||
if (PLATFORM_HAIKU)
|
||||
if (HAIKUOS)
|
||||
# glslangValidator WILL crash, glslang will not
|
||||
set(GLSLANGVALIDATOR "glslang")
|
||||
else()
|
||||
|
||||
@@ -441,7 +441,7 @@ void MacroInterpreterImpl::Reset() {
|
||||
pc = 0;
|
||||
delayed_pc = {};
|
||||
method_address.raw = 0;
|
||||
// Vector must hold its last indices otherwise wonky shit will happen
|
||||
// Vector must hold its last indices otherwise chaos will ensue
|
||||
// The next parameter index starts at 1, because $r1 already has the value of the first
|
||||
// parameter.
|
||||
next_parameter_index = 1;
|
||||
|
||||
@@ -261,8 +261,6 @@ struct BufferCacheParams {
|
||||
|
||||
// TODO: Investigate why OpenGL seems to perform worse with persistently mapped buffer uploads
|
||||
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = false;
|
||||
static constexpr bool USE_UNIFIED_MEMORY = false;
|
||||
static constexpr bool USE_UNIFIED_UPLOADS = false;
|
||||
};
|
||||
|
||||
using BufferCache = VideoCommon::BufferCache<BufferCacheParams>;
|
||||
|
||||
@@ -59,7 +59,7 @@ std::vector<std::string> GetExtensions() {
|
||||
std::vector<std::string> extensions;
|
||||
for (GLint index = 0; index < num_extensions; ++index) {
|
||||
auto const* p = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, GLuint(index)));
|
||||
if (p != nullptr) // Fuck you? - sincerely, buggy mesa drivers
|
||||
if (p != nullptr)
|
||||
extensions.push_back(std::string{p});
|
||||
}
|
||||
return extensions;
|
||||
|
||||
@@ -32,14 +32,6 @@ VkBufferCopy MakeBufferCopy(const VideoCommon::BufferCopy& copy) {
|
||||
};
|
||||
}
|
||||
|
||||
VkBufferCopy MakeUnifiedUploadCopy(const VideoCommon::BufferCopy& copy) {
|
||||
return VkBufferCopy{
|
||||
.srcOffset = copy.dst_offset,
|
||||
.dstOffset = copy.src_offset,
|
||||
.size = copy.size,
|
||||
};
|
||||
}
|
||||
|
||||
VkIndexType IndexTypeFromNumElements(const Device& device, u32 num_elements) {
|
||||
if (num_elements <= 0xff && device.IsExtIndexTypeUint8Supported()) {
|
||||
return VK_INDEX_TYPE_UINT8_EXT;
|
||||
@@ -373,169 +365,6 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& m
|
||||
scheduler_, staging_pool_);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::TryEnableUnifiedMemory(void* base, size_t size,
|
||||
std::span<AHardwareBuffer* const> hardware_buffers,
|
||||
size_t hardware_buffer_window,
|
||||
size_t hardware_buffer_base) {
|
||||
unified_memory = std::make_unique<HostMemoryImport>(
|
||||
device, base, size, hardware_buffers, hardware_buffer_window, hardware_buffer_base);
|
||||
if (!unified_memory->IsValid()) {
|
||||
unified_memory.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::CopyToUnifiedMemory(
|
||||
size_t window_index, VkBuffer src_buffer,
|
||||
std::span<const VideoCommon::BufferCopy> copies) {
|
||||
if (!unified_memory || src_buffer == VK_NULL_HANDLE || copies.empty() ||
|
||||
window_index >= unified_memory->GetWindowCount()) {
|
||||
return;
|
||||
}
|
||||
const VkBuffer dst_buffer = unified_memory->GetWindowBuffer(window_index);
|
||||
if (dst_buffer == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
VkDeviceSize covered_begin = std::numeric_limits<VkDeviceSize>::max();
|
||||
VkDeviceSize covered_end = 0;
|
||||
for (const VideoCommon::BufferCopy& copy : copies) {
|
||||
covered_begin = (std::min)(covered_begin, static_cast<VkDeviceSize>(copy.dst_offset));
|
||||
covered_end = (std::max)(covered_end,
|
||||
static_cast<VkDeviceSize>(copy.dst_offset + copy.size));
|
||||
}
|
||||
|
||||
boost::container::small_vector<VkBufferCopy, 8> vk_copies(copies.size());
|
||||
std::ranges::transform(copies, vk_copies.begin(), MakeBufferCopy);
|
||||
|
||||
const bool foreign = unified_memory->NeedsForeignOwnershipTransfer();
|
||||
const u32 queue_family = device.GetGraphicsFamily();
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([src_buffer, dst_buffer, vk_copies, foreign, queue_family, covered_begin,
|
||||
covered_end](vk::CommandBuffer cmdbuf) {
|
||||
if (foreign) {
|
||||
const VkBufferMemoryBarrier acquire{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
|
||||
.dstQueueFamilyIndex = queue_family,
|
||||
.buffer = dst_buffer,
|
||||
.offset = covered_begin,
|
||||
.size = covered_end - covered_begin,
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, acquire);
|
||||
}
|
||||
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VideoCommon::FixSmallVectorADL(vk_copies));
|
||||
if (foreign) {
|
||||
const VkBufferMemoryBarrier release{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = 0,
|
||||
.srcQueueFamilyIndex = queue_family,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
|
||||
.buffer = dst_buffer,
|
||||
.offset = covered_begin,
|
||||
.size = covered_end - covered_begin,
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, release);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::CopyFromUnifiedMemory(
|
||||
size_t window_index, VkBuffer dst_buffer,
|
||||
std::span<const VideoCommon::BufferCopy> copies) {
|
||||
if (!unified_memory || dst_buffer == VK_NULL_HANDLE || copies.empty() ||
|
||||
window_index >= unified_memory->GetWindowCount()) {
|
||||
return;
|
||||
}
|
||||
const VkBuffer src_buffer = unified_memory->GetWindowBuffer(window_index);
|
||||
if (src_buffer == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
VkDeviceSize covered_begin = std::numeric_limits<VkDeviceSize>::max();
|
||||
VkDeviceSize covered_end = 0;
|
||||
for (const VideoCommon::BufferCopy& copy : copies) {
|
||||
covered_begin = (std::min)(covered_begin, static_cast<VkDeviceSize>(copy.dst_offset));
|
||||
covered_end = (std::max)(covered_end,
|
||||
static_cast<VkDeviceSize>(copy.dst_offset + copy.size));
|
||||
}
|
||||
|
||||
boost::container::small_vector<VkBufferCopy, 8> vk_copies(copies.size());
|
||||
std::ranges::transform(copies, vk_copies.begin(), MakeUnifiedUploadCopy);
|
||||
|
||||
const bool foreign = unified_memory->NeedsForeignOwnershipTransfer();
|
||||
const u32 queue_family = device.GetGraphicsFamily();
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([src_buffer, dst_buffer, vk_copies, foreign, queue_family, covered_begin,
|
||||
covered_end](vk::CommandBuffer cmdbuf) {
|
||||
if (foreign) {
|
||||
const VkBufferMemoryBarrier acquire{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
|
||||
.dstQueueFamilyIndex = queue_family,
|
||||
.buffer = src_buffer,
|
||||
.offset = covered_begin,
|
||||
.size = covered_end - covered_begin,
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, acquire);
|
||||
}
|
||||
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VideoCommon::FixSmallVectorADL(vk_copies));
|
||||
if (foreign) {
|
||||
const VkBufferMemoryBarrier release{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
.dstAccessMask = 0,
|
||||
.srcQueueFamilyIndex = queue_family,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
|
||||
.buffer = src_buffer,
|
||||
.offset = covered_begin,
|
||||
.size = covered_end - covered_begin,
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, release);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::UnifiedMemoryUploadBarrier() {
|
||||
static constexpr VkMemoryBarrier HOST_WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
HOST_WRITE_BARRIER);
|
||||
});
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::UnifiedMemoryHostBarrier() {
|
||||
static constexpr VkMemoryBarrier HOST_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT,
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0,
|
||||
HOST_BARRIER);
|
||||
});
|
||||
}
|
||||
|
||||
StagingBufferRef BufferCacheRuntime::UploadStagingBuffer(size_t size) {
|
||||
return staging_pool.Request(size, MemoryUsage::Upload);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
#include "video_core/buffer_cache/buffer_cache_base.h"
|
||||
#include "video_core/buffer_cache/memory_tracker_base.h"
|
||||
@@ -99,36 +97,6 @@ public:
|
||||
|
||||
void TickFrame(Common::SlotVector<Buffer>& slot_buffers) noexcept;
|
||||
|
||||
void TryEnableUnifiedMemory(void* base, size_t size,
|
||||
std::span<AHardwareBuffer* const> hardware_buffers,
|
||||
size_t hardware_buffer_window, size_t hardware_buffer_base);
|
||||
|
||||
[[nodiscard]] bool HasUnifiedMemory() const noexcept {
|
||||
return unified_memory != nullptr && unified_memory->IsValid();
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 UnifiedMemorySize() const noexcept {
|
||||
return unified_memory ? unified_memory->GetSize() : 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 UnifiedMemoryBase() const noexcept {
|
||||
return unified_memory ? unified_memory->GetBaseOffset() : 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 UnifiedMemoryWindowSize() const noexcept {
|
||||
return unified_memory ? unified_memory->GetWindowSize() : 0;
|
||||
}
|
||||
|
||||
void CopyToUnifiedMemory(size_t window_index, VkBuffer src_buffer,
|
||||
std::span<const VideoCommon::BufferCopy> copies);
|
||||
|
||||
void CopyFromUnifiedMemory(size_t window_index, VkBuffer dst_buffer,
|
||||
std::span<const VideoCommon::BufferCopy> copies);
|
||||
|
||||
void UnifiedMemoryHostBarrier();
|
||||
|
||||
void UnifiedMemoryUploadBarrier();
|
||||
|
||||
u64 CurrentTick();
|
||||
|
||||
u64 KnownGpuTick();
|
||||
@@ -236,7 +204,6 @@ private:
|
||||
std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer;
|
||||
|
||||
vk::Buffer null_buffer;
|
||||
std::unique_ptr<HostMemoryImport> unified_memory;
|
||||
|
||||
std::unique_ptr<Uint8Pass> uint8_pass;
|
||||
QuadIndexedPass quad_index_pass;
|
||||
@@ -259,8 +226,6 @@ struct BufferCacheParams {
|
||||
static constexpr bool USE_MEMORY_MAPS = true;
|
||||
static constexpr bool SEPARATE_IMAGE_BUFFER_BINDINGS = false;
|
||||
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = true;
|
||||
static constexpr bool USE_UNIFIED_MEMORY = true;
|
||||
static constexpr bool USE_UNIFIED_UPLOADS = true;
|
||||
};
|
||||
|
||||
using BufferCache = VideoCommon::BufferCache<BufferCacheParams>;
|
||||
|
||||
@@ -225,13 +225,6 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
|
||||
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
|
||||
wfi_event(device.GetLogical().CreateEvent()) {
|
||||
scheduler.SetQueryCache(query_cache);
|
||||
if (Settings::values.use_unified_memory.GetValue() && device_memory.IsBackingShared()) {
|
||||
buffer_cache_runtime.TryEnableUnifiedMemory(
|
||||
device_memory.GetPhysicalBase(), device_memory.GetPhysicalSize(),
|
||||
device_memory.GetBackingHardwareBuffers(),
|
||||
device_memory.GetBackingHardwareBufferWindowSize(),
|
||||
device_memory.GetBackingHardwareBufferBase());
|
||||
}
|
||||
}
|
||||
|
||||
RasterizerVulkan::~RasterizerVulkan() {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/host_memory.h"
|
||||
#include "common/literals.h"
|
||||
#include <ranges>
|
||||
#include "common/settings.h"
|
||||
@@ -975,7 +974,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
|
||||
FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION);
|
||||
FOR_EACH_VK_EXTENSION(EXTENSION);
|
||||
FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION);
|
||||
|
||||
if (supported_extensions.contains(VK_KHR_ROBUSTNESS_2_EXTENSION_NAME)) {
|
||||
loaded_extensions.erase(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
|
||||
@@ -988,13 +986,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
extensions.robustness_2 = false;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (extensions.external_memory_ahb && !extensions.queue_family_foreign) {
|
||||
loaded_extensions.erase(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
|
||||
extensions.external_memory_ahb = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef FEATURE_EXTENSION
|
||||
#undef EXTENSION
|
||||
|
||||
@@ -1151,21 +1142,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR;
|
||||
SetNext(next, properties.maintenance5);
|
||||
}
|
||||
if (extensions.external_memory_host) {
|
||||
properties.external_memory_host.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
|
||||
SetNext(next, properties.external_memory_host);
|
||||
}
|
||||
if (extensions.maintenance3 || instance_version >= VK_API_VERSION_1_1) {
|
||||
properties.maintenance3.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
|
||||
SetNext(next, properties.maintenance3);
|
||||
}
|
||||
if (extensions.maintenance4 || features.maintenance4.maintenance4) {
|
||||
properties.maintenance4.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES;
|
||||
SetNext(next, properties.maintenance4);
|
||||
}
|
||||
|
||||
// Perform the property fetch.
|
||||
physical.GetProperties2(properties2);
|
||||
@@ -1540,27 +1516,12 @@ void Device::CollectPhysicalMemoryInfo() {
|
||||
device_access_memory = 0;
|
||||
u64 device_initial_usage = 0;
|
||||
u64 local_memory = 0;
|
||||
const auto heap_has_usable_type = [&mem_properties](size_t heap) {
|
||||
for (u32 index = 0; index < mem_properties.memoryTypeCount; ++index) {
|
||||
if (mem_properties.memoryTypes[index].heapIndex != heap) {
|
||||
continue;
|
||||
}
|
||||
if ((mem_properties.memoryTypes[index].propertyFlags &
|
||||
VK_MEMORY_PROPERTY_PROTECTED_BIT) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (size_t element = 0; element < num_properties; ++element) {
|
||||
const bool is_heap_local =
|
||||
(mem_properties.memoryHeaps[element].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
|
||||
if (!is_integrated && !is_heap_local) {
|
||||
continue;
|
||||
}
|
||||
if (!heap_has_usable_type(element)) {
|
||||
continue;
|
||||
}
|
||||
valid_heap_memory.push_back(element);
|
||||
if (is_heap_local) {
|
||||
local_memory += mem_properties.memoryHeaps[element].size;
|
||||
@@ -1572,13 +1533,6 @@ void Device::CollectPhysicalMemoryInfo() {
|
||||
}
|
||||
device_access_memory += mem_properties.memoryHeaps[element].size;
|
||||
}
|
||||
const u64 committed_backing = Common::GetCommittedBackingSize();
|
||||
if (committed_backing != 0) {
|
||||
LOG_INFO(Render_Vulkan, "Discounting {} MiB of guest memory committed by the host",
|
||||
committed_backing >> 20);
|
||||
local_memory -= std::min(local_memory, committed_backing);
|
||||
device_access_memory -= std::min(device_access_memory, committed_backing);
|
||||
}
|
||||
if (is_integrated) {
|
||||
const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
|
||||
const u64 memory_size = Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Aggressive ? 6_GiB : 4_GiB;
|
||||
|
||||
@@ -83,7 +83,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
EXTENSION(EXT, CONDITIONAL_RENDERING, conditional_rendering) \
|
||||
EXTENSION(EXT, CONSERVATIVE_RASTERIZATION, conservative_rasterization) \
|
||||
EXTENSION(EXT, DEPTH_RANGE_UNRESTRICTED, depth_range_unrestricted) \
|
||||
EXTENSION(EXT, EXTERNAL_MEMORY_HOST, external_memory_host) \
|
||||
EXTENSION(EXT, MEMORY_BUDGET, memory_budget) \
|
||||
EXTENSION(EXT, ROBUSTNESS_2, robustness_2) \
|
||||
EXTENSION(EXT, SAMPLER_FILTER_MINMAX, sampler_filter_minmax) \
|
||||
@@ -113,14 +112,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
EXTENSION(IMG, FILTER_CUBIC, filter_cubic_img) \
|
||||
EXTENSION(QCOM, FILTER_CUBIC_WEIGHTS, filter_cubic_weights)
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION) \
|
||||
EXTENSION(EXT, QUEUE_FAMILY_FOREIGN, queue_family_foreign) \
|
||||
EXTENSION(ANDROID, EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER, external_memory_ahb)
|
||||
#else
|
||||
#define FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION)
|
||||
#endif
|
||||
|
||||
// Define extensions which must be supported.
|
||||
#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \
|
||||
EXTENSION_NAME(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) \
|
||||
@@ -847,30 +838,6 @@ FN_MAX_LIMIT_LIST
|
||||
return extensions.conditional_rendering;
|
||||
}
|
||||
|
||||
bool IsExtExternalMemoryHostSupported() const {
|
||||
return extensions.external_memory_host;
|
||||
}
|
||||
|
||||
bool IsExtExternalMemoryAhbSupported() const {
|
||||
#ifdef __ANDROID__
|
||||
return extensions.external_memory_ahb && extensions.queue_family_foreign;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 GetMinImportedHostPointerAlignment() const {
|
||||
return properties.external_memory_host.minImportedHostPointerAlignment;
|
||||
}
|
||||
|
||||
u64 GetMaxBufferSize() const {
|
||||
return properties.maintenance4.maxBufferSize;
|
||||
}
|
||||
|
||||
u64 GetMaxMemoryAllocationSize() const {
|
||||
return properties.maintenance3.maxMemoryAllocationSize;
|
||||
}
|
||||
|
||||
bool IsExtAstcDecodeModeSupported() const {
|
||||
return extensions.astc_decode_mode;
|
||||
}
|
||||
@@ -1143,7 +1110,6 @@ private:
|
||||
FOR_EACH_VK_FEATURE_1_4(FEATURE);
|
||||
FOR_EACH_VK_FEATURE_EXT(FEATURE);
|
||||
FOR_EACH_VK_EXTENSION(EXTENSION);
|
||||
FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION);
|
||||
|
||||
#undef EXTENSION
|
||||
#undef FEATURE
|
||||
@@ -1175,10 +1141,7 @@ private:
|
||||
VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer{};
|
||||
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
||||
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
||||
VkPhysicalDeviceMaintenance3Properties maintenance3{};
|
||||
VkPhysicalDeviceMaintenance4Properties maintenance4{};
|
||||
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};
|
||||
VkPhysicalDeviceExternalMemoryHostPropertiesEXT external_memory_host{};
|
||||
|
||||
VkPhysicalDeviceProperties properties{};
|
||||
};
|
||||
|
||||
@@ -25,34 +25,9 @@
|
||||
#include "video_core/gpu_logging/gpu_logging.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/hardware_buffer.h>
|
||||
#endif
|
||||
|
||||
namespace Vulkan {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] std::optional<u32> FindImportMemoryType(
|
||||
const VkPhysicalDeviceMemoryProperties &props, u32 type_mask) {
|
||||
const auto find = [&](VkMemoryPropertyFlags wanted) -> std::optional<u32> {
|
||||
for (u32 i = 0; i < props.memoryTypeCount; ++i) {
|
||||
if (((type_mask >> i) & 1u) != 0 &&
|
||||
(props.memoryTypes[i].propertyFlags & wanted) == wanted) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
};
|
||||
auto type_index = find(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
|
||||
if (!type_index) {
|
||||
type_index = find(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
}
|
||||
return type_index;
|
||||
}
|
||||
|
||||
// Helpers translating MemoryUsage to flags/usage
|
||||
|
||||
[[maybe_unused]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) {
|
||||
@@ -225,263 +200,6 @@ namespace Vulkan {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
HostMemoryImport::HostMemoryImport(const Device &device_, void *base, size_t size,
|
||||
std::span<AHardwareBuffer *const> hardware_buffers,
|
||||
size_t hardware_buffer_window, size_t hardware_buffer_base)
|
||||
: device{device_} {
|
||||
if (ImportHardwareBuffers(hardware_buffers, hardware_buffer_window, hardware_buffer_base,
|
||||
size)) {
|
||||
return;
|
||||
}
|
||||
if (device.IsTiler()) {
|
||||
return;
|
||||
}
|
||||
if (!hardware_buffers.empty()) {
|
||||
return;
|
||||
}
|
||||
if (ImportHostPointer(base, size)) {
|
||||
return;
|
||||
}
|
||||
LOG_INFO(Render_Vulkan, "Unified memory disabled, no host memory import path");
|
||||
}
|
||||
|
||||
bool HostMemoryImport::ImportHostPointer(void *base, size_t size) {
|
||||
if (!device.IsExtExternalMemoryHostSupported()) {
|
||||
return false;
|
||||
}
|
||||
const u64 alignment = device.GetMinImportedHostPointerAlignment();
|
||||
if (alignment == 0 || !Common::IsAligned(reinterpret_cast<uintptr_t>(base), alignment) ||
|
||||
!Common::IsAligned(size, alignment)) {
|
||||
return false;
|
||||
}
|
||||
using namespace Common::Literals;
|
||||
constexpr VkDeviceSize DesktopWindowSize = 4_GiB;
|
||||
VkDeviceSize candidate_window = DesktopWindowSize;
|
||||
const u64 max_buffer_size = device.GetMaxBufferSize();
|
||||
if (max_buffer_size != 0 && max_buffer_size < candidate_window) {
|
||||
candidate_window = max_buffer_size;
|
||||
}
|
||||
const u64 max_allocation_size = device.GetMaxMemoryAllocationSize();
|
||||
if (max_allocation_size != 0 && max_allocation_size < candidate_window) {
|
||||
candidate_window = max_allocation_size;
|
||||
}
|
||||
candidate_window = Common::AlignDown(candidate_window, alignment);
|
||||
if (candidate_window == 0) {
|
||||
return false;
|
||||
}
|
||||
window_size = candidate_window;
|
||||
|
||||
const auto &logical = device.GetLogical();
|
||||
const auto memory_props = device.GetPhysical().GetMemoryProperties().memoryProperties;
|
||||
|
||||
for (size_t offset = 0; offset < size; offset += window_size) {
|
||||
u8 *const window_base = static_cast<u8 *>(base) + offset;
|
||||
const VkDeviceSize window_len =
|
||||
(std::min)(static_cast<VkDeviceSize>(size - offset), window_size);
|
||||
VkMemoryHostPointerPropertiesEXT host_props{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
|
||||
.pNext = nullptr,
|
||||
.memoryTypeBits = 0,
|
||||
};
|
||||
if (logical.GetMemoryHostPointerPropertiesEXT(
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, window_base,
|
||||
&host_props) != VK_SUCCESS ||
|
||||
host_props.memoryTypeBits == 0) {
|
||||
break;
|
||||
}
|
||||
const VkExternalMemoryBufferCreateInfo external_info{
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
|
||||
};
|
||||
const VkBufferCreateInfo buffer_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = &external_info,
|
||||
.flags = 0,
|
||||
.size = window_len,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
};
|
||||
VkBuffer new_buffer{};
|
||||
if (logical.CreateBufferRaw(buffer_ci, &new_buffer) != VK_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
const VkMemoryRequirements requirements =
|
||||
logical.GetBufferMemoryRequirements(new_buffer);
|
||||
const u32 type_mask = requirements.memoryTypeBits & host_props.memoryTypeBits;
|
||||
if (type_mask == 0 || requirements.size > window_len) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const auto type_index = FindImportMemoryType(memory_props, type_mask);
|
||||
if (!type_index) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const u32 heap_index = memory_props.memoryTypes[*type_index].heapIndex;
|
||||
const VkDeviceSize heap_size = memory_props.memoryHeaps[heap_index].size;
|
||||
if (imported_size + window_len > heap_size / 2) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const VkImportMemoryHostPointerInfoEXT import_info{
|
||||
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
|
||||
.pNext = nullptr,
|
||||
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
|
||||
.pHostPointer = window_base,
|
||||
};
|
||||
const VkMemoryAllocateInfo alloc_info{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = &import_info,
|
||||
.allocationSize = window_len,
|
||||
.memoryTypeIndex = *type_index,
|
||||
};
|
||||
vk::DeviceMemory memory = logical.TryAllocateMemory(alloc_info);
|
||||
if (!memory) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
if (logical.BindBufferMemory(new_buffer, *memory, 0) != VK_SUCCESS) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
windows.push_back(Window{
|
||||
.memory = std::move(memory),
|
||||
.buffer = new_buffer,
|
||||
});
|
||||
imported_size += static_cast<size_t>(window_len);
|
||||
}
|
||||
if (windows.empty()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HostMemoryImport::ImportHardwareBuffers(
|
||||
[[maybe_unused]] std::span<AHardwareBuffer *const> hardware_buffers,
|
||||
[[maybe_unused]] size_t hardware_buffer_window,
|
||||
[[maybe_unused]] size_t hardware_buffer_base, [[maybe_unused]] size_t size) {
|
||||
#ifdef __ANDROID__
|
||||
if (hardware_buffers.empty() || hardware_buffer_window == 0 ||
|
||||
!device.IsExtExternalMemoryAhbSupported()) {
|
||||
return false;
|
||||
}
|
||||
const u64 max_allocation_size = device.GetMaxMemoryAllocationSize();
|
||||
if (max_allocation_size != 0 && hardware_buffer_window > max_allocation_size) {
|
||||
return false;
|
||||
}
|
||||
if (hardware_buffer_base >= size) {
|
||||
return false;
|
||||
}
|
||||
const auto &logical = device.GetLogical();
|
||||
const auto memory_props = device.GetPhysical().GetMemoryProperties().memoryProperties;
|
||||
window_size = hardware_buffer_window;
|
||||
base_offset = hardware_buffer_base;
|
||||
for (size_t i = 0; i < hardware_buffers.size(); ++i) {
|
||||
const size_t offset = hardware_buffer_base + i * hardware_buffer_window;
|
||||
if (offset >= size) {
|
||||
break;
|
||||
}
|
||||
const VkDeviceSize window_len = (std::min)(
|
||||
static_cast<VkDeviceSize>(size - offset),
|
||||
static_cast<VkDeviceSize>(hardware_buffer_window));
|
||||
VkAndroidHardwareBufferPropertiesANDROID ahb_props{
|
||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
||||
.pNext = nullptr,
|
||||
.allocationSize = 0,
|
||||
.memoryTypeBits = 0,
|
||||
};
|
||||
if (logical.GetAndroidHardwareBufferPropertiesANDROID(hardware_buffers[i],
|
||||
&ahb_props) != VK_SUCCESS ||
|
||||
ahb_props.memoryTypeBits == 0 || ahb_props.allocationSize < window_len) {
|
||||
break;
|
||||
}
|
||||
const VkExternalMemoryBufferCreateInfo external_info{
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.handleTypes =
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
|
||||
};
|
||||
const VkBufferCreateInfo buffer_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = &external_info,
|
||||
.flags = 0,
|
||||
.size = window_len,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
};
|
||||
VkBuffer new_buffer{};
|
||||
if (logical.CreateBufferRaw(buffer_ci, &new_buffer) != VK_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
const VkMemoryRequirements requirements =
|
||||
logical.GetBufferMemoryRequirements(new_buffer);
|
||||
const u32 type_mask = requirements.memoryTypeBits & ahb_props.memoryTypeBits;
|
||||
if (type_mask == 0 || requirements.size > ahb_props.allocationSize) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const auto type_index = FindImportMemoryType(memory_props, type_mask);
|
||||
if (!type_index) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const VkImportAndroidHardwareBufferInfoANDROID import_info{
|
||||
.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
|
||||
.pNext = nullptr,
|
||||
.buffer = hardware_buffers[i],
|
||||
};
|
||||
const VkMemoryDedicatedAllocateInfo dedicated_info{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
|
||||
.pNext = &import_info,
|
||||
.image = VK_NULL_HANDLE,
|
||||
.buffer = new_buffer,
|
||||
};
|
||||
const VkMemoryAllocateInfo alloc_info{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = &dedicated_info,
|
||||
.allocationSize = ahb_props.allocationSize,
|
||||
.memoryTypeIndex = *type_index,
|
||||
};
|
||||
vk::DeviceMemory memory = logical.TryAllocateMemory(alloc_info);
|
||||
if (!memory) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
if (logical.BindBufferMemory(new_buffer, *memory, 0) != VK_SUCCESS) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
windows.push_back(Window{
|
||||
.memory = std::move(memory),
|
||||
.buffer = new_buffer,
|
||||
});
|
||||
imported_size += static_cast<size_t>(window_len);
|
||||
}
|
||||
if (windows.empty()) {
|
||||
window_size = 0;
|
||||
base_offset = 0;
|
||||
return false;
|
||||
}
|
||||
foreign_ownership = true;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
HostMemoryImport::~HostMemoryImport() {
|
||||
for (Window &window : windows) {
|
||||
if (window.buffer != VK_NULL_HANDLE) {
|
||||
device.GetLogical().DestroyBufferRaw(window.buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryAllocator::MemoryAllocator(const Device &device_)
|
||||
: device{device_}, allocator{device.GetAllocator()},
|
||||
properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -15,8 +15,6 @@
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
#include "video_core/vulkan_common/vma.h"
|
||||
|
||||
struct AHardwareBuffer;
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
class Device;
|
||||
@@ -86,66 +84,6 @@ namespace Vulkan {
|
||||
void *mapped_ptr{}; ///< Optional persistent mapped pointer
|
||||
};
|
||||
|
||||
class HostMemoryImport {
|
||||
public:
|
||||
explicit HostMemoryImport(const Device &device_, void *base, size_t size,
|
||||
std::span<AHardwareBuffer *const> hardware_buffers,
|
||||
size_t hardware_buffer_window, size_t hardware_buffer_base);
|
||||
|
||||
~HostMemoryImport();
|
||||
|
||||
HostMemoryImport(const HostMemoryImport &) = delete;
|
||||
|
||||
HostMemoryImport &operator=(const HostMemoryImport &) = delete;
|
||||
|
||||
[[nodiscard]] bool IsValid() const noexcept {
|
||||
return !windows.empty();
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t GetSize() const noexcept {
|
||||
return imported_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t GetBaseOffset() const noexcept {
|
||||
return base_offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool NeedsForeignOwnershipTransfer() const noexcept {
|
||||
return foreign_ownership;
|
||||
}
|
||||
|
||||
[[nodiscard]] VkDeviceSize GetWindowSize() const noexcept {
|
||||
return window_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] VkBuffer GetWindowBuffer(size_t index) const noexcept {
|
||||
return windows[index].buffer;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t GetWindowCount() const noexcept {
|
||||
return windows.size();
|
||||
}
|
||||
|
||||
private:
|
||||
struct Window {
|
||||
vk::DeviceMemory memory;
|
||||
VkBuffer buffer{};
|
||||
};
|
||||
|
||||
bool ImportHostPointer(void *base, size_t size);
|
||||
|
||||
bool ImportHardwareBuffers(std::span<AHardwareBuffer *const> hardware_buffers,
|
||||
size_t hardware_buffer_window, size_t hardware_buffer_base,
|
||||
size_t size);
|
||||
|
||||
const Device &device;
|
||||
std::vector<Window> windows;
|
||||
VkDeviceSize window_size{};
|
||||
size_t imported_size{};
|
||||
size_t base_offset{};
|
||||
bool foreign_ownership{};
|
||||
};
|
||||
|
||||
/// Memory allocator container.
|
||||
/// Allocates and releases memory allocations on demand.
|
||||
class MemoryAllocator {
|
||||
|
||||
@@ -216,16 +216,12 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
X(vkGetBufferMemoryRequirements2);
|
||||
X(vkGetDeviceQueue);
|
||||
X(vkGetEventStatus);
|
||||
X(vkGetMemoryHostPointerPropertiesEXT);
|
||||
X(vkGetFenceStatus);
|
||||
X(vkGetImageMemoryRequirements);
|
||||
X(vkGetPipelineCacheData);
|
||||
X(vkGetMemoryFdKHR);
|
||||
#ifdef _WIN32
|
||||
X(vkGetMemoryWin32HandleKHR);
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
X(vkGetAndroidHardwareBufferPropertiesANDROID);
|
||||
#endif
|
||||
X(vkGetQueryPoolResults);
|
||||
X(vkGetPipelineExecutablePropertiesKHR);
|
||||
|
||||
@@ -332,16 +332,12 @@ struct DeviceDispatch : InstanceDispatch {
|
||||
PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2{};
|
||||
PFN_vkGetDeviceQueue vkGetDeviceQueue{};
|
||||
PFN_vkGetEventStatus vkGetEventStatus{};
|
||||
PFN_vkGetMemoryHostPointerPropertiesEXT vkGetMemoryHostPointerPropertiesEXT{};
|
||||
PFN_vkGetFenceStatus vkGetFenceStatus{};
|
||||
PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements{};
|
||||
PFN_vkGetPipelineCacheData vkGetPipelineCacheData{};
|
||||
PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR{};
|
||||
#ifdef _WIN32
|
||||
PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR{};
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID{};
|
||||
#endif
|
||||
PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR{};
|
||||
PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR{};
|
||||
@@ -1086,34 +1082,6 @@ public:
|
||||
VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer,
|
||||
void* pnext = nullptr) const noexcept;
|
||||
|
||||
VkResult GetMemoryHostPointerPropertiesEXT(
|
||||
VkExternalMemoryHandleTypeFlagBits handle_type, const void* host_pointer,
|
||||
VkMemoryHostPointerPropertiesEXT* out_properties) const noexcept {
|
||||
return dld->vkGetMemoryHostPointerPropertiesEXT(handle, handle_type, host_pointer,
|
||||
out_properties);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
VkResult GetAndroidHardwareBufferPropertiesANDROID(
|
||||
const struct AHardwareBuffer* buffer,
|
||||
VkAndroidHardwareBufferPropertiesANDROID* out_properties) const noexcept {
|
||||
return dld->vkGetAndroidHardwareBufferPropertiesANDROID(handle, buffer, out_properties);
|
||||
}
|
||||
#endif
|
||||
|
||||
VkResult CreateBufferRaw(const VkBufferCreateInfo& ci, VkBuffer* out_buffer) const noexcept {
|
||||
return dld->vkCreateBuffer(handle, &ci, nullptr, out_buffer);
|
||||
}
|
||||
|
||||
void DestroyBufferRaw(VkBuffer buffer) const noexcept {
|
||||
dld->vkDestroyBuffer(handle, buffer, nullptr);
|
||||
}
|
||||
|
||||
VkResult BindBufferMemory(VkBuffer buffer, VkDeviceMemory memory,
|
||||
VkDeviceSize offset) const noexcept {
|
||||
return dld->vkBindBufferMemory(handle, buffer, memory, offset);
|
||||
}
|
||||
|
||||
VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept;
|
||||
|
||||
std::vector<VkPipelineExecutablePropertiesKHR> GetPipelineExecutablePropertiesKHR(
|
||||
|
||||
@@ -8,7 +8,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
# Set the RPATH for Qt Libraries
|
||||
# This must be done before the `yuzu` target is created
|
||||
if (YUZU_USE_BUNDLED_QT AND PLATFORM_LINUX)
|
||||
if (YUZU_USE_BUNDLED_QT AND LINUX)
|
||||
set(CMAKE_BUILD_RPATH "${CMAKE_BINARY_DIR}/bin/lib/")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(Core::HID::HIDCore& hid_core_, QW
|
||||
|
||||
#ifndef _WIN32
|
||||
ui->enable_raw_input->setVisible(false);
|
||||
ui->disable_wgi_xinput->setVisible(false);
|
||||
#endif
|
||||
|
||||
LoadConfiguration();
|
||||
@@ -139,6 +140,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
|
||||
Settings::values.emulate_analog_keyboard = ui->emulate_analog_keyboard->isChecked();
|
||||
Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
|
||||
Settings::values.enable_raw_input = ui->enable_raw_input->isChecked();
|
||||
Settings::values.disable_wgi_xinput = ui->disable_wgi_xinput->isChecked();
|
||||
Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked();
|
||||
Settings::values.controller_navigation = ui->controller_navigation->isChecked();
|
||||
Settings::values.enable_ring_controller = ui->enable_ring_controller->isChecked();
|
||||
@@ -174,6 +176,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {
|
||||
ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard.GetValue());
|
||||
ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
|
||||
ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue());
|
||||
ui->disable_wgi_xinput->setChecked(Settings::values.disable_wgi_xinput.GetValue());
|
||||
ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue());
|
||||
ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue());
|
||||
ui->enable_ring_controller->setChecked(Settings::values.enable_ring_controller.GetValue());
|
||||
|
||||
@@ -2757,6 +2757,22 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="disable_wgi_xinput">
|
||||
<property name="toolTip">
|
||||
<string>Aimed to disable SDL GUIDE button hack: synthetic GUIDE(HOME) event when SELECT(MINUS) + START(PLUS) pressed. May impact Win related trigger/rumble/etc stuff</string>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>23</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disable SDL WGI/XInput (Requires restart)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#include "main_window.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -126,6 +132,16 @@ int main(int argc, char* argv[]) {
|
||||
#endif // _WIN32
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// Convert the relative path to an absolute path before the chdir
|
||||
char resolved[PATH_MAX];
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "-u") == 0 || strcmp(argv[i], "-input-profile") == 0) {
|
||||
++i;
|
||||
} else if (argv[i][0] != '-' && argv[i][0] != '/' && realpath(argv[i], resolved)) {
|
||||
argv[i] = strdup(resolved);
|
||||
}
|
||||
}
|
||||
|
||||
// If you start a bundle (binary) on OSX without the Terminal, the working directory is "/".
|
||||
// But since we require the working directory to be the executable path for the location of
|
||||
// the user folder in the Qt Frontend, we need to cd into that working directory
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// Qt on macOS doesn't define VMA shit
|
||||
// Static Qt on macOS doesn't use Vulkan
|
||||
// Other platforms do, and thus have conflicting VulkanMemoryAllocator symbols
|
||||
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
|
||||
#undef VMA_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
@@ -38,7 +38,7 @@ void MigrationWorker::process() {
|
||||
try {
|
||||
fs::remove_all(eden_dir);
|
||||
} catch (fs::filesystem_error& _) {
|
||||
// ignore because linux does stupid crap sometimes
|
||||
// directory may not exist at this point, that's fine
|
||||
}
|
||||
|
||||
switch (strategy) {
|
||||
|
||||
@@ -75,3 +75,15 @@ if (NOT MSVC)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-parameter>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-missing-field-initializers>)
|
||||
endif()
|
||||
|
||||
if (PLATFORM_EMSCRIPTEN)
|
||||
# 10GB is required at max... yikes!
|
||||
target_link_options(yuzu-cmd PRIVATE
|
||||
-sALLOW_MEMORY_GROWTH=1
|
||||
-sINITIAL_MEMORY=33554432
|
||||
-sMAXIMUM_MEMORY=10737418240
|
||||
-sGLOBAL_BASE=16777216
|
||||
-sEXPORTED_RUNTIME_METHODS=['FS']
|
||||
-sPTHREAD_POOL_SIZE_STRICT=0
|
||||
-sPTHREAD_POOL_SIZE=navigator.hardwareConcurrency)
|
||||
endif()
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_timer.h>
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/scm_rev.h"
|
||||
@@ -26,9 +30,17 @@ EmuWindow_SDL3::EmuWindow_SDL3(InputCommon::InputSubsystem* input_subsystem_, Co
|
||||
LOG_CRITICAL(Frontend, "Failed to initialize SDL3: {}, Exiting...", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
titlebar_timer = SDL_AddTimer(2000, [](void *userdata, SDL_TimerID, Uint32) -> Uint32 {
|
||||
auto* this_ = (EmuWindow_SDL3*)userdata;
|
||||
auto const results = this_->system.GetAndResetPerfStats();
|
||||
auto const title = fmt::format("{} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc, results.average_game_fps, results.emulation_speed * 100.0f);
|
||||
SDL_SetWindowTitle(this_->render_window, title.c_str());
|
||||
return 2000;
|
||||
}, this);
|
||||
}
|
||||
|
||||
EmuWindow_SDL3::~EmuWindow_SDL3() {
|
||||
SDL_RemoveTimer(titlebar_timer);
|
||||
system.HIDCore().UnloadInputDevices();
|
||||
input_subsystem->Shutdown();
|
||||
SDL_Quit();
|
||||
@@ -132,8 +144,7 @@ void EmuWindow_SDL3::Fullscreen() {
|
||||
switch (Settings::values.fullscreen_mode.GetValue()) {
|
||||
case Settings::FullscreenMode::Exclusive:
|
||||
// Set window size to render size before entering fullscreen in exclusive mode.
|
||||
if (const SDL_DisplayMode* display_mode_ptr =
|
||||
SDL_GetDesktopDisplayMode(SDL_GetDisplayForWindow(render_window))) {
|
||||
if (const SDL_DisplayMode* display_mode_ptr = SDL_GetDesktopDisplayMode(SDL_GetDisplayForWindow(render_window))) {
|
||||
display_mode = *display_mode_ptr;
|
||||
SDL_SetWindowSize(render_window, display_mode.w, display_mode.h);
|
||||
SDL_SetWindowFullscreenMode(render_window, &display_mode);
|
||||
@@ -165,92 +176,60 @@ void EmuWindow_SDL3::Fullscreen() {
|
||||
}
|
||||
}
|
||||
|
||||
void EmuWindow_SDL3::WaitEvent() {
|
||||
// Called on main thread
|
||||
SDL_Event event;
|
||||
|
||||
if (!SDL_WaitEvent(&event)) {
|
||||
const char* error = SDL_GetError();
|
||||
if (!error || strcmp(error, "") == 0) {
|
||||
// https://github.com/libsdl-org/SDL/issues/5780
|
||||
// Sometimes SDL will return without actually having hit an error condition;
|
||||
// just ignore it in this case.
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", error);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void EmuWindow_SDL3::OnEvent(SDL_Event& event) {
|
||||
// Notice how we skip the "update title" aspect on most events
|
||||
// this is because some WMs do NOT like changing titles while resizing
|
||||
// so let's just... not do that, thanks :)
|
||||
// Afterall we don't really expect the user to pay attention to the titlebar
|
||||
// while they're moving a lot of shit around...
|
||||
switch (event.type) {
|
||||
case SDL_EVENT_WINDOW_RESIZED:
|
||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||
case SDL_EVENT_WINDOW_MAXIMIZED:
|
||||
case SDL_EVENT_WINDOW_RESTORED:
|
||||
OnResize();
|
||||
break;
|
||||
return OnResize();
|
||||
case SDL_EVENT_WINDOW_MINIMIZED:
|
||||
is_shown = false;
|
||||
OnResize();
|
||||
break;
|
||||
return OnResize();
|
||||
case SDL_EVENT_WINDOW_EXPOSED:
|
||||
is_shown = true;
|
||||
OnResize();
|
||||
break;
|
||||
return OnResize();
|
||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||
is_open = false;
|
||||
break;
|
||||
return;
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
OnKeyEvent(static_cast<int>(event.key.scancode), event.key.down ? 1 : 0);
|
||||
break;
|
||||
return OnKeyEvent(int(event.key.scancode), event.key.down ? 1 : 0);
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
// ignore if it came from touch
|
||||
if (event.button.which != SDL_TOUCH_MOUSEID)
|
||||
OnMouseMotion(event.motion.x, event.motion.y);
|
||||
break;
|
||||
return;
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
// ignore if it came from touch
|
||||
if (event.button.which != SDL_TOUCH_MOUSEID) {
|
||||
OnMouseButton(event.button.button, event.button.down ? 1 : 0,
|
||||
static_cast<s32>(event.button.x), static_cast<s32>(event.button.y));
|
||||
}
|
||||
break;
|
||||
if (event.button.which != SDL_TOUCH_MOUSEID)
|
||||
OnMouseButton(event.button.button, event.button.down ? 1 : 0, s32(event.button.x), s32(event.button.y));
|
||||
return;
|
||||
case SDL_EVENT_FINGER_DOWN:
|
||||
OnFingerDown(event.tfinger.x, event.tfinger.y,
|
||||
static_cast<std::size_t>(event.tfinger.touchID));
|
||||
break;
|
||||
return OnFingerDown(event.tfinger.x, event.tfinger.y, std::size_t(event.tfinger.touchID));
|
||||
case SDL_EVENT_FINGER_MOTION:
|
||||
OnFingerMotion(event.tfinger.x, event.tfinger.y,
|
||||
static_cast<std::size_t>(event.tfinger.touchID));
|
||||
break;
|
||||
return OnFingerMotion(event.tfinger.x, event.tfinger.y, std::size_t(event.tfinger.touchID));
|
||||
case SDL_EVENT_FINGER_UP:
|
||||
OnFingerUp();
|
||||
break;
|
||||
return OnFingerUp();
|
||||
case SDL_EVENT_QUIT:
|
||||
is_open = false;
|
||||
break;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const u32 current_time = SDL_GetTicks();
|
||||
if (current_time > last_time + 2000) {
|
||||
const auto results = system.GetAndResetPerfStats();
|
||||
const auto title = fmt::format("{} | {}-{} | FPS: {:.0f} ({:.0f}%)",
|
||||
Common::g_build_fullname,
|
||||
Common::g_scm_branch,
|
||||
Common::g_scm_desc,
|
||||
results.average_game_fps,
|
||||
results.emulation_speed * 100.0);
|
||||
SDL_SetWindowTitle(render_window, title.c_str());
|
||||
last_time = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
// Credits to Samantas5855 and others for this function.
|
||||
void EmuWindow_SDL3::SetWindowIcon() {
|
||||
#if defined(__EMSCRIPTEN__) || defined(__wasi__)
|
||||
// Icons do not work yet
|
||||
#else
|
||||
SDL_IOStream* const yuzu_icon_stream = SDL_IOFromConstMem((void*)yuzu_icon, yuzu_icon_size);
|
||||
if (yuzu_icon_stream == nullptr) {
|
||||
LOG_WARNING(Frontend, "Failed to create Eden icon stream.");
|
||||
@@ -264,6 +243,7 @@ void EmuWindow_SDL3::SetWindowIcon() {
|
||||
// The icon is attached to the window pointer
|
||||
SDL_SetWindowIcon(render_window, window_icon);
|
||||
SDL_DestroySurface(window_icon);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EmuWindow_SDL3::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user