mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-25 00:40:32 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 213a9a7813 | |||
| 48ba1f3f24 | |||
| d59fcf01bf | |||
| b8456394f1 | |||
| a467dd1ba6 | |||
| c156f4760f | |||
| 13f11ebf49 | |||
| 6065e9aa09 | |||
| 8ed0ed5828 | |||
| 33067af283 | |||
| d0a054270e | |||
| 2a3507c2b9 | |||
| f71f43561d | |||
| ecbfad4193 | |||
| d76b2b5d26 | |||
| cd9527072d | |||
| ffdaf7369a |
@@ -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()
|
|
||||||
@@ -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")
|
|
||||||
@@ -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>
|
From: crueter <crueter@eden-emu.dev>
|
||||||
Date: Fri, 24 Oct 2025 23:41:09 -0700
|
Date: Sun, 1 Feb 2026 16:21:10 -0500
|
||||||
Subject: [PATCH] [build] Fix MinGW missing GetAddrInfoExCancel definition
|
Subject: [PATCH] Fix build on MinGW
|
||||||
|
|
||||||
MinGW does not define GetAddrInfoExCancel in its wstcpi whatever header,
|
MinGW doesn't define GetAddrInfoExCancel.
|
||||||
so to get around this we can just load it with GetProcAddress et al.
|
|
||||||
|
|
||||||
Signed-off-by: crueter <crueter@eden-emu.dev>
|
Signed-off-by: crueter <crueter@eden-emu.dev>
|
||||||
---
|
---
|
||||||
httplib.h | 14 ++++++++++++--
|
httplib.h | 18 ++++++++++++++++--
|
||||||
1 file changed, 12 insertions(+), 2 deletions(-)
|
1 file changed, 16 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
diff --git a/httplib.h b/httplib.h
|
diff --git a/httplib.h b/httplib.h
|
||||||
index e15ba44..90a76dc 100644
|
index ec8d2a2..5f9a510 100644
|
||||||
--- a/httplib.h
|
--- a/httplib.h
|
||||||
+++ b/httplib.h
|
+++ b/httplib.h
|
||||||
@@ -203,11 +203,13 @@
|
@@ -203,14 +203,17 @@
|
||||||
#error Sorry, Visual Studio versions prior to 2015 are not supported
|
#error Sorry, Visual Studio versions prior to 2015 are not supported
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
-#pragma comment(lib, "ws2_32.lib")
|
-#pragma comment(lib, "ws2_32.lib")
|
||||||
-
|
-
|
||||||
|
#ifndef _SSIZE_T_DEFINED
|
||||||
using ssize_t = __int64;
|
using ssize_t = __int64;
|
||||||
|
#define _SSIZE_T_DEFINED
|
||||||
|
#endif
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
+#if defined(_MSC_VER) || defined(__MINGW32__)
|
+#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
+#pragma comment(lib, "ws2_32.lib")
|
+#pragma comment(lib, "ws2_32.lib")
|
||||||
+#endif
|
+#endif
|
||||||
|
+
|
||||||
+
|
+
|
||||||
#ifndef S_ISREG
|
#ifndef S_ISREG
|
||||||
#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
|
#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
|
||||||
#endif // S_ISREG
|
#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 =
|
auto wait_result =
|
||||||
::WaitForSingleObject(event, static_cast<DWORD>(timeout_sec * 1000));
|
::WaitForSingleObject(event, static_cast<DWORD>(timeout_sec * 1000));
|
||||||
if (wait_result == WAIT_TIMEOUT) {
|
if (wait_result == WAIT_TIMEOUT) {
|
||||||
+#ifdef __MINGW32__
|
+#ifdef __MINGW32__
|
||||||
+ typedef INT (WSAAPI *PFN_GETADDRINFOEXCANCEL)(HANDLE *CancelHandle);
|
+ typedef INT(WSAAPI * PFN_GETADDRINFOEXCANCEL)(HANDLE * CancelHandle);
|
||||||
+ auto wsdll = LoadLibraryW((wchar_t*) "ws2_32.lib");
|
+ auto wsdll = LoadLibraryW((wchar_t *)"ws2_32.lib");
|
||||||
+ PFN_GETADDRINFOEXCANCEL GetAddrInfoExCancel = (PFN_GETADDRINFOEXCANCEL) GetProcAddress(wsdll, "GetAddrInfoExCancel");
|
+ PFN_GETADDRINFOEXCANCEL GetAddrInfoExCancel =
|
||||||
|
+ (PFN_GETADDRINFOEXCANCEL)GetProcAddress(wsdll, "GetAddrInfoExCancel");
|
||||||
+
|
+
|
||||||
+ if (cancel_handle) { GetAddrInfoExCancel(&cancel_handle); }
|
+ if (cancel_handle) { GetAddrInfoExCancel(&cancel_handle); }
|
||||||
+#else
|
+#else
|
||||||
if (cancel_handle) { ::GetAddrInfoExCancel(&cancel_handle); }
|
if (cancel_handle) { ::GetAddrInfoExCancel(&cancel_handle); }
|
||||||
+#endif
|
+#endif
|
||||||
|
+
|
||||||
::CloseHandle(event);
|
::CloseHandle(event);
|
||||||
return EAI_AGAIN;
|
return EAI_AGAIN;
|
||||||
}
|
}
|
||||||
--
|
@@ -13952,3 +13965,4 @@ inline SSL_CTX *Client::ssl_context() const {
|
||||||
2.51.0
|
} // namespace httplib
|
||||||
|
|
||||||
|
#endif // CPPHTTPLIB_HTTPLIB_H
|
||||||
|
+
|
||||||
|
--
|
||||||
|
2.51.2
|
||||||
|
|
||||||
|
|||||||
+9
-1
@@ -178,7 +178,9 @@ endif()
|
|||||||
|
|
||||||
# Disable Warnings as Errors for MSVC
|
# Disable Warnings as Errors for MSVC
|
||||||
if (MSVC AND NOT CXX_CLANG)
|
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()
|
endif()
|
||||||
|
|
||||||
# Set bundled sdl2/qt as dependent options.
|
# Set bundled sdl2/qt as dependent options.
|
||||||
@@ -587,6 +589,7 @@ if (NOT YUZU_STATIC_ROOM)
|
|||||||
find_package(sirit)
|
find_package(sirit)
|
||||||
find_package(gamemode)
|
find_package(gamemode)
|
||||||
find_package(mcl)
|
find_package(mcl)
|
||||||
|
find_package(frozen)
|
||||||
|
|
||||||
if (ARCHITECTURE_riscv64)
|
if (ARCHITECTURE_riscv64)
|
||||||
find_package(biscuit)
|
find_package(biscuit)
|
||||||
@@ -693,6 +696,11 @@ if (ENABLE_QT)
|
|||||||
set(QT_MAJOR_VERSION 6)
|
set(QT_MAJOR_VERSION 6)
|
||||||
# Qt6 sets cxx_std_17 and we need to undo that
|
# Qt6 sets cxx_std_17 and we need to undo that
|
||||||
set_target_properties(Qt6::Platform PROPERTIES INTERFACE_COMPILE_FEATURES "")
|
set_target_properties(Qt6::Platform PROPERTIES INTERFACE_COMPILE_FEATURES "")
|
||||||
|
|
||||||
|
## Qt Externals ##
|
||||||
|
|
||||||
|
# QuaZip
|
||||||
|
AddJsonPackage(quazip)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT YUZU_STATIC_ROOM AND NOT (YUZU_USE_BUNDLED_FFMPEG OR YUZU_USE_EXTERNAL_FFMPEG))
|
if (NOT YUZU_STATIC_ROOM AND NOT (YUZU_USE_BUNDLED_FFMPEG OR YUZU_USE_EXTERNAL_FFMPEG))
|
||||||
|
|||||||
+129
-62
@@ -41,6 +41,11 @@ function(cpm_utils_message level name message)
|
|||||||
message(${level} "[CPMUtil] ${name}: ${message}")
|
message(${level} "[CPMUtil] ${name}: ${message}")
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
# propagate a variable to parent scope
|
||||||
|
macro(Propagate var)
|
||||||
|
set(${var} ${${var}} PARENT_SCOPE)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
function(array_to_list array length out)
|
function(array_to_list array length out)
|
||||||
math(EXPR range "${length} - 1")
|
math(EXPR range "${length} - 1")
|
||||||
|
|
||||||
@@ -72,45 +77,68 @@ function(get_json_element object out member default)
|
|||||||
set("${out}" "${outvar}" PARENT_SCOPE)
|
set("${out}" "${outvar}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# The preferred usage
|
# Determine whether or not a package has a viable system candidate.
|
||||||
function(AddJsonPackage)
|
function(SystemPackageViable JSON_NAME)
|
||||||
set(oneValueArgs
|
string(JSON object GET "${CPMFILE_CONTENT}" "${JSON_NAME}")
|
||||||
NAME
|
|
||||||
|
|
||||||
# these are overrides that can be generated at runtime,
|
parse_object(${object})
|
||||||
# so can be defined separately from the json
|
|
||||||
DOWNLOAD_ONLY
|
|
||||||
BUNDLED_PACKAGE)
|
|
||||||
|
|
||||||
set(multiValueArgs OPTIONS)
|
string(REPLACE " " ";" find_args "${find_args}")
|
||||||
|
find_package(${package} ${version} ${find_args} QUIET NO_POLICY_SCOPE)
|
||||||
|
|
||||||
cmake_parse_arguments(JSON "" "${oneValueArgs}" "${multiValueArgs}"
|
set(${pkg}_VIABLE ${${package}_FOUND} PARENT_SCOPE)
|
||||||
"${ARGN}")
|
set(${pkg}_PACKAGE ${package} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
list(LENGTH ARGN argnLength)
|
# 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)
|
||||||
|
|
||||||
# single name argument
|
foreach(pkg ${ARGN})
|
||||||
if(argnLength EQUAL 1)
|
SystemPackageViable(${pkg})
|
||||||
set(JSON_NAME "${ARGV0}")
|
|
||||||
|
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()
|
endif()
|
||||||
|
|
||||||
if(NOT DEFINED CPMFILE_CONTENT)
|
foreach(pkg ${ARGN})
|
||||||
cpm_utils_message(WARNING ${name}
|
AddJsonPackage(${pkg})
|
||||||
"No cpmfile, AddJsonPackage is a no-op")
|
endforeach()
|
||||||
return()
|
endfunction()
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT DEFINED JSON_NAME)
|
|
||||||
cpm_utils_message(FATAL_ERROR "json package" "No name specified")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
string(JSON object ERROR_VARIABLE
|
|
||||||
err GET "${CPMFILE_CONTENT}" "${JSON_NAME}")
|
|
||||||
|
|
||||||
if(err)
|
|
||||||
cpm_utils_message(FATAL_ERROR ${JSON_NAME} "Not found in cpmfile")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
# json util
|
||||||
|
macro(parse_object object)
|
||||||
get_json_element("${object}" package package ${JSON_NAME})
|
get_json_element("${object}" package package ${JSON_NAME})
|
||||||
get_json_element("${object}" repo repo "")
|
get_json_element("${object}" repo repo "")
|
||||||
get_json_element("${object}" ci ci OFF)
|
get_json_element("${object}" ci ci OFF)
|
||||||
@@ -128,27 +156,7 @@ function(AddJsonPackage)
|
|||||||
else()
|
else()
|
||||||
set(disabled_platforms "")
|
set(disabled_platforms "")
|
||||||
endif()
|
endif()
|
||||||
|
else()
|
||||||
AddCIPackage(
|
|
||||||
VERSION ${version}
|
|
||||||
NAME ${name}
|
|
||||||
REPO ${repo}
|
|
||||||
PACKAGE ${package}
|
|
||||||
EXTENSION ${extension}
|
|
||||||
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 hash "")
|
||||||
get_json_element("${object}" hash_suffix hash_suffix "")
|
get_json_element("${object}" hash_suffix hash_suffix "")
|
||||||
get_json_element("${object}" sha sha "")
|
get_json_element("${object}" sha sha "")
|
||||||
@@ -181,7 +189,8 @@ function(AddJsonPackage)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(artifact)
|
if(artifact)
|
||||||
string(REPLACE "%VERSION%" "${version_replace}" artifact ${artifact})
|
string(REPLACE "%VERSION%" "${version_replace}"
|
||||||
|
artifact ${artifact})
|
||||||
string(REPLACE "%TAG%" "${tag}" artifact ${artifact})
|
string(REPLACE "%TAG%" "${tag}" artifact ${artifact})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -218,6 +227,65 @@ function(AddJsonPackage)
|
|||||||
if(bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE)
|
if(bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE)
|
||||||
set(bundled ${JSON_BUNDLED_PACKAGE})
|
set(bundled ${JSON_BUNDLED_PACKAGE})
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# The preferred usage
|
||||||
|
function(AddJsonPackage)
|
||||||
|
set(oneValueArgs
|
||||||
|
NAME
|
||||||
|
|
||||||
|
# these are overrides that can be generated at runtime,
|
||||||
|
# so can be defined separately from the json
|
||||||
|
DOWNLOAD_ONLY
|
||||||
|
BUNDLED_PACKAGE
|
||||||
|
FORCE_BUNDLED_PACKAGE)
|
||||||
|
|
||||||
|
set(multiValueArgs OPTIONS)
|
||||||
|
|
||||||
|
cmake_parse_arguments(JSON "" "${oneValueArgs}" "${multiValueArgs}"
|
||||||
|
"${ARGN}")
|
||||||
|
|
||||||
|
list(LENGTH ARGN argnLength)
|
||||||
|
|
||||||
|
# single name argument
|
||||||
|
if(argnLength EQUAL 1)
|
||||||
|
set(JSON_NAME "${ARGV0}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED CPMFILE_CONTENT)
|
||||||
|
cpm_utils_message(WARNING ${name}
|
||||||
|
"No cpmfile, AddJsonPackage is a no-op")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED JSON_NAME)
|
||||||
|
cpm_utils_message(FATAL_ERROR "json package" "No name specified")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(JSON object ERROR_VARIABLE
|
||||||
|
err GET "${CPMFILE_CONTENT}" "${JSON_NAME}")
|
||||||
|
|
||||||
|
if(err)
|
||||||
|
cpm_utils_message(FATAL_ERROR ${JSON_NAME} "Not found in cpmfile")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
parse_object(${object})
|
||||||
|
|
||||||
|
if(ci)
|
||||||
|
AddCIPackage(
|
||||||
|
VERSION ${version}
|
||||||
|
NAME ${name}
|
||||||
|
REPO ${repo}
|
||||||
|
PACKAGE ${package}
|
||||||
|
EXTENSION ${extension}
|
||||||
|
MIN_VERSION ${min_version}
|
||||||
|
DISABLED_PLATFORMS ${disabled_platforms})
|
||||||
|
|
||||||
|
else()
|
||||||
|
if (NOT DEFINED JSON_FORCE_BUNDLED_PACKAGE)
|
||||||
|
set(JSON_FORCE_BUNDLED_PACKAGE OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
AddPackage(
|
AddPackage(
|
||||||
NAME "${package}"
|
NAME "${package}"
|
||||||
@@ -232,6 +300,7 @@ function(AddJsonPackage)
|
|||||||
OPTIONS "${options}"
|
OPTIONS "${options}"
|
||||||
FIND_PACKAGE_ARGUMENTS "${find_args}"
|
FIND_PACKAGE_ARGUMENTS "${find_args}"
|
||||||
BUNDLED_PACKAGE "${bundled}"
|
BUNDLED_PACKAGE "${bundled}"
|
||||||
|
FORCE_BUNDLED_PACKAGE "${JSON_FORCE_BUNDLED_PACKAGE}"
|
||||||
SOURCE_SUBDIR "${source_subdir}"
|
SOURCE_SUBDIR "${source_subdir}"
|
||||||
|
|
||||||
GIT_VERSION ${git_version}
|
GIT_VERSION ${git_version}
|
||||||
@@ -239,15 +308,12 @@ function(AddJsonPackage)
|
|||||||
|
|
||||||
ARTIFACT ${artifact}
|
ARTIFACT ${artifact}
|
||||||
TAG ${tag})
|
TAG ${tag})
|
||||||
|
endif()
|
||||||
|
|
||||||
# pass stuff to parent scope
|
# pass stuff to parent scope
|
||||||
set(${package}_ADDED "${${package}_ADDED}"
|
Propagate(${package}_ADDED)
|
||||||
PARENT_SCOPE)
|
Propagate(${package}_SOURCE_DIR)
|
||||||
set(${package}_SOURCE_DIR "${${package}_SOURCE_DIR}"
|
Propagate(${package}_BINARY_DIR)
|
||||||
PARENT_SCOPE)
|
|
||||||
set(${package}_BINARY_DIR "${${package}_BINARY_DIR}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(AddPackage)
|
function(AddPackage)
|
||||||
@@ -343,7 +409,7 @@ function(AddPackage)
|
|||||||
|
|
||||||
if(DEFINED PKG_ARGS_ARTIFACT)
|
if(DEFINED PKG_ARGS_ARTIFACT)
|
||||||
set(pkg_url
|
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()
|
else()
|
||||||
set(pkg_url
|
set(pkg_url
|
||||||
${pkg_git_url}/archive/refs/tags/${PKG_ARGS_TAG}.tar.gz)
|
${pkg_git_url}/archive/refs/tags/${PKG_ARGS_TAG}.tar.gz)
|
||||||
@@ -625,7 +691,8 @@ function(AddCIPackage)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (DEFINED pkgname AND NOT "${pkgname}" IN_LIST DISABLED_PLATFORMS)
|
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(
|
AddPackage(
|
||||||
NAME ${ARTIFACT_PACKAGE}
|
NAME ${ARTIFACT_PACKAGE}
|
||||||
|
|||||||
+18
-7
@@ -12,14 +12,12 @@
|
|||||||
"repo": "boostorg/boost",
|
"repo": "boostorg/boost",
|
||||||
"tag": "boost-%VERSION%",
|
"tag": "boost-%VERSION%",
|
||||||
"artifact": "%TAG%-cmake.tar.xz",
|
"artifact": "%TAG%-cmake.tar.xz",
|
||||||
"hash": "4fb7f6fde92762305aad8754d7643cd918dd1f3f67e104e9ab385b18c73178d72a17321354eb203b790b6702f2cf6d725a5d6e2dfbc63b1e35f9eb59fb42ece9",
|
"hash": "6ae6e94664fe7f2fb01976b59b276ac5df8085c7503fa829d810fbfe495960cfec44fa2c36e2cb23480bc19c956ed199d4952b02639a00a6c07625d4e7130c2d",
|
||||||
"git_version": "1.89.0",
|
"git_version": "1.90.0",
|
||||||
"version": "1.57",
|
"version": "1.57",
|
||||||
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
||||||
"patches": [
|
"patches": [
|
||||||
"0001-clang-cl.patch",
|
"0001-clang-cl.patch"
|
||||||
"0002-use-marmasm.patch",
|
|
||||||
"0003-armasm-options.patch"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"fmt": {
|
"fmt": {
|
||||||
@@ -48,9 +46,9 @@
|
|||||||
"package": "ZLIB",
|
"package": "ZLIB",
|
||||||
"repo": "madler/zlib",
|
"repo": "madler/zlib",
|
||||||
"tag": "v%VERSION%",
|
"tag": "v%VERSION%",
|
||||||
"hash": "8c9642495bafd6fad4ab9fb67f09b268c69ff9af0f4f20cf15dfc18852ff1f312bd8ca41de761b3f8d8e90e77d79f2ccacd3d4c5b19e475ecf09d021fdfe9088",
|
"hash": "06eaa3a1eaaeb31f461a2283b03a91ed8eb2406e62cd97ea1c69836324909edeecd93edd03ff0bf593d9dde223e3376149134c5b1fe2e8688c258cadf8cd60ff",
|
||||||
"version": "1.2",
|
"version": "1.2",
|
||||||
"git_version": "1.3.1",
|
"git_version": "1.3.1.2",
|
||||||
"options": [
|
"options": [
|
||||||
"ZLIB_BUILD_SHARED OFF",
|
"ZLIB_BUILD_SHARED OFF",
|
||||||
"ZLIB_INSTALL OFF"
|
"ZLIB_INSTALL OFF"
|
||||||
@@ -103,5 +101,18 @@
|
|||||||
"git_version": "1.4.335.0",
|
"git_version": "1.4.335.0",
|
||||||
"artifact": "android-binaries-%VERSION%.zip",
|
"artifact": "android-binaries-%VERSION%.zip",
|
||||||
"hash": "48167c4a17736301bd08f9290f41830443e1f18cce8ad867fc6f289b49e18b40e93c9850b377951af82f51b5b6d7313aa6a884fc5df79f5ce3df82696c1c1244"
|
"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
@@ -18,7 +18,7 @@
|
|||||||
src/web_service @AleksandrPopovich
|
src/web_service @AleksandrPopovich
|
||||||
src/dynarmic @Lizzie
|
src/dynarmic @Lizzie
|
||||||
src/core @Lizzie @Maufeat @PavelBARABANOV @MrPurple666 @JPikachu
|
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/core/arm @Lizzie @MrPurple666
|
||||||
src/*_room @AleksandrPopovich
|
src/*_room @AleksandrPopovich
|
||||||
src/video_core @CamilleLaVey @MaranBr @Wildcard @weakboson
|
src/video_core @CamilleLaVey @MaranBr @Wildcard @weakboson
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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.
|
[`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`](./AddQt.md) adds a specific version of Qt to your project.
|
[`AddQt`](./AddQt.md) adds a specific version of Qt to your project.
|
||||||
|
|||||||
Vendored
+4
-6
@@ -83,13 +83,11 @@ endif()
|
|||||||
# mcl
|
# mcl
|
||||||
AddJsonPackage(mcl)
|
AddJsonPackage(mcl)
|
||||||
|
|
||||||
# VulkanUtilityHeaders - pulls in headers and utility libs
|
# Vulkan stuff
|
||||||
AddJsonPackage(vulkan-utility-headers)
|
AddDependentPackages(vulkan-headers vulkan-utility-libraries)
|
||||||
|
|
||||||
# small hack
|
# frozen
|
||||||
if (NOT VulkanUtilityLibraries_ADDED)
|
AddJsonPackage(frozen)
|
||||||
find_package(VulkanHeaders 1.3.274 REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# DiscordRPC
|
# DiscordRPC
|
||||||
if (USE_DISCORD_PRESENCE)
|
if (USE_DISCORD_PRESENCE)
|
||||||
|
|||||||
Vendored
+25
-13
@@ -28,8 +28,8 @@
|
|||||||
"httplib": {
|
"httplib": {
|
||||||
"repo": "yhirose/cpp-httplib",
|
"repo": "yhirose/cpp-httplib",
|
||||||
"tag": "v%VERSION%",
|
"tag": "v%VERSION%",
|
||||||
"hash": "e7a8877d489c97669a8ee536e1498575be921e558ed947253013fe6b67a49d4569eedd01f543caa70183b92d8ac0e8687d662a70d880954412e387317008a239",
|
"hash": "a229e24cca4afe78e5c0aa2e482f15108ac34101fd8dbd927365f15e8c37dec4de38c5277d635017d692a5b320e1b929f8bfcc076f52b8e4dcdab8fe53bfdf2e",
|
||||||
"git_version": "0.28.0",
|
"git_version": "0.30.1",
|
||||||
"find_args": "MODULE GLOBAL",
|
"find_args": "MODULE GLOBAL",
|
||||||
"patches": [
|
"patches": [
|
||||||
"0001-mingw.patch"
|
"0001-mingw.patch"
|
||||||
@@ -118,15 +118,6 @@
|
|||||||
"git_version": "1.3.18",
|
"git_version": "1.3.18",
|
||||||
"find_args": "MODULE"
|
"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": {
|
"spirv-tools": {
|
||||||
"package": "SPIRV-Tools",
|
"package": "SPIRV-Tools",
|
||||||
"repo": "KhronosGroup/SPIRV-Tools",
|
"repo": "KhronosGroup/SPIRV-Tools",
|
||||||
@@ -174,9 +165,9 @@
|
|||||||
"package": "Catch2",
|
"package": "Catch2",
|
||||||
"repo": "catchorg/Catch2",
|
"repo": "catchorg/Catch2",
|
||||||
"tag": "v%VERSION%",
|
"tag": "v%VERSION%",
|
||||||
"hash": "a95495142f915d6e9c2a23e80fe360343e9097680066a2f9d3037a070ba5f81ee5559a0407cc9e972dc2afae325873f1fc7ea07a64012c0f01aac6e549f03e3f",
|
"hash": "acb3f463a7404d6a3bce52e474075cdadf9bb241d93feaf147c182d756e5a2f8bd412f4658ca186d15ab8fed36fc587d79ec311f55642d8e4ded16df9e213656",
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"git_version": "3.11.0",
|
"git_version": "3.12.0",
|
||||||
"patches": [
|
"patches": [
|
||||||
"0001-solaris-isnan-fix.patch"
|
"0001-solaris-isnan-fix.patch"
|
||||||
]
|
]
|
||||||
@@ -281,5 +272,26 @@
|
|||||||
"tag": "%VERSION%",
|
"tag": "%VERSION%",
|
||||||
"hash": "dc37a189a44ce8b5c988ca550582431a6c7eadfd3c6e709bee6277116ee803e714333e85c9e6cbb5c69346a14d6f2cc7ed96e8aa09cc5fb8a89f945059651db6",
|
"hash": "dc37a189a44ce8b5c988ca550582431a6c7eadfd3c6e709bee6277116ee803e714333e85c9e6cbb5c69346a14d6f2cc7ed96e8aa09cc5fb8a89f945059651db6",
|
||||||
"version": "121125"
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,14 +22,6 @@ import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
|
|||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||||
|
|
||||||
class QuickSettings(val emulationFragment: EmulationFragment) {
|
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() {
|
private fun saveSettings() {
|
||||||
if (emulationFragment.shouldUseCustom) {
|
if (emulationFragment.shouldUseCustom) {
|
||||||
NativeConfig.savePerGameConfig()
|
NativeConfig.savePerGameConfig()
|
||||||
@@ -60,6 +52,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
// settings
|
// settings
|
||||||
|
|
||||||
fun addIntSetting(
|
fun addIntSetting(
|
||||||
|
name: Int,
|
||||||
container: ViewGroup,
|
container: ViewGroup,
|
||||||
setting: IntSetting,
|
setting: IntSetting,
|
||||||
namesArrayId: Int,
|
namesArrayId: Int,
|
||||||
@@ -73,7 +66,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.expand_icon)
|
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.expand_icon)
|
||||||
val radioGroup = itemView.findViewById<RadioGroup>(R.id.radio_group)
|
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 names = emulationFragment.resources.getStringArray(namesArrayId)
|
||||||
val values = emulationFragment.resources.getIntArray(valuesArrayId)
|
val values = emulationFragment.resources.getIntArray(valuesArrayId)
|
||||||
@@ -115,6 +108,8 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addBooleanSetting(
|
fun addBooleanSetting(
|
||||||
|
name: Int,
|
||||||
|
|
||||||
container: ViewGroup,
|
container: ViewGroup,
|
||||||
setting: BooleanSetting
|
setting: BooleanSetting
|
||||||
) {
|
) {
|
||||||
@@ -125,7 +120,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
val titleView = itemView.findViewById<TextView>(R.id.switch_title)
|
val titleView = itemView.findViewById<TextView>(R.id.switch_title)
|
||||||
val switchView = itemView.findViewById<com.google.android.material.materialswitch.MaterialSwitch>(R.id.setting_switch)
|
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
|
switchContainer.visibility = View.VISIBLE
|
||||||
switchView.isChecked = setting.getBoolean()
|
switchView.isChecked = setting.getBoolean()
|
||||||
|
|
||||||
@@ -141,6 +136,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addSliderSetting(
|
fun addSliderSetting(
|
||||||
|
name: Int,
|
||||||
container: ViewGroup,
|
container: ViewGroup,
|
||||||
setting: AbstractSetting,
|
setting: AbstractSetting,
|
||||||
minValue: Int = 0,
|
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)
|
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
|
sliderContainer.visibility = View.VISIBLE
|
||||||
|
|
||||||
slider.valueFrom = minValue.toFloat()
|
slider.valueFrom = minValue.toFloat()
|
||||||
|
|||||||
+6
-1
@@ -24,6 +24,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
|
RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
|
||||||
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
|
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
|
||||||
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
||||||
|
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
|
||||||
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
|
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
|
||||||
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
|
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
|
||||||
RENDERER_DEBUG("debug"),
|
RENDERER_DEBUG("debug"),
|
||||||
@@ -36,6 +37,9 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
USE_CUSTOM_RTC("custom_rtc_enabled"),
|
USE_CUSTOM_RTC("custom_rtc_enabled"),
|
||||||
BLACK_BACKGROUNDS("black_backgrounds"),
|
BLACK_BACKGROUNDS("black_backgrounds"),
|
||||||
|
|
||||||
|
ENABLE_FOLDER_BUTTON("enable_folder_button"),
|
||||||
|
ENABLE_QLAUNCH_BUTTON("enable_qlaunch_button"),
|
||||||
|
|
||||||
ENABLE_UPDATE_CHECKS("enable_update_checks"),
|
ENABLE_UPDATE_CHECKS("enable_update_checks"),
|
||||||
JOYSTICK_REL_CENTER("joystick_rel_center"),
|
JOYSTICK_REL_CENTER("joystick_rel_center"),
|
||||||
DPAD_SLIDE("dpad_slide"),
|
DPAD_SLIDE("dpad_slide"),
|
||||||
@@ -79,8 +83,9 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
GPU_LOG_VULKAN_CALLS("gpu_log_vulkan_calls"),
|
GPU_LOG_VULKAN_CALLS("gpu_log_vulkan_calls"),
|
||||||
GPU_LOG_SHADER_DUMPS("gpu_log_shader_dumps"),
|
GPU_LOG_SHADER_DUMPS("gpu_log_shader_dumps"),
|
||||||
GPU_LOG_MEMORY_TRACKING("gpu_log_memory_tracking"),
|
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 isFrameSkippingEnabled(): Boolean
|
||||||
external fun isFrameInterpolationEnabled(): Boolean
|
external fun isFrameInterpolationEnabled(): Boolean
|
||||||
|
|||||||
+33
@@ -60,6 +60,11 @@ abstract class SettingsItem(
|
|||||||
return NativeInput.getStyleIndex(0) != NpadStyleIndex.Handheld
|
return NativeInput.getStyleIndex(0) != NpadStyleIndex.Handheld
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can't edit enable_qlaunch_button if firmware is not available
|
||||||
|
if (setting.key == BooleanSetting.ENABLE_QLAUNCH_BUTTON.key) {
|
||||||
|
return NativeLibrary.isFirmwareAvailable()
|
||||||
|
}
|
||||||
|
|
||||||
// Can't edit settings that aren't saveable in per-game config even if they are switchable
|
// Can't edit settings that aren't saveable in per-game config even if they are switchable
|
||||||
if (NativeConfig.isPerGameConfigLoaded() && !setting.isSaveable) {
|
if (NativeConfig.isPerGameConfigLoaded() && !setting.isSaveable) {
|
||||||
return false
|
return false
|
||||||
@@ -740,6 +745,13 @@ abstract class SettingsItem(
|
|||||||
descriptionId = R.string.renderer_reactive_flushing_description
|
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(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.SYNC_MEMORY_OPERATIONS,
|
BooleanSetting.SYNC_MEMORY_OPERATIONS,
|
||||||
@@ -794,6 +806,27 @@ abstract class SettingsItem(
|
|||||||
descriptionId = R.string.enable_update_checks_description,
|
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,
|
||||||
|
titleId = R.string.enable_folder_button,
|
||||||
|
descriptionId = R.string.enable_folder_button_description,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
put(
|
||||||
|
SwitchSetting(
|
||||||
|
BooleanSetting.ENABLE_QLAUNCH_BUTTON,
|
||||||
|
titleId = R.string.enable_qlaunch_button,
|
||||||
|
descriptionId = R.string.enable_qlaunch_button_description,
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SingleChoiceSetting(
|
SingleChoiceSetting(
|
||||||
IntSetting.APP_LANGUAGE,
|
IntSetting.APP_LANGUAGE,
|
||||||
|
|||||||
+10
@@ -275,6 +275,7 @@ class SettingsFragmentPresenter(
|
|||||||
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
|
||||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||||
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
||||||
|
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
|
||||||
|
|
||||||
add(HeaderSetting(R.string.hacks))
|
add(HeaderSetting(R.string.hacks))
|
||||||
|
|
||||||
@@ -1074,6 +1075,8 @@ class SettingsFragmentPresenter(
|
|||||||
add(BooleanSetting.ENABLE_UPDATE_CHECKS.key)
|
add(BooleanSetting.ENABLE_UPDATE_CHECKS.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add(BooleanSetting.ENABLE_QUICK_SETTINGS.key)
|
||||||
|
|
||||||
add(HeaderSetting(R.string.theme_and_color))
|
add(HeaderSetting(R.string.theme_and_color))
|
||||||
|
|
||||||
|
|
||||||
@@ -1191,6 +1194,13 @@ class SettingsFragmentPresenter(
|
|||||||
descriptionId = R.string.use_black_backgrounds_description
|
descriptionId = R.string.use_black_backgrounds_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add(HeaderSetting(R.string.buttons))
|
||||||
|
add(BooleanSetting.ENABLE_FOLDER_BUTTON.key)
|
||||||
|
add(BooleanSetting.ENABLE_QLAUNCH_BUTTON.key)
|
||||||
|
if (!NativeLibrary.isFirmwareAvailable()) {
|
||||||
|
BooleanSetting.ENABLE_QLAUNCH_BUTTON.setBoolean(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -690,8 +690,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
})
|
})
|
||||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
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()
|
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 {
|
binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply {
|
||||||
val lockMode = IntSetting.LOCK_DRAWER.getInt()
|
val lockMode = IntSetting.LOCK_DRAWER.getInt()
|
||||||
val titleId = if (lockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
|
val titleId = if (lockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
|
||||||
@@ -749,7 +759,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_quick_settings -> {
|
if (BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean())
|
||||||
|
R.id.menu_quick_settings else 0 -> {
|
||||||
openQuickSettingsMenu()
|
openQuickSettingsMenu()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -1045,11 +1056,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
quickSettings.addBooleanSetting(
|
quickSettings.addBooleanSetting(
|
||||||
|
R.string.frame_limit_enable,
|
||||||
container,
|
container,
|
||||||
BooleanSetting.RENDERER_USE_SPEED_LIMIT,
|
BooleanSetting.RENDERER_USE_SPEED_LIMIT,
|
||||||
)
|
)
|
||||||
|
|
||||||
quickSettings.addSliderSetting(
|
quickSettings.addSliderSetting(
|
||||||
|
R.string.frame_limit_slider,
|
||||||
container,
|
container,
|
||||||
ShortSetting.RENDERER_SPEED_LIMIT,
|
ShortSetting.RENDERER_SPEED_LIMIT,
|
||||||
minValue = 0,
|
minValue = 0,
|
||||||
@@ -1058,6 +1071,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
)
|
)
|
||||||
|
|
||||||
quickSettings.addBooleanSetting(
|
quickSettings.addBooleanSetting(
|
||||||
|
R.string.use_docked_mode,
|
||||||
container,
|
container,
|
||||||
BooleanSetting.USE_DOCKED_MODE,
|
BooleanSetting.USE_DOCKED_MODE,
|
||||||
)
|
)
|
||||||
@@ -1065,6 +1079,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
quickSettings.addDivider(container)
|
quickSettings.addDivider(container)
|
||||||
|
|
||||||
quickSettings.addIntSetting(
|
quickSettings.addIntSetting(
|
||||||
|
R.string.renderer_accuracy,
|
||||||
container,
|
container,
|
||||||
IntSetting.RENDERER_ACCURACY,
|
IntSetting.RENDERER_ACCURACY,
|
||||||
R.array.rendererAccuracyNames,
|
R.array.rendererAccuracyNames,
|
||||||
@@ -1073,6 +1088,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
|
|
||||||
|
|
||||||
quickSettings.addIntSetting(
|
quickSettings.addIntSetting(
|
||||||
|
R.string.renderer_scaling_filter,
|
||||||
container,
|
container,
|
||||||
IntSetting.RENDERER_SCALING_FILTER,
|
IntSetting.RENDERER_SCALING_FILTER,
|
||||||
R.array.rendererScalingFilterNames,
|
R.array.rendererScalingFilterNames,
|
||||||
@@ -1080,6 +1096,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
)
|
)
|
||||||
|
|
||||||
quickSettings.addSliderSetting(
|
quickSettings.addSliderSetting(
|
||||||
|
R.string.fsr_sharpness,
|
||||||
container,
|
container,
|
||||||
IntSetting.FSR_SHARPENING_SLIDER,
|
IntSetting.FSR_SHARPENING_SLIDER,
|
||||||
minValue = 0,
|
minValue = 0,
|
||||||
@@ -1088,6 +1105,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
)
|
)
|
||||||
|
|
||||||
quickSettings.addIntSetting(
|
quickSettings.addIntSetting(
|
||||||
|
R.string.renderer_anti_aliasing,
|
||||||
container,
|
container,
|
||||||
IntSetting.RENDERER_ANTI_ALIASING,
|
IntSetting.RENDERER_ANTI_ALIASING,
|
||||||
R.array.rendererAntiAliasingNames,
|
R.array.rendererAntiAliasingNames,
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.ui
|
package org.yuzu.yuzu_emu.ui
|
||||||
@@ -13,6 +13,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
@@ -27,10 +28,14 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.adapters.GameAdapter
|
import org.yuzu.yuzu_emu.adapters.GameAdapter
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
|
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||||
|
import org.yuzu.yuzu_emu.model.AppletInfo
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.model.GamesViewModel
|
import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
@@ -173,10 +178,16 @@ class GamesFragment : Fragment() {
|
|||||||
|
|
||||||
setupTopView()
|
setupTopView()
|
||||||
|
|
||||||
|
updateButtonsVisibility()
|
||||||
|
|
||||||
binding.addDirectory.setOnClickListener {
|
binding.addDirectory.setOnClickListener {
|
||||||
getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
|
getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.launchQlaunch?.setOnClickListener {
|
||||||
|
launchQLaunch()
|
||||||
|
}
|
||||||
|
|
||||||
setInsets()
|
setInsets()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,6 +456,47 @@ class GamesFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun launchQLaunch() {
|
||||||
|
try {
|
||||||
|
val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.QLaunch.entryId)
|
||||||
|
if (appletPath.isEmpty()) {
|
||||||
|
Toast.makeText(
|
||||||
|
requireContext(),
|
||||||
|
R.string.applets_error_applet,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeLibrary.setCurrentAppletId(AppletInfo.QLaunch.appletId)
|
||||||
|
|
||||||
|
val qlaunchGame = Game(
|
||||||
|
title = getString(R.string.qlaunch_applet),
|
||||||
|
path = appletPath
|
||||||
|
)
|
||||||
|
|
||||||
|
val action = HomeNavigationDirections.actionGlobalEmulationActivity(qlaunchGame)
|
||||||
|
findNavController().navigate(action)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(
|
||||||
|
requireContext(),
|
||||||
|
"Failed to launch QLaunch: ${e.message}",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateButtonsVisibility() {
|
||||||
|
val showQLaunch = BooleanSetting.ENABLE_QLAUNCH_BUTTON.getBoolean()
|
||||||
|
val showFolder = BooleanSetting.ENABLE_FOLDER_BUTTON.getBoolean()
|
||||||
|
val isFirmwareAvailable = NativeLibrary.isFirmwareAvailable()
|
||||||
|
|
||||||
|
val shouldShowQLaunch = showQLaunch && isFirmwareAvailable
|
||||||
|
binding.launchQlaunch.visibility = if (shouldShowQLaunch) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
|
binding.addDirectory.visibility = if (showFolder) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
private fun setInsets() =
|
private fun setInsets() =
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(
|
ViewCompat.setOnApplyWindowInsetsListener(
|
||||||
binding.root
|
binding.root
|
||||||
@@ -498,6 +550,13 @@ class GamesFragment : Fragment() {
|
|||||||
mlpFab.rightMargin = rightInset + fabPadding
|
mlpFab.rightMargin = rightInset + fabPadding
|
||||||
binding.addDirectory.layoutParams = mlpFab
|
binding.addDirectory.layoutParams = mlpFab
|
||||||
|
|
||||||
|
binding.launchQlaunch?.let { qlaunchButton ->
|
||||||
|
val mlpQLaunch = qlaunchButton.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
|
mlpQLaunch.leftMargin = leftInset + fabPadding
|
||||||
|
mlpQLaunch.bottomMargin = barInsets.bottom + fabPadding
|
||||||
|
qlaunchButton.layoutParams = mlpQLaunch
|
||||||
|
}
|
||||||
|
|
||||||
val navInsets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
val navInsets = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars())
|
||||||
val gestureInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
|
val gestureInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
|
||||||
val bottomInset = maxOf(navInsets.bottom, gestureInsets.bottom, cutoutInsets.bottom)
|
val bottomInset = maxOf(navInsets.bottom, gestureInsets.bottom, cutoutInsets.bottom)
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ namespace AndroidSettings {
|
|||||||
Settings::Setting<s32> app_language{linkage, 0, "app_language", Settings::Category::Android};
|
Settings::Setting<s32> app_language{linkage, 0, "app_language", Settings::Category::Android};
|
||||||
Settings::Setting<bool> enable_update_checks{linkage, true, "enable_update_checks",
|
Settings::Setting<bool> enable_update_checks{linkage, true, "enable_update_checks",
|
||||||
Settings::Category::Android};
|
Settings::Category::Android};
|
||||||
|
Settings::Setting<bool> enable_folder_button{linkage, true, "enable_folder_button",
|
||||||
|
Settings::Category::Android};
|
||||||
|
Settings::Setting<bool> enable_qlaunch_button{linkage, false, "enable_qlaunch_button",
|
||||||
|
Settings::Category::Android};
|
||||||
|
|
||||||
// Input/performance overlay settings
|
// Input/performance overlay settings
|
||||||
std::vector<OverlayControlData> overlay_control_data;
|
std::vector<OverlayControlData> overlay_control_data;
|
||||||
@@ -198,9 +202,14 @@ namespace AndroidSettings {
|
|||||||
Settings::Specialization::Default, true, true,
|
Settings::Specialization::Default, true, true,
|
||||||
&show_soc_overlay};
|
&show_soc_overlay};
|
||||||
|
|
||||||
|
// MISC
|
||||||
Settings::Setting<bool> dont_show_driver_shader_warning{linkage, false,
|
Settings::Setting<bool> dont_show_driver_shader_warning{linkage, false,
|
||||||
"dont_show_driver_shader_warning",
|
"dont_show_driver_shader_warning",
|
||||||
Settings::Category::Android, Settings::Specialization::Default, true, true};
|
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;
|
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
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <common/fs/path_util.h>
|
|
||||||
|
|
||||||
#include "android_config.h"
|
#include "android_config.h"
|
||||||
#include "android_settings.h"
|
#include "android_settings.h"
|
||||||
#include "common/android/android_common.h"
|
#include "common/android/android_common.h"
|
||||||
#include "common/android/id_cache.h"
|
#include "common/android/id_cache.h"
|
||||||
|
#include "common/fs/path_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "frontend_common/config.h"
|
#include "frontend_common/config.h"
|
||||||
|
#include "frontend_common/settings_generator.h"
|
||||||
#include "native.h"
|
#include "native.h"
|
||||||
|
|
||||||
std::unique_ptr<AndroidConfig> global_config;
|
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) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
global_config = std::make_unique<AndroidConfig>();
|
global_config = std::make_unique<AndroidConfig>();
|
||||||
|
FrontendCommon::GenerateSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
|
|||||||
@@ -220,6 +220,23 @@
|
|||||||
android:textColor="?attr/colorOnPrimary"
|
android:textColor="?attr/colorOnPrimary"
|
||||||
app:backgroundTint="?attr/colorPrimary"
|
app:backgroundTint="?attr/colorPrimary"
|
||||||
app:iconTint="?attr/colorOnPrimary"
|
app:iconTint="?attr/colorOnPrimary"
|
||||||
|
app:rippleColor="#99FFFFFF"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/launch_qlaunch"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:contentDescription="Launch QLaunch"
|
||||||
|
android:text="@string/qlaunch_applet"
|
||||||
|
app:icon="@drawable/ic_home"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:textColor="?attr/colorOnPrimary"
|
||||||
|
app:backgroundTint="?attr/colorPrimary"
|
||||||
|
app:iconTint="?attr/colorOnPrimary"
|
||||||
|
app:rippleColor="#99FFFFFF"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -214,6 +214,22 @@
|
|||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/launch_qlaunch"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:contentDescription="Launch QLaunch"
|
||||||
|
android:text="@string/qlaunch_applet"
|
||||||
|
app:icon="@drawable/ic_home"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:textColor="?attr/colorOnPrimary"
|
||||||
|
app:backgroundTint="?attr/colorPrimary"
|
||||||
|
app:iconTint="?attr/colorOnPrimary"
|
||||||
|
app:rippleColor="#99FFFFFF"
|
||||||
|
/>
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
android:id="@+id/add_directory"
|
android:id="@+id/add_directory"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -227,6 +243,7 @@
|
|||||||
android:textColor="?attr/colorOnPrimary"
|
android:textColor="?attr/colorOnPrimary"
|
||||||
app:backgroundTint="?attr/colorPrimary"
|
app:backgroundTint="?attr/colorPrimary"
|
||||||
app:iconTint="?attr/colorOnPrimary"
|
app:iconTint="?attr/colorOnPrimary"
|
||||||
|
app:rippleColor="#99FFFFFF"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -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_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">Use reactive flushing</string>
|
||||||
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</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>
|
<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>
|
<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 -->
|
<!-- GPU Logging strings -->
|
||||||
<string name="gpu_logging">GPU Logging</string>
|
|
||||||
<string name="gpu_logging_header">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">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_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">Log Level</string>
|
||||||
<string name="gpu_log_level_description">Detail level for GPU logs (higher = more detail, more overhead)</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">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_vulkan_calls_description">Track all Vulkan API calls in ring buffer</string>
|
||||||
<string name="gpu_log_shader_dumps">Dump Shaders</string>
|
<string name="gpu_log_shader_dumps">Dump Shaders</string>
|
||||||
@@ -738,6 +738,8 @@
|
|||||||
<string name="preferences_graphics">Graphics</string>
|
<string name="preferences_graphics">Graphics</string>
|
||||||
<string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
|
<string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
|
||||||
<string name="quick_settings">Quick Settings</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">Audio</string>
|
||||||
<string name="preferences_audio_description">Output engine, volume</string>
|
<string name="preferences_audio_description">Output engine, volume</string>
|
||||||
<string name="preferences_controls">Controls</string>
|
<string name="preferences_controls">Controls</string>
|
||||||
@@ -1163,6 +1165,12 @@
|
|||||||
<string name="use_black_backgrounds">Black backgrounds</string>
|
<string name="use_black_backgrounds">Black backgrounds</string>
|
||||||
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
|
<string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
|
||||||
|
|
||||||
|
<!-- Buttons -->
|
||||||
|
<string name="enable_folder_button">Folder</string>
|
||||||
|
<string name="enable_folder_button_description">Show the button to add game folders</string>
|
||||||
|
<string name="enable_qlaunch_button">QLaunch</string>
|
||||||
|
<string name="enable_qlaunch_button_description">Show the button to launch QLaunch</string>
|
||||||
|
|
||||||
<!-- App Language -->
|
<!-- App Language -->
|
||||||
<string name="app_language">App Language</string>
|
<string name="app_language">App Language</string>
|
||||||
<string name="app_language_description">Change the language of the app interface</string>
|
<string name="app_language_description">Change the language of the app interface</string>
|
||||||
|
|||||||
+10
-2
@@ -481,6 +481,14 @@ struct Values {
|
|||||||
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
|
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops",
|
||||||
Category::RendererAdvanced};
|
Category::RendererAdvanced};
|
||||||
|
|
||||||
|
SwitchableSetting<bool> enable_buffer_history{linkage,
|
||||||
|
false,
|
||||||
|
"enable_buffer_history",
|
||||||
|
Category::RendererAdvanced,
|
||||||
|
Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
|
||||||
// Renderer Hacks //
|
// Renderer Hacks //
|
||||||
SwitchableSetting<GpuOverclock> fast_gpu_time{linkage,
|
SwitchableSetting<GpuOverclock> fast_gpu_time{linkage,
|
||||||
GpuOverclock::Medium,
|
GpuOverclock::Medium,
|
||||||
@@ -739,7 +747,7 @@ struct Values {
|
|||||||
Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Debugging};
|
Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Debugging};
|
||||||
|
|
||||||
// GPU Logging
|
// 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",
|
SwitchableSetting<GpuLogLevel> gpu_log_level{linkage, GpuLogLevel::Standard, "gpu_log_level",
|
||||||
Category::Debugging};
|
Category::Debugging};
|
||||||
Setting<bool> gpu_log_vulkan_calls{linkage, true, "gpu_log_vulkan_calls", Category::Debugging};
|
Setting<bool> gpu_log_vulkan_calls{linkage, true, "gpu_log_vulkan_calls", Category::Debugging};
|
||||||
@@ -778,7 +786,7 @@ struct Values {
|
|||||||
Category::WebService};
|
Category::WebService};
|
||||||
Setting<std::string> eden_username{linkage, "Eden", "eden_username",
|
Setting<std::string> eden_username{linkage, "Eden", "eden_username",
|
||||||
Category::WebService};
|
Category::WebService};
|
||||||
Setting<std::string> eden_token{linkage, "njausoolxygtpvraofqunuufhmupriifnpfggjxefntlyglr",
|
Setting<std::string> eden_token{linkage, "",
|
||||||
"eden_token", Category::WebService};
|
"eden_token", Category::WebService};
|
||||||
|
|
||||||
// Add-Ons
|
// 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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -99,11 +99,6 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
|
|||||||
slots[slot].acquire_called = true;
|
slots[slot].acquire_called = true;
|
||||||
slots[slot].needs_cleanup_on_release = false;
|
slots[slot].needs_cleanup_on_release = false;
|
||||||
slots[slot].buffer_state = BufferState::Acquired;
|
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
|
// 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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -17,6 +17,39 @@ BufferQueueCore::BufferQueueCore() = default;
|
|||||||
|
|
||||||
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() {
|
void BufferQueueCore::SignalDequeueCondition() {
|
||||||
dequeue_possible.store(true);
|
dequeue_possible.store(true);
|
||||||
dequeue_condition.notify_all();
|
dequeue_condition.notify_all();
|
||||||
@@ -30,7 +63,6 @@ bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const {
|
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) {
|
if (!use_async_buffer) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -55,8 +87,6 @@ s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const {
|
|||||||
return override_max_buffer_count;
|
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) {
|
for (s32 slot = max_buffer_count; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
|
||||||
const auto state = slots[slot].buffer_state;
|
const auto state = slots[slot].buffer_state;
|
||||||
if (state == BufferState::Queued || state == BufferState::Dequeued) {
|
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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -10,20 +10,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <deque>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "core/hle/service/nvnflinger/buffer_item.h"
|
#include "core/hle/service/nvnflinger/buffer_item.h"
|
||||||
#include "core/hle/service/nvnflinger/buffer_queue_defs.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/pixel_format.h"
|
||||||
#include "core/hle/service/nvnflinger/status.h"
|
#include "core/hle/service/nvnflinger/status.h"
|
||||||
#include "core/hle/service/nvnflinger/window.h"
|
#include "core/hle/service/nvnflinger/window.h"
|
||||||
|
|
||||||
namespace Service::android {
|
namespace Service::android {
|
||||||
|
|
||||||
|
struct BufferHistoryInfo {
|
||||||
|
u64 frame_number{};
|
||||||
|
s64 queue_time{};
|
||||||
|
s64 presentation_time{};
|
||||||
|
BufferState state{};
|
||||||
|
};
|
||||||
|
|
||||||
class IConsumerListener;
|
class IConsumerListener;
|
||||||
class IProducerListener;
|
class IProducerListener;
|
||||||
|
|
||||||
@@ -33,10 +44,14 @@ class BufferQueueCore final {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT;
|
static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT;
|
||||||
|
static constexpr u32 BUFFER_HISTORY_SIZE = 8;
|
||||||
|
|
||||||
BufferQueueCore();
|
BufferQueueCore();
|
||||||
~BufferQueueCore();
|
~BufferQueueCore();
|
||||||
|
|
||||||
|
void PushHistory(u64 frame_number, s64 queue_time, s64 presentation_time, BufferState state);
|
||||||
|
void UpdateHistory(u64 frame_number, BufferState state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SignalDequeueCondition();
|
void SignalDequeueCondition();
|
||||||
bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
|
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
|
const s32 max_acquired_buffer_count{}; // This is always zero on HOS
|
||||||
bool buffer_has_been_queued{};
|
bool buffer_has_been_queued{};
|
||||||
u64 frame_counter{};
|
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{};
|
u32 transform_hint{};
|
||||||
bool is_allocating{};
|
bool is_allocating{};
|
||||||
mutable std::condition_variable_any is_allocating_condition;
|
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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/settings.h"
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
#include "core/hle/kernel/k_readable_event.h"
|
#include "core/hle/kernel/k_readable_event.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
@@ -26,7 +27,7 @@ BufferQueueProducer::BufferQueueProducer(Service::KernelHelpers::ServiceContext&
|
|||||||
std::shared_ptr<BufferQueueCore> buffer_queue_core_,
|
std::shared_ptr<BufferQueueCore> buffer_queue_core_,
|
||||||
Service::Nvidia::NvCore::NvMap& nvmap_)
|
Service::Nvidia::NvCore::NvMap& nvmap_)
|
||||||
: service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots),
|
: 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");
|
buffer_wait_event = service_context.CreateEvent("BufferQueue:WaitEvent");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,8 +429,7 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
|
|||||||
return return_flags;
|
return return_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input, QueueBufferOutput* output) {
|
||||||
QueueBufferOutput* output) {
|
|
||||||
s64 timestamp{};
|
s64 timestamp{};
|
||||||
bool is_auto_timestamp{};
|
bool is_auto_timestamp{};
|
||||||
Common::Rectangle<s32> crop;
|
Common::Rectangle<s32> crop;
|
||||||
@@ -440,8 +440,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
|||||||
s32 swap_interval{};
|
s32 swap_interval{};
|
||||||
Fence fence{};
|
Fence fence{};
|
||||||
|
|
||||||
input.Deflate(×tamp, &is_auto_timestamp, &crop, &scaling_mode, &transform,
|
input.Deflate(×tamp, &is_auto_timestamp, &crop, &scaling_mode, &transform, &sticky_transform_, &async, &swap_interval, &fence);
|
||||||
&sticky_transform_, &async, &swap_interval, &fence);
|
|
||||||
|
|
||||||
switch (scaling_mode) {
|
switch (scaling_mode) {
|
||||||
case NativeWindowScalingMode::Freeze:
|
case NativeWindowScalingMode::Freeze:
|
||||||
@@ -455,10 +454,9 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
|
|||||||
return Status::BadValue;
|
return Status::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IConsumerListener> frame_available_listener;
|
|
||||||
std::shared_ptr<IConsumerListener> frame_replaced_listener;
|
|
||||||
s32 callback_ticket{};
|
|
||||||
BufferItem item;
|
BufferItem item;
|
||||||
|
std::shared_ptr<IConsumerListener> listener_available;
|
||||||
|
std::shared_ptr<IConsumerListener> listener_replaced;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::scoped_lock lock{core->mutex};
|
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);
|
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) {
|
if (slot < 0 || slot >= max_buffer_count) {
|
||||||
LOG_ERROR(Service_Nvnflinger, "slot index {} out of range [0, {})", slot,
|
LOG_ERROR(Service_Nvnflinger, "slot {} out of range [0, {})", slot, max_buffer_count);
|
||||||
max_buffer_count);
|
|
||||||
return Status::BadValue;
|
return Status::BadValue;
|
||||||
} else if (slots[slot].buffer_state != BufferState::Dequeued) {
|
}
|
||||||
LOG_ERROR(Service_Nvnflinger,
|
if (slots[slot].buffer_state != BufferState::Dequeued) {
|
||||||
"slot {} is not owned by the producer "
|
LOG_ERROR(Service_Nvnflinger, "slot {} is not owned by producer", slot);
|
||||||
"(state = {})",
|
|
||||||
slot, slots[slot].buffer_state);
|
|
||||||
return Status::BadValue;
|
return Status::BadValue;
|
||||||
} else if (!slots[slot].request_buffer_called) {
|
}
|
||||||
LOG_ERROR(Service_Nvnflinger,
|
if (!slots[slot].request_buffer_called) {
|
||||||
"slot {} was queued without requesting "
|
LOG_ERROR(Service_Nvnflinger, "slot {} was queued without request", slot);
|
||||||
"a buffer",
|
|
||||||
slot);
|
|
||||||
return Status::BadValue;
|
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;
|
++core->frame_counter;
|
||||||
|
slots[slot].buffer_state = BufferState::Queued;
|
||||||
slots[slot].frame_number = core->frame_counter;
|
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.graphic_buffer = slots[slot].graphic_buffer;
|
||||||
item.crop = crop;
|
item.frame_number = core->frame_counter;
|
||||||
item.transform = transform & ~NativeWindowTransform::InverseDisplay;
|
|
||||||
item.transform_to_display_inverse =
|
|
||||||
(transform & NativeWindowTransform::InverseDisplay) != NativeWindowTransform::None;
|
|
||||||
item.scaling_mode = static_cast<u32>(scaling_mode);
|
|
||||||
item.timestamp = timestamp;
|
item.timestamp = timestamp;
|
||||||
item.is_auto_timestamp = is_auto_timestamp;
|
item.is_auto_timestamp = is_auto_timestamp;
|
||||||
item.frame_number = core->frame_counter;
|
item.crop = crop;
|
||||||
item.slot = slot;
|
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.fence = fence;
|
||||||
item.is_droppable = core->dequeue_buffer_cannot_block || async;
|
item.is_droppable = core->dequeue_buffer_cannot_block || async;
|
||||||
item.swap_interval = swap_interval;
|
item.swap_interval = swap_interval;
|
||||||
|
item.acquire_called = slots[slot].acquire_called;
|
||||||
|
|
||||||
sticky_transform = sticky_transform_;
|
sticky_transform = sticky_transform_;
|
||||||
|
|
||||||
if (core->queue.empty()) {
|
if (core->queue.empty()) {
|
||||||
// When the queue is empty, we can simply queue this buffer
|
|
||||||
core->queue.push_back(item);
|
core->queue.push_back(item);
|
||||||
frame_available_listener = core->consumer_listener;
|
listener_available = core->consumer_listener;
|
||||||
} else {
|
} else {
|
||||||
// When the queue is not empty, we need to look at the front buffer
|
auto front = core->queue.begin();
|
||||||
// state to see if we need to replace it
|
if (front->is_droppable && core->StillTracking(*front)) {
|
||||||
auto front(core->queue.begin());
|
|
||||||
|
|
||||||
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;
|
slots[front->slot].buffer_state = BufferState::Free;
|
||||||
// Reset the frame number of the freed buffer so that it is the first in line to
|
if (Settings::values.enable_buffer_history.GetValue()) {
|
||||||
// be dequeued again
|
core->UpdateHistory(front->frame_number, BufferState::Free);
|
||||||
|
}
|
||||||
slots[front->slot].frame_number = 0;
|
slots[front->slot].frame_number = 0;
|
||||||
}
|
}
|
||||||
// Overwrite the droppable buffer with the incoming one
|
|
||||||
|
if (front->is_droppable) {
|
||||||
*front = item;
|
*front = item;
|
||||||
frame_replaced_listener = core->consumer_listener;
|
listener_replaced = core->consumer_listener;
|
||||||
} else {
|
} else {
|
||||||
core->queue.push_back(item);
|
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->buffer_has_been_queued = true;
|
||||||
core->SignalDequeueCondition();
|
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
|
output->Inflate(core->default_width, core->default_height, core->transform_hint, static_cast<u32>(core->queue.size()));
|
||||||
callback_ticket = next_callback_ticket++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.graphic_buffer.reset();
|
||||||
item.slot = BufferItem::INVALID_BUFFER_SLOT;
|
item.slot = BufferItem::INVALID_BUFFER_SLOT;
|
||||||
|
|
||||||
// Call back without the main BufferQueue lock held, but with the callback lock held so we can
|
if (listener_available) {
|
||||||
// ensure that callbacks occur in order
|
listener_available->OnFrameAvailable(item);
|
||||||
{
|
} else if (listener_replaced) {
|
||||||
std::scoped_lock lock{callback_mutex};
|
listener_replaced->OnFrameReplaced(item);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Status::NoError;
|
return Status::NoError;
|
||||||
@@ -810,6 +763,10 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
|
|||||||
return Status::NoError;
|
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,
|
void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
|
||||||
std::span<u8> parcel_reply, u32 flags) {
|
std::span<u8> parcel_reply, u32 flags) {
|
||||||
// Values used by BnGraphicBufferProducer onTransact
|
// Values used by BnGraphicBufferProducer onTransact
|
||||||
@@ -929,9 +886,42 @@ void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
|
|||||||
status = SetBufferCount(buffer_count);
|
status = SetBufferCount(buffer_count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TransactionId::GetBufferHistory:
|
case TransactionId::GetBufferHistory: {
|
||||||
LOG_DEBUG(Service_Nvnflinger, "(STUBBED) called, transaction=GetBufferHistory");
|
if (!Settings::values.enable_buffer_history.GetValue()) {
|
||||||
|
LOG_DEBUG(Service_Nvnflinger, "(STUBBED) called");
|
||||||
break;
|
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:
|
default:
|
||||||
ASSERT_MSG(false, "Unimplemented TransactionId {}", code);
|
ASSERT_MSG(false, "Unimplemented TransactionId {}", code);
|
||||||
break;
|
break;
|
||||||
@@ -944,8 +934,4 @@ void BufferQueueProducer::Transact(u32 code, std::span<const u8> parcel_data,
|
|||||||
(std::min)(parcel_reply.size(), serialized.size()));
|
(std::min)(parcel_reply.size(), serialized.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KReadableEvent* BufferQueueProducer::GetNativeHandle(u32 type_id) {
|
|
||||||
return &buffer_wait_event->GetReadableEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::android
|
} // 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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/wall_clock.h"
|
||||||
#include "core/hle/service/nvdrv/nvdata.h"
|
#include "core/hle/service/nvdrv/nvdata.h"
|
||||||
#include "core/hle/service/nvnflinger/binder.h"
|
#include "core/hle/service/nvnflinger/binder.h"
|
||||||
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
|
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
|
||||||
@@ -88,6 +89,7 @@ private:
|
|||||||
s32 next_callback_ticket{};
|
s32 next_callback_ticket{};
|
||||||
s32 current_callback_ticket{};
|
s32 current_callback_ticket{};
|
||||||
std::condition_variable_any callback_condition;
|
std::condition_variable_any callback_condition;
|
||||||
|
std::unique_ptr<Common::WallClock> clock;
|
||||||
|
|
||||||
Service::Nvidia::NvCore::NvMap& nvmap;
|
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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
@@ -37,6 +37,7 @@ struct BufferSlot final {
|
|||||||
bool needs_cleanup_on_release{};
|
bool needs_cleanup_on_release{};
|
||||||
bool attached_by_consumer{};
|
bool attached_by_consumer{};
|
||||||
bool is_preallocated{};
|
bool is_preallocated{};
|
||||||
|
s64 queue_time{}, presentation_time{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::android
|
} // 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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
@@ -12,7 +12,8 @@ add_library(frontend_common STATIC
|
|||||||
firmware_manager.cpp
|
firmware_manager.cpp
|
||||||
data_manager.h data_manager.cpp
|
data_manager.h data_manager.cpp
|
||||||
play_time_manager.cpp
|
play_time_manager.cpp
|
||||||
play_time_manager.h)
|
play_time_manager.h
|
||||||
|
settings_generator.h settings_generator.cpp)
|
||||||
|
|
||||||
if (ENABLE_UPDATE_CHECKER)
|
if (ENABLE_UPDATE_CHECKER)
|
||||||
target_link_libraries(frontend_common PRIVATE httplib::httplib)
|
target_link_libraries(frontend_common PRIVATE httplib::httplib)
|
||||||
@@ -29,4 +30,6 @@ if (ENABLE_UPDATE_CHECKER)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
create_target_directory_groups(frontend_common)
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -176,6 +176,5 @@ std::optional<UpdateChecker::Update> UpdateChecker::GetUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
empty:
|
empty:
|
||||||
return UpdateChecker::Update{};
|
return std::nullopt;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
add_library(qt_common STATIC
|
add_library(qt_common STATIC
|
||||||
@@ -78,14 +78,9 @@ target_compile_definitions(qt_common PUBLIC
|
|||||||
QT_NO_URL_CAST_FROM_STRING
|
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 PRIVATE core Qt6::Core Qt6::Concurrent SimpleIni::SimpleIni QuaZip::QuaZip)
|
||||||
target_link_libraries(qt_common PUBLIC frozen::frozen-headers)
|
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)
|
if (NOT APPLE AND ENABLE_OPENGL)
|
||||||
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
|
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
|
||||||
|
|||||||
@@ -329,6 +329,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||||||
barrier_feedback_loops,
|
barrier_feedback_loops,
|
||||||
tr("Barrier feedback loops"),
|
tr("Barrier feedback loops"),
|
||||||
tr("Improves rendering of transparency effects in specific games."));
|
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,
|
INSERT(Settings,
|
||||||
fix_bloom_effects,
|
fix_bloom_effects,
|
||||||
tr("Fix bloom effects"),
|
tr("Fix bloom effects"),
|
||||||
|
|||||||
-19
@@ -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)
|
|
||||||
Vendored
-18
@@ -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-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -148,10 +151,13 @@ Id EmitConvertU32U64(EmitContext& ctx, Id value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitConvertF16F32(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 result = ctx.OpFConvert(ctx.F16[1], value);
|
||||||
const auto isOverflowing = ctx.OpIsNan(ctx.U1, result);
|
const auto isOverflowing = ctx.OpIsNan(ctx.U1, result);
|
||||||
return ctx.OpSelect(ctx.F16[1], isOverflowing, ctx.Constant(ctx.F16[1], 0), 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) {
|
Id EmitConvertF32F16(EmitContext& ctx, Id value) {
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
|
|||||||
target_link_libraries(video_core PRIVATE sirit::sirit)
|
target_link_libraries(video_core PRIVATE sirit::sirit)
|
||||||
|
|
||||||
# Header-only stuff needed by all dependent targets
|
# 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 (ENABLE_NSIGHT_AFTERMATH)
|
||||||
if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
|
if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ void WriteResults(uvec2 results[LOCAL_RESULTS]) {
|
|||||||
const uvec2 accum = accumulated_data;
|
const uvec2 accum = accumulated_data;
|
||||||
for (uint i = 0; i < LOCAL_RESULTS; i++) {
|
for (uint i = 0; i < LOCAL_RESULTS; i++) {
|
||||||
uvec2 base_data = current_id * LOCAL_RESULTS + i < min_accumulation_base ? accum : uvec2(0, 0);
|
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++) {
|
for (uint i = 0; i < LOCAL_RESULTS; i++) {
|
||||||
output_data[buffer_offset + current_id * LOCAL_RESULTS + i] = 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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// 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,
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, image_barrier);
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, image_barrier);
|
||||||
});
|
});
|
||||||
|
scheduler.Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u32 BL3D_BINDING_SWIZZLE_TABLE = 0;
|
constexpr u32 BL3D_BINDING_SWIZZLE_TABLE = 0;
|
||||||
|
|||||||
@@ -1230,6 +1230,10 @@ void Device::RemoveUnsuitableExtensions() {
|
|||||||
}
|
}
|
||||||
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
|
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
|
||||||
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
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
|
// VK_EXT_depth_bias_control
|
||||||
extensions.depth_bias_control =
|
extensions.depth_bias_control =
|
||||||
|
|||||||
@@ -70,7 +70,9 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
|
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
|
||||||
pipeline_executable_properties) \
|
pipeline_executable_properties) \
|
||||||
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
|
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 miscellaneous extensions which may be used by the implementation here.
|
||||||
#define FOR_EACH_VK_EXTENSION(EXTENSION) \
|
#define FOR_EACH_VK_EXTENSION(EXTENSION) \
|
||||||
|
|||||||
+126
-41
@@ -1,7 +1,6 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include "yuzu/game_list.h"
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
@@ -11,22 +10,28 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QScroller>
|
||||||
|
#include <QScrollBar>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
|
#include <QVariantAnimation>
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
#include <qnamespace.h>
|
||||||
|
#include <qscroller.h>
|
||||||
|
#include <qscrollerproperties.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/file_sys/patch_manager.h"
|
#include "core/file_sys/patch_manager.h"
|
||||||
#include "core/file_sys/registered_cache.h"
|
#include "core/file_sys/registered_cache.h"
|
||||||
#include "qt_common/util/game.h"
|
|
||||||
#include "qt_common/config/uisettings.h"
|
#include "qt_common/config/uisettings.h"
|
||||||
|
#include "qt_common/util/game.h"
|
||||||
#include "yuzu/compatibility_list.h"
|
#include "yuzu/compatibility_list.h"
|
||||||
|
#include "yuzu/game_list.h"
|
||||||
#include "yuzu/game_list_p.h"
|
#include "yuzu/game_list_p.h"
|
||||||
#include "yuzu/game_list_worker.h"
|
#include "yuzu/game_list_worker.h"
|
||||||
#include "yuzu/main_window.h"
|
#include "yuzu/main_window.h"
|
||||||
#include "yuzu/util/controller_navigation.h"
|
#include "yuzu/util/controller_navigation.h"
|
||||||
#include <fmt/ranges.h>
|
|
||||||
#include <regex>
|
|
||||||
|
|
||||||
GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent)
|
GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent)
|
||||||
: QObject(parent), gamelist{gamelist_} {}
|
: QObject(parent), gamelist{gamelist_} {}
|
||||||
@@ -328,6 +333,22 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
|
|||||||
item_model = new QStandardItemModel(tree_view);
|
item_model = new QStandardItemModel(tree_view);
|
||||||
tree_view->setModel(item_model);
|
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->setAlternatingRowColors(true);
|
||||||
tree_view->setSelectionMode(QHeaderView::SingleSelection);
|
tree_view->setSelectionMode(QHeaderView::SingleSelection);
|
||||||
tree_view->setSelectionBehavior(QHeaderView::SelectRows);
|
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::customContextMenuRequested, this, &GameList::PopupContextMenu);
|
||||||
connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
|
connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
|
||||||
connect(tree_view, &QTreeView::collapsed, 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) {
|
[this](Qt::Key key) {
|
||||||
// Avoid pressing buttons while playing
|
// Avoid pressing buttons while playing
|
||||||
if (system.IsPoweredOn()) {
|
if (system.IsPoweredOn()) {
|
||||||
@@ -477,7 +498,7 @@ void GameList::DonePopulating(const QStringList& watch_list) {
|
|||||||
UISettings::values.favorited_ids.size() == 0);
|
UISettings::values.favorited_ids.size() == 0);
|
||||||
tree_view->setExpanded(item_model->invisibleRootItem()->child(0)->index(),
|
tree_view->setExpanded(item_model->invisibleRootItem()->child(0)->index(),
|
||||||
UISettings::values.favorites_expanded.GetValue());
|
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);
|
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);
|
auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
|
||||||
navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0);
|
navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0);
|
||||||
|
|
||||||
connect(favorite, &QAction::triggered, [this, program_id]() { ToggleFavorite(program_id); });
|
connect(favorite, &QAction::triggered, this, [this, program_id]() { ToggleFavorite(program_id); });
|
||||||
connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
|
connect(open_save_location, &QAction::triggered, this, [this, program_id, path]() {
|
||||||
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, 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); });
|
[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); });
|
[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);
|
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); });
|
[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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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); });
|
[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); });
|
[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);
|
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);
|
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);
|
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::SDMC);
|
||||||
});
|
});
|
||||||
connect(verify_integrity, &QAction::triggered,
|
connect(verify_integrity, &QAction::triggered, this,
|
||||||
[this, path]() { emit VerifyIntegrityRequested(path); });
|
[this, path]() { emit VerifyIntegrityRequested(path); });
|
||||||
connect(copy_tid, &QAction::triggered,
|
connect(copy_tid, &QAction::triggered, this,
|
||||||
[this, program_id]() { emit CopyTIDRequested(program_id); });
|
[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);
|
emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
|
||||||
});
|
});
|
||||||
// TODO: Implement shortcut creation for macOS
|
// TODO: Implement shortcut creation for macOS
|
||||||
#if !defined(__APPLE__)
|
#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);
|
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);
|
emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Applications);
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
connect(properties, &QAction::triggered,
|
connect(properties, &QAction::triggered, this,
|
||||||
[this, path]() { emit OpenPerGameGeneralRequested(path); });
|
[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->setCheckable(true);
|
||||||
deep_scan->setChecked(game_dir.deep_scan);
|
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;
|
game_dir.deep_scan = !game_dir.deep_scan;
|
||||||
PopulateAsync(UISettings::values.game_dirs);
|
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);
|
UISettings::values.game_dirs.removeOne(game_dir);
|
||||||
item_model->invisibleRootItem()->removeRow(selected.row());
|
item_model->invisibleRootItem()->removeRow(selected.row());
|
||||||
OnTextChanged(search_field->filterText());
|
OnTextChanged(search_field->filterText());
|
||||||
@@ -716,7 +737,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
|||||||
move_up->setEnabled(row > 1);
|
move_up->setEnabled(row > 1);
|
||||||
move_down->setEnabled(row < item_model->rowCount() - 2);
|
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();
|
const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt();
|
||||||
// swap the items in the settings
|
// swap the items in the settings
|
||||||
std::swap(UISettings::values.game_dirs[game_dir_index],
|
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);
|
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();
|
const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt();
|
||||||
// swap the items in the settings
|
// swap the items in the settings
|
||||||
std::swap(UISettings::values.game_dirs[game_dir_index],
|
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);
|
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(
|
emit OpenDirectory(
|
||||||
QString::fromStdString(UISettings::values.game_dirs[game_dir_index].path));
|
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) {
|
void GameList::AddFavoritesPopup(QMenu& context_menu) {
|
||||||
QAction* clear = context_menu.addAction(tr("Clear"));
|
QAction* clear = context_menu.addAction(tr("Clear"));
|
||||||
|
|
||||||
connect(clear, &QAction::triggered, [this] {
|
connect(clear, &QAction::triggered, this, [this] {
|
||||||
for (const auto id : UISettings::values.favorited_ids) {
|
for (const auto id : std::as_const(UISettings::values.favorited_ids)) {
|
||||||
RemoveFavorite(id);
|
RemoveFavorite(id);
|
||||||
}
|
}
|
||||||
UISettings::values.favorited_ids.clear();
|
UISettings::values.favorited_ids.clear();
|
||||||
@@ -788,7 +809,7 @@ void GameList::LoadCompatibilityList() {
|
|||||||
const QJsonDocument json = QJsonDocument::fromJson(content);
|
const QJsonDocument json = QJsonDocument::fromJson(content);
|
||||||
const QJsonArray arr = json.array();
|
const QJsonArray arr = json.array();
|
||||||
|
|
||||||
for (const QJsonValue value : arr) {
|
for (const QJsonValue &value : arr) {
|
||||||
const QJsonObject game = value.toObject();
|
const QJsonObject game = value.toObject();
|
||||||
const QString compatibility_key = QStringLiteral("compatibility");
|
const QString compatibility_key = QStringLiteral("compatibility");
|
||||||
|
|
||||||
@@ -800,7 +821,7 @@ void GameList::LoadCompatibilityList() {
|
|||||||
const QString directory = game[QStringLiteral("directory")].toString();
|
const QString directory = game[QStringLiteral("directory")].toString();
|
||||||
const QJsonArray ids = game[QStringLiteral("releases")].toArray();
|
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 QJsonObject id_object = id_ref.toObject();
|
||||||
const QString id = id_object[QStringLiteral("id")].toString();
|
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);
|
tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SaveConfig();
|
emit SaveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameList::AddFavorite(u64 program_id) {
|
void GameList::AddFavorite(u64 program_id) {
|
||||||
@@ -989,6 +1010,70 @@ void GameListPlaceholder::mouseDoubleClickEvent(QMouseEvent* event) {
|
|||||||
emit GameListPlaceholder::AddDirectory();
|
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) {
|
void GameListPlaceholder::changeEvent(QEvent* event) {
|
||||||
if (event->type() == QEvent::LanguageChange) {
|
if (event->type() == QEvent::LanguageChange) {
|
||||||
RetranslateUI();
|
RetranslateUI();
|
||||||
|
|||||||
+10
-1
@@ -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-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "yuzu/compatibility_list.h"
|
#include "yuzu/compatibility_list.h"
|
||||||
#include "frontend_common/play_time_manager.h"
|
#include "frontend_common/play_time_manager.h"
|
||||||
|
|
||||||
|
class QVariantAnimation;
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
@@ -162,6 +163,14 @@ private:
|
|||||||
ControllerNavigation* controller_navigation = nullptr;
|
ControllerNavigation* controller_navigation = nullptr;
|
||||||
CompatibilityList compatibility_list;
|
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;
|
friend class GameListSearchField;
|
||||||
|
|
||||||
const PlayTime::PlayTimeManager& play_time_manager;
|
const PlayTime::PlayTimeManager& play_time_manager;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
// Qt on macOS doesn't define VMA shit
|
// Qt on macOS doesn't define VMA shit
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include "frontend_common/settings_generator.h"
|
||||||
#include "qt_common/qt_string_lookup.h"
|
#include "qt_common/qt_string_lookup.h"
|
||||||
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
|
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
|
||||||
#undef VMA_IMPLEMENTATION
|
#undef VMA_IMPLEMENTATION
|
||||||
@@ -432,6 +433,7 @@ MainWindow::MainWindow(bool has_broken_vulkan)
|
|||||||
Common::Log::Start();
|
Common::Log::Start();
|
||||||
|
|
||||||
LoadTranslation();
|
LoadTranslation();
|
||||||
|
FrontendCommon::GenerateSettings();
|
||||||
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ MAXDEPTH=3
|
|||||||
# For your project you'll want to change this to define what dirs you have cpmfiles in
|
# For your project you'll want to change this to define what dirs you have cpmfiles in
|
||||||
# Remember to account for the MAXDEPTH variable!
|
# Remember to account for the MAXDEPTH variable!
|
||||||
# Adding ./ before each will help to remove duplicates
|
# 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
|
# shellcheck disable=SC2016
|
||||||
PACKAGES=$(echo "$CPMFILES" | xargs jq -s 'reduce .[] as $item ({}; . * $item)')
|
PACKAGES=$(echo "$CPMFILES" | xargs jq -s 'reduce .[] as $item ({}; . * $item)')
|
||||||
|
|||||||
Reference in New Issue
Block a user