Compare commits

...

15 Commits

Author SHA1 Message Date
wildcard 213a9a7813 [host_shaders] Store the value of results instead of discarding it
the function generated the value but we never stored it effectively discarding the result.
2026-02-04 22:13:11 +01:00
wildcard 48ba1f3f24 [vk, cmake] Bump minimum VulkanTools to 1.4.317 and add UnifiedImageLayouts (#3318)
It seems too easy, the specification does not state anything more to be done for it towork.
Requires performance testing on android.

Co-authored-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3318
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-02-04 19:15:10 +01:00
crueter d59fcf01bf [frontend] Generate web token at runtime (#3462)
Rather than having that hardcoded one like before. Also adds
infrastructure which should make it easier to setup defaults at runtime
(e.g. GPU stuff?)

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3462
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2026-02-04 04:16:39 +01:00
PavelBARABANOV b8456394f1 [spirv] Fix F16 conversion on Android (skip NaN check) (#3458)
Fixes the yellow texture issue in Outer Wilds on Android.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3458
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
Co-committed-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
2026-02-04 00:44:03 +01:00
wildcard a467dd1ba6 [vk] fix flickering caused by recent swizzle changes (#3457)
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3457
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-02-04 00:37:58 +01:00
lizzie c156f4760f [meta] update codeowners (#3460)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3460
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-02-03 23:42:53 +01:00
MaranBr 13f11ebf49 [nvnflinger] Reimplement GetBufferHistory (#3394)
Reimplements GetBufferHistory, enabling tracking and retrieval of recent buffer states. This can improve rendering performance and stability in some games.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3394
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2026-02-03 18:25:15 +01:00
xbzk 6065e9aa09 [cmake] Reduce spam on builds for MSVC (#3454)
Fix for disable-warning-as-error flags set for MSVC not CLANG dripping into externals and causing override warnings on Ninja (cl)

Signed-off-by: xbzk <xbzk@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3454
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-02-03 13:53:07 +01:00
crueter 8ed0ed5828 [desktop] Add smooth scrolling and shift scrolling to game list (#3452)
Intercepts Qt's awful scroll wheel handling and passes it off to a
continuously self-integrating animation on the scroll bar positions.
Code kind of sucks right now and I think has a bit of a perf bottleneck,
but that's somewhat expected in the way I implemented it. Maybe look for
a better sln? QScroller?

Also while I was at it I added shift scrolling.

TODO:
- [ ] TouchGesture? With overshoot off
- [ ] Perf

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3452
2026-02-02 19:07:12 +01:00
crueter 33067af283 [settings] Disable GPU logging by default (#3455)
Why was this enabled?

Signed-off-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3455
Reviewed-by: DraVee <dravee@eden-emu.dev>
2026-02-02 19:00:44 +01:00
crueter d0a054270e [cmake] Move back to individual handling of Vulkan deps (#3450)
VUL version mismatches are solved upstream. Anything else is user error,
not that the prior solution really helped let's be real.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3450
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: DraVee <dravee@eden-emu.dev>
2026-02-02 06:54:58 +01:00
crueter 2a3507c2b9 [cmake] Move Qt externals handling to root CMakeLists.txt, and move QuaZip to upstream (#3447)
QuaZip lets you disable QTextCodec now so we can use it.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3447
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2026-02-02 06:17:57 +01:00
crueter f71f43561d [externals] Update zlib, httplib, and catch2 (#3449)
whynot

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3449
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2026-02-02 06:17:41 +01:00
crueter ecbfad4193 [externals] Update Boost to 1.90.0 (#3448)
Removes the need for those MSVC/ARM patches

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3448
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2026-02-02 06:12:36 +01:00
nekle d76b2b5d26 [android] add toggle for quick settings to hide it and fix setting names (#3435)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3435
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: nekle <nekle@protonmail.com>
Co-committed-by: nekle <nekle@protonmail.com>
2026-02-02 06:07:26 +01:00
44 changed files with 750 additions and 421 deletions
-11
View File
@@ -1,11 +0,0 @@
--- a/libs/context/CMakeLists.txt 2025-09-08 00:42:31.303651800 -0400
+++ b/libs/context/CMakeLists.txt 2025-09-08 00:42:40.592184300 -0400
@@ -146,7 +146,7 @@
set(ASM_LANGUAGE ASM)
endif()
elseif(BOOST_CONTEXT_ASSEMBLER STREQUAL armasm)
- set(ASM_LANGUAGE ASM_ARMASM)
+ set(ASM_LANGUAGE ASM_MARMASM)
else()
set(ASM_LANGUAGE ASM_MASM)
endif()
-14
View File
@@ -1,14 +0,0 @@
diff --git a/libs/context/CMakeLists.txt b/libs/context/CMakeLists.txt
index 8210f65..0e59dd7 100644
--- a/libs/context/CMakeLists.txt
+++ b/libs/context/CMakeLists.txt
@@ -186,7 +186,8 @@ if(BOOST_CONTEXT_IMPLEMENTATION STREQUAL "fcontext")
set_property(SOURCE ${ASM_SOURCES} APPEND PROPERTY COMPILE_OPTIONS "/safeseh")
endif()
- else() # masm
+ # armasm doesn't support most of these options
+ elseif(NOT BOOST_CONTEXT_ASSEMBLER STREQUAL armasm) # masm
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_property(SOURCE ${ASM_SOURCES} APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+24 -14
View File
@@ -1,52 +1,62 @@
From e1a946ffb79022d38351a0623f819a5419965c3e Mon Sep 17 00:00:00 2001
From 436fc1978c78edd085d99b33275b24be0ac96aa0 Mon Sep 17 00:00:00 2001
From: crueter <crueter@eden-emu.dev>
Date: Fri, 24 Oct 2025 23:41:09 -0700
Subject: [PATCH] [build] Fix MinGW missing GetAddrInfoExCancel definition
Date: Sun, 1 Feb 2026 16:21:10 -0500
Subject: [PATCH] Fix build on MinGW
MinGW does not define GetAddrInfoExCancel in its wstcpi whatever header,
so to get around this we can just load it with GetProcAddress et al.
MinGW doesn't define GetAddrInfoExCancel.
Signed-off-by: crueter <crueter@eden-emu.dev>
---
httplib.h | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
httplib.h | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/httplib.h b/httplib.h
index e15ba44..90a76dc 100644
index ec8d2a2..5f9a510 100644
--- a/httplib.h
+++ b/httplib.h
@@ -203,11 +203,13 @@
@@ -203,14 +203,17 @@
#error Sorry, Visual Studio versions prior to 2015 are not supported
#endif
-#pragma comment(lib, "ws2_32.lib")
-
#ifndef _SSIZE_T_DEFINED
using ssize_t = __int64;
#define _SSIZE_T_DEFINED
#endif
#endif // _MSC_VER
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#pragma comment(lib, "ws2_32.lib")
+#endif
+
+
#ifndef S_ISREG
#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
#endif // S_ISREG
@@ -3557,7 +3559,15 @@ inline int getaddrinfo_with_timeout(const char *node, const char *service,
@@ -4528,7 +4531,17 @@ inline int getaddrinfo_with_timeout(const char *node, const char *service,
auto wait_result =
::WaitForSingleObject(event, static_cast<DWORD>(timeout_sec * 1000));
if (wait_result == WAIT_TIMEOUT) {
+#ifdef __MINGW32__
+ typedef INT (WSAAPI *PFN_GETADDRINFOEXCANCEL)(HANDLE *CancelHandle);
+ auto wsdll = LoadLibraryW((wchar_t*) "ws2_32.lib");
+ PFN_GETADDRINFOEXCANCEL GetAddrInfoExCancel = (PFN_GETADDRINFOEXCANCEL) GetProcAddress(wsdll, "GetAddrInfoExCancel");
+ typedef INT(WSAAPI * PFN_GETADDRINFOEXCANCEL)(HANDLE * CancelHandle);
+ auto wsdll = LoadLibraryW((wchar_t *)"ws2_32.lib");
+ PFN_GETADDRINFOEXCANCEL GetAddrInfoExCancel =
+ (PFN_GETADDRINFOEXCANCEL)GetProcAddress(wsdll, "GetAddrInfoExCancel");
+
+ if (cancel_handle) { GetAddrInfoExCancel(&cancel_handle); }
+#else
if (cancel_handle) { ::GetAddrInfoExCancel(&cancel_handle); }
+#endif
+
::CloseHandle(event);
return EAI_AGAIN;
}
@@ -13952,3 +13965,4 @@ inline SSL_CTX *Client::ssl_context() const {
} // namespace httplib
#endif // CPPHTTPLIB_HTTPLIB_H
+
--
2.51.0
2.51.2
+9 -1
View File
@@ -178,7 +178,9 @@ endif()
# Disable Warnings as Errors for MSVC
if (MSVC AND NOT CXX_CLANG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /WX-")
# This was dripping into spirv, being overriden, and causing cl flag override warning
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /WX-")
set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} /W3 /WX-")
endif()
# Set bundled sdl2/qt as dependent options.
@@ -587,6 +589,7 @@ if (NOT YUZU_STATIC_ROOM)
find_package(sirit)
find_package(gamemode)
find_package(mcl)
find_package(frozen)
if (ARCHITECTURE_riscv64)
find_package(biscuit)
@@ -693,6 +696,11 @@ if (ENABLE_QT)
set(QT_MAJOR_VERSION 6)
# Qt6 sets cxx_std_17 and we need to undo that
set_target_properties(Qt6::Platform PROPERTIES INTERFACE_COMPILE_FEATURES "")
## Qt Externals ##
# QuaZip
AddJsonPackage(quazip)
endif()
if (NOT YUZU_STATIC_ROOM AND NOT (YUZU_USE_BUNDLED_FFMPEG OR YUZU_USE_EXTERNAL_FFMPEG))
+192 -125
View File
@@ -41,6 +41,11 @@ function(cpm_utils_message level name message)
message(${level} "[CPMUtil] ${name}: ${message}")
endfunction()
# propagate a variable to parent scope
macro(Propagate var)
set(${var} ${${var}} PARENT_SCOPE)
endmacro()
function(array_to_list array length out)
math(EXPR range "${length} - 1")
@@ -72,6 +77,159 @@ function(get_json_element object out member default)
set("${out}" "${outvar}" PARENT_SCOPE)
endfunction()
# Determine whether or not a package has a viable system candidate.
function(SystemPackageViable JSON_NAME)
string(JSON object GET "${CPMFILE_CONTENT}" "${JSON_NAME}")
parse_object(${object})
string(REPLACE " " ";" find_args "${find_args}")
find_package(${package} ${version} ${find_args} QUIET NO_POLICY_SCOPE)
set(${pkg}_VIABLE ${${package}_FOUND} PARENT_SCOPE)
set(${pkg}_PACKAGE ${package} PARENT_SCOPE)
endfunction()
# Add several packages such that if one is bundled,
# all the rest must also be bundled.
function(AddDependentPackages)
set(_some_system OFF)
set(_some_bundled OFF)
foreach(pkg ${ARGN})
SystemPackageViable(${pkg})
if (${pkg}_VIABLE)
set(_some_system ON)
list(APPEND _system_pkgs ${${pkg}_PACKAGE})
else()
set(_some_bundled ON)
list(APPEND _bundled_pkgs ${${pkg}_PACKAGE})
endif()
endforeach()
if (_some_system AND _some_bundled)
foreach(pkg ${ARGN})
list(APPEND package_names ${${pkg}_PACKAGE})
endforeach()
string(REPLACE ";" ", " package_names "${package_names}")
string(REPLACE ";" ", " bundled_names "${_bundled_pkgs}")
foreach(sys ${_system_pkgs})
list(APPEND system_names ${sys}_FORCE_BUNDLED)
endforeach()
string(REPLACE ";" ", " system_names "${system_names}")
message(FATAL_ERROR "Partial dependency installation detected "
"for the following packages:\n${package_names}\n"
"You can solve this in one of two ways:\n"
"1. Install the following packages to your system if available:"
"\n\t${bundled_names}\n"
"2. Set the following variables to ON:"
"\n\t${system_names}\n"
"This may also be caused by a version mismatch, "
"such as one package being newer than the other.")
endif()
foreach(pkg ${ARGN})
AddJsonPackage(${pkg})
endforeach()
endfunction()
# json util
macro(parse_object object)
get_json_element("${object}" package package ${JSON_NAME})
get_json_element("${object}" repo repo "")
get_json_element("${object}" ci ci OFF)
get_json_element("${object}" version version "")
if(ci)
get_json_element("${object}" name name "${JSON_NAME}")
get_json_element("${object}" extension extension "tar.zst")
get_json_element("${object}" min_version min_version "")
get_json_element("${object}" raw_disabled disabled_platforms "")
if(raw_disabled)
array_to_list("${raw_disabled}"
${raw_disabled_LENGTH} disabled_platforms)
else()
set(disabled_platforms "")
endif()
else()
get_json_element("${object}" hash hash "")
get_json_element("${object}" hash_suffix hash_suffix "")
get_json_element("${object}" sha sha "")
get_json_element("${object}" url url "")
get_json_element("${object}" key key "")
get_json_element("${object}" tag tag "")
get_json_element("${object}" artifact artifact "")
get_json_element("${object}" git_version git_version "")
get_json_element("${object}" git_host git_host "")
get_json_element("${object}" source_subdir source_subdir "")
get_json_element("${object}" bundled bundled "unset")
get_json_element("${object}" find_args find_args "")
get_json_element("${object}" raw_patches patches "")
# okay here comes the fun part: REPLACEMENTS!
# first: tag gets %VERSION% replaced if applicable,
# with either git_version (preferred) or version
# second: artifact gets %VERSION% and %TAG% replaced
# accordingly (same rules for VERSION)
if(git_version)
set(version_replace ${git_version})
else()
set(version_replace ${version})
endif()
# TODO(crueter): fmt module for cmake
if(tag)
string(REPLACE "%VERSION%" "${version_replace}" tag ${tag})
endif()
if(artifact)
string(REPLACE "%VERSION%" "${version_replace}"
artifact ${artifact})
string(REPLACE "%TAG%" "${tag}" artifact ${artifact})
endif()
# format patchdir
if(raw_patches)
math(EXPR range "${raw_patches_LENGTH} - 1")
foreach(IDX RANGE ${range})
string(JSON _patch GET "${raw_patches}" "${IDX}")
set(full_patch
"${PROJECT_SOURCE_DIR}/.patch/${JSON_NAME}/${_patch}")
if(NOT EXISTS ${full_patch})
cpm_utils_message(FATAL_ERROR ${JSON_NAME}
"specifies patch ${full_patch} which does not exist")
endif()
list(APPEND patches "${full_patch}")
endforeach()
endif()
# end format patchdir
# options
get_json_element("${object}" raw_options options "")
if(raw_options)
array_to_list("${raw_options}" ${raw_options_LENGTH} options)
endif()
set(options ${options} ${JSON_OPTIONS})
# end options
# system/bundled
if(bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE)
set(bundled ${JSON_BUNDLED_PACKAGE})
endif()
endif()
endmacro()
# The preferred usage
function(AddJsonPackage)
set(oneValueArgs
@@ -80,7 +238,8 @@ function(AddJsonPackage)
# these are overrides that can be generated at runtime,
# so can be defined separately from the json
DOWNLOAD_ONLY
BUNDLED_PACKAGE)
BUNDLED_PACKAGE
FORCE_BUNDLED_PACKAGE)
set(multiValueArgs OPTIONS)
@@ -111,24 +270,9 @@ function(AddJsonPackage)
cpm_utils_message(FATAL_ERROR ${JSON_NAME} "Not found in cpmfile")
endif()
get_json_element("${object}" package package ${JSON_NAME})
get_json_element("${object}" repo repo "")
get_json_element("${object}" ci ci OFF)
get_json_element("${object}" version version "")
parse_object(${object})
if(ci)
get_json_element("${object}" name name "${JSON_NAME}")
get_json_element("${object}" extension extension "tar.zst")
get_json_element("${object}" min_version min_version "")
get_json_element("${object}" raw_disabled disabled_platforms "")
if(raw_disabled)
array_to_list("${raw_disabled}"
${raw_disabled_LENGTH} disabled_platforms)
else()
set(disabled_platforms "")
endif()
AddCIPackage(
VERSION ${version}
NAME ${name}
@@ -138,116 +282,38 @@ function(AddJsonPackage)
MIN_VERSION ${min_version}
DISABLED_PLATFORMS ${disabled_platforms})
# pass stuff to parent scope
set(${package}_ADDED "${${package}_ADDED}"
PARENT_SCOPE)
set(${package}_SOURCE_DIR "${${package}_SOURCE_DIR}"
PARENT_SCOPE)
set(${package}_BINARY_DIR "${${package}_BINARY_DIR}"
PARENT_SCOPE)
return()
endif()
get_json_element("${object}" hash hash "")
get_json_element("${object}" hash_suffix hash_suffix "")
get_json_element("${object}" sha sha "")
get_json_element("${object}" url url "")
get_json_element("${object}" key key "")
get_json_element("${object}" tag tag "")
get_json_element("${object}" artifact artifact "")
get_json_element("${object}" git_version git_version "")
get_json_element("${object}" git_host git_host "")
get_json_element("${object}" source_subdir source_subdir "")
get_json_element("${object}" bundled bundled "unset")
get_json_element("${object}" find_args find_args "")
get_json_element("${object}" raw_patches patches "")
# okay here comes the fun part: REPLACEMENTS!
# first: tag gets %VERSION% replaced if applicable,
# with either git_version (preferred) or version
# second: artifact gets %VERSION% and %TAG% replaced
# accordingly (same rules for VERSION)
if(git_version)
set(version_replace ${git_version})
else()
set(version_replace ${version})
if (NOT DEFINED JSON_FORCE_BUNDLED_PACKAGE)
set(JSON_FORCE_BUNDLED_PACKAGE OFF)
endif()
AddPackage(
NAME "${package}"
VERSION "${version}"
URL "${url}"
HASH "${hash}"
HASH_SUFFIX "${hash_suffix}"
SHA "${sha}"
REPO "${repo}"
KEY "${key}"
PATCHES "${patches}"
OPTIONS "${options}"
FIND_PACKAGE_ARGUMENTS "${find_args}"
BUNDLED_PACKAGE "${bundled}"
FORCE_BUNDLED_PACKAGE "${JSON_FORCE_BUNDLED_PACKAGE}"
SOURCE_SUBDIR "${source_subdir}"
GIT_VERSION ${git_version}
GIT_HOST ${git_host}
ARTIFACT ${artifact}
TAG ${tag})
endif()
# TODO(crueter): fmt module for cmake
if(tag)
string(REPLACE "%VERSION%" "${version_replace}" tag ${tag})
endif()
if(artifact)
string(REPLACE "%VERSION%" "${version_replace}" artifact ${artifact})
string(REPLACE "%TAG%" "${tag}" artifact ${artifact})
endif()
# format patchdir
if(raw_patches)
math(EXPR range "${raw_patches_LENGTH} - 1")
foreach(IDX RANGE ${range})
string(JSON _patch GET "${raw_patches}" "${IDX}")
set(full_patch
"${PROJECT_SOURCE_DIR}/.patch/${JSON_NAME}/${_patch}")
if(NOT EXISTS ${full_patch})
cpm_utils_message(FATAL_ERROR ${JSON_NAME}
"specifies patch ${full_patch} which does not exist")
endif()
list(APPEND patches "${full_patch}")
endforeach()
endif()
# end format patchdir
# options
get_json_element("${object}" raw_options options "")
if(raw_options)
array_to_list("${raw_options}" ${raw_options_LENGTH} options)
endif()
set(options ${options} ${JSON_OPTIONS})
# end options
# system/bundled
if(bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE)
set(bundled ${JSON_BUNDLED_PACKAGE})
endif()
AddPackage(
NAME "${package}"
VERSION "${version}"
URL "${url}"
HASH "${hash}"
HASH_SUFFIX "${hash_suffix}"
SHA "${sha}"
REPO "${repo}"
KEY "${key}"
PATCHES "${patches}"
OPTIONS "${options}"
FIND_PACKAGE_ARGUMENTS "${find_args}"
BUNDLED_PACKAGE "${bundled}"
SOURCE_SUBDIR "${source_subdir}"
GIT_VERSION ${git_version}
GIT_HOST ${git_host}
ARTIFACT ${artifact}
TAG ${tag})
# pass stuff to parent scope
set(${package}_ADDED "${${package}_ADDED}"
PARENT_SCOPE)
set(${package}_SOURCE_DIR "${${package}_SOURCE_DIR}"
PARENT_SCOPE)
set(${package}_BINARY_DIR "${${package}_BINARY_DIR}"
PARENT_SCOPE)
Propagate(${package}_ADDED)
Propagate(${package}_SOURCE_DIR)
Propagate(${package}_BINARY_DIR)
endfunction()
function(AddPackage)
@@ -343,7 +409,7 @@ function(AddPackage)
if(DEFINED PKG_ARGS_ARTIFACT)
set(pkg_url
${pkg_git_url}/releases/download/${PKG_ARGS_TAG}/${PKG_ARGS_ARTIFACT})
"${pkg_git_url}/releases/download/${PKG_ARGS_TAG}/${PKG_ARGS_ARTIFACT}")
else()
set(pkg_url
${pkg_git_url}/archive/refs/tags/${PKG_ARGS_TAG}.tar.gz)
@@ -625,7 +691,8 @@ function(AddCIPackage)
endif()
if (DEFINED pkgname AND NOT "${pkgname}" IN_LIST DISABLED_PLATFORMS)
set(ARTIFACT "${ARTIFACT_NAME}-${pkgname}-${ARTIFACT_VERSION}.${ARTIFACT_EXT}")
set(ARTIFACT
"${ARTIFACT_NAME}-${pkgname}-${ARTIFACT_VERSION}.${ARTIFACT_EXT}")
AddPackage(
NAME ${ARTIFACT_PACKAGE}
+18 -7
View File
@@ -12,14 +12,12 @@
"repo": "boostorg/boost",
"tag": "boost-%VERSION%",
"artifact": "%TAG%-cmake.tar.xz",
"hash": "4fb7f6fde92762305aad8754d7643cd918dd1f3f67e104e9ab385b18c73178d72a17321354eb203b790b6702f2cf6d725a5d6e2dfbc63b1e35f9eb59fb42ece9",
"git_version": "1.89.0",
"hash": "6ae6e94664fe7f2fb01976b59b276ac5df8085c7503fa829d810fbfe495960cfec44fa2c36e2cb23480bc19c956ed199d4952b02639a00a6c07625d4e7130c2d",
"git_version": "1.90.0",
"version": "1.57",
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
"patches": [
"0001-clang-cl.patch",
"0002-use-marmasm.patch",
"0003-armasm-options.patch"
"0001-clang-cl.patch"
]
},
"fmt": {
@@ -48,9 +46,9 @@
"package": "ZLIB",
"repo": "madler/zlib",
"tag": "v%VERSION%",
"hash": "8c9642495bafd6fad4ab9fb67f09b268c69ff9af0f4f20cf15dfc18852ff1f312bd8ca41de761b3f8d8e90e77d79f2ccacd3d4c5b19e475ecf09d021fdfe9088",
"hash": "06eaa3a1eaaeb31f461a2283b03a91ed8eb2406e62cd97ea1c69836324909edeecd93edd03ff0bf593d9dde223e3376149134c5b1fe2e8688c258cadf8cd60ff",
"version": "1.2",
"git_version": "1.3.1",
"git_version": "1.3.1.2",
"options": [
"ZLIB_BUILD_SHARED OFF",
"ZLIB_INSTALL OFF"
@@ -103,5 +101,18 @@
"git_version": "1.4.335.0",
"artifact": "android-binaries-%VERSION%.zip",
"hash": "48167c4a17736301bd08f9290f41830443e1f18cce8ad867fc6f289b49e18b40e93c9850b377951af82f51b5b6d7313aa6a884fc5df79f5ce3df82696c1c1244"
},
"quazip": {
"package": "QuaZip-Qt6",
"repo": "stachenov/quazip",
"sha": "2e95c9001b",
"hash": "609c240c7f029ac26a37d8fbab51bc16284e05e128b78b9b9c0e95d083538c36047a67d682759ac990e4adb0eeb90f04f1ea7fe2253bbda7e7e3bcce32e53dd8",
"version": "1.3",
"git_version": "1.5",
"options": [
"QUAZIP_QT_MAJOR_VERSION 6",
"QUAZIP_INSTALL OFF",
"QUAZIP_ENABLE_QTEXTCODEC OFF"
]
}
}
+1 -1
View File
@@ -18,7 +18,7 @@
src/web_service @AleksandrPopovich
src/dynarmic @Lizzie
src/core @Lizzie @Maufeat @PavelBARABANOV @MrPurple666 @JPikachu
src/core/hle @Maufeat @PavelBARABANOV @SDK-Chan
src/core/hle @Maufeat @PavelBARABANOV
src/core/arm @Lizzie @MrPurple666
src/*_room @AleksandrPopovich
src/video_core @CamilleLaVey @MaranBr @Wildcard @weakboson
+41
View File
@@ -0,0 +1,41 @@
# AddDependentPackage
Use `AddDependentPackage` when you have multiple packages that are required to all be from the system, OR bundled. This is useful in cases where e.g. versions must absolutely match.
## Versioning
Versioning must be handled by the package itself.
## Examples
### Vulkan
`cpmfile.json`
```json
{
"vulkan-headers": {
"repo": "KhronosGroup/Vulkan-Headers",
"package": "VulkanHeaders",
"version": "1.4.317",
"hash": "26e0ad8fa34ab65a91ca62ddc54cc4410d209a94f64f2817dcdb8061dc621539a4262eab6387e9b9aa421db3dbf2cf8e2a4b041b696d0d03746bae1f25191272",
"git_version": "1.4.342",
"tag": "v%VERSION%"
},
"vulkan-utility-libraries": {
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
"package": "VulkanUtilityLibraries",
"hash": "8147370f964fd82c315d6bb89adeda30186098427bf3efaa641d36282d42a263f31e96e4586bfd7ae0410ff015379c19aa4512ba160630444d3d8553afd1ec14",
"git_version": "1.4.342",
"tag": "v%VERSION%"
}
}
```
`CMakeLists.txt`:
```cmake
AddDependentPackages(vulkan-headers vulkan-utility-libraries)
```
If Vulkan Headers are installed, but NOT Vulkan Utility Libraries, then CPMUtil will throw an error.
+4
View File
@@ -31,6 +31,10 @@ The core of CPMUtil is the [`AddPackage`](./AddPackage.md) function. [`AddPackag
[`AddJsonPackage`](./AddJsonPackage.md) is the recommended method of usage for CPMUtil.
## AddDependentPackage
[`AddDependentPackage`](./AddDependentPackage.md) allows you to add multiple packages such that all of them must be from the system OR bundled.
## AddQt
[`AddQt`](./AddQt.md) adds a specific version of Qt to your project.
+4 -6
View File
@@ -83,13 +83,11 @@ endif()
# mcl
AddJsonPackage(mcl)
# VulkanUtilityHeaders - pulls in headers and utility libs
AddJsonPackage(vulkan-utility-headers)
# Vulkan stuff
AddDependentPackages(vulkan-headers vulkan-utility-libraries)
# small hack
if (NOT VulkanUtilityLibraries_ADDED)
find_package(VulkanHeaders 1.3.274 REQUIRED)
endif()
# frozen
AddJsonPackage(frozen)
# DiscordRPC
if (USE_DISCORD_PRESENCE)
+25 -13
View File
@@ -28,8 +28,8 @@
"httplib": {
"repo": "yhirose/cpp-httplib",
"tag": "v%VERSION%",
"hash": "e7a8877d489c97669a8ee536e1498575be921e558ed947253013fe6b67a49d4569eedd01f543caa70183b92d8ac0e8687d662a70d880954412e387317008a239",
"git_version": "0.28.0",
"hash": "a229e24cca4afe78e5c0aa2e482f15108ac34101fd8dbd927365f15e8c37dec4de38c5277d635017d692a5b320e1b929f8bfcc076f52b8e4dcdab8fe53bfdf2e",
"git_version": "0.30.1",
"find_args": "MODULE GLOBAL",
"patches": [
"0001-mingw.patch"
@@ -118,15 +118,6 @@
"git_version": "1.3.18",
"find_args": "MODULE"
},
"vulkan-utility-headers": {
"package": "VulkanUtilityLibraries",
"repo": "scripts/VulkanUtilityHeaders",
"tag": "%VERSION%",
"git_version": "1.4.335",
"artifact": "VulkanUtilityHeaders.tar.zst",
"git_host": "git.crueter.xyz",
"hash": "16dac0e6586702580c4279e4cd37ffe3cf909c93eb31b5069da7af36436d47b270a9cbaac953bb66c22ed12ed67ffa096688599267f307dfb62be1bc09f79833"
},
"spirv-tools": {
"package": "SPIRV-Tools",
"repo": "KhronosGroup/SPIRV-Tools",
@@ -174,9 +165,9 @@
"package": "Catch2",
"repo": "catchorg/Catch2",
"tag": "v%VERSION%",
"hash": "a95495142f915d6e9c2a23e80fe360343e9097680066a2f9d3037a070ba5f81ee5559a0407cc9e972dc2afae325873f1fc7ea07a64012c0f01aac6e549f03e3f",
"hash": "acb3f463a7404d6a3bce52e474075cdadf9bb241d93feaf147c182d756e5a2f8bd412f4658ca186d15ab8fed36fc587d79ec311f55642d8e4ded16df9e213656",
"version": "3.0.1",
"git_version": "3.11.0",
"git_version": "3.12.0",
"patches": [
"0001-solaris-isnan-fix.patch"
]
@@ -281,5 +272,26 @@
"tag": "%VERSION%",
"hash": "dc37a189a44ce8b5c988ca550582431a6c7eadfd3c6e709bee6277116ee803e714333e85c9e6cbb5c69346a14d6f2cc7ed96e8aa09cc5fb8a89f945059651db6",
"version": "121125"
},
"vulkan-headers": {
"repo": "KhronosGroup/Vulkan-Headers",
"package": "VulkanHeaders",
"version": "1.4.317",
"hash": "26e0ad8fa34ab65a91ca62ddc54cc4410d209a94f64f2817dcdb8061dc621539a4262eab6387e9b9aa421db3dbf2cf8e2a4b041b696d0d03746bae1f25191272",
"git_version": "1.4.342",
"tag": "v%VERSION%"
},
"vulkan-utility-libraries": {
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
"package": "VulkanUtilityLibraries",
"hash": "8147370f964fd82c315d6bb89adeda30186098427bf3efaa641d36282d42a263f31e96e4586bfd7ae0410ff015379c19aa4512ba160630444d3d8553afd1ec14",
"git_version": "1.4.342",
"tag": "v%VERSION%"
},
"frozen": {
"package": "frozen",
"repo": "serge-sans-paille/frozen",
"sha": "61dce5ae18",
"hash": "b8dfe741c82bc178dfc9749d4ab5a130cee718d9ee7b71d9b547cf5f7f23027ed0152ad250012a8546399fcc1e12187efc68d89d6731256c4d2df7d04eef8d5c"
}
}
+1 -1
View File
@@ -20,4 +20,4 @@ pkgs.mkShellNoCC {
# optional components
discord-rpc gamemode
];
}
}
@@ -22,14 +22,6 @@ import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
class QuickSettings(val emulationFragment: EmulationFragment) {
// Kinda a crappy workaround to get a title from setting keys
// Idk how to do this witthout hardcoding every single one
private fun getSettingTitle(settingKey: String): String {
return settingKey.replace("_", " ").split(" ")
.joinToString(" ") { it.replaceFirstChar { c -> c.uppercase() } }
}
private fun saveSettings() {
if (emulationFragment.shouldUseCustom) {
NativeConfig.savePerGameConfig()
@@ -60,6 +52,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
// settings
fun addIntSetting(
name: Int,
container: ViewGroup,
setting: IntSetting,
namesArrayId: Int,
@@ -73,7 +66,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.expand_icon)
val radioGroup = itemView.findViewById<RadioGroup>(R.id.radio_group)
titleView.text = getSettingTitle(setting.key)
titleView.text = YuzuApplication.appContext.getString(name)
val names = emulationFragment.resources.getStringArray(namesArrayId)
val values = emulationFragment.resources.getIntArray(valuesArrayId)
@@ -115,6 +108,8 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
}
fun addBooleanSetting(
name: Int,
container: ViewGroup,
setting: BooleanSetting
) {
@@ -125,7 +120,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
val titleView = itemView.findViewById<TextView>(R.id.switch_title)
val switchView = itemView.findViewById<com.google.android.material.materialswitch.MaterialSwitch>(R.id.setting_switch)
titleView.text = getSettingTitle(setting.key)
titleView.text = YuzuApplication.appContext.getString(name)
switchContainer.visibility = View.VISIBLE
switchView.isChecked = setting.getBoolean()
@@ -141,6 +136,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
}
fun addSliderSetting(
name: Int,
container: ViewGroup,
setting: AbstractSetting,
minValue: Int = 0,
@@ -156,7 +152,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
val slider = itemView.findViewById<com.google.android.material.slider.Slider>(R.id.setting_slider)
titleView.text = getSettingTitle(setting.key)
titleView.text = YuzuApplication.appContext.getString(name)
sliderContainer.visibility = View.VISIBLE
slider.valueFrom = minValue.toFloat()
@@ -24,6 +24,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
RENDERER_DEBUG("debug"),
@@ -82,8 +83,9 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
GPU_LOG_VULKAN_CALLS("gpu_log_vulkan_calls"),
GPU_LOG_SHADER_DUMPS("gpu_log_shader_dumps"),
GPU_LOG_MEMORY_TRACKING("gpu_log_memory_tracking"),
GPU_LOG_DRIVER_DEBUG("gpu_log_driver_debug");
GPU_LOG_DRIVER_DEBUG("gpu_log_driver_debug"),
ENABLE_QUICK_SETTINGS("enable_quick_settings");
// external fun isFrameSkippingEnabled(): Boolean
external fun isFrameInterpolationEnabled(): Boolean
@@ -745,6 +745,13 @@ abstract class SettingsItem(
descriptionId = R.string.renderer_reactive_flushing_description
)
)
put(
SwitchSetting(
BooleanSetting.ENABLE_BUFFER_HISTORY,
titleId = R.string.enable_buffer_history,
descriptionId = R.string.enable_buffer_history_description
)
)
put(
SwitchSetting(
BooleanSetting.SYNC_MEMORY_OPERATIONS,
@@ -799,6 +806,13 @@ abstract class SettingsItem(
descriptionId = R.string.enable_update_checks_description,
)
)
put(
SwitchSetting(
BooleanSetting.ENABLE_QUICK_SETTINGS,
titleId = R.string.enable_quick_settings,
descriptionId = R.string.enable_quick_settings_description,
)
)
put(
SwitchSetting(
BooleanSetting.ENABLE_FOLDER_BUTTON,
@@ -275,6 +275,7 @@ class SettingsFragmentPresenter(
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
add(HeaderSetting(R.string.hacks))
@@ -1074,6 +1075,8 @@ class SettingsFragmentPresenter(
add(BooleanSetting.ENABLE_UPDATE_CHECKS.key)
}
add(BooleanSetting.ENABLE_QUICK_SETTINGS.key)
add(HeaderSetting(R.string.theme_and_color))
@@ -690,8 +690,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
})
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
if (!BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean()) {
binding.drawerLayout.setDrawerLockMode(
DrawerLayout.LOCK_MODE_LOCKED_CLOSED,
binding.quickSettingsSheet
)
}
updateGameTitle()
binding.inGameMenu.menu.findItem(R.id.menu_quick_settings)?.isVisible =
BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean()
binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply {
val lockMode = IntSetting.LOCK_DRAWER.getInt()
val titleId = if (lockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
@@ -749,10 +759,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
true
}
R.id.menu_quick_settings -> {
openQuickSettingsMenu()
true
}
if (BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean())
R.id.menu_quick_settings else 0 -> {
openQuickSettingsMenu()
true
}
R.id.menu_settings_per_game -> {
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
@@ -1045,11 +1056,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
quickSettings.addBooleanSetting(
R.string.frame_limit_enable,
container,
BooleanSetting.RENDERER_USE_SPEED_LIMIT,
)
quickSettings.addSliderSetting(
R.string.frame_limit_slider,
container,
ShortSetting.RENDERER_SPEED_LIMIT,
minValue = 0,
@@ -1058,6 +1071,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
)
quickSettings.addBooleanSetting(
R.string.use_docked_mode,
container,
BooleanSetting.USE_DOCKED_MODE,
)
@@ -1065,6 +1079,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
quickSettings.addDivider(container)
quickSettings.addIntSetting(
R.string.renderer_accuracy,
container,
IntSetting.RENDERER_ACCURACY,
R.array.rendererAccuracyNames,
@@ -1073,6 +1088,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
quickSettings.addIntSetting(
R.string.renderer_scaling_filter,
container,
IntSetting.RENDERER_SCALING_FILTER,
R.array.rendererScalingFilterNames,
@@ -1080,6 +1096,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
)
quickSettings.addSliderSetting(
R.string.fsr_sharpness,
container,
IntSetting.FSR_SHARPENING_SLIDER,
minValue = 0,
@@ -1088,6 +1105,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
)
quickSettings.addIntSetting(
R.string.renderer_anti_aliasing,
container,
IntSetting.RENDERER_ANTI_ALIASING,
R.array.rendererAntiAliasingNames,
@@ -202,9 +202,14 @@ namespace AndroidSettings {
Settings::Specialization::Default, true, true,
&show_soc_overlay};
// MISC
Settings::Setting<bool> dont_show_driver_shader_warning{linkage, false,
"dont_show_driver_shader_warning",
Settings::Category::Android, Settings::Specialization::Default, true, true};
Settings::Setting<bool> enable_quick_settings{linkage, true,
"enable_quick_settings",
Settings::Category::Android, Settings::Specialization::Default, true,
false};
};
extern Values values;
@@ -1,18 +1,19 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <string>
#include <jni.h>
#include <common/fs/path_util.h>
#include "android_config.h"
#include "android_settings.h"
#include "common/android/android_common.h"
#include "common/android/id_cache.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "frontend_common/config.h"
#include "frontend_common/settings_generator.h"
#include "native.h"
std::unique_ptr<AndroidConfig> global_config;
@@ -37,6 +38,7 @@ extern "C" {
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeGlobalConfig(JNIEnv* env, jobject obj) {
global_config = std::make_unique<AndroidConfig>();
FrontendCommon::GenerateSettings();
}
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) {
@@ -493,6 +493,8 @@
<string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string>
<string name="renderer_reactive_flushing">Use reactive flushing</string>
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
<string name="enable_buffer_history">Enable buffer history</string>
<string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string>
<string name="hacks">Hacks</string>
@@ -556,13 +558,11 @@
<string name="flush_by_line_description">Flushes debugging logs on each line written, making debugging easier in cases of crashing or freezing.</string>
<!-- GPU Logging strings -->
<string name="gpu_logging">GPU Logging</string>
<string name="gpu_logging_header">GPU Logging</string>
<string name="gpu_logging_enabled">Enable GPU Logging</string>
<string name="gpu_logging_enabled_description">Log GPU operations to eden_gpu.log for debugging Adreno drivers</string>
<string name="gpu_log_level">Log Level</string>
<string name="gpu_log_level_description">Detail level for GPU logs (higher = more detail, more overhead)</string>
<string name="gpu_logging_features">Logging Features</string>
<string name="gpu_log_vulkan_calls">Log Vulkan API Calls</string>
<string name="gpu_log_vulkan_calls_description">Track all Vulkan API calls in ring buffer</string>
<string name="gpu_log_shader_dumps">Dump Shaders</string>
@@ -738,6 +738,8 @@
<string name="preferences_graphics">Graphics</string>
<string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
<string name="quick_settings">Quick Settings</string>
<string name="enable_quick_settings">Enable Quick Settings</string>
<string name="enable_quick_settings_description">Allow access to quick settings menu via swipe and menu button</string>
<string name="preferences_audio">Audio</string>
<string name="preferences_audio_description">Output engine, volume</string>
<string name="preferences_controls">Controls</string>
+10 -2
View File
@@ -481,6 +481,14 @@ struct Values {
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
Category::RendererAdvanced};
SwitchableSetting<bool> enable_buffer_history{linkage,
false,
"enable_buffer_history",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
// Renderer Hacks //
SwitchableSetting<GpuOverclock> fast_gpu_time{linkage,
GpuOverclock::Medium,
@@ -739,7 +747,7 @@ struct Values {
Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Debugging};
// GPU Logging
Setting<bool> gpu_logging_enabled{linkage, true, "gpu_logging_enabled", Category::Debugging};
Setting<bool> gpu_logging_enabled{linkage, false, "gpu_logging_enabled", Category::Debugging};
SwitchableSetting<GpuLogLevel> gpu_log_level{linkage, GpuLogLevel::Standard, "gpu_log_level",
Category::Debugging};
Setting<bool> gpu_log_vulkan_calls{linkage, true, "gpu_log_vulkan_calls", Category::Debugging};
@@ -778,7 +786,7 @@ struct Values {
Category::WebService};
Setting<std::string> eden_username{linkage, "Eden", "eden_username",
Category::WebService};
Setting<std::string> eden_token{linkage, "njausoolxygtpvraofqunuufhmupriifnpfggjxefntlyglr",
Setting<std::string> eden_token{linkage, "",
"eden_token", Category::WebService};
// Add-Ons
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -99,11 +99,6 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
slots[slot].acquire_called = true;
slots[slot].needs_cleanup_on_release = false;
slots[slot].buffer_state = BufferState::Acquired;
// TODO: for now, avoid resetting the fence, so that when we next return this
// slot to the producer, it will wait for the fence to pass. We should fix this
// by properly waiting for the fence in the BufferItemConsumer.
// slots[slot].fence = Fence::NoFence();
}
// If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -17,6 +17,39 @@ BufferQueueCore::BufferQueueCore() = default;
BufferQueueCore::~BufferQueueCore() = default;
void BufferQueueCore::PushHistory(u64 frame_number, s64 queue_time, s64 presentation_time, BufferState state) {
std::lock_guard lk(buffer_history_mutex);
auto it = buffer_history_map.find(frame_number);
if (it != buffer_history_map.end()) {
it->second.state = state;
return;
}
buffer_history_map.emplace(frame_number, BufferHistoryInfo{
frame_number,
queue_time,
presentation_time,
state
});
buffer_history_order.push_back(frame_number);
if (buffer_history_order.size() > BUFFER_HISTORY_SIZE) {
u64 oldest_frame = buffer_history_order.front();
buffer_history_order.pop_front();
buffer_history_map.erase(oldest_frame);
}
}
void BufferQueueCore::UpdateHistory(u64 frame_number, BufferState state) {
std::lock_guard lk(buffer_history_mutex);
auto it = buffer_history_map.find(frame_number);
if (it != buffer_history_map.end()) {
it->second.state = state;
}
}
void BufferQueueCore::SignalDequeueCondition() {
dequeue_possible.store(true);
dequeue_condition.notify_all();
@@ -30,7 +63,6 @@ bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk)
}
s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const {
// If DequeueBuffer is allowed to error out, we don't have to add an extra buffer.
if (!use_async_buffer) {
return 0;
}
@@ -55,8 +87,6 @@ s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const {
return override_max_buffer_count;
}
// Any buffers that are dequeued by the producer or sitting in the queue waiting to be consumed
// need to have their slots preserved.
for (s32 slot = max_buffer_count; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
const auto state = slots[slot].buffer_state;
if (state == BufferState::Queued || state == BufferState::Dequeued) {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -10,20 +10,31 @@
#pragma once
#include <condition_variable>
#include <deque>
#include <list>
#include <memory>
#include <mutex>
#include <set>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include "core/hle/service/nvnflinger/buffer_item.h"
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
#include "core/hle/service/nvnflinger/buffer_slot.h"
#include "core/hle/service/nvnflinger/pixel_format.h"
#include "core/hle/service/nvnflinger/status.h"
#include "core/hle/service/nvnflinger/window.h"
namespace Service::android {
struct BufferHistoryInfo {
u64 frame_number{};
s64 queue_time{};
s64 presentation_time{};
BufferState state{};
};
class IConsumerListener;
class IProducerListener;
@@ -33,10 +44,14 @@ class BufferQueueCore final {
public:
static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT;
static constexpr u32 BUFFER_HISTORY_SIZE = 8;
BufferQueueCore();
~BufferQueueCore();
void PushHistory(u64 frame_number, s64 queue_time, s64 presentation_time, BufferState state);
void UpdateHistory(u64 frame_number, BufferState state);
private:
void SignalDequeueCondition();
bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
@@ -72,6 +87,11 @@ private:
const s32 max_acquired_buffer_count{}; // This is always zero on HOS
bool buffer_has_been_queued{};
u64 frame_counter{};
std::unordered_map<u64, BufferHistoryInfo> buffer_history_map{};
mutable std::mutex buffer_history_mutex{};
std::deque<u64> buffer_history_order;
u32 transform_hint{};
bool is_allocating{};
mutable std::condition_variable_any is_allocating_condition;
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -9,6 +9,7 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/kernel.h"
@@ -26,7 +27,7 @@ BufferQueueProducer::BufferQueueProducer(Service::KernelHelpers::ServiceContext&
std::shared_ptr<BufferQueueCore> buffer_queue_core_,
Service::Nvidia::NvCore::NvMap& nvmap_)
: service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots),
nvmap(nvmap_) {
clock{Common::CreateOptimalClock()}, nvmap(nvmap_) {
buffer_wait_event = service_context.CreateEvent("BufferQueue:WaitEvent");
}
@@ -428,8 +429,7 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
return return_flags;
}
Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
QueueBufferOutput* output) {
Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, QueueBufferOutput* output) {
s64 timestamp{};
bool is_auto_timestamp{};
Common::Rectangle<s32> crop;
@@ -440,8 +440,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
s32 swap_interval{};
Fence fence{};
input.Deflate(&timestamp, &is_auto_timestamp, &crop, &scaling_mode, &transform,
&sticky_transform_, &async, &swap_interval, &fence);
input.Deflate(&timestamp, &is_auto_timestamp, &crop, &scaling_mode, &transform, &sticky_transform_, &async, &swap_interval, &fence);
switch (scaling_mode) {
case NativeWindowScalingMode::Freeze:
@@ -455,10 +454,9 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
return Status::BadValue;
}
std::shared_ptr<IConsumerListener> frame_available_listener;
std::shared_ptr<IConsumerListener> frame_replaced_listener;
s32 callback_ticket{};
BufferItem item;
std::shared_ptr<IConsumerListener> listener_available;
std::shared_ptr<IConsumerListener> listener_replaced;
{
std::scoped_lock lock{core->mutex};
@@ -469,127 +467,82 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
}
const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
if (async && core->override_max_buffer_count) {
if (core->override_max_buffer_count < max_buffer_count) {
LOG_ERROR(Service_Nvnflinger, "async mode is invalid with "
"buffer count override");
return Status::BadValue;
}
}
if (slot < 0 || slot >= max_buffer_count) {
LOG_ERROR(Service_Nvnflinger, "slot index {} out of range [0, {})", slot,
max_buffer_count);
LOG_ERROR(Service_Nvnflinger, "slot {} out of range [0, {})", slot, max_buffer_count);
return Status::BadValue;
} else if (slots[slot].buffer_state != BufferState::Dequeued) {
LOG_ERROR(Service_Nvnflinger,
"slot {} is not owned by the producer "
"(state = {})",
slot, slots[slot].buffer_state);
}
if (slots[slot].buffer_state != BufferState::Dequeued) {
LOG_ERROR(Service_Nvnflinger, "slot {} is not owned by producer", slot);
return Status::BadValue;
} else if (!slots[slot].request_buffer_called) {
LOG_ERROR(Service_Nvnflinger,
"slot {} was queued without requesting "
"a buffer",
slot);
}
if (!slots[slot].request_buffer_called) {
LOG_ERROR(Service_Nvnflinger, "slot {} was queued without request", slot);
return Status::BadValue;
}
LOG_DEBUG(Service_Nvnflinger,
"slot={} frame={} time={} crop=[{},{},{},{}] transform={} scale={}", slot,
core->frame_counter + 1, timestamp, crop.Left(), crop.Top(), crop.Right(),
crop.Bottom(), transform, scaling_mode);
const std::shared_ptr<GraphicBuffer>& graphic_buffer(slots[slot].graphic_buffer);
Common::Rectangle<s32> buffer_rect(graphic_buffer->Width(), graphic_buffer->Height());
Common::Rectangle<s32> cropped_rect;
[[maybe_unused]] const bool unused = crop.Intersect(buffer_rect, &cropped_rect);
if (cropped_rect != crop) {
LOG_ERROR(Service_Nvnflinger, "crop rect is not contained within the buffer in slot {}",
slot);
return Status::BadValue;
}
slots[slot].fence = fence;
slots[slot].buffer_state = BufferState::Queued;
++core->frame_counter;
slots[slot].buffer_state = BufferState::Queued;
slots[slot].frame_number = core->frame_counter;
slots[slot].queue_time = timestamp;
slots[slot].presentation_time = clock->GetTimeNS().count();
slots[slot].fence = fence;
item.acquire_called = slots[slot].acquire_called;
item.slot = slot;
item.graphic_buffer = slots[slot].graphic_buffer;
item.crop = crop;
item.transform = transform & ~NativeWindowTransform::InverseDisplay;
item.transform_to_display_inverse =
(transform & NativeWindowTransform::InverseDisplay) != NativeWindowTransform::None;
item.scaling_mode = static_cast<u32>(scaling_mode);
item.frame_number = core->frame_counter;
item.timestamp = timestamp;
item.is_auto_timestamp = is_auto_timestamp;
item.frame_number = core->frame_counter;
item.slot = slot;
item.crop = crop;
item.transform = transform & ~NativeWindowTransform::InverseDisplay;
item.transform_to_display_inverse = (transform & NativeWindowTransform::InverseDisplay) != NativeWindowTransform::None;
item.scaling_mode = static_cast<u32>(scaling_mode);
item.fence = fence;
item.is_droppable = core->dequeue_buffer_cannot_block || async;
item.swap_interval = swap_interval;
item.acquire_called = slots[slot].acquire_called;
sticky_transform = sticky_transform_;
if (core->queue.empty()) {
// When the queue is empty, we can simply queue this buffer
core->queue.push_back(item);
frame_available_listener = core->consumer_listener;
listener_available = core->consumer_listener;
} else {
// When the queue is not empty, we need to look at the front buffer
// state to see if we need to replace it
auto front(core->queue.begin());
auto front = core->queue.begin();
if (front->is_droppable && core->StillTracking(*front)) {
slots[front->slot].buffer_state = BufferState::Free;
if (Settings::values.enable_buffer_history.GetValue()) {
core->UpdateHistory(front->frame_number, BufferState::Free);
}
slots[front->slot].frame_number = 0;
}
if (front->is_droppable) {
// If the front queued buffer is still being tracked, we first
// mark it as freed
if (core->StillTracking(*front)) {
slots[front->slot].buffer_state = BufferState::Free;
// Reset the frame number of the freed buffer so that it is the first in line to
// be dequeued again
slots[front->slot].frame_number = 0;
}
// Overwrite the droppable buffer with the incoming one
*front = item;
frame_replaced_listener = core->consumer_listener;
listener_replaced = core->consumer_listener;
} else {
core->queue.push_back(item);
frame_available_listener = core->consumer_listener;
listener_available = core->consumer_listener;
}
}
if (Settings::values.enable_buffer_history.GetValue()) {
core->PushHistory(core->frame_counter, slots[slot].queue_time, slots[slot].presentation_time, BufferState::Queued);
}
core->buffer_has_been_queued = true;
core->SignalDequeueCondition();
output->Inflate(core->default_width, core->default_height, core->transform_hint,
static_cast<u32>(core->queue.size()));
// Take a ticket for the callback functions
callback_ticket = next_callback_ticket++;
output->Inflate(core->default_width, core->default_height, core->transform_hint, static_cast<u32>(core->queue.size()));
}
// Don't send the GraphicBuffer through the callback, and don't send the slot number, since the
// consumer shouldn't need it
item.graphic_buffer.reset();
item.slot = BufferItem::INVALID_BUFFER_SLOT;
// Call back without the main BufferQueue lock held, but with the callback lock held so we can
// ensure that callbacks occur in order
{
std::scoped_lock lock{callback_mutex};
while (callback_ticket != current_callback_ticket) {
callback_condition.wait(callback_mutex);
}
if (frame_available_listener != nullptr) {
frame_available_listener->OnFrameAvailable(item);
} else if (frame_replaced_listener != nullptr) {
frame_replaced_listener->OnFrameReplaced(item);
}
++current_callback_ticket;
callback_condition.notify_all();
if (listener_available) {
listener_available->OnFrameAvailable(item);
} else if (listener_replaced) {
listener_replaced->OnFrameReplaced(item);
}
return Status::NoError;
@@ -810,6 +763,10 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
return Status::NoError;
}
Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) {
return &buffer_wait_event->GetReadableEvent();
}
void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
std::span<u8> parcel_reply, u32 flags) {
// Values used by BnGraphicBufferProducer onTransact
@@ -929,9 +886,42 @@ void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
status = SetBufferCount(buffer_count);
break;
}
case TransactionId::GetBufferHistory:
LOG_DEBUG(Service_Nvnflinger, "(STUBBED) called, transaction=GetBufferHistory");
case TransactionId::GetBufferHistory: {
if (!Settings::values.enable_buffer_history.GetValue()) {
LOG_DEBUG(Service_Nvnflinger, "(STUBBED) called");
break;
}
LOG_DEBUG(Service_Nvnflinger, "called, transaction=GetBufferHistory");
const s32 request = parcel_in.Read<s32>();
if (request <= 0) {
parcel_out.Write(Status::BadValue);
parcel_out.Write<s32>(0);
break;
}
std::vector<BufferHistoryInfo> snapshot;
{
std::scoped_lock lk(core->buffer_history_mutex);
for (auto& [frame, info] : core->buffer_history_map) {
snapshot.push_back(info);
}
}
std::sort(snapshot.begin(), snapshot.end(), [](auto& a, auto& b){
return a.frame_number > b.frame_number;
});
const s32 limit = std::min(request, (s32)snapshot.size());
parcel_out.Write(Status::NoError);
parcel_out.Write<s32>(limit);
for (s32 i = 0; i < limit; ++i) {
parcel_out.Write(snapshot[i]);
}
break;
}
default:
ASSERT_MSG(false, "Unimplemented TransactionId {}", code);
break;
@@ -944,8 +934,4 @@ void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
(std::min)(parcel_reply.size(), serialized.size()));
}
Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) {
return &buffer_wait_event->GetReadableEvent();
}
} // namespace Service::android
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -14,6 +14,7 @@
#include <mutex>
#include "common/common_funcs.h"
#include "common/wall_clock.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvnflinger/binder.h"
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
@@ -88,6 +89,7 @@ private:
s32 next_callback_ticket{};
s32 current_callback_ticket{};
std::condition_variable_any callback_condition;
std::unique_ptr<Common::WallClock> clock;
Service::Nvidia::NvCore::NvMap& nvmap;
};
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -37,6 +37,7 @@ struct BufferSlot final {
bool needs_cleanup_on_release{};
bool attached_by_consumer{};
bool is_preallocated{};
s64 queue_time{}, presentation_time{};
};
} // namespace Service::android
+6 -3
View File
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -12,7 +12,8 @@ add_library(frontend_common STATIC
firmware_manager.cpp
data_manager.h data_manager.cpp
play_time_manager.cpp
play_time_manager.h)
play_time_manager.h
settings_generator.h settings_generator.cpp)
if (ENABLE_UPDATE_CHECKER)
target_link_libraries(frontend_common PRIVATE httplib::httplib)
@@ -29,4 +30,6 @@ if (ENABLE_UPDATE_CHECKER)
endif()
create_target_directory_groups(frontend_common)
target_link_libraries(frontend_common PUBLIC core SimpleIni::SimpleIni PRIVATE common Boost::headers)
target_link_libraries(frontend_common
PUBLIC core SimpleIni::SimpleIni frozen::frozen-headers
PRIVATE common Boost::headers)
@@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <random>
#include <frozen/string.h>
#include "common/settings.h"
#include "settings_generator.h"
namespace FrontendCommon {
void GenerateSettings() {
static std::random_device rd;
// Web Token //
auto &token_setting = Settings::values.eden_token;
if (token_setting.GetValue().empty()) {
static constexpr const size_t token_length = 48;
static constexpr const frozen::string token_set = "abcdefghijklmnopqrstuvwxyz";
static std::uniform_int_distribution<int> token_dist(0, token_set.size() - 1);
std::string result;
for (size_t i = 0; i < token_length; ++i) {
size_t idx = token_dist(rd);
result += token_set[idx];
}
token_setting.SetValue(result);
}
}
}
+14
View File
@@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
namespace FrontendCommon {
/**
* @brief GenerateSettings Generate platform-specific or randomized settings.
* Run this function at initialization time for your frontend.
*/
void GenerateSettings();
}
+2 -7
View File
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
add_library(qt_common STATIC
@@ -78,14 +78,9 @@ target_compile_definitions(qt_common PUBLIC
QT_NO_URL_CAST_FROM_STRING
)
add_subdirectory(externals)
# pass targets
find_package(frozen)
target_link_libraries(qt_common PRIVATE core Qt6::Core Qt6::Concurrent SimpleIni::SimpleIni QuaZip::QuaZip)
target_link_libraries(qt_common PUBLIC frozen::frozen-headers)
target_link_libraries(qt_common PRIVATE gamemode::headers)
target_link_libraries(qt_common PRIVATE gamemode::headers frontend_common)
if (NOT APPLE AND ENABLE_OPENGL)
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
@@ -329,6 +329,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
barrier_feedback_loops,
tr("Barrier feedback loops"),
tr("Improves rendering of transparency effects in specific games."));
INSERT(Settings,
enable_buffer_history,
tr("Enable buffer history"),
tr("Enables access to previous buffer states.\nThis option may improve rendering quality and performance consistency in some games."));
INSERT(Settings,
fix_bloom_effects,
tr("Fix bloom effects"),
-19
View File
@@ -1,19 +0,0 @@
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
include(CPMUtil)
# Disable tests/tools in all externals supporting the standard option name
set(BUILD_TESTING OFF)
# Build only static externals
set(BUILD_SHARED_LIBS OFF)
# Skip install rules for all externals
set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON)
# QuaZip
AddJsonPackage(quazip)
# frozen
AddJsonPackage(frozen)
-18
View File
@@ -1,18 +0,0 @@
{
"quazip": {
"package": "QuaZip-Qt6",
"repo": "crueter/quazip-qt6",
"sha": "f838774d63",
"hash": "e8f950f47c1f358e2666f08517a9b5b06980677540d3836384e2c27ff5bb129b218f1502b03fdb207d7fd4cd56893f0a0d9094ba8309f19a49cb11e3bb911594",
"version": "1.3",
"options": [
"QUAZIP_INSTALL OFF"
]
},
"frozen": {
"package": "frozen",
"repo": "serge-sans-paille/frozen",
"sha": "61dce5ae18",
"hash": "b8dfe741c82bc178dfc9749d4ab5a130cee718d9ee7b71d9b547cf5f7f23027ed0152ad250012a8546399fcc1e12187efc68d89d6731256c4d2df7d04eef8d5c"
}
}
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -148,10 +151,13 @@ Id EmitConvertU32U64(EmitContext& ctx, Id value) {
}
Id EmitConvertF16F32(EmitContext& ctx, Id value) {
#ifdef ANDROID
return ctx.OpFConvert(ctx.F16[1], value);
#else
const auto result = ctx.OpFConvert(ctx.F16[1], value);
const auto isOverflowing = ctx.OpIsNan(ctx.U1, result);
return ctx.OpSelect(ctx.F16[1], isOverflowing, ctx.Constant(ctx.F16[1], 0), result);
//return ctx.OpFConvert(ctx.F16[1], value);
#endif
}
Id EmitConvertF32F16(EmitContext& ctx, Id value) {
+1 -1
View File
@@ -331,7 +331,7 @@ target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
target_link_libraries(video_core PRIVATE sirit::sirit)
# Header-only stuff needed by all dependent targets
target_link_libraries(video_core PUBLIC Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator)
target_link_libraries(video_core PUBLIC Vulkan::Headers Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator)
if (ENABLE_NSIGHT_AFTERMATH)
if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
@@ -86,7 +86,7 @@ void WriteResults(uvec2 results[LOCAL_RESULTS]) {
const uvec2 accum = accumulated_data;
for (uint i = 0; i < LOCAL_RESULTS; i++) {
uvec2 base_data = current_id * LOCAL_RESULTS + i < min_accumulation_base ? accum : uvec2(0, 0);
AddUint64(results[i], base_data);
results[i] = AddUint64(results[i], base_data);
}
for (uint i = 0; i < LOCAL_RESULTS; i++) {
output_data[buffer_offset + current_id * LOCAL_RESULTS + i] = results[i];
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
@@ -640,6 +640,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, image_barrier);
});
scheduler.Finish();
}
constexpr u32 BL3D_BINDING_SWIZZLE_TABLE = 0;
@@ -1230,6 +1230,10 @@ void Device::RemoveUnsuitableExtensions() {
}
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
// VK_KHR_unified_image_layouts
extensions.unified_image_layouts = features.unified_image_layouts.unifiedImageLayouts;
RemoveExtensionFeatureIfUnsuitable(extensions.unified_image_layouts, features.unified_image_layouts,
VK_KHR_UNIFIED_IMAGE_LAYOUTS_EXTENSION_NAME);
// VK_EXT_depth_bias_control
extensions.depth_bias_control =
+3 -1
View File
@@ -70,7 +70,9 @@ VK_DEFINE_HANDLE(VmaAllocator)
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
pipeline_executable_properties) \
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
workgroup_memory_explicit_layout)
workgroup_memory_explicit_layout) \
FEATURE(KHR, UnifiedImageLayouts, UNIFIED_IMAGE_LAYOUTS, unified_image_layouts)
// Define miscellaneous extensions which may be used by the implementation here.
#define FOR_EACH_VK_EXTENSION(EXTENSION) \
+126 -41
View File
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "yuzu/game_list.h"
#include <QApplication>
#include <QDir>
#include <QFileInfo>
@@ -11,22 +10,28 @@
#include <QJsonObject>
#include <QList>
#include <QMenu>
#include <QScroller>
#include <QScrollBar>
#include <QThreadPool>
#include <QToolButton>
#include <QVariantAnimation>
#include <fmt/ranges.h>
#include <qnamespace.h>
#include <qscroller.h>
#include <qscrollerproperties.h>
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "qt_common/util/game.h"
#include "qt_common/config/uisettings.h"
#include "qt_common/util/game.h"
#include "yuzu/compatibility_list.h"
#include "yuzu/game_list.h"
#include "yuzu/game_list_p.h"
#include "yuzu/game_list_worker.h"
#include "yuzu/main_window.h"
#include "yuzu/util/controller_navigation.h"
#include <fmt/ranges.h>
#include <regex>
GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent)
: QObject(parent), gamelist{gamelist_} {}
@@ -328,6 +333,22 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
item_model = new QStandardItemModel(tree_view);
tree_view->setModel(item_model);
SetupScrollAnimation();
tree_view->viewport()->installEventFilter(this);
// touch gestures
tree_view->viewport()->grabGesture(Qt::SwipeGesture);
tree_view->viewport()->grabGesture(Qt::PanGesture);
// TODO: touch?
QScroller::grabGesture(tree_view->viewport(), QScroller::LeftMouseButtonGesture);
auto scroller = QScroller::scroller(tree_view->viewport());
QScrollerProperties props;
props.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
props.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
scroller->setScrollerProperties(props);
tree_view->setAlternatingRowColors(true);
tree_view->setSelectionMode(QHeaderView::SingleSelection);
tree_view->setSelectionBehavior(QHeaderView::SelectRows);
@@ -352,7 +373,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded);
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, this,
[this](Qt::Key key) {
// Avoid pressing buttons while playing
if (system.IsPoweredOn()) {
@@ -477,7 +498,7 @@ void GameList::DonePopulating(const QStringList& watch_list) {
UISettings::values.favorited_ids.size() == 0);
tree_view->setExpanded(item_model->invisibleRootItem()->child(0)->index(),
UISettings::values.favorites_expanded.GetValue());
for (const auto id : UISettings::values.favorited_ids) {
for (const auto id : std::as_const(UISettings::values.favorited_ids)) {
AddFavorite(id);
}
@@ -613,73 +634,73 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0);
connect(favorite, &QAction::triggered, [this, program_id]() { ToggleFavorite(program_id); });
connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
connect(favorite, &QAction::triggered, this, [this, program_id]() { ToggleFavorite(program_id); });
connect(open_save_location, &QAction::triggered, this, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
});
connect(start_game, &QAction::triggered,
connect(start_game, &QAction::triggered, this,
[this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Normal); });
connect(start_game_global, &QAction::triggered,
connect(start_game_global, &QAction::triggered, this,
[this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Global); });
connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
connect(open_mod_location, &QAction::triggered, this, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
});
connect(open_transferable_shader_cache, &QAction::triggered,
connect(open_transferable_shader_cache, &QAction::triggered, this,
[this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); });
connect(remove_all_content, &QAction::triggered, [this, program_id]() {
connect(remove_all_content, &QAction::triggered, this, [this, program_id]() {
emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Game);
});
connect(remove_update, &QAction::triggered, [this, program_id]() {
connect(remove_update, &QAction::triggered, this, [this, program_id]() {
emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Update);
});
connect(remove_dlc, &QAction::triggered, [this, program_id]() {
connect(remove_dlc, &QAction::triggered, this, [this, program_id]() {
emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::AddOnContent);
});
connect(remove_gl_shader_cache, &QAction::triggered, [this, program_id, path]() {
connect(remove_gl_shader_cache, &QAction::triggered, this, [this, program_id, path]() {
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::GlShaderCache, path);
});
connect(remove_vk_shader_cache, &QAction::triggered, [this, program_id, path]() {
connect(remove_vk_shader_cache, &QAction::triggered, this, [this, program_id, path]() {
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::VkShaderCache, path);
});
connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() {
connect(remove_shader_cache, &QAction::triggered, this, [this, program_id, path]() {
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::AllShaderCache, path);
});
connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() {
connect(remove_custom_config, &QAction::triggered, this, [this, program_id, path]() {
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CustomConfiguration, path);
});
connect(set_play_time, &QAction::triggered,
connect(set_play_time, &QAction::triggered, this,
[this, program_id]() { emit SetPlayTimeRequested(program_id); });
connect(remove_play_time_data, &QAction::triggered,
connect(remove_play_time_data, &QAction::triggered, this,
[this, program_id]() { emit RemovePlayTimeRequested(program_id); });
connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] {
connect(remove_cache_storage, &QAction::triggered, this, [this, program_id, path] {
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CacheStorage, path);
});
connect(dump_romfs, &QAction::triggered, [this, program_id, path]() {
connect(dump_romfs, &QAction::triggered, this, [this, program_id, path]() {
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal);
});
connect(dump_romfs_sdmc, &QAction::triggered, [this, program_id, path]() {
connect(dump_romfs_sdmc, &QAction::triggered, this, [this, program_id, path]() {
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::SDMC);
});
connect(verify_integrity, &QAction::triggered,
connect(verify_integrity, &QAction::triggered, this,
[this, path]() { emit VerifyIntegrityRequested(path); });
connect(copy_tid, &QAction::triggered,
connect(copy_tid, &QAction::triggered, this,
[this, program_id]() { emit CopyTIDRequested(program_id); });
connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {
connect(navigate_to_gamedb_entry, &QAction::triggered, this, [this, program_id]() {
emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
});
// TODO: Implement shortcut creation for macOS
#if !defined(__APPLE__)
connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() {
connect(create_desktop_shortcut, &QAction::triggered, this, [this, program_id, path]() {
emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Desktop);
});
connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() {
connect(create_applications_menu_shortcut, &QAction::triggered, this, [this, program_id, path]() {
emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Applications);
});
#endif
connect(properties, &QAction::triggered,
connect(properties, &QAction::triggered, this,
[this, path]() { emit OpenPerGameGeneralRequested(path); });
connect(ryujinx, &QAction::triggered, [this, program_id]() { emit LinkToRyujinxRequested(program_id);
connect(ryujinx, &QAction::triggered, this, [this, program_id]() { emit LinkToRyujinxRequested(program_id);
});
};
@@ -693,11 +714,11 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
deep_scan->setCheckable(true);
deep_scan->setChecked(game_dir.deep_scan);
connect(deep_scan, &QAction::triggered, [this, &game_dir] {
connect(deep_scan, &QAction::triggered, this, [this, &game_dir] {
game_dir.deep_scan = !game_dir.deep_scan;
PopulateAsync(UISettings::values.game_dirs);
});
connect(delete_dir, &QAction::triggered, [this, &game_dir, selected] {
connect(delete_dir, &QAction::triggered, this, [this, &game_dir, selected] {
UISettings::values.game_dirs.removeOne(game_dir);
item_model->invisibleRootItem()->removeRow(selected.row());
OnTextChanged(search_field->filterText());
@@ -716,7 +737,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
move_up->setEnabled(row > 1);
move_down->setEnabled(row < item_model->rowCount() - 2);
connect(move_up, &QAction::triggered, [this, selected, row, game_dir_index] {
connect(move_up, &QAction::triggered, this, [this, selected, row, game_dir_index] {
const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt();
// swap the items in the settings
std::swap(UISettings::values.game_dirs[game_dir_index],
@@ -732,7 +753,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
UISettings::values.game_dirs[other_index].expanded);
});
connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] {
connect(move_down, &QAction::triggered, this, [this, selected, row, game_dir_index] {
const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt();
// swap the items in the settings
std::swap(UISettings::values.game_dirs[game_dir_index],
@@ -748,7 +769,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
UISettings::values.game_dirs[other_index].expanded);
});
connect(open_directory_location, &QAction::triggered, [this, game_dir_index] {
connect(open_directory_location, &QAction::triggered, this, [this, game_dir_index] {
emit OpenDirectory(
QString::fromStdString(UISettings::values.game_dirs[game_dir_index].path));
});
@@ -757,8 +778,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
void GameList::AddFavoritesPopup(QMenu& context_menu) {
QAction* clear = context_menu.addAction(tr("Clear"));
connect(clear, &QAction::triggered, [this] {
for (const auto id : UISettings::values.favorited_ids) {
connect(clear, &QAction::triggered, this, [this] {
for (const auto id : std::as_const(UISettings::values.favorited_ids)) {
RemoveFavorite(id);
}
UISettings::values.favorited_ids.clear();
@@ -788,7 +809,7 @@ void GameList::LoadCompatibilityList() {
const QJsonDocument json = QJsonDocument::fromJson(content);
const QJsonArray arr = json.array();
for (const QJsonValue value : arr) {
for (const QJsonValue &value : arr) {
const QJsonObject game = value.toObject();
const QString compatibility_key = QStringLiteral("compatibility");
@@ -800,7 +821,7 @@ void GameList::LoadCompatibilityList() {
const QString directory = game[QStringLiteral("directory")].toString();
const QJsonArray ids = game[QStringLiteral("releases")].toArray();
for (const QJsonValue id_ref : ids) {
for (const QJsonValue &id_ref : ids) {
const QJsonObject id_object = id_ref.toObject();
const QString id = id_object[QStringLiteral("id")].toString();
@@ -919,7 +940,7 @@ void GameList::ToggleFavorite(u64 program_id) {
tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true);
}
}
SaveConfig();
emit SaveConfig();
}
void GameList::AddFavorite(u64 program_id) {
@@ -989,6 +1010,70 @@ void GameListPlaceholder::mouseDoubleClickEvent(QMouseEvent* event) {
emit GameListPlaceholder::AddDirectory();
}
void GameList::SetupScrollAnimation() {
auto setup = [this](QVariantAnimation* anim, QScrollBar* bar) {
// animation handles moving the bar instead of Qt's built in crap
anim->setEasingCurve(QEasingCurve::OutCubic);
anim->setDuration(200);
connect(anim, &QVariantAnimation::valueChanged, this, [bar](const QVariant& value) {
bar->setValue(value.toInt());
});
};
vertical_scroll = new QVariantAnimation(this);
horizontal_scroll = new QVariantAnimation(this);
setup(vertical_scroll, tree_view->verticalScrollBar());
setup(horizontal_scroll, tree_view->horizontalScrollBar());
}
bool GameList::eventFilter(QObject* obj, QEvent* event) {
if (obj == tree_view->viewport() && event->type() == QEvent::Wheel) {
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
bool horizontal = wheelEvent->modifiers() & Qt::ShiftModifier;
int deltaX = wheelEvent->angleDelta().x();
int deltaY = wheelEvent->angleDelta().y();
// if shift is held do a horizontal scroll
if (horizontal && deltaY != 0 && deltaX == 0) {
deltaX = deltaY;
deltaY = 0;
}
// TODO(crueter): dedup this
if (deltaY != 0) {
if (vertical_scroll->state() == QAbstractAnimation::Stopped)
vertical_scroll_target = tree_view->verticalScrollBar()->value();
vertical_scroll_target -= deltaY;
vertical_scroll_target = qBound(0, vertical_scroll_target, tree_view->verticalScrollBar()->maximum());
vertical_scroll->stop();
vertical_scroll->setStartValue(tree_view->verticalScrollBar()->value());
vertical_scroll->setEndValue(vertical_scroll_target);
vertical_scroll->start();
}
if (deltaX != 0) {
if (horizontal_scroll->state() == QAbstractAnimation::Stopped)
horizontal_scroll_target = tree_view->horizontalScrollBar()->value();
horizontal_scroll_target -= deltaX;
horizontal_scroll_target = qBound(0, horizontal_scroll_target, tree_view->horizontalScrollBar()->maximum());
horizontal_scroll->stop();
horizontal_scroll->setStartValue(tree_view->horizontalScrollBar()->value());
horizontal_scroll->setEndValue(horizontal_scroll_target);
horizontal_scroll->start();
}
return true;
}
return QWidget::eventFilter(obj, event);
}
void GameListPlaceholder::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
+10 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
@@ -25,6 +25,7 @@
#include "yuzu/compatibility_list.h"
#include "frontend_common/play_time_manager.h"
class QVariantAnimation;
namespace Core {
class System;
}
@@ -162,6 +163,14 @@ private:
ControllerNavigation* controller_navigation = nullptr;
CompatibilityList compatibility_list;
QVariantAnimation* vertical_scroll = nullptr;
QVariantAnimation* horizontal_scroll = nullptr;
int vertical_scroll_target = 0;
int horizontal_scroll_target = 0;
void SetupScrollAnimation();
bool eventFilter(QObject* obj, QEvent* event) override;
friend class GameListSearchField;
const PlayTime::PlayTimeManager& play_time_manager;
+2
View File
@@ -3,6 +3,7 @@
// Qt on macOS doesn't define VMA shit
#include <boost/algorithm/string/split.hpp>
#include "frontend_common/settings_generator.h"
#include "qt_common/qt_string_lookup.h"
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
#undef VMA_IMPLEMENTATION
@@ -432,6 +433,7 @@ MainWindow::MainWindow(bool has_broken_vulkan)
Common::Log::Start();
LoadTranslation();
FrontendCommon::GenerateSettings();
setAcceptDrops(true);
ui->setupUi(this);
+1 -1
View File
@@ -23,7 +23,7 @@ MAXDEPTH=3
# For your project you'll want to change this to define what dirs you have cpmfiles in
# Remember to account for the MAXDEPTH variable!
# Adding ./ before each will help to remove duplicates
CPMFILES=$(find . src -maxdepth "$MAXDEPTH" -name cpmfile.json | sort | uniq)
CPMFILES=$(find . -maxdepth "$MAXDEPTH" -name cpmfile.json | sort | uniq)
# shellcheck disable=SC2016
PACKAGES=$(echo "$CPMFILES" | xargs jq -s 'reduce .[] as $item ({}; . * $item)')