Compare commits

..

25 Commits

Author SHA1 Message Date
lizzie ab932a21f5 PLATFORM_EMSCRIPTEN -> EMSCRIPTEN 2026-09-01 21:26:37 +00:00
lizzie 59f01af896 prepare 2026-09-01 21:21:52 +00:00
lizzie 63230d247e build adjustments 2026-09-01 21:21:52 +00:00
lizzie 24fb119204 ok no broken make 2026-09-01 21:21:52 +00:00
lizzie 04852efa63 boost asio fix in android 2026-09-01 21:21:52 +00:00
lizzie 87a30d017b it loads the fucker :) 2026-09-01 21:21:52 +00:00
lizzie 4940c02134 BUT PROPERLY SHOW THE LOGS for fucks sake 2026-09-01 21:21:52 +00:00
lizzie 9789fe74c5 force services into guest process and singlecore option 2026-09-01 21:21:52 +00:00
lizzie eea821c4f3 add filter options 2026-09-01 21:21:52 +00:00
lizzie ff81b362f5 --null-renderer 2026-09-01 21:21:52 +00:00
lizzie abc7ad2129 emscripten friendly sdl loop 2026-09-01 21:21:52 +00:00
lizzie 7f5051767d fixup make program 2026-09-01 21:21:52 +00:00
lizzie c25c531f5d fixup caveats + add miniserver 2026-09-01 21:21:52 +00:00
lizzie 77bce8f709 10gb of ram 2026-09-01 21:21:52 +00:00
lizzie a08925c561 small writeup of wasm 2026-09-01 21:21:51 +00:00
lizzie 46a8a76dbb fix openssl 2026-09-01 21:21:29 +00:00
lizzie cd2833a420 proper jthread support 2026-09-01 21:21:29 +00:00
lizzie c7dbea0b22 fix wasm flags 2026-09-01 21:21:29 +00:00
lizzie 3d13ef9309 disable JIT service 2026-09-01 21:21:29 +00:00
lizzie 0e94895536 emscripten can't memfd 2026-09-01 21:21:29 +00:00
lizzie 5c12446f8d emscripten doesnt have arc4random but wasi does? 2026-09-01 21:21:29 +00:00
lizzie 9ab9bfb712 fix non existant pthread funcs 2026-09-01 21:21:29 +00:00
lizzie 9e651d9460 initial wasm support 2026-09-01 21:21:29 +00:00
lizzie fbb05fc5d5 ok fixup but better with bool returns 2026-09-01 21:21:29 +00:00
lizzie caf0c82a99 Use managarm special fastmem fallback 2026-09-01 21:21:28 +00:00
377 changed files with 13551 additions and 20124 deletions
+92
View File
@@ -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
-3
View File
@@ -63,6 +63,3 @@ artifacts
/install*
vulkansdk*.exe
*.tar.zst
# Build-time generated external sources
externals/generated
@@ -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}
+112
View File
@@ -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)
@@ -0,0 +1,28 @@
From cc15da16e533b2a801934eab2dfeaf3c3949a1dc Mon Sep 17 00:00:00 2001
From: crueter <crueter@eden-emu.dev>
Date: Mon, 8 Sep 2025 12:28:55 -0400
Subject: [PATCH] [cmake] disable NEON runtime check on clang-cl
When enabling runtime NEON checking for clang-cl, the linker would error out with `undefined symbol: __emit`, since clang doesn't actually implement this instruction. Therefore it makes sense to disable the runtime check by default on this platform, until either this is fixed or a clang-cl compatible intrinsic check is added (I don't have enough knowledge of MSVC to do this)
---
cmake/OpusConfig.cmake | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/cmake/OpusConfig.cmake b/cmake/OpusConfig.cmake
index e9319fbad..d0f459e88 100644
--- a/cmake/OpusConfig.cmake
+++ b/cmake/OpusConfig.cmake
@@ -71,7 +71,12 @@ elseif(OPUS_CPU_ARM AND NOT OPUS_DISABLE_INTRINSICS)
opus_detect_neon(COMPILER_SUPPORT_NEON)
if(COMPILER_SUPPORT_NEON)
option(OPUS_USE_NEON "Option to enable NEON" ON)
- option(OPUS_MAY_HAVE_NEON "Does runtime check for neon support" ON)
+ if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(NEON_RUNTIME_CHECK_DEFAULT OFF)
+ else()
+ set(NEON_RUNTIME_CHECK_DEFAULT ON)
+ endif()
+ option(OPUS_MAY_HAVE_NEON "Does runtime check for neon support" ${NEON_RUNTIME_CHECK_DEFAULT})
option(OPUS_PRESUME_NEON "Assume target CPU has NEON support" OFF)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
set(OPUS_PRESUME_NEON ON)
+153
View File
@@ -0,0 +1,153 @@
From bf455b67b4eaa446ffae5d25410b141b7b1b1082 Mon Sep 17 00:00:00 2001
From: crueter <crueter@eden-emu.dev>
Date: Mon, 8 Sep 2025 12:08:20 -0400
Subject: [PATCH] [cmake] `OPUS_INSTALL` option; only default install if root
project
Signed-off-by: crueter <crueter@eden-emu.dev>
---
CMakeLists.txt | 112 ++++++++++++++++++++++++++++---------------------
1 file changed, 64 insertions(+), 48 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fcf034b19..08b5e16f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,13 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(OpusPackageVersion)
get_package_version(PACKAGE_VERSION PROJECT_VERSION)
+# root project detection
+if(DEFINED PROJECT_NAME)
+ set(root_project OFF)
+else()
+ set(root_project ON)
+endif()
+
project(Opus LANGUAGES C VERSION ${PROJECT_VERSION})
include(OpusFunctions)
@@ -83,12 +90,16 @@ set(OPUS_DNN_FLOAT_DEBUG_HELP_STR "Run DNN computations as float for debugging p
option(OPUS_DNN_FLOAT_DEBUG ${OPUS_DNN_FLOAT_DEBUG_HELP_STR} OFF)
add_feature_info(OPUS_DNN_FLOAT_DEBUG OPUS_DNN_FLOAT_DEBUG ${OPUS_DNN_FLOAT_DEBUG_HELP_STR})
+set(OPUS_INSTALL_HELP_STR "Install Opus targets")
+option(OPUS_INSTALL ${OPUS_INSTALL_HELP_STR} ${root_project})
+add_feature_info(OPUS_INSTALL OPUS_INSTALL ${OPUS_INSTALL_HELP_STR})
+
set(OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR "install pkg-config module.")
-option(OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR} ON)
+option(OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR} ${OPUS_INSTALL})
add_feature_info(OPUS_INSTALL_PKG_CONFIG_MODULE OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR})
set(OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR "install CMake package config module.")
-option(OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR} ON)
+option(OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR} ${OPUS_INSTALL})
add_feature_info(OPUS_INSTALL_CMAKE_CONFIG_MODULE OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR})
set(OPUS_DRED_HELP_STR "enable DRED.")
@@ -613,53 +624,58 @@ if(OPUS_BUILD_FRAMEWORK)
OUTPUT_NAME Opus)
endif()
-install(TARGETS opus
- EXPORT OpusTargets
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
- FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX}
- PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus)
-
-if(OPUS_INSTALL_PKG_CONFIG_MODULE)
- set(prefix ${CMAKE_INSTALL_PREFIX})
- set(exec_prefix ${CMAKE_INSTALL_PREFIX})
- set(libdir ${CMAKE_INSTALL_FULL_LIBDIR})
- set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
- set(VERSION ${PACKAGE_VERSION})
- if(HAVE_LIBM)
- set(LIBM "-lm")
+if (OPUS_INSTALL)
+ install(TARGETS opus
+ EXPORT OpusTargets
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus)
+
+ if(OPUS_INSTALL_PKG_CONFIG_MODULE)
+ set(prefix ${CMAKE_INSTALL_PREFIX})
+ set(exec_prefix ${CMAKE_INSTALL_PREFIX})
+ set(libdir ${CMAKE_INSTALL_FULL_LIBDIR})
+ set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
+ set(VERSION ${PACKAGE_VERSION})
+ if(HAVE_LIBM)
+ set(LIBM "-lm")
+ endif()
+ configure_file(opus.pc.in opus.pc)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+ endif()
+
+ if(OPUS_INSTALL_CMAKE_CONFIG_MODULE)
+ set(CPACK_GENERATOR TGZ)
+ include(CPack)
+ set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
+ install(EXPORT OpusTargets
+ NAMESPACE Opus::
+ DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
+
+ include(CMakePackageConfigHelpers)
+
+ set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
+ configure_package_config_file(
+ ${PROJECT_SOURCE_DIR}/cmake/OpusConfig.cmake.in
+ OpusConfig.cmake
+ INSTALL_DESTINATION
+ ${CMAKE_INSTALL_PACKAGEDIR}
+ PATH_VARS
+ INCLUDE_INSTALL_DIR
+ INSTALL_PREFIX
+ ${CMAKE_INSTALL_PREFIX})
+
+ write_basic_package_version_file(OpusConfigVersion.cmake
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY SameMajorVersion)
+
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake
+ DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
endif()
- configure_file(opus.pc.in opus.pc)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
-endif()
-
-if(OPUS_INSTALL_CMAKE_CONFIG_MODULE)
- set(CPACK_GENERATOR TGZ)
- include(CPack)
- set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
- install(EXPORT OpusTargets
- NAMESPACE Opus::
- DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
-
- include(CMakePackageConfigHelpers)
-
- set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
- configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/OpusConfig.cmake.in
- OpusConfig.cmake
- INSTALL_DESTINATION
- ${CMAKE_INSTALL_PACKAGEDIR}
- PATH_VARS
- INCLUDE_INSTALL_DIR
- INSTALL_PREFIX
- ${CMAKE_INSTALL_PREFIX})
- write_basic_package_version_file(OpusConfigVersion.cmake
- VERSION ${PROJECT_VERSION}
- COMPATIBILITY SameMajorVersion)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake
- ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake
- DESTINATION ${CMAKE_INSTALL_PACKAGEDIR})
endif()
if(OPUS_BUILD_PROGRAMS)
@@ -1,11 +0,0 @@
--- a/source/effect_lexer.cpp
+++ b/source/effect_lexer.cpp
@@ -1181,7 +1181,7 @@
}
else
{
-#if 0
+#if !defined(__cpp_lib_to_chars)
exponent += decimal_location - mantissa_size;
const bool exponent_negative = exponent < 0;
@@ -1,112 +0,0 @@
diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h
index 8df0364..4856064 100644
--- a/include/vk_mem_alloc.h
+++ b/include/vk_mem_alloc.h
@@ -3017,7 +3017,7 @@ remove them if not needed.
#if defined(__ANDROID_API__) && (__ANDROID_API__ < 16)
#include <cstdlib>
-static void* vma_aligned_alloc(size_t alignment, size_t size)
+static inline void* vma_aligned_alloc(size_t alignment, size_t size)
{
// alignment must be >= sizeof(void*)
if(alignment < sizeof(void*))
@@ -3860,7 +3860,7 @@ Returned value is the found element, if present in the collection or place where
new element with value (key) should be inserted.
*/
template <typename CmpLess, typename IterT, typename KeyT>
-static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
+static inline IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
{
size_t down = 0;
size_t up = size_t(end - beg);
@@ -3898,7 +3898,7 @@ Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT.
T must be pointer type, e.g. VmaAllocation, VmaPool.
*/
template<typename T>
-static bool VmaValidatePointerArray(uint32_t count, const T* arr)
+static inline bool VmaValidatePointerArray(uint32_t count, const T* arr)
{
for (uint32_t i = 0; i < count; ++i)
{
@@ -4188,13 +4188,13 @@ static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr
}
template<typename T>
-static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
+static inline T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
{
return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
}
template<typename T>
-static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
+static inline T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
{
return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
}
@@ -4204,14 +4204,14 @@ static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, si
#define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
template<typename T>
-static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
+static inline void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
{
ptr->~T();
VmaFree(pAllocationCallbacks, ptr);
}
template<typename T>
-static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
+static inline void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
{
if (ptr != VMA_NULL)
{
@@ -4658,13 +4658,13 @@ void VmaVector<T, AllocatorT>::remove(size_t index)
#endif // _VMA_VECTOR_FUNCTIONS
template<typename T, typename allocatorT>
-static void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
+static inline void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
{
vec.insert(index, item);
}
template<typename T, typename allocatorT>
-static void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
+static inline void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
{
vec.remove(index);
}
@@ -10620,19 +10620,19 @@ static void VmaFree(VmaAllocator hAllocator, void* ptr)
}
template<typename T>
-static T* VmaAllocate(VmaAllocator hAllocator)
+static inline T* VmaAllocate(VmaAllocator hAllocator)
{
return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
}
template<typename T>
-static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
+static inline T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
{
return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
}
template<typename T>
-static void vma_delete(VmaAllocator hAllocator, T* ptr)
+static inline void vma_delete(VmaAllocator hAllocator, T* ptr)
{
if(ptr != VMA_NULL)
{
@@ -10642,7 +10642,7 @@ static void vma_delete(VmaAllocator hAllocator, T* ptr)
}
template<typename T>
-static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
+static inline void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
{
if(ptr != VMA_NULL)
{
+40 -12
View File
@@ -3,7 +3,6 @@
cmake_minimum_required(VERSION 3.31)
set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE STRING "macOS deployment target")
project(yuzu)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
@@ -85,8 +84,6 @@ option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
# Lossless Scaling frame generation. Only Android.
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON)
# non-linux bundled qt are static
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
set(YUZU_STATIC_BUILD ON)
@@ -217,6 +214,8 @@ if(MSVC)
endif()
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
cmake_dependent_option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" "${MSVC}" "NOT ANDROID" OFF)
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
set(EXT_DEFAULT OFF)
@@ -224,8 +223,6 @@ if (MSVC OR ANDROID)
set(EXT_DEFAULT ON)
endif()
option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" ${EXT_DEFAULT})
# ffmpeg
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${SOLARIS}" "NOT WIN32 AND NOT ANDROID" OFF)
@@ -241,7 +238,7 @@ 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 LINUX OR FREEBSD OR APPLE" OFF)
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE AND NOT ANDROID" OFF)
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE" OFF)
mark_as_advanced(FORCE ENABLE_OPENGL)
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
@@ -380,6 +377,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 (EMSCRIPTEN)
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-pthread>)
add_link_options($<$<COMPILE_LANGUAGE:C,CXX>:-pthread>)
endif()
find_package(RenderDoc MODULE)
@@ -408,7 +414,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 (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)
@@ -429,10 +440,12 @@ if (Boost_ADDED)
target_compile_options(boost_heap INTERFACE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>)
target_compile_options(boost_icl INTERFACE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>)
target_compile_options(boost_asio INTERFACE
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-conversion>
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-implicit-fallthrough>
)
# May not exist (i.e emscripten)
if (TARGET boost_asio)
target_compile_options(boost_asio INTERFACE
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-conversion>
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-implicit-fallthrough>)
endif()
endif()
endif()
@@ -464,6 +477,21 @@ if (NOT YUZU_STATIC_ROOM)
if (ZLIB_ADDED)
add_library(ZLIB::ZLIB ALIAS zlibstatic)
endif()
# Opus
AddJsonPackage(opus)
if (Opus_ADDED)
if (MSVC AND CXX_CLANG)
target_compile_options(opus PRIVATE
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-implicit-function-declaration>
)
endif()
endif()
if (NOT TARGET Opus::opus)
add_library(Opus::opus ALIAS opus)
endif()
endif()
if(NOT TARGET Boost::headers)
@@ -500,7 +528,7 @@ endfunction()
# =============================================
if (APPLE)
foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers Foundation)
foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers)
find_library(${fw}_LIBRARY ${fw} REQUIRED)
list(APPEND PLATFORM_LIBRARIES ${${fw}_LIBRARY})
endforeach()
+22
View File
@@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
find_package(PkgConfig QUIET)
pkg_search_module(OPUS QUIET IMPORTED_TARGET opus)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Opus
REQUIRED_VARS OPUS_LINK_LIBRARIES
VERSION_VAR OPUS_VERSION
)
if (MSYS2)
FixMsysPath(PkgConfig::OPUS)
endif()
if (Opus_FOUND AND NOT TARGET Opus::opus)
add_library(Opus::opus ALIAS PkgConfig::OPUS)
endif()
+37 -17
View File
@@ -1,4 +1,12 @@
{
"": {
"ci": true,
"hash": "9f50d993c39529e022ad456163de91ac5934e16faf8fc348f305355fc0a643c534f87ded707e11bd03bcbc0a1760bd20852b6533a67ac0558a078385181cb184",
"name": "SDL3",
"package": "SDL3",
"repo": "crueter-ci/SDL3",
"version": "3.4.14-1788231389-147a8ee32d"
},
"biscuit": {
"hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a",
"min_version": "0.9.1",
@@ -60,10 +68,10 @@
},
"discord-rpc": {
"find_args": "MODULE",
"hash": "8d680b3a16d6f6bf292ad823cf8635595ff986f2a49f758e3009f505b540a9d75194a8cf44cddea75736a8c3e3b5160166e716a0939ce3f18cc463cf648753fe",
"hash": "8213c43dcb0f7d479f5861091d111ed12fbdec1e62e6d729d65a4bc181d82f48a35d5fd3cd5c291f2393ac7c9681eabc6b76609755f55376284c8a8d67e148f3",
"package": "DiscordRPC",
"repo": "eden-emulator/discord-rpc",
"version": "76616d8675"
"version": "0d8b2d6a37"
},
"enet": {
"find_args": "MODULE",
@@ -82,7 +90,7 @@
"name": "ffmpeg",
"package": "FFmpeg",
"repo": "crueter-ci/FFmpeg",
"version": "9.0.1-1788303113-bf1b838f2a"
"version": "9.0.1-1788120736-bf1b838f2a"
},
"fmt": {
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
@@ -107,7 +115,7 @@
"find_args": "MODULE GLOBAL",
"hash": "159ed94965018f2a371d45a3bfc1961e5fb1549e501ded70a6b4532d7fe99d0579c18b5195aff6e35f96f399b426cea2650ec9fb75ef80d4c9edeccb51f2e6c9",
"options": [
"HTTPLIB_REQUIRE_OPENSSL ON",
"HTTPLIB_REQUIRE_OPENSSL OFF",
"HTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES ON"
],
"patches": [
@@ -178,12 +186,19 @@
"repo": "eden-emulator/oaknut",
"version": "v2.0.3"
},
"oboe": {
"bundled": true,
"hash": "ce4011afe7345370d4ead3b891cd69a5ef224b129535783586c0ca75051d303ed446e6c7f10bde8da31fff58d6e307f1732a3ffd03b249f9ef1fd48fd4132715",
"repo": "google/oboe",
"version": "1.10.0"
},
"openssl": {
"hash": "29002ce50cb95a4f4f1d0e9d3f684401fbd4eac34203dc2eef3b6334af5d44aa46bf788b63a6f5c139c383eafb7269ae87a58a9a3ad5912903b9773e545ccc0a",
"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"
@@ -205,11 +220,27 @@
"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"
},
"opus": {
"find_args": "MODULE",
"hash": "9506147b0de35befda8633ff272981cc2575c860874791bd455b752f797fd7dbd1079f0ba42ccdd7bb1fe6773fa5e84b3d75667c2883dd1fb2d0e4a5fa4f8387",
"min_version": "1.3",
"options": [
"OPUS_PRESUME_NEON ON"
],
"package": "Opus",
"patches": [
"0001-disable-clang-runtime-neon.patch",
"0002-no-install.patch"
],
"repo": "xiph/opus",
"version": "a3f0ec02b3"
},
"quazip": {
"hash": "609c240c7f029ac26a37d8fbab51bc16284e05e128b78b9b9c0e95d083538c36047a67d682759ac990e4adb0eeb90f04f1ea7fe2253bbda7e7e3bcce32e53dd8",
"min_version": "1.3",
@@ -223,14 +254,6 @@
"repo": "stachenov/quazip",
"version": "2e95c9001b"
},
"reshade": {
"hash": "6fc9b39821ca6e2d91160f05846b3a42159fec759f5d6fba91d1a57801a1bdaf6047740578c136f0b1a60a9c29ad160d87dbfe0dbfbcdf6ea879a8a078377b8c",
"patches": [
"0001-from-chars-fallback.patch"
],
"repo": "crosire/reshade",
"version": "v6.8.0"
},
"sdl3": {
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
"min_version": "3.2.10",
@@ -296,9 +319,6 @@
"find_args": "CONFIG",
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
"package": "VulkanMemoryAllocator",
"patches": [
"0001-macos-clang.patch"
],
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
"version": "v3.3.0"
},
+328 -320
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+369 -371
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+323 -315
View File
File diff suppressed because it is too large Load Diff
+322 -314
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+335 -327
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+381 -387
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
-3
View File
@@ -1,3 +0,0 @@
name=Anime
description=Cel shaded look: the picture is cleaned first, then the lighting is collapsed into flat bands with inked edges, finished with a small glow.
chain=Denoise.fx|Denoise|Strength=0.18,Radius=1.2;CelShading.fx|CelShading|Bands=5,BandContrast=0.35,BandEdge=0.2,Detail=0.7,OutlineStrength=0.7,OutlineThreshold=0.2,Saturation=1.3;Bloom.fx|Bloom|Radius=1.2,Amount=0.25
-3
View File
@@ -1,3 +0,0 @@
name=Cinematic
description=Film look: soft glow on the highlights, a filmic contrast curve, cool shadows against warm highlights, fine grain and a gentle vignette.
chain=Bloom.fx|Bloom|Radius=1.6,Amount=0.35;FilmicCurve.fx|FilmicCurve|Toe=1.35,Shoulder=1.3,Amount=0.85;SplitToning.fx|SplitToning|ShadowHue=210,ShadowStrength=0.25,HighlightHue=38,HighlightStrength=0.3;FilmGrain.fx|FilmGrain|Intensity=0.022;Vignette.fx|Vignette|Strength=0.5
-3
View File
@@ -1,3 +0,0 @@
name=Clean
description=Cleans up a low internal resolution: removes dithering and compression noise, smooths banded skies and brings edge detail back. The safe starting point if you are not sure what you want.
chain=Denoise.fx|Denoise|Strength=0.14,Curve=1.2;Deband.fx|Deband|;Sharpen.fx|Sharpen|Amount=0.75
-3
View File
@@ -1,3 +0,0 @@
name=Dreamy
description=Soft focus: the centre of the screen stays sharp while everything around it blurs, with a wide glow over the highlights. Good for slower games and cutscenes.
chain=Blur.fx|Blur|Radius=6,Strength=0.85,FocusSize=0.28,FocusSoftness=0.5;Bloom.fx|Bloom|Radius=2.0,Amount=0.55
-3
View File
@@ -1,3 +0,0 @@
name=Retro
description=Old television look: colour fringing at the edges of the screen, curved scanlines with a phosphor mask, and darkened corners. The scanline roll is switched off so it does not crawl.
chain=ChromaticAberration.fx|ChromaticAberration|Strength=1.0;CRT.fx|CRT|RollSpeed=0,Bleed=1.2;Vignette.fx|Vignette|Strength=0.7
-3
View File
@@ -1,3 +0,0 @@
name=Vivid
description=Punchier colour without stylising the image: warmer and more saturated, blacks and whites pushed to the ends of the range, and a light sharpen.
chain=NaturalColors.fx|NaturalColors|Luma=1.15,Chroma=1.35;Levels.fx|Levels|InputBlack=0.02,InputWhite=0.98;Sharpen.fx|Sharpen|Amount=0.5
-70
View File
@@ -1,70 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from bloomnoblur.fsh in PPSSPP.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Radius <
ui_type = "slider";
ui_label = "Radius";
ui_tooltip = "How far the glow spreads from bright areas.";
ui_min = 0.0; ui_max = 4.0; ui_step = 0.05;
> = 1.0;
uniform float Amount <
ui_type = "slider";
ui_label = "Amount";
ui_tooltip = "Strength of the glow added on top of the image.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 0.6;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float Weight(float3 color)
{
float gray = (color.r + color.g + color.b) / 3.0;
float saturation = (abs(color.r - gray) + abs(color.g - gray) + abs(color.b - gray)) / 3.0;
return gray * gray / max(saturation, 0.25);
}
float4 PS_Bloom(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 color = tex2D(BackBuffer, uv).rgb;
float gray = (color.r + color.g + color.b) / 3.0;
float saturation = (abs(color.r - gray) + abs(color.g - gray) + abs(color.b - gray)) / 3.0;
float spread = 0.002 * gray / max(saturation, 0.25) * Radius;
float3 sum = float3(0.0, 0.0, 0.0);
[unroll] for (int x = -3; x <= 3; x += 2)
{
[unroll] for (int y = -3; y <= 3; y += 2)
{
float3 tap = tex2D(BackBuffer, uv + float2(x, y) * spread).rgb;
sum += tap * Weight(tap);
}
}
sum /= 16.0;
return float4(saturate(color + sum * Amount), 1.0);
}
technique Bloom <
ui_label = "Bloom";
ui_tooltip = "Bleeds light out of the brightest areas into a soft halo, the way a camera does when pointed at something too bright.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Bloom;
}
}
-87
View File
@@ -1,87 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Radius <
ui_type = "slider";
ui_label = "Radius";
ui_tooltip = "How far the blur reaches, in pixels.";
ui_min = 1.0; ui_max = 12.0; ui_step = 0.5;
> = 4.0;
uniform float Strength <
ui_type = "slider";
ui_label = "Strength";
ui_tooltip = "Blend between the original image and the blurred one.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 1.0;
uniform float FocusSize <
ui_type = "slider";
ui_label = "Sharp Centre";
ui_tooltip = "Size of the region left in focus at the centre of the screen. At zero the whole image is blurred evenly.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.0;
uniform float FocusSoftness <
ui_type = "slider";
ui_label = "Focus Falloff";
ui_tooltip = "How gradually the sharp centre gives way to the blur.";
ui_min = 0.05; ui_max = 1.0; ui_step = 0.05;
> = 0.4;
static const int TAPS = 17;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Blur(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 original = tex2D(BackBuffer, uv).rgb;
float2 centred = (uv - 0.5) * float2(BUFFER_WIDTH * BUFFER_RCP_HEIGHT, 1.0) * 2.0;
float distance_from_centre = length(centred);
float no_focus = 1.0 - step(0.001, FocusSize);
float focus = max(smoothstep(FocusSize, FocusSize + FocusSoftness, distance_from_centre), no_focus);
float amount = Strength * focus;
float angle = frac(sin(dot(pos.xy, float2(12.9898, 78.233))) * 43758.5453) * 6.2831853;
float2 spoke = float2(cos(angle), sin(angle));
const float2 turn = float2(cos(2.39996323), sin(2.39996323));
const float decay = exp(-2.0 / float(TAPS));
float weight = exp(-1.0 / float(TAPS));
float3 sum = float3(0.0, 0.0, 0.0);
float total = 0.0;
[unroll] for (int i = 0; i < TAPS; ++i)
{
float reach = sqrt((float(i) + 0.5) / float(TAPS));
sum += tex2D(BackBuffer, uv + spoke * reach * texel * Radius).rgb * weight;
total += weight;
weight *= decay;
spoke = float2(spoke.x * turn.x - spoke.y * turn.y,
spoke.x * turn.y + spoke.y * turn.x);
}
float3 blurred = sum / total;
return float4(lerp(original, blurred, amount), 1.0);
}
technique Blur <
ui_label = "Blur";
ui_tooltip = "Gaussian blur with an optional sharp centre, for softening the picture or faking depth of field.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Blur;
}
}
-74
View File
@@ -1,74 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from crt.fsh in PPSSPP, by KillaMaaki.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Timer < source = "timer"; > = 0.0;
uniform float Density <
ui_type = "slider";
ui_label = "Line Density";
ui_min = 60.0; ui_max = 720.0; ui_step = 10.0;
> = 272.0;
uniform float RollSpeed <
ui_type = "slider";
ui_label = "Roll Speed";
ui_tooltip = "Speed of the rolling bar. Zero disables it.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 1.0;
uniform float Bleed <
ui_type = "slider";
ui_label = "Colour Bleed";
ui_tooltip = "Horizontal separation of the red and green channels.";
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_CRT(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float seconds = Timer * 0.001;
float scan = floor((uv.y + seconds * RollSpeed * 0.5) * Density);
float line_intensity = frac(scan * 0.5) * 2.0;
float2 shift = float2(line_intensity * 0.0005, 0.0);
float2 bleed = float2(BUFFER_RCP_WIDTH * Bleed, 0.0);
float r = tex2D(BackBuffer, uv + bleed + shift).r;
float g = tex2D(BackBuffer, uv - bleed + shift).g;
float b = tex2D(BackBuffer, uv).b;
float3 color = float3(r, g * 0.99, b) * clamp(line_intensity, 0.85, 1.0);
if (RollSpeed > 0.0)
{
float rollbar = sin((uv.y + seconds * RollSpeed) * 4.0);
color += rollbar * 0.02;
}
return float4(saturate(color), 1.0);
}
technique CRT <
ui_label = "CRT";
ui_tooltip = "Curved scanlines and the phosphor mask of a CRT television, for games that were drawn with that kind of screen in mind.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_CRT;
}
}
-79
View File
@@ -1,79 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-FileCopyrightText: guest(r)
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from cartoon.fsh in PPSSPP, Advanced Cartoon shader I by guest(r).
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float EdgeStrength <
ui_type = "slider";
ui_label = "Edge Strength";
ui_tooltip = "Darkness of the ink outline drawn around detected edges.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 0.5;
uniform float Levels <
ui_type = "slider";
ui_label = "Colour Levels";
ui_tooltip = "How many bands the colours are quantised into.";
ui_min = 2.0; ui_max = 16.0; ui_step = 1.0;
> = 4.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Cartoon(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 c00 = tex2D(BackBuffer, uv + texel * float2(-1.0, -1.0)).rgb;
float3 c10 = tex2D(BackBuffer, uv + texel * float2( 0.0, -1.0)).rgb;
float3 c20 = tex2D(BackBuffer, uv + texel * float2( 1.0, -1.0)).rgb;
float3 c01 = tex2D(BackBuffer, uv + texel * float2(-1.0, 0.0)).rgb;
float3 c11 = tex2D(BackBuffer, uv).rgb;
float3 c21 = tex2D(BackBuffer, uv + texel * float2( 1.0, 0.0)).rgb;
float3 c02 = tex2D(BackBuffer, uv + texel * float2(-1.0, 1.0)).rgb;
float3 c12 = tex2D(BackBuffer, uv + texel * float2( 0.0, 1.0)).rgb;
float3 c22 = tex2D(BackBuffer, uv + texel * float2( 1.0, 1.0)).rgb;
const float3 dt = float3(1.0, 1.0, 1.0);
float d1 = dot(abs(c00 - c22), dt);
float d2 = dot(abs(c20 - c02), dt);
float hl = dot(abs(c01 - c21), dt);
float vl = dot(abs(c10 - c12), dt);
float edge = EdgeStrength * (d1 + d2 + hl + vl) / (dot(c11, dt) + 0.15);
float lc = Levels * length(c11);
float f = frac(lc);
f *= f;
lc = (floor(lc) + f * f) / Levels + 0.05;
float3 unit = normalize(max(c11, 0.0001));
float3 quant = Levels * unit;
float3 frct = frac(quant);
frct *= frct;
quant = floor(quant) + 0.05 * dt + frct * frct;
float3 color = lc * (1.1 - edge * sqrt(edge)) * quant / Levels;
return float4(saturate(color), 1.0);
}
technique Cartoon <
ui_label = "Cartoon";
ui_tooltip = "Ink outlines and flat colour bands. Faithful port of the PPSSPP shader; the outline gets heavy in dark scenes, so try Cartoon Soft or Cel Shading if the blacks smear.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Cartoon;
}
}
-100
View File
@@ -1,100 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-FileCopyrightText: guest(r)
// SPDX-License-Identifier: GPL-2.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float EdgeStrength <
ui_type = "slider";
ui_label = "Edge Strength";
ui_tooltip = "Darkness of the ink outline drawn around detected edges.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 0.45;
uniform float ShadowGuard <
ui_type = "slider";
ui_label = "Shadow Guard";
ui_tooltip = "Holds the outline back in dark areas. Raise it if shadows turn into black blobs.";
ui_min = 0.1; ui_max = 2.0; ui_step = 0.05;
> = 0.8;
uniform float Levels <
ui_type = "slider";
ui_label = "Colour Levels";
ui_tooltip = "How many bands the colours are quantised into.";
ui_min = 2.0; ui_max = 16.0; ui_step = 1.0;
> = 6.0;
uniform float Smoothing <
ui_type = "slider";
ui_label = "Banding";
ui_tooltip = "How far the picture is pushed towards flat bands.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.75;
uniform float Saturation <
ui_type = "slider";
ui_label = "Saturation";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 1.15;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_CartoonSoft(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 c00 = tex2D(BackBuffer, uv + texel * float2(-1.0, -1.0)).rgb;
float3 c10 = tex2D(BackBuffer, uv + texel * float2( 0.0, -1.0)).rgb;
float3 c20 = tex2D(BackBuffer, uv + texel * float2( 1.0, -1.0)).rgb;
float3 c01 = tex2D(BackBuffer, uv + texel * float2(-1.0, 0.0)).rgb;
float3 c11 = tex2D(BackBuffer, uv).rgb;
float3 c21 = tex2D(BackBuffer, uv + texel * float2( 1.0, 0.0)).rgb;
float3 c02 = tex2D(BackBuffer, uv + texel * float2(-1.0, 1.0)).rgb;
float3 c12 = tex2D(BackBuffer, uv + texel * float2( 0.0, 1.0)).rgb;
float3 c22 = tex2D(BackBuffer, uv + texel * float2( 1.0, 1.0)).rgb;
const float3 dt = float3(1.0, 1.0, 1.0);
const float3 luma_weights = float3(0.299, 0.587, 0.114);
float d1 = dot(abs(c00 - c22), dt);
float d2 = dot(abs(c20 - c02), dt);
float hl = dot(abs(c01 - c21), dt);
float vl = dot(abs(c10 - c12), dt);
float luma = dot(c11, luma_weights);
float response = (d1 + d2 + hl + vl) / (luma * 2.0 + ShadowGuard);
float ink = 1.0 - saturate(response * EdgeStrength);
float scaled = luma * Levels;
float step_position = frac(scaled);
float eased = step_position * step_position * (3.0 - 2.0 * step_position);
float banded = (floor(scaled) + eased) / Levels;
float target = lerp(luma, banded, Smoothing);
float3 tinted = c11 * (target / max(luma, 0.001));
float3 grey = dot(tinted, luma_weights);
float3 color = lerp(grey, tinted, Saturation) * ink;
return float4(saturate(color), 1.0);
}
technique CartoonSoft <
ui_label = "Cartoon Soft";
ui_tooltip = "Ink outlines and flat colour bands, with the outline held back in the shadows so dark scenes do not turn into black blobs.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_CartoonSoft;
}
}
-120
View File
@@ -1,120 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Bands <
ui_type = "slider";
ui_label = "Shading Bands";
ui_tooltip = "How many flat steps the lighting is collapsed into. Three or four gives the classic look.";
ui_min = 2.0; ui_max = 8.0; ui_step = 1.0;
> = 4.0;
uniform float BandContrast <
ui_type = "slider";
ui_label = "Band Contrast";
ui_tooltip = "Spreads the bands towards pure black and white. Lower it if the shadows crush.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.5;
uniform float BandEdge <
ui_type = "slider";
ui_label = "Band Edge";
ui_tooltip = "Width of the transition between bands. Low values give hard cel steps.";
ui_min = 0.02; ui_max = 1.0; ui_step = 0.02;
> = 0.15;
uniform float Detail <
ui_type = "slider";
ui_label = "Texture Detail";
ui_tooltip = "How much surface texture survives the flattening. At zero the bands are completely flat.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.6;
uniform float OutlineStrength <
ui_type = "slider";
ui_label = "Outline Strength";
ui_tooltip = "Opacity of the ink line drawn along detected edges.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.8;
uniform float OutlineThreshold <
ui_type = "slider";
ui_label = "Outline Threshold";
ui_tooltip = "How strong an edge has to be before it is inked. Raise it to keep ink off textures and specular highlights.";
ui_min = 0.01; ui_max = 0.4; ui_step = 0.01;
> = 0.18;
uniform float Saturation <
ui_type = "slider";
ui_label = "Saturation";
ui_tooltip = "Colour intensity of the flat regions.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 1.25;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_CelShading(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
const float3 luma_weights = float3(0.2126, 0.7152, 0.0722);
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 centre = tex2D(BackBuffer, uv).rgb;
float luma = dot(centre, luma_weights);
float2 near = texel * 1.5;
float2 far = texel * 3.5;
float a00 = dot(tex2D(BackBuffer, uv + near * float2(-1.0, -1.0)).rgb, luma_weights);
float a20 = dot(tex2D(BackBuffer, uv + near * float2( 1.0, -1.0)).rgb, luma_weights);
float a02 = dot(tex2D(BackBuffer, uv + near * float2(-1.0, 1.0)).rgb, luma_weights);
float a22 = dot(tex2D(BackBuffer, uv + near * float2( 1.0, 1.0)).rgb, luma_weights);
float b00 = dot(tex2D(BackBuffer, uv + far * float2(-1.0, -1.0)).rgb, luma_weights);
float b20 = dot(tex2D(BackBuffer, uv + far * float2( 1.0, -1.0)).rgb, luma_weights);
float b02 = dot(tex2D(BackBuffer, uv + far * float2(-1.0, 1.0)).rgb, luma_weights);
float b22 = dot(tex2D(BackBuffer, uv + far * float2( 1.0, 1.0)).rgb, luma_weights);
float gx = (a00 + a02) - (a20 + a22);
float gy = (a00 + a20) - (a02 + a22);
float gradient = sqrt(gx * gx + gy * gy);
float ink = smoothstep(OutlineThreshold, OutlineThreshold + 0.04, gradient);
float lighting = (a00 + a20 + a02 + a22 + b00 + b20 + b02 + b22) * 0.125;
float detail = luma - lighting;
float softness = max(BandEdge, 0.001);
float coord = lighting * Bands - softness * 0.5;
float index = floor(coord) + smoothstep(1.0 - softness, 1.0, frac(coord));
float centred = (index + 0.5) / Bands;
float stretched = index / max(Bands - 1.0, 1.0);
float banded = saturate(lerp(centred, stretched, BandContrast));
float target = saturate(banded + detail * Detail);
float gain = min(target / max(luma, 0.001), 4.0);
float3 shaded = centre * gain;
float3 grey = dot(shaded, luma_weights);
float3 color = lerp(grey, shaded, Saturation);
color *= 1.0 - ink * OutlineStrength;
return float4(saturate(color), 1.0);
}
technique CelShading <
ui_label = "Cel Shading";
ui_tooltip = "Collapses the lighting into a few hard steps and inks the edges, keeping texture detail and hue intact.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_CelShading;
}
}
-53
View File
@@ -1,53 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Strength <
ui_type = "slider";
ui_label = "Strength";
ui_tooltip = "Channel separation in pixels, measured at the edge of the screen.";
ui_min = 0.0; ui_max = 8.0; ui_step = 0.1;
> = 1.5;
uniform float Falloff <
ui_type = "slider";
ui_label = "Falloff";
ui_tooltip = "How fast the separation grows away from the centre. Higher keeps the middle clean.";
ui_min = 1.0; ui_max = 4.0; ui_step = 0.1;
> = 2.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_ChromaticAberration(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float2 direction = uv - float2(0.5, 0.5);
float radius = length(direction);
float2 unit = direction / max(radius, 0.0001);
float2 offset = unit * Strength * pow(radius * 2.0, Falloff) * texel;
float red = tex2D(BackBuffer, uv + offset).r;
float green = tex2D(BackBuffer, uv).g;
float blue = tex2D(BackBuffer, uv - offset).b;
return float4(red, green, blue, 1.0);
}
technique ChromaticAberration <
ui_label = "Chromatic Aberration";
ui_tooltip = "Splits the colour channels apart towards the edges of the screen, the way a cheap lens fails to focus every colour on the same spot.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_ChromaticAberration;
}
}
-64
View File
@@ -1,64 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Based on colorcorrection.fsh in PPSSPP.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Saturation <
ui_type = "slider";
ui_label = "Saturation";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
uniform float Brightness <
ui_type = "slider";
ui_label = "Brightness";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
uniform float Contrast <
ui_type = "slider";
ui_label = "Contrast";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
uniform float Gamma <
ui_type = "slider";
ui_label = "Gamma";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_ColorGrade(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
float luma = dot(rgb, float3(0.2126, 0.7152, 0.0722));
rgb = lerp(float3(luma, luma, luma), rgb, Saturation);
rgb *= Brightness;
rgb = (rgb - 0.5) * Contrast + 0.5;
rgb = pow(max(rgb, 0.0), 1.0 / max(Gamma, 0.0001));
return float4(saturate(rgb), 1.0);
}
technique ColorGrade <
ui_label = "Colour Grade";
ui_tooltip = "The four basic colour controls in one pass: saturation, brightness, contrast and gamma. Reach for this before anything more specialised.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_ColorGrade;
}
}
-91
View File
@@ -1,91 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2015 Niklas Haas
// SPDX-License-Identifier: MIT
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Threshold <
ui_type = "slider";
ui_label = "Threshold";
ui_tooltip = "How flat a neighbourhood must be before it gets smoothed. Raise it to catch wider bands, lower it to keep more detail.";
ui_min = 0.002; ui_max = 0.05; ui_step = 0.001;
> = 0.012;
uniform float Radius <
ui_type = "slider";
ui_label = "Radius";
ui_tooltip = "How far the sampling reaches, in pixels. Wider gradients need a larger radius.";
ui_min = 1.0; ui_max = 32.0; ui_step = 1.0;
> = 8.0;
uniform float Grain <
ui_type = "slider";
ui_label = "Dither";
ui_tooltip = "Noise added to break up whatever banding survives the smoothing.";
ui_min = 0.0; ui_max = 0.02; ui_step = 0.001;
> = 0.004;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float Hash(float2 p)
{
float3 scattered = frac(float3(p.x, p.y, p.x) * 0.1031);
scattered += dot(scattered, scattered.yzx + 33.33);
return frac((scattered.x + scattered.y) * scattered.z);
}
float4 PS_Deband(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 centre = tex2D(BackBuffer, uv).rgb;
float base = Hash(pos.xy) * 6.2831853;
float3 total = float3(0.0, 0.0, 0.0);
float3 deviation = float3(0.0, 0.0, 0.0);
[unroll] for (int ring = 1; ring <= 2; ++ring)
{
float angle = base + float(ring) * 2.3999632;
float reach = Radius * float(ring) * 0.5;
float2 along = float2(cos(angle), sin(angle)) * reach;
float2 across = float2(-along.y, along.x);
float3 s0 = tex2D(BackBuffer, uv + along * texel).rgb;
float3 s1 = tex2D(BackBuffer, uv - along * texel).rgb;
float3 s2 = tex2D(BackBuffer, uv + across * texel).rgb;
float3 s3 = tex2D(BackBuffer, uv - across * texel).rgb;
total += s0 + s1 + s2 + s3;
deviation = max(deviation, max(max(abs(s0 - centre), abs(s1 - centre)),
max(abs(s2 - centre), abs(s3 - centre))));
}
float3 average = total * 0.125;
float3 flatness = float3(1.0, 1.0, 1.0) -
smoothstep(Threshold * 0.5, Threshold, deviation);
float3 result = lerp(centre, average, flatness);
float dither = (Hash(pos.xy + float2(71.3, 41.7)) - 0.5) * Grain;
return float4(saturate(result + dither), 1.0);
}
technique Deband <
ui_label = "Deband";
ui_tooltip = "Smooths the visible steps in gradients such as skies, then dithers whatever survives. Worth adding whenever large flat areas show rings.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Deband;
}
}
-83
View File
@@ -1,83 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019-2021 bloc97
// SPDX-License-Identifier: MIT
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Strength <
ui_type = "slider";
ui_label = "Strength";
ui_min = 0.01; ui_max = 0.5; ui_step = 0.01;
> = 0.1;
uniform float Radius <
ui_type = "slider";
ui_label = "Radius";
ui_min = 0.3; ui_max = 2.0; ui_step = 0.05;
> = 1.0;
uniform float Curve <
ui_type = "slider";
ui_label = "Shadow Bias";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float3 IntensityWeight(float3 value, float3 sigma, float3 centre)
{
float3 scaled = (value - centre) / sigma;
return exp(-0.5 * scaled * scaled);
}
float SpatialWeight(float distance, float sigma)
{
float scaled = distance / sigma;
return exp(-0.5 * scaled * scaled);
}
float4 PS_Denoise(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 centre = tex2D(BackBuffer, uv).rgb;
float3 intensity_sigma = max(pow(centre + 0.0001, Curve) * Strength, 0.0001);
float spatial_sigma = max(Radius, 0.05);
float3 sum = float3(0.0, 0.0, 0.0);
float3 total = float3(0.0, 0.0, 0.0);
[unroll] for (int y = -2; y <= 2; ++y)
{
[unroll] for (int x = -2; x <= 2; ++x)
{
float2 offset = float2(x, y);
float3 tap = tex2D(BackBuffer, uv + offset * texel).rgb;
float3 weight = IntensityWeight(tap, intensity_sigma, centre) *
SpatialWeight(length(offset), spatial_sigma);
sum += weight * tap;
total += weight;
}
}
return float4(sum / total, 1.0);
}
technique Denoise <
ui_label = "Denoise";
ui_tooltip = "Edge preserving blur that clears dithering and compression noise while leaving outlines sharp. Ported from Anime4K.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Denoise;
}
}
-65
View File
@@ -1,65 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Intensity <
ui_type = "slider";
ui_label = "Intensity";
ui_min = 0.0; ui_max = 0.2; ui_step = 0.005;
> = 0.03;
uniform float Size <
ui_type = "slider";
ui_label = "Size";
ui_tooltip = "Grain cell size in pixels.";
ui_min = 1.0; ui_max = 4.0; ui_step = 1.0;
> = 1.0;
uniform float Colored <
ui_type = "slider";
ui_label = "Colour";
ui_tooltip = "Zero gives monochrome grain, one gives independent noise per channel.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float Hash(float2 p)
{
float3 scattered = frac(float3(p.x, p.y, p.x) * 0.1031);
scattered += dot(scattered, scattered.yzx + 33.33);
return frac((scattered.x + scattered.y) * scattered.z);
}
float4 PS_FilmGrain(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
float2 cell = floor(pos.xy / max(Size, 1.0));
float mono = Hash(cell) - 0.5;
float3 chroma = float3(Hash(cell + 11.7), Hash(cell + 23.1), Hash(cell + 37.5)) - 0.5;
float3 noise = lerp(float3(mono, mono, mono), chroma, Colored);
float luma = dot(rgb, float3(0.2126, 0.7152, 0.0722));
float response = 1.0 - abs(luma * 2.0 - 1.0);
return float4(saturate(rgb + noise * Intensity * response), 1.0);
}
technique FilmGrain <
ui_label = "Film Grain";
ui_tooltip = "Adds photographic grain, strongest in the midtones and fading out in blacks and whites.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_FilmGrain;
}
}
-60
View File
@@ -1,60 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Exposure <
ui_type = "slider";
ui_label = "Exposure";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
uniform float Toe <
ui_type = "slider";
ui_label = "Toe";
ui_tooltip = "Above 1.0 deepens the shadows, below 1.0 lifts them.";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.2;
uniform float Shoulder <
ui_type = "slider";
ui_label = "Shoulder";
ui_tooltip = "Above 1.0 opens up the highlights, below 1.0 compresses them.";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.2;
uniform float Amount <
ui_type = "slider";
ui_label = "Amount";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.7;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_FilmicCurve(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
float3 curved = saturate(rgb * Exposure);
curved = pow(max(curved, 0.0), Toe);
curved = 1.0 - pow(max(1.0 - curved, 0.0), Shoulder);
return float4(saturate(lerp(rgb, curved, Amount)), 1.0);
}
technique FilmicCurve <
ui_label = "Filmic Curve";
ui_tooltip = "Filmic contrast curve. Deepens the shadows and opens the highlights without clipping either end.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_FilmicCurve;
}
}
-53
View File
@@ -1,53 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Distortion <
ui_type = "slider";
ui_label = "Distortion";
ui_tooltip = "Positive bulges the picture outwards, negative pinches it inwards.";
ui_min = -0.5; ui_max = 0.5; ui_step = 0.01;
> = 0.1;
uniform float Zoom <
ui_type = "slider";
ui_label = "Zoom";
ui_tooltip = "Scales the picture to hide the edges the warp pulls in.";
ui_min = 0.5; ui_max = 1.5; ui_step = 0.01;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_LensDistortion(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float aspect = BUFFER_WIDTH * BUFFER_RCP_HEIGHT;
float2 half_size = float2(aspect, 1.0);
float2 unit = half_size / length(half_size);
float2 centred = (uv - 0.5) * 2.0 * unit;
float r2 = dot(centred, centred);
centred *= 1.0 + Distortion * r2;
centred /= max(Zoom, 0.001);
float2 source = centred / (2.0 * unit) + 0.5;
return float4(tex2D(BackBuffer, source).rgb, 1.0);
}
technique LensDistortion <
ui_label = "Lens Distortion";
ui_tooltip = "Barrel or pincushion warp, like looking through a wide angle lens.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_LensDistortion;
}
}
-66
View File
@@ -1,66 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float InputBlack <
ui_type = "slider";
ui_label = "Input Black";
ui_tooltip = "Input level mapped to black. Raise it to deepen washed out shadows.";
ui_min = 0.0; ui_max = 0.5; ui_step = 0.005;
> = 0.0;
uniform float InputWhite <
ui_type = "slider";
ui_label = "Input White";
ui_min = 0.5; ui_max = 1.0; ui_step = 0.005;
> = 1.0;
uniform float Gamma <
ui_type = "slider";
ui_label = "Gamma";
ui_min = 0.2; ui_max = 3.0; ui_step = 0.01;
> = 1.0;
uniform float OutputBlack <
ui_type = "slider";
ui_label = "Output Black";
ui_tooltip = "Lifts crushed shadows so detail stops collapsing into one flat black.";
ui_min = 0.0; ui_max = 0.5; ui_step = 0.005;
> = 0.0;
uniform float OutputWhite <
ui_type = "slider";
ui_label = "Output White";
ui_min = 0.5; ui_max = 1.0; ui_step = 0.005;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Levels(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
rgb = saturate((rgb - InputBlack) / max(InputWhite - InputBlack, 0.001));
rgb = pow(max(rgb, 0.0), 1.0 / max(Gamma, 0.001));
rgb = lerp(OutputBlack, OutputWhite, rgb);
return float4(saturate(rgb), 1.0);
}
technique Levels <
ui_label = "Levels";
ui_tooltip = "Black point, white point, gamma and output range. Use it to fix crushed or washed out shadows.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Levels;
}
}
-88
View File
@@ -1,88 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Length <
ui_type = "slider";
ui_label = "Length";
ui_tooltip = "How far the streaks reach, as a percentage of screen height.";
ui_min = 0.0; ui_max = 20.0; ui_step = 0.5;
> = 5.0;
uniform float Zoom <
ui_type = "slider";
ui_label = "Zoom";
ui_tooltip = "Streaks running out from the centre of the screen, as if rushing forward. The centre stays sharp.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 1.0;
uniform float Pan <
ui_type = "slider";
ui_label = "Pan";
ui_tooltip = "Streaks running in one fixed direction, as if the camera were sweeping across.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.0;
uniform float Angle <
ui_type = "slider";
ui_label = "Pan Angle";
ui_tooltip = "Direction of the sweep, in degrees.";
ui_min = 0.0; ui_max = 360.0; ui_step = 5.0;
> = 0.0;
uniform float Spin <
ui_type = "slider";
ui_label = "Spin";
ui_tooltip = "Streaks curling around the centre, as if the camera were rolling. Negative turns the other way.";
ui_min = -1.0; ui_max = 1.0; ui_step = 0.05;
> = 0.0;
static const int TAPS = 24;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_MotionBlur(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float aspect = BUFFER_WIDTH * BUFFER_RCP_HEIGHT;
float2 to_screen = float2(aspect, 1.0);
float2 centred = (uv - 0.5) * to_screen * 2.0;
float2 outward = centred;
float2 around = float2(-centred.y, centred.x);
float radians_angle = Angle * 0.01745329;
float2 sweep = float2(cos(radians_angle), sin(radians_angle));
float2 velocity = sweep * Pan + outward * Zoom + around * Spin;
velocity *= Length * 0.01;
velocity /= to_screen;
float jitter = frac(sin(dot(pos.xy, float2(12.9898, 78.233))) * 43758.5453);
float3 sum = float3(0.0, 0.0, 0.0);
[unroll] for (int i = 0; i < TAPS; ++i)
{
float t = (float(i) + jitter) / float(TAPS) - 0.5;
sum += tex2D(BackBuffer, uv + velocity * t).rgb;
}
return float4(sum / float(TAPS), 1.0);
}
technique MotionBlur <
ui_label = "Motion Blur";
ui_tooltip = "Camera style motion blur: streaks the picture outwards, sideways or around, without touching still detail at the centre.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_MotionBlur;
}
}
-60
View File
@@ -1,60 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from naturalA.fsh in PPSSPP, by ShadX, modified by SimoneT.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Luma <
ui_type = "slider";
ui_label = "Luma Curve";
ui_tooltip = "Gamma applied to the luminance channel in YIQ space.";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.2;
uniform float Chroma <
ui_type = "slider";
ui_label = "Chroma Gain";
ui_tooltip = "Boost applied to the two colour difference channels.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 1.2;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Natural(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
const float3x3 RGBtoYIQ = float3x3(0.299, 0.587, 0.114,
0.596, -0.275, -0.321,
0.212, -0.523, 0.311);
const float3x3 YIQtoRGB = float3x3(1.0, 0.95568806, 0.61985809,
1.0, -0.27158180, -0.64687382,
1.0, -1.10817733, 1.70506456);
float3 rgb = tex2D(BackBuffer, uv).rgb;
float3 yiq = mul(RGBtoYIQ, rgb);
yiq.x = pow(max(yiq.x, 0.0), Luma);
yiq.yz *= Chroma;
return float4(saturate(mul(YIQtoRGB, yiq)), 1.0);
}
technique NaturalColors <
ui_label = "Natural Colours";
ui_tooltip = "Warms the picture and lifts saturation for a less washed out look. Ported from the PPSSPP shader.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Natural;
}
}
-90
View File
@@ -1,90 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Timer < source = "timer"; > = 0.0;
uniform float Horizon <
ui_type = "slider";
ui_label = "Reflection Line";
ui_tooltip = "Height on screen where the reflective floor begins. Everything above it is left untouched.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.55;
uniform float Amount <
ui_type = "slider";
ui_label = "Amount";
ui_tooltip = "How strongly the reflection shows through the floor.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.35;
uniform float Falloff <
ui_type = "slider";
ui_label = "Falloff";
ui_tooltip = "How quickly the reflection fades as the floor comes towards the viewer. At zero it stays even.";
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
> = 1.2;
uniform float Perspective <
ui_type = "slider";
ui_label = "Perspective";
ui_tooltip = "Stretches or squashes the mirrored image. One is a true mirror, higher values pull it towards the line.";
ui_min = 0.2; ui_max = 2.0; ui_step = 0.05;
> = 1.0;
uniform float Ripple <
ui_type = "slider";
ui_label = "Ripple";
ui_tooltip = "Amplitude of the waves disturbing the reflection. At zero the mirror is perfectly still.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.0;
uniform float RippleSpeed <
ui_type = "slider";
ui_label = "Ripple Speed";
ui_tooltip = "How fast the waves travel.";
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Reflections(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 color = tex2D(BackBuffer, uv).rgb;
float depth = uv.y - Horizon;
float on_floor = step(0.0, depth);
float span = max(1.0 - Horizon, 0.001);
float distance_down = saturate(depth / span);
float seconds = Timer * 0.001;
float wave = sin(uv.x * 38.0 + seconds * RippleSpeed * 2.0) *
sin(uv.y * 21.0 - seconds * RippleSpeed * 1.3);
float2 disturbance = float2(wave * 0.004, wave * 0.002) * Ripple * distance_down;
float2 mirrored = float2(uv.x, Horizon - depth * Perspective) + disturbance;
float3 reflection = tex2D(BackBuffer, saturate(mirrored)).rgb;
float fade = pow(max(1.0 - distance_down, 0.0001), Falloff);
float strength = Amount * fade * on_floor;
return float4(lerp(color, reflection, strength), 1.0);
}
technique Reflections <
ui_label = "Reflections";
ui_tooltip = "Mirrors the picture into a reflective floor below a line you choose, with optional water ripples.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Reflections;
}
}
-66
View File
@@ -1,66 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from scanlines.fsh in PPSSPP.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Density <
ui_type = "slider";
ui_label = "Line Density";
ui_tooltip = "Number of scanline pairs across the screen.";
ui_min = 60.0; ui_max = 720.0; ui_step = 10.0;
> = 340.0;
uniform float Intensity <
ui_type = "slider";
ui_label = "Intensity";
ui_tooltip = "How dark the gaps between lines become.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.5;
uniform float Tint <
ui_type = "slider";
ui_label = "Phosphor Tint";
ui_tooltip = "Strength of the green-warm phosphor cast.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Scanlines(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float line_pos = uv.y * Density * 0.5;
float gate = cos((frac(line_pos) - 0.5) * 3.1415926 * Intensity) * 1.5;
float3 rgb = tex2D(BackBuffer, uv).rgb;
float3 color = rgb * 0.5 + 0.5 * rgb * rgb * 1.2;
float3 phosphor = lerp(float3(1.0, 1.0, 1.0), float3(0.9, 1.0, 0.7), Tint);
color *= phosphor;
float2 diff = uv - 0.5;
color *= 1.1 - 0.6 * (dot(diff, diff) * 2.0);
return float4(saturate(color * saturate(gate)), 1.0);
}
technique Scanlines <
ui_label = "Scanlines";
ui_tooltip = "Darkens alternating rows of pixels to imitate the horizontal scanlines of a CRT. Cheaper than the full CRT effect when you only want the lines.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Scanlines;
}
}
-43
View File
@@ -1,43 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Amount <
ui_type = "slider";
ui_label = "Amount";
ui_min = 0.0; ui_max = 3.0; ui_step = 0.01;
> = 0.6;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Sharpen(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 centre = tex2D(BackBuffer, uv).rgb;
float3 blur = tex2D(BackBuffer, uv + float2(-texel.x, 0.0)).rgb;
blur += tex2D(BackBuffer, uv + float2(texel.x, 0.0)).rgb;
blur += tex2D(BackBuffer, uv + float2(0.0, -texel.y)).rgb;
blur += tex2D(BackBuffer, uv + float2(0.0, texel.y)).rgb;
blur *= 0.25;
return float4(centre + (centre - blur) * Amount, 1.0);
}
technique Sharpen <
ui_label = "Sharpen";
ui_tooltip = "Unsharp mask that brings back edge detail lost to scaling. Most useful after upscaling a low internal resolution.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Sharpen;
}
}
-75
View File
@@ -1,75 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float ShadowHue <
ui_type = "slider";
ui_label = "Shadow Hue";
ui_min = 0.0; ui_max = 360.0; ui_step = 1.0;
> = 210.0;
uniform float ShadowStrength <
ui_type = "slider";
ui_label = "Shadow Strength";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.0;
uniform float HighlightHue <
ui_type = "slider";
ui_label = "Highlight Hue";
ui_min = 0.0; ui_max = 360.0; ui_step = 1.0;
> = 45.0;
uniform float HighlightStrength <
ui_type = "slider";
ui_label = "Highlight Strength";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.0;
uniform float Balance <
ui_type = "slider";
ui_label = "Balance";
ui_tooltip = "Moves the split between what counts as shadow and what counts as highlight.";
ui_min = -0.5; ui_max = 0.5; ui_step = 0.01;
> = 0.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float3 HueToRGB(float hue)
{
float h = frac(hue / 360.0) * 6.0;
return saturate(float3(abs(h - 3.0) - 1.0, 2.0 - abs(h - 2.0), 2.0 - abs(h - 4.0)));
}
float4 PS_SplitToning(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
float luma = saturate(dot(rgb, float3(0.2126, 0.7152, 0.0722)) + Balance);
float3 shadow_tint = HueToRGB(ShadowHue) - 0.5;
float3 highlight_tint = HueToRGB(HighlightHue) - 0.5;
rgb += shadow_tint * ShadowStrength * 0.25 * (1.0 - luma);
rgb += highlight_tint * HighlightStrength * 0.25 * luma;
return float4(saturate(rgb), 1.0);
}
technique SplitToning <
ui_label = "Split Toning";
ui_tooltip = "Tints the shadows and the highlights towards two different hues.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_SplitToning;
}
}
-52
View File
@@ -1,52 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from vignette.fsh in PPSSPP, by Henrik Rydgard.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Strength <
ui_type = "slider";
ui_label = "Strength";
ui_tooltip = "How dark the corners become.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 0.6;
uniform float Aspect <
ui_type = "slider";
ui_label = "Aspect";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Vignette(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 diff = uv - 0.5;
diff.x *= Aspect;
diff.y /= max(Aspect, 0.0001);
float falloff = 1.0 - min(1.0, Strength * dot(diff, diff) * 2.0);
float3 rgb = tex2D(BackBuffer, uv).rgb;
return float4(rgb * falloff, 1.0);
}
technique Vignette <
ui_label = "Vignette";
ui_tooltip = "Darkens the corners of the screen to pull the eye towards the middle, the way a camera lens falls off at its edges.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Vignette;
}
}
-76
View File
@@ -1,76 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Temperature <
ui_type = "slider";
ui_label = "Temperature";
ui_tooltip = "Negative cools the picture towards blue, positive warms it towards orange.";
ui_min = -100.0; ui_max = 100.0; ui_step = 1.0;
> = 0.0;
uniform float Tint <
ui_type = "slider";
ui_label = "Tint";
ui_tooltip = "Negative shifts towards green, positive towards magenta.";
ui_min = -100.0; ui_max = 100.0; ui_step = 1.0;
> = 0.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float3 WhitePointLMS(float t1, float t2)
{
float shift = 0.05;
if (t1 < 0.0)
{
shift = 0.10;
}
float x = 0.31271 - t1 * shift;
float y = 2.87 * x - 3.0 * x * x - 0.27509507 + t2 * 0.05;
float big_y = 1.0;
float big_x = big_y * x / y;
float big_z = big_y * (1.0 - x - y) / y;
return float3( 0.7328 * big_x + 0.4296 * big_y - 0.1624 * big_z,
-0.7036 * big_x + 1.6975 * big_y + 0.0061 * big_z,
0.0030 * big_x + 0.0136 * big_y + 0.9834 * big_z);
}
float4 PS_WhiteBalance(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = pow(max(tex2D(BackBuffer, uv).rgb, 0.0), 2.2);
float3 balance = float3(0.949237, 1.03542, 1.08728) /
WhitePointLMS(Temperature / 65.0, Tint / 65.0);
const float3x3 rgb_to_lms = float3x3(0.390405, 0.549941, 0.008926,
0.070841, 0.963172, 0.001358,
0.023108, 0.128021, 0.936245);
const float3x3 lms_to_rgb = float3x3( 2.858470, -1.628790, -0.024891,
-0.210182, 1.158200, 0.000324,
-0.041812, -0.118169, 1.068670);
float3 lms = mul(rgb_to_lms, rgb) * balance;
rgb = mul(lms_to_rgb, lms);
return float4(saturate(pow(max(rgb, 0.0), 1.0 / 2.2)), 1.0);
}
technique WhiteBalance <
ui_label = "White Balance";
ui_tooltip = "Corrects a picture that looks too cool, too warm or tinted.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_WhiteBalance;
}
}
+17
View File
@@ -12,6 +12,7 @@
- [NetBSD](#netbsd)
- [MSYS2](#msys2)
- [RedoxOS](#redoxos)
- [WebAssembly](#webassembly)
<!-- /TOC -->
## Arch Linux
@@ -242,3 +243,19 @@ find ./*/ -name "*.dll" | while read -r dll; do deps "$dll"; done
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
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.
+18 -9
View File
@@ -60,6 +60,7 @@ All other dependencies will be downloaded and built by [CPM](https://github.com/
* [ZLIB](https://www.zlib.net/) 1.2+
* [zstd](https://facebook.github.io/zstd/) 1.5+
* [enet](http://enet.bespin.org/) 1.3+
* [Opus](https://opus-codec.org/) 1.3+
Vulkan 1.3.274+ is also needed:
@@ -120,7 +121,7 @@ sudo emerge -a \
dev-libs/boost dev-libs/openssl dev-libs/discord-rpc \
dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \
dev-util/vulkan-utility-libraries dev-util/glslang \
media-gfx/renderdoc media-libs/libva media-video/ffmpeg \
media-gfx/renderdoc media-libs/libva media-libs/opus media-video/ffmpeg \
media-libs/VulkanMemoryAllocator media-libs/libsdl3 media-libs/cubeb \
net-libs/enet \
sys-libs/zlib \
@@ -152,7 +153,7 @@ Required USE flags:
<summary>Arch Linux</summary>
```sh
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 ninja nlohmann-json openssl qt6-base qt6-multimedia qt6-charts sdl3 zlib zstd zip unzip vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 ninja nlohmann-json openssl opus qt6-base qt6-multimedia qt6-charts sdl3 zlib zstd zip unzip vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
```
* Building with QT Web Engine requires `qt6-webengine` as well.
@@ -165,7 +166,7 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl
<summary>Ubuntu, Debian, Mint Linux</summary>
```sh
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev qt6-charts-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl3-dev libasound2t64 vulkan-utility-libraries-dev
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev qt6-charts-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl3-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev
```
* Ubuntu 26.04, Linux Mint 22.3, or Debian 13 or later is required.
@@ -212,7 +213,7 @@ First, enable the community repository; [see here](https://wiki.alpinelinux.org/
# Enable the community repository
setup-apkrepos -c
# Install
apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-charts-dev libusb-dev libtool boost-dev sdl3-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev jq patch
apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-charts-dev libusb-dev libtool boost-dev sdl3-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev jq patch
```
</details>
@@ -260,7 +261,7 @@ brew install molten-vk
As root run:
```sh
pkg install devel/cmake devel/sdl3 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base x11-toolkits/qt6-charts devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib graphics/vulkan-utility-libraries graphics/vulkan-headers graphics/spirv-headers quazip-qt6
pkg install devel/cmake devel/sdl3 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base x11-toolkits/qt6-charts devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib graphics/vulkan-utility-libraries graphics/vulkan-headers graphics/spirv-headers quazip-qt6
```
If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
@@ -274,7 +275,7 @@ If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
For NetBSD +10.1:
```sh
pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq qt6-qtbase qt6-qtcharts qt6-qtmultimedia qt6-qttools cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx frozen
pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6-qtbase qt6-qtcharts qt6-qtmultimedia qt6-qttools cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx frozen
```
[Caveats](./Caveats.md#netbsd).
@@ -305,7 +306,7 @@ pkg install gcc14 git cmake unzip nasm autoconf bash pkgconf ffmpeg glslang gmak
<summary>OpenIndiana</summary>
```sh
sudo pkg install git cmake qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl sdl3 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt
sudo pkg install git cmake qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl3 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt
```
[Caveats](./Caveats.md#openindiana).
@@ -329,7 +330,7 @@ sudo pkgin install git cmake autoconf build-essential libusb-1 nasm gcc13
```sh
BASE="git make autoconf libtool automake-wrapper jq patch"
MINGW="qt6-base qt6-charts qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet libusb openssl SDL3"
MINGW="qt6-base qt6-charts qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet opus libusb openssl SDL3"
# Either x86_64 or clang-aarch64 (Windows on ARM)
packages="$BASE"
for pkg in $MINGW; do
@@ -355,11 +356,19 @@ pacman -Syuu --needed --noconfirm $packages
<summary>HaikuOS</summary>
```sh
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl3_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel cubeb_devel simpleini quazip_qt6_devel
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl3_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel cubeb_devel simpleini quazip_qt6_devel
```
[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>
+1 -1
View File
@@ -76,7 +76,7 @@ The following options are desktop only.
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input backend (HIGHLY RECOMMENDED)
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend
- Unavailable on Windows/ARM64 and on Android
- Unavailable on Windows/ARM64
- You probably shouldn't turn this off.
### Qt
+43 -81
View File
@@ -136,50 +136,49 @@ if(ENABLE_CUBEB)
endif()
endif()
if (NOT YUZU_USE_BUNDLED_SDL3)
if (NOT WIN32)
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
set(SDL_UNUSED_SUBSYSTEMS
File Filesystem
Locale Power Render)
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
string(TOUPPER ${_SUB} _OPT)
set(SDL_${_OPT} OFF)
endforeach()
if (NOT ANDROID)
if (NOT YUZU_USE_BUNDLED_SDL3)
if (NOT WIN32)
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
set(SDL_UNUSED_SUBSYSTEMS
File Filesystem
Locale Power Render)
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
string(TOUPPER ${_SUB} _OPT)
set(SDL_${_OPT} OFF)
endforeach()
set(HIDAPI ON)
endif()
set(HIDAPI ON)
endif()
if (APPLE)
set(SDL_FILE ON)
endif()
if (APPLE)
set(SDL_FILE ON)
endif()
AddJsonPackage(sdl3)
else()
message(STATUS "Using bundled SDL3")
AddJsonPackage(sdl3-ci)
# copy sdl java sources for consumption by Gradle
if (ANDROID)
file(COPY ${SDL3_SOURCE_DIR}/java DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/generated/sdl)
endif()
endif()
# Normalize SDL3 link target across package variants.
# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
if (NOT TARGET SDL3::SDL3)
if (TARGET SDL3::SDL3-shared)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
elseif (TARGET SDL3::SDL3-static)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
AddJsonPackage(sdl3)
else()
message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
message(STATUS "Using bundled SDL3")
AddJsonPackage(sdl3-ci)
endif()
# Normalize SDL3 link target across package variants.
# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
if (NOT TARGET SDL3::SDL3)
if (TARGET SDL3::SDL3-shared)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
elseif (TARGET SDL3::SDL3-static)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
else()
message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
endif()
endif()
endif()
set(BUILD_SHARED_LIBS OFF)
# SPIRV Headers
AddJsonPackage(spirv-headers)
@@ -195,50 +194,6 @@ else()
endif()
endif()
# reshadefx
if (ENABLE_RESHADE)
AddJsonPackage(NAME reshade DOWNLOAD_ONLY)
set(RESHADEFX_SHIM_DIR ${CMAKE_CURRENT_BINARY_DIR}/reshadefx_shim)
file(WRITE ${RESHADEFX_SHIM_DIR}/spirv.hpp "#include <spirv/unified1/spirv.hpp>\n")
file(WRITE ${RESHADEFX_SHIM_DIR}/GLSL.std.450.h "#include <spirv/unified1/GLSL.std.450.h>\n")
if (APPLE)
file(WRITE ${RESHADEFX_SHIM_DIR}/malloc.h "#include <stdlib.h>\n#include <alloca.h>\n")
endif()
add_library(reshadefx STATIC
${reshade_SOURCE_DIR}/source/effect_codegen_spirv.cpp
${reshade_SOURCE_DIR}/source/effect_expression.cpp
${reshade_SOURCE_DIR}/source/effect_lexer.cpp
${reshade_SOURCE_DIR}/source/effect_parser_exp.cpp
${reshade_SOURCE_DIR}/source/effect_parser_stmt.cpp
${reshade_SOURCE_DIR}/source/effect_preprocessor.cpp
${reshade_SOURCE_DIR}/source/effect_symbol_table.cpp
)
target_include_directories(reshadefx SYSTEM PUBLIC ${reshade_SOURCE_DIR}/source)
target_include_directories(reshadefx PRIVATE ${RESHADEFX_SHIM_DIR})
target_link_libraries(reshadefx PUBLIC SPIRV-Headers::SPIRV-Headers)
if (NOT MSVC)
target_compile_options(reshadefx PRIVATE -w -fno-char8_t)
else()
target_compile_options(reshadefx PRIVATE /w /Zc:char8_t-)
endif()
if (WIN32)
if (NOT MSVC)
target_compile_options(reshadefx PRIVATE -include share.h)
else()
target_compile_options(reshadefx PRIVATE /FIshare.h)
endif()
endif()
if (NOT TARGET reshadefx::reshadefx)
add_library(reshadefx::reshadefx ALIAS reshadefx)
endif()
endif()
# Catch2
if (YUZU_TESTS OR DYNARMIC_TESTS)
AddJsonPackage(catch2)
@@ -430,6 +385,13 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
endif()
endif()
# oboe
if (ANDROID)
AddJsonPackage(oboe)
add_library(oboe::oboe ALIAS oboe)
endif()
if (APPLE)
# moltenvk
if (NOT YUZU_USE_BUNDLED_MOLTENVK)
+9 -5
View File
@@ -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
+25
View File
@@ -20,6 +20,9 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "managarm")
set(MANAGARM ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Haiku")
set(HAIKUOS ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
set(EMSCRIPTEN ON)
message(WARNING "${CMAKE_LIBRARY_ARCHITECTURE} support is highly experimental!!!")
endif()
# BSD
@@ -97,3 +100,25 @@ if (MINGW)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE
"${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${MINGW_FLAGS}")
endif()
if (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 (FREEBSD OR DRAGONFLYBSD)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/local/lib")
endif()
+54 -19
View File
@@ -35,26 +35,37 @@ 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 (NETBSD OR SOLARIS OR FREEBSD OR OPENBSD OR DRAGONFLYBSD OR HAIKU
OR LINUX OR 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}")
# Emscripten doesn't use CMAKE_SYSROOT I'm afraid, but it does well use EMSCRIPTEN_SYSROOT
if (EMSCRIPTEN)
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 (OPENORBIS OR 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)
@@ -162,8 +173,7 @@ if (OPENORBIS)
-lSceUserService
-lSceSysmodule
-lSceNet
-lSceLibcInternal
)
-lSceLibcInternal)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--disable-pthreads
--extra-cflags=${CMAKE_SYSROOT}/usr/include
@@ -174,8 +184,18 @@ 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)
@@ -205,6 +225,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.
@@ -213,6 +234,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")
@@ -246,7 +273,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 (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
@@ -256,7 +289,7 @@ else()
OUTPUT
${FFmpeg_MAKEFILE}
COMMAND
${BASH_PROGRAM} ${FFmpeg_PREFIX}/configure
${FFmpeg_CONFIGURE_WRAPPER} ${FFmpeg_PREFIX}/configure
--disable-avdevice
--disable-avformat
--disable-doc
@@ -265,6 +298,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
@@ -272,7 +309,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}
@@ -288,11 +325,7 @@ 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})
@@ -300,6 +333,8 @@ else()
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()
@@ -307,7 +342,7 @@ else()
OUTPUT
${FFmpeg_BUILD_LIBRARIES}
COMMAND
gmake ${FFmpeg_MAKE_ARGS}
${MAKE} ${FFmpeg_MAKE_ARGS}
WORKING_DIRECTORY
${FFmpeg_BUILD_DIR}
)
+2
View File
@@ -14,7 +14,9 @@
namespace Tz {
namespace {
#ifndef EINVAL
#define EINVAL 22
#endif
static Rule gmtmem{};
static Rule* const gmtptr = &gmtmem;
-1
View File
@@ -11,7 +11,6 @@
#include <limits>
#include <span>
#include <array>
#include <algorithm>
#include <time.h>
namespace Tz {
+1 -1
View File
@@ -12,7 +12,7 @@ pkgs.mkShellNoCC {
git cmake clang gnumake patch jq pkg-config
# libraries
openssl boost fmt nlohmann_json lz4 zlib zstd
enet vulkan-headers vulkan-utility-libraries
enet libopus vulkan-headers vulkan-utility-libraries
spirv-tools spirv-headers vulkan-loader unzip
glslang python3 httplib cpp-jwt ffmpeg-headless
libusb1 cubeb
+5 -2
View File
@@ -177,7 +177,6 @@ else()
$<$<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(
@@ -191,7 +190,11 @@ else()
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-nullability-completeness>)
endif()
if (ARCHITECTURE_x86_64)
if (ARCHITECTURE_wasm)
# we are evil but fmt is even more evil
add_compile_options(
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shorten-64-to-32>)
elseif (ARCHITECTURE_x86_64)
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-mcx16>)
if (LINUX OR FREEBSD)
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-mtls-dialect=gnu2>)
-7
View File
@@ -272,13 +272,6 @@ android {
resValue("string", "app_name_suffixed", "$currentName$suffix")
resValue("string", "app_name", "Eden$suffix")
}
sourceSets {
named("main") {
java.srcDir("${edenDir}/externals/generated/sdl/java")
kotlin.srcDir("${edenDir}/externals/generated/sdl/java")
}
}
}
idea {
-3
View File
@@ -9,9 +9,6 @@
-keep class org.ini4j.spi.IniBuilder
-keep class org.ini4j.spi.IniFormatter
-keep class org.libsdl.app.** { *; }
-keepclassmembers class org.libsdl.app.** { *; }
# Suppress warnings for R8
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
@@ -16,7 +16,6 @@ import android.widget.TextView
import androidx.annotation.Keep
import androidx.core.net.toUri
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.libsdl.app.SDL
import java.lang.ref.WeakReference
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
@@ -53,8 +52,6 @@ object NativeLibrary {
init {
try {
System.loadLibrary("yuzu-android")
SDL.setupJNI()
initJvm()
} catch (ex: UnsatisfiedLinkError) {
error("[NativeLibrary] $ex")
}
@@ -370,7 +367,6 @@ object NativeLibrary {
NetPlayManager.clearChat()
}
external fun initJvm()
external fun initMultiplayer()
@Keep
@@ -3,8 +3,6 @@
package org.yuzu.yuzu_emu.dialogs
import android.content.res.ColorStateList
import android.graphics.Rect
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
@@ -20,28 +18,11 @@ import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.fragments.EmulationFragment
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.NativePostProcessing
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
class QuickSettings(val emulationFragment: EmulationFragment) {
private val expandedShaders = mutableSetOf<Int>()
private fun forgetShaderSlot(index: Int) {
val shifted = mutableSetOf<Int>()
for (slot in expandedShaders) {
if (slot < index) {
shifted.add(slot)
}
if (slot > index) {
shifted.add(slot - 1)
}
}
expandedShaders.clear()
expandedShaders.addAll(shifted)
}
private fun saveSettings() {
if (emulationFragment.shouldUseCustom) {
NativeConfig.savePerGameConfig()
@@ -251,428 +232,6 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
container.addView(itemView)
}
fun addChoice(
title: String,
container: ViewGroup,
choices: List<String>,
selectedIndex: Int,
onSelected: (Int) -> Unit
) {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
val headerView = itemView.findViewById<ViewGroup>(R.id.setting_header)
val titleView = itemView.findViewById<TextView>(R.id.setting_title)
val valueView = itemView.findViewById<TextView>(R.id.setting_value)
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.expand_icon)
val radioGroup = itemView.findViewById<RadioGroup>(R.id.radio_group)
titleView.text = title
var current = ""
if (selectedIndex in choices.indices) {
current = choices[selectedIndex]
}
valueView.text = current
headerView.visibility = View.VISIBLE
var isExpanded = false
choices.forEachIndexed { index, name ->
val radioButton = com.google.android.material.radiobutton.MaterialRadioButton(
emulationFragment.requireContext()
)
radioButton.text = name
radioButton.id = View.generateViewId()
radioButton.isChecked = index == selectedIndex
radioButton.setPadding(16, 8, 16, 8)
radioButton.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
valueView.text = name
onSelected(index)
}
}
radioGroup.addView(radioButton)
}
headerView.setOnClickListener {
isExpanded = !isExpanded
if (isExpanded) {
radioGroup.visibility = View.VISIBLE
expandIcon.animate().rotation(180f).setDuration(200).start()
} else {
radioGroup.visibility = View.GONE
expandIcon.animate().rotation(0f).setDuration(200).start()
}
}
container.addView(itemView)
}
fun addStepSlider(
title: String,
container: ViewGroup,
steps: Int,
selectedStep: Int,
describe: (Int) -> String,
onCommitted: (Int) -> Unit,
onChanged: (Int) -> Unit
) {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
val sliderContainer = itemView.findViewById<ViewGroup>(R.id.slider_container)
val titleView = itemView.findViewById<TextView>(R.id.slider_title)
val valueDisplay = itemView.findViewById<TextView>(R.id.slider_value_display)
val slider = itemView.findViewById<com.google.android.material.slider.Slider>(
R.id.setting_slider
)
titleView.text = title
sliderContainer.visibility = View.VISIBLE
slider.valueFrom = 0f
slider.valueTo = steps.toFloat()
slider.stepSize = 1f
slider.value = selectedStep.toFloat().coerceIn(0f, steps.toFloat())
valueDisplay.text = describe(slider.value.toInt())
slider.addOnChangeListener { _, value, fromUser ->
if (fromUser) {
val step = value.toInt()
onChanged(step)
valueDisplay.text = describe(step)
}
}
var pressedValue = slider.value
slider.setOnTouchListener { _, event ->
val drawer = emulationFragment.view?.findViewById<DrawerLayout>(R.id.drawer_layout)
when (event.action) {
MotionEvent.ACTION_DOWN -> {
drawer?.requestDisallowInterceptTouchEvent(true)
pressedValue = slider.value
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
drawer?.requestDisallowInterceptTouchEvent(false)
if (slider.value != pressedValue) {
onCommitted(slider.value.toInt())
}
}
}
false
}
container.addView(itemView)
}
fun addShaderCard(
index: Int,
title: String,
summary: String,
container: ViewGroup,
onRemove: () -> Unit
): ViewGroup {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val itemView = inflater.inflate(R.layout.item_quick_settings_shader, container, false)
val headerView = itemView.findViewById<ViewGroup>(R.id.shader_header)
val titleView = itemView.findViewById<TextView>(R.id.shader_title)
val summaryView = itemView.findViewById<TextView>(R.id.shader_summary)
val removeView = itemView.findViewById<android.widget.ImageView>(R.id.shader_remove)
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.shader_expand)
val bodyView = itemView.findViewById<ViewGroup>(R.id.shader_body)
titleView.text = title
if (summary.isEmpty()) {
summaryView.visibility = View.GONE
} else {
summaryView.text = summary
}
var isExpanded = expandedShaders.contains(index)
if (isExpanded) {
bodyView.visibility = View.VISIBLE
expandIcon.rotation = 180f
}
headerView.setOnClickListener {
isExpanded = !isExpanded
if (isExpanded) {
expandedShaders.add(index)
bodyView.visibility = View.VISIBLE
expandIcon.animate().rotation(180f).setDuration(200).start()
} else {
expandedShaders.remove(index)
bodyView.visibility = View.GONE
expandIcon.animate().rotation(0f).setDuration(200).start()
}
}
removeView.setOnClickListener {
onRemove()
}
container.addView(itemView)
return bodyView
}
fun addEffectPicker(
container: ViewGroup,
choices: List<String>,
hasEffects: Boolean,
onRemoveAll: () -> Unit,
onPicked: (Int) -> Unit
) {
val context = emulationFragment.requireContext()
val inflater = LayoutInflater.from(context)
val itemView = inflater.inflate(R.layout.item_quick_settings_add, container, false)
val button = itemView.findViewById<com.google.android.material.button.MaterialButton>(
R.id.add_button
)
val removeButton =
itemView.findViewById<com.google.android.material.button.MaterialButton>(
R.id.remove_all_button
)
val choiceGroup = itemView.findViewById<RadioGroup>(R.id.add_choices)
choices.forEachIndexed { index, name ->
val radioButton = com.google.android.material.radiobutton.MaterialRadioButton(context)
radioButton.text = name
radioButton.id = View.generateViewId()
radioButton.setPadding(16, 8, 16, 8)
radioButton.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
onPicked(index)
}
}
choiceGroup.addView(radioButton)
}
var closedLabel = R.string.post_processing_add
if (hasEffects) {
closedLabel = R.string.post_processing_open_list
removeButton.visibility = View.VISIBLE
}
button.setText(closedLabel)
val removeBackground = MaterialColors.getColor(
removeButton,
com.google.android.material.R.attr.colorErrorContainer
)
val removeForeground = MaterialColors.getColor(
removeButton,
com.google.android.material.R.attr.colorOnErrorContainer
)
removeButton.backgroundTintList = ColorStateList.valueOf(removeBackground)
removeButton.setTextColor(removeForeground)
removeButton.iconTint = ColorStateList.valueOf(removeForeground)
removeButton.setOnClickListener {
onRemoveAll()
}
val slide = context.resources.displayMetrics.density * 24.0f
var isOpen = false
button.setOnClickListener {
isOpen = !isOpen
if (isOpen) {
choiceGroup.alpha = 0.0f
choiceGroup.translationY = slide
choiceGroup.visibility = View.VISIBLE
choiceGroup.animate()
.alpha(1.0f)
.translationY(0.0f)
.setDuration(220)
.withEndAction {
choiceGroup.requestRectangleOnScreen(
Rect(0, 0, choiceGroup.width, choiceGroup.height),
false
)
}
.start()
button.setText(R.string.post_processing_close_list)
button.setIconResource(R.drawable.ic_clear)
} else {
choiceGroup.animate()
.alpha(0.0f)
.translationY(slide)
.setDuration(160)
.withEndAction {
choiceGroup.visibility = View.GONE
}
.start()
button.setText(closedLabel)
button.setIconResource(R.drawable.ic_add)
}
}
container.addView(itemView)
}
fun addPresetBand(container: ViewGroup, name: String, summary: String) {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val itemView = inflater.inflate(R.layout.item_quick_settings_preset, container, false)
val titleView = itemView.findViewById<TextView>(R.id.preset_title)
val summaryView = itemView.findViewById<TextView>(R.id.preset_summary)
val switchView = itemView.findViewById<MaterialSwitch>(R.id.preset_switch)
titleView.text = name
if (summary.isEmpty()) {
summaryView.visibility = View.GONE
} else {
summaryView.text = summary
}
switchView.isChecked = NativePostProcessing.isEnabled()
switchView.setOnCheckedChangeListener { _, checked ->
emulationFragment.editPostProcessing {
NativePostProcessing.setEnabled(checked)
}
}
container.addView(itemView)
}
fun addPostProcessing(container: ViewGroup, onStructureChanged: () -> Unit) {
val usable = NativePostProcessing.catalog().filter { it.valid }
if (usable.isEmpty()) {
return
}
val preset = NativePostProcessing.getActivePreset()
if (preset.isNotEmpty()) {
addDivider(container)
var summary = ""
val described = NativePostProcessing.presets().firstOrNull { it.name == preset }
if (described != null) {
summary = described.description
}
if (summary.isEmpty()) {
summary =
YuzuApplication.appContext.getString(R.string.post_processing_preset_locked)
}
if (NativePostProcessing.isPresetModified()) {
summary = summary + "\n" +
YuzuApplication.appContext.getString(R.string.post_processing_preset_modified)
}
addPresetBand(container, preset, summary)
return
}
val labels = mutableListOf<String>()
val files = mutableListOf<String>()
val techniques = mutableListOf<String>()
for (effect in usable) {
for (technique in effect.techniques) {
var label = effect.label
if (effect.techniques.size > 1) {
label = effect.label + " \u00b7 " + technique
}
labels.add(label)
files.add(effect.file)
techniques.add(technique)
}
}
addDivider(container)
val chain = NativePostProcessing.chain()
chain.forEachIndexed { index, entry ->
val effect = usable.firstOrNull { it.file == entry.file }
var title = entry.file
var summary = ""
if (effect != null) {
title = effect.label
if (effect.techniques.size > 1) {
title = effect.label + " \u00b7 " + entry.technique
}
summary = effect.description
}
val body = addShaderCard(index, title, summary, container) {
emulationFragment.editPostProcessing {
NativePostProcessing.remove(index)
}
forgetShaderSlot(index)
onStructureChanged()
}
if (effect != null) {
for (uniform in effect.uniforms) {
addUniformSliders(body, index, uniform)
}
}
}
addEffectPicker(
container,
labels,
chain.isNotEmpty(),
{
emulationFragment.editPostProcessing {
NativePostProcessing.clearChain()
}
expandedShaders.clear()
onStructureChanged()
}
) { picked ->
emulationFragment.editPostProcessing {
NativePostProcessing.append(files[picked], techniques[picked])
}
onStructureChanged()
}
}
private fun addUniformSliders(
container: ViewGroup,
index: Int,
uniform: NativePostProcessing.Uniform
) {
if (uniform.uiType == NativePostProcessing.UI_HIDDEN) {
return
}
for (component in 0 until uniform.components) {
var title = uniform.label
if (uniform.components > 1) {
title = uniform.label + " [" + component + "]"
}
var value = uniform.defaultAt(component)
if (NativePostProcessing.hasValue(index, uniform.name)) {
value = NativePostProcessing.getValue(index, uniform.name, component)
}
val steps = uniform.steps
val step = Math.round((value - uniform.min) / uniform.step)
addStepSlider(
title,
container,
steps,
step,
{ position -> uniform.describe(position) },
{ emulationFragment.persistPostProcessing() }
) { position ->
NativePostProcessing.setValue(
index,
uniform.name,
component,
uniform.min + position * uniform.step
)
}
}
}
fun addDivider(container: ViewGroup) {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val dividerView = inflater.inflate(R.layout.item_quick_settings_divider, container, false)
@@ -83,7 +83,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
SHOW_SHADERS_BUILDING("show_shaders_building"),
DEBUG_FLUSH_BY_LINE("flush_line"),
EXTENDED_LOGGING("extended_logging"),
DONT_SHOW_DRIVER_SHADER_WARNING("dont_show_driver_shader_warning"),
ENABLE_OVERLAY("enable_overlay"),
@@ -1,36 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model
class FxPresetNameSetting(private val onNamed: (String) -> Unit) : AbstractStringSetting {
override val key: String
get() = "fx_preset_name"
override val defaultValue: Any
get() = ""
override val isRuntimeModifiable: Boolean
get() = true
override val pairedSettingKey: String
get() = ""
override val isSwitchable: Boolean
get() = false
override val isSaveable: Boolean
get() = true
override var global: Boolean
get() = true
set(_) {}
override fun getString(needsGlobal: Boolean): String = ""
override fun setString(value: String) = onNamed(value)
override fun getValueAsString(needsGlobal: Boolean): String = ""
override fun reset() {}
}
@@ -1,67 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model
import org.yuzu.yuzu_emu.utils.NativePostProcessing
import kotlin.math.roundToInt
abstract class FxUniformSetting(
protected val index: Int,
protected val uniform: NativePostProcessing.Uniform,
protected val component: Int
) : AbstractSetting {
override val key: String
get() = "fx_${index}_${uniform.name}_$component"
override val isRuntimeModifiable: Boolean
get() = true
override val pairedSettingKey: String
get() = ""
override val isSwitchable: Boolean
get() = false
override val isSaveable: Boolean
get() = true
override var global: Boolean
get() = true
set(_) {}
protected fun currentValue(): Float {
if (NativePostProcessing.hasValue(index, uniform.name)) {
return NativePostProcessing.getValue(index, uniform.name, component)
}
return uniform.defaultAt(component)
}
protected fun commit(value: Float) {
NativePostProcessing.setValue(index, uniform.name, component, value)
NativePostProcessing.store()
}
override fun reset() = commit(uniform.defaultAt(component))
}
class FxUniformSliderSetting(
index: Int,
uniform: NativePostProcessing.Uniform,
component: Int
) : FxUniformSetting(index, uniform, component), AbstractIntSetting {
override val defaultValue: Any
get() = ((uniform.defaultAt(component) - uniform.min) / uniform.step).roundToInt()
override fun getInt(needsGlobal: Boolean): Int =
((currentValue() - uniform.min) / uniform.step).roundToInt()
override fun setInt(value: Int) = commit(uniform.min + value * uniform.step)
override fun getValueAsString(needsGlobal: Boolean): String {
if (uniform.kind == NativePostProcessing.KIND_FLOAT) {
return String.format("%.3f", currentValue())
}
return currentValue().roundToInt().toString()
}
}
@@ -12,7 +12,6 @@ object Settings {
SECTION_SYSTEM(R.string.preferences_system),
SECTION_RENDERER(R.string.preferences_graphics),
SECTION_FRAME_GEN(R.string.frame_gen),
SECTION_POST_PROCESSING(R.string.post_processing),
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
@@ -13,7 +13,6 @@ enum class StringSetting(override val key: String) : AbstractStringSetting {
DEVICE_NAME("device_name"),
LOG_FILTER("log_filter"),
PROGRAM_ARGS("program_args"),
POST_SHADER_CHAIN("post_shader_chain"),
WEB_TOKEN("eden_token"),
WEB_USERNAME("eden_username")
@@ -1,13 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import androidx.annotation.StringRes
class FxButtonSetting(
@StringRes titleId: Int,
val onClick: () -> Unit
) : SettingsItem(emptySetting, titleId, "", 0, "") {
override val type = TYPE_FX_BUTTON
}
@@ -1,14 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
class FxPresetSetting(
titleString: String,
descriptionString: String = "",
val deletable: Boolean = false,
val onApply: () -> Unit,
val onDelete: () -> Unit = {}
) : SettingsItem(emptySetting, 0, titleString, 0, descriptionString) {
override val type = TYPE_FX_PRESET
}
@@ -1,19 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import org.yuzu.yuzu_emu.utils.NativePostProcessing
class FxShaderCardSetting(
titleString: String,
descriptionString: String,
val index: Int,
val expanded: Boolean,
val uniforms: List<NativePostProcessing.Uniform>,
val onToggle: () -> Unit,
val onRemove: () -> Unit,
val onReset: () -> Unit
) : SettingsItem(emptySetting, 0, titleString, 0, descriptionString) {
override val type = TYPE_FX_SHADER
}
@@ -1,19 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import androidx.annotation.StringRes
class FxToolbarSetting(
@StringRes val addLabelId: Int,
val listOpen: Boolean,
val presetLabel: String,
val hasEffects: Boolean,
val createPreset: StringInputSetting,
val onAdd: () -> Unit,
val onPresets: () -> Unit,
val onRemoveAll: () -> Unit
) : SettingsItem(emptySetting, 0, "", 0, "") {
override val type = TYPE_FX_TOOLBAR
}
@@ -144,10 +144,6 @@ abstract class SettingsItem(
const val TYPE_LAUNCHABLE = 13
const val TYPE_PATH = 14
const val TYPE_GPU_UNSWIZZLE = 15
const val TYPE_FX_TOOLBAR = 16
const val TYPE_FX_PRESET = 17
const val TYPE_FX_SHADER = 18
const val TYPE_FX_BUTTON = 19
const val FASTMEM_COMBINED = "fastmem_combined"
const val GPU_UNSWIZZLE_COMBINED = "gpu_unswizzle_combined"
@@ -266,13 +262,6 @@ abstract class SettingsItem(
descriptionId = R.string.flush_by_line_description
)
)
put(
SwitchSetting(
BooleanSetting.EXTENDED_LOGGING,
titleId = R.string.extended_logging,
descriptionId = R.string.extended_logging_description
)
)
val dockedModeSetting = object : AbstractBooleanSetting {
override val key = BooleanSetting.USE_DOCKED_MODE.key
@@ -23,10 +23,6 @@ import com.google.android.material.timepicker.TimeFormat
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.SettingsNavigationDirections
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxButtonBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxPresetBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxShaderBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxToolbarBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingInputBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding
@@ -110,34 +106,6 @@ class SettingsAdapter(
GpuUnswizzleViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
SettingsItem.TYPE_FX_TOOLBAR -> {
FxToolbarViewHolder(
ListItemSettingFxToolbarBinding.inflate(inflater, parent, false),
this
)
}
SettingsItem.TYPE_FX_PRESET -> {
FxPresetViewHolder(
ListItemSettingFxPresetBinding.inflate(inflater, parent, false),
this
)
}
SettingsItem.TYPE_FX_SHADER -> {
FxShaderCardViewHolder(
ListItemSettingFxShaderBinding.inflate(inflater, parent, false),
this
)
}
SettingsItem.TYPE_FX_BUTTON -> {
FxButtonViewHolder(
ListItemSettingFxButtonBinding.inflate(inflater, parent, false),
this
)
}
else -> {
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
}
@@ -18,7 +18,6 @@ import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.FxPresetNameSetting
import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
@@ -31,7 +30,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.NativePostProcessing
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FullscreenHelper
import androidx.core.content.edit
@@ -46,14 +44,6 @@ class SettingsFragmentPresenter(
) {
private var settingsList = ArrayList<SettingsItem>()
private val expandedShaderSlots = mutableSetOf<Int>()
private var shaderPickerOpen = false
private var presetPickerOpen = false
private var postProcessingSynced = false
private val context get() = YuzuApplication.appContext
// Extension for altering settings list based on each setting's properties
@@ -173,7 +163,6 @@ class SettingsFragmentPresenter(
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl)
MenuTag.SECTION_POST_PROCESSING -> addPostProcessingSettings(sl)
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
@@ -201,209 +190,6 @@ class SettingsFragmentPresenter(
}
}
private fun addPostProcessingSettings(sl: ArrayList<SettingsItem>) {
if (!postProcessingSynced) {
postProcessingSynced = true
NativePostProcessing.reload()
}
val usable = NativePostProcessing.catalog().filter { it.valid }
sl.apply {
if (usable.isEmpty()) {
add(
RunnableSetting(
titleId = R.string.post_processing_empty,
descriptionString = NativePostProcessing.getShaderDirectory(),
isRunnable = false
) {}
)
return@apply
}
val labels = mutableListOf<String>()
val summaries = mutableListOf<String>()
val files = mutableListOf<String>()
val techniques = mutableListOf<String>()
for (effect in usable) {
for (technique in effect.techniques) {
if (effect.techniques.size == 1) {
labels.add(effect.label)
} else {
labels.add(effect.label + " \u00b7 " + technique)
}
summaries.add(effect.description)
files.add(effect.file)
techniques.add(technique)
}
}
val chain = NativePostProcessing.chain()
val active = NativePostProcessing.getActivePreset()
var addLabel = R.string.post_processing_add
if (chain.isNotEmpty()) {
addLabel = R.string.post_processing_open_list
}
if (shaderPickerOpen) {
addLabel = R.string.post_processing_close_list
}
var presetLabel = context.getString(R.string.post_processing_presets)
if (active.isNotEmpty()) {
presetLabel = active
}
val createPreset = StringInputSetting(
setting = FxPresetNameSetting { name ->
NativePostProcessing.savePreset(name, "")
settingsViewModel.setReloadListAndNotifyDataset(true)
},
titleId = R.string.post_processing_preset_new,
descriptionId = R.string.post_processing_preset_new_description,
validator = { it != null && it.isNotBlank() && !it.contains('=') },
errorId = R.string.post_processing_preset_name_invalid
)
add(
FxToolbarSetting(
addLabelId = addLabel,
listOpen = shaderPickerOpen,
presetLabel = presetLabel,
hasEffects = chain.isNotEmpty(),
createPreset = createPreset,
onAdd = {
shaderPickerOpen = !shaderPickerOpen
presetPickerOpen = false
settingsViewModel.setReloadListAndNotifyDataset(true)
},
onPresets = {
presetPickerOpen = !presetPickerOpen
shaderPickerOpen = false
settingsViewModel.setReloadListAndNotifyDataset(true)
},
onRemoveAll = {
NativePostProcessing.clearChain()
NativePostProcessing.clearPreset()
NativePostProcessing.store()
expandedShaderSlots.clear()
shaderPickerOpen = false
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
)
if (shaderPickerOpen) {
for (choice in labels.indices) {
add(
RunnableSetting(
titleString = labels[choice],
descriptionString = summaries[choice],
isRunnable = true
) {
NativePostProcessing.append(files[choice], techniques[choice])
NativePostProcessing.store()
shaderPickerOpen = false
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
}
if (presetPickerOpen) {
add(
FxPresetSetting(
titleString = context.getString(R.string.post_processing_preset_none),
onApply = {
NativePostProcessing.clearPreset()
presetPickerOpen = false
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
)
for (preset in NativePostProcessing.presets()) {
add(
FxPresetSetting(
titleString = preset.name,
descriptionString = preset.description,
deletable = !preset.bundled,
onApply = {
NativePostProcessing.applyPreset(preset.name)
NativePostProcessing.store()
presetPickerOpen = false
expandedShaderSlots.clear()
settingsViewModel.setReloadListAndNotifyDataset(true)
},
onDelete = {
NativePostProcessing.deletePreset(preset.name)
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
)
}
}
if (active.isNotEmpty()) {
add(
FxButtonSetting(titleId = R.string.post_processing_preset_reset) {
NativePostProcessing.applyPreset(active)
NativePostProcessing.store()
expandedShaderSlots.clear()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
for (index in chain.indices) {
val entry = chain[index]
val effect = usable.firstOrNull { it.file == entry.file }
var header = entry.file
var summary = ""
var uniforms = emptyList<NativePostProcessing.Uniform>()
if (effect != null) {
header = effect.label
if (effect.techniques.size > 1) {
header = effect.label + " \u00b7 " + entry.technique
}
summary = effect.description
uniforms = effect.uniforms
}
val isOpen = expandedShaderSlots.contains(index)
add(
FxShaderCardSetting(
titleString = header,
descriptionString = summary,
index = index,
expanded = isOpen,
uniforms = uniforms,
onToggle = {
if (isOpen) {
expandedShaderSlots.remove(index)
} else {
expandedShaderSlots.add(index)
}
settingsViewModel.setReloadListAndNotifyDataset(true)
},
onRemove = {
NativePostProcessing.remove(index)
NativePostProcessing.store()
expandedShaderSlots.clear()
settingsViewModel.setReloadListAndNotifyDataset(true)
},
onReset = {
NativePostProcessing.resetValues(index)
NativePostProcessing.store()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
)
}
}
}
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
sl.apply {
add(
@@ -1537,7 +1323,6 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.log))
add(BooleanSetting.DEBUG_FLUSH_BY_LINE.key)
add(BooleanSetting.EXTENDED_LOGGING.key)
add(StringSetting.LOG_FILTER.key)
}
@@ -1,28 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxButtonBinding
import org.yuzu.yuzu_emu.features.settings.model.view.FxButtonSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
class FxButtonViewHolder(
val binding: ListItemSettingFxButtonBinding,
adapter: SettingsAdapter
) : SettingViewHolder(binding.root, adapter) {
private lateinit var setting: FxButtonSetting
override fun bind(item: SettingsItem) {
setting = item as FxButtonSetting
binding.fxButton.text = item.title
binding.fxButton.setOnClickListener { setting.onClick.invoke() }
}
override fun onClick(clicked: View) {}
override fun onLongClick(clicked: View): Boolean = true
}
@@ -1,35 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxPresetBinding
import org.yuzu.yuzu_emu.features.settings.model.view.FxPresetSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class FxPresetViewHolder(
val binding: ListItemSettingFxPresetBinding,
adapter: SettingsAdapter
) : SettingViewHolder(binding.root, adapter) {
private lateinit var setting: FxPresetSetting
override fun bind(item: SettingsItem) {
setting = item as FxPresetSetting
binding.presetName.text = item.title
binding.presetDescription.text = item.description
binding.presetDescription.setVisible(item.description.isNotEmpty())
binding.presetRow.setOnClickListener { setting.onApply.invoke() }
binding.presetDelete.setVisible(setting.deletable)
binding.presetDelete.setOnClickListener { setting.onDelete.invoke() }
}
override fun onClick(clicked: View) {}
override fun onLongClick(clicked: View): Boolean = true
}
@@ -1,100 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.LayoutInflater
import android.view.View
import org.yuzu.yuzu_emu.databinding.ItemSettingFxActionsBinding
import org.yuzu.yuzu_emu.databinding.ItemSettingFxSliderBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxShaderBinding
import org.yuzu.yuzu_emu.features.settings.model.FxUniformSliderSetting
import org.yuzu.yuzu_emu.features.settings.model.view.FxShaderCardSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativePostProcessing
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class FxShaderCardViewHolder(
val binding: ListItemSettingFxShaderBinding,
adapter: SettingsAdapter
) : SettingViewHolder(binding.root, adapter) {
private lateinit var setting: FxShaderCardSetting
override fun bind(item: SettingsItem) {
setting = item as FxShaderCardSetting
binding.shaderTitle.text = item.title
binding.shaderSummary.text = item.description
binding.shaderSummary.setVisible(item.description.isNotEmpty())
var rotation = 0f
if (setting.expanded) {
rotation = 180f
}
binding.shaderExpand.rotation = rotation
binding.shaderHeader.setOnClickListener { setting.onToggle.invoke() }
binding.shaderRemove.setOnClickListener { setting.onRemove.invoke() }
binding.shaderBody.removeAllViews()
binding.shaderBody.setVisible(setting.expanded)
if (!setting.expanded) {
return
}
val inflater = LayoutInflater.from(binding.root.context)
for (uniform in setting.uniforms) {
if (uniform.uiType == NativePostProcessing.UI_HIDDEN) {
continue
}
for (component in 0 until uniform.components) {
addSlider(inflater, uniform, component)
}
}
addActions(inflater)
}
private fun addSlider(
inflater: LayoutInflater,
uniform: NativePostProcessing.Uniform,
component: Int
) {
val row = ItemSettingFxSliderBinding.inflate(inflater, binding.shaderBody, false)
val value = FxUniformSliderSetting(setting.index, uniform, component)
var title = uniform.label
if (uniform.components > 1) {
title = uniform.label + " [" + component + "]"
}
row.fxSliderTitle.text = title
val steps = uniform.steps.toFloat()
row.fxSlider.valueFrom = 0f
row.fxSlider.valueTo = steps
row.fxSlider.stepSize = 1f
row.fxSlider.value = value.getInt(false).toFloat().coerceIn(0f, steps)
row.fxSliderValue.text = uniform.describe(row.fxSlider.value.toInt())
row.fxSlider.addOnChangeListener { _, position, fromUser ->
if (fromUser) {
value.setInt(position.toInt())
row.fxSliderValue.text = uniform.describe(position.toInt())
}
}
binding.shaderBody.addView(row.root)
}
private fun addActions(inflater: LayoutInflater) {
val row = ItemSettingFxActionsBinding.inflate(inflater, binding.shaderBody, false)
row.fxReset.setOnClickListener { setting.onReset.invoke() }
binding.shaderBody.addView(row.root)
}
override fun onClick(clicked: View) {}
override fun onLongClick(clicked: View): Boolean = true
}
@@ -1,57 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.content.res.ColorStateList
import android.view.View
import com.google.android.material.color.MaterialColors
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxToolbarBinding
import org.yuzu.yuzu_emu.features.settings.model.view.FxToolbarSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
class FxToolbarViewHolder(
val binding: ListItemSettingFxToolbarBinding,
adapter: SettingsAdapter
) : SettingViewHolder(binding.root, adapter) {
private lateinit var setting: FxToolbarSetting
override fun bind(item: SettingsItem) {
setting = item as FxToolbarSetting
binding.fxAdd.setText(setting.addLabelId)
var addIcon = R.drawable.ic_add
if (setting.listOpen) {
addIcon = R.drawable.ic_clear
}
binding.fxAdd.setIconResource(addIcon)
binding.fxAdd.setOnClickListener { setting.onAdd.invoke() }
binding.fxPresets.text = setting.presetLabel
binding.fxPresets.setOnClickListener { setting.onPresets.invoke() }
binding.fxCreatePreset.isEnabled = setting.hasEffects
binding.fxCreatePreset.setOnClickListener {
adapter.onStringInputClick(setting.createPreset, bindingAdapterPosition)
}
val removeBackground = MaterialColors.getColor(
binding.fxRemoveAll,
com.google.android.material.R.attr.colorErrorContainer
)
val removeForeground = MaterialColors.getColor(
binding.fxRemoveAll,
com.google.android.material.R.attr.colorOnErrorContainer
)
binding.fxRemoveAll.backgroundTintList = ColorStateList.valueOf(removeBackground)
binding.fxRemoveAll.iconTint = ColorStateList.valueOf(removeForeground)
binding.fxRemoveAll.isEnabled = setting.hasEffects
binding.fxRemoveAll.setOnClickListener { setting.onRemoveAll.invoke() }
}
override fun onClick(clicked: View) {}
override fun onLongClick(clicked: View): Boolean = true
}
@@ -94,7 +94,6 @@ import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
import org.yuzu.yuzu_emu.utils.NativePostProcessing
import org.yuzu.yuzu_emu.utils.ViewUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
@@ -884,8 +883,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (shouldUseCustom) {
SettingsFile.loadCustomConfig(game!!)
}
refreshPostProcessing()
addQuickSettings()
}
}
@@ -1090,34 +1087,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
private fun withPerGameConfig(create: Boolean, action: () -> Unit) {
val target = game
var owned = false
if (target != null && !NativeConfig.isPerGameConfigLoaded()) {
if (create || SettingsFile.getCustomSettingsFile(target).exists()) {
SettingsFile.loadCustomConfig(target)
owned = true
}
}
action()
if (owned) {
NativeConfig.unloadPerGameConfig()
}
}
fun refreshPostProcessing() = withPerGameConfig(false) {
NativePostProcessing.reload()
}
fun persistPostProcessing() = withPerGameConfig(true) {
NativePostProcessing.persist()
}
fun editPostProcessing(action: () -> Unit) = withPerGameConfig(true) {
action()
NativePostProcessing.persist()
}
private fun addQuickSettings() {
binding.quickSettingsSheet.apply {
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
@@ -1225,10 +1194,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
R.array.rendererAntiAliasingNames,
R.array.rendererAntiAliasingValues
)
quickSettings.addPostProcessing(container) {
addQuickSettings()
}
}
}
@@ -383,20 +383,6 @@ class GamePropertiesFragment : Fragment() {
}
)
)
add(
SubmenuProperty(
R.string.post_processing,
R.string.post_processing_per_game_description,
R.drawable.ic_post_processing,
action = {
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
args.game,
Settings.MenuTag.SECTION_POST_PROCESSING
)
binding.root.findNavController().navigate(action)
}
)
)
if (GpuDriverHelper.isAdrenoGpu()) {
add(
@@ -171,20 +171,6 @@ class HomeSettingsFragment : Fragment() {
)
)
}
add(
HomeSetting(
R.string.post_processing,
R.string.post_processing_description,
R.drawable.ic_post_processing,
{
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
null,
Settings.MenuTag.SECTION_POST_PROCESSING
)
binding.root.findNavController().navigate(action)
}
)
)
add(
HomeSetting(
R.string.lossless_scaling,

Some files were not shown because too many files have changed in this diff Show More