mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-17 05:43:15 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1cc2f97ad | |||
| 670764b535 | |||
| 8ed0ed5828 | |||
| 33067af283 | |||
| d0a054270e | |||
| 2a3507c2b9 | |||
| f71f43561d | |||
| ecbfad4193 | |||
| d76b2b5d26 |
@@ -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>
|
||||
Date: Fri, 24 Oct 2025 23:41:09 -0700
|
||||
Subject: [PATCH] [build] Fix MinGW missing GetAddrInfoExCancel definition
|
||||
Date: Sun, 1 Feb 2026 16:21:10 -0500
|
||||
Subject: [PATCH] Fix build on MinGW
|
||||
|
||||
MinGW does not define GetAddrInfoExCancel in its wstcpi whatever header,
|
||||
so to get around this we can just load it with GetProcAddress et al.
|
||||
MinGW doesn't define GetAddrInfoExCancel.
|
||||
|
||||
Signed-off-by: crueter <crueter@eden-emu.dev>
|
||||
---
|
||||
httplib.h | 14 ++++++++++++--
|
||||
1 file changed, 12 insertions(+), 2 deletions(-)
|
||||
httplib.h | 18 ++++++++++++++++--
|
||||
1 file changed, 16 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/httplib.h b/httplib.h
|
||||
index e15ba44..90a76dc 100644
|
||||
index ec8d2a2..5f9a510 100644
|
||||
--- a/httplib.h
|
||||
+++ b/httplib.h
|
||||
@@ -203,11 +203,13 @@
|
||||
@@ -203,14 +203,17 @@
|
||||
#error Sorry, Visual Studio versions prior to 2015 are not supported
|
||||
#endif
|
||||
|
||||
-#pragma comment(lib, "ws2_32.lib")
|
||||
-
|
||||
#ifndef _SSIZE_T_DEFINED
|
||||
using ssize_t = __int64;
|
||||
#define _SSIZE_T_DEFINED
|
||||
#endif
|
||||
#endif // _MSC_VER
|
||||
|
||||
+#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
+#pragma comment(lib, "ws2_32.lib")
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
#ifndef S_ISREG
|
||||
#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
|
||||
#endif // S_ISREG
|
||||
@@ -3557,7 +3559,15 @@ inline int getaddrinfo_with_timeout(const char *node, const char *service,
|
||||
@@ -4528,7 +4531,17 @@ inline int getaddrinfo_with_timeout(const char *node, const char *service,
|
||||
auto wait_result =
|
||||
::WaitForSingleObject(event, static_cast<DWORD>(timeout_sec * 1000));
|
||||
if (wait_result == WAIT_TIMEOUT) {
|
||||
+#ifdef __MINGW32__
|
||||
+ typedef INT (WSAAPI *PFN_GETADDRINFOEXCANCEL)(HANDLE *CancelHandle);
|
||||
+ auto wsdll = LoadLibraryW((wchar_t*) "ws2_32.lib");
|
||||
+ PFN_GETADDRINFOEXCANCEL GetAddrInfoExCancel = (PFN_GETADDRINFOEXCANCEL) GetProcAddress(wsdll, "GetAddrInfoExCancel");
|
||||
+ typedef INT(WSAAPI * PFN_GETADDRINFOEXCANCEL)(HANDLE * CancelHandle);
|
||||
+ auto wsdll = LoadLibraryW((wchar_t *)"ws2_32.lib");
|
||||
+ PFN_GETADDRINFOEXCANCEL GetAddrInfoExCancel =
|
||||
+ (PFN_GETADDRINFOEXCANCEL)GetProcAddress(wsdll, "GetAddrInfoExCancel");
|
||||
+
|
||||
+ if (cancel_handle) { GetAddrInfoExCancel(&cancel_handle); }
|
||||
+#else
|
||||
if (cancel_handle) { ::GetAddrInfoExCancel(&cancel_handle); }
|
||||
+#endif
|
||||
+
|
||||
::CloseHandle(event);
|
||||
return EAI_AGAIN;
|
||||
}
|
||||
@@ -13952,3 +13965,4 @@ inline SSL_CTX *Client::ssl_context() const {
|
||||
} // namespace httplib
|
||||
|
||||
#endif // CPPHTTPLIB_HTTPLIB_H
|
||||
+
|
||||
--
|
||||
2.51.0
|
||||
2.51.2
|
||||
|
||||
|
||||
@@ -693,6 +693,14 @@ if (ENABLE_QT)
|
||||
set(QT_MAJOR_VERSION 6)
|
||||
# Qt6 sets cxx_std_17 and we need to undo that
|
||||
set_target_properties(Qt6::Platform PROPERTIES INTERFACE_COMPILE_FEATURES "")
|
||||
|
||||
## Qt Externals ##
|
||||
|
||||
# QuaZip
|
||||
AddJsonPackage(quazip)
|
||||
|
||||
# frozen
|
||||
AddJsonPackage(frozen)
|
||||
endif()
|
||||
|
||||
if (NOT YUZU_STATIC_ROOM AND NOT (YUZU_USE_BUNDLED_FFMPEG OR YUZU_USE_EXTERNAL_FFMPEG))
|
||||
|
||||
+24
-7
@@ -12,14 +12,12 @@
|
||||
"repo": "boostorg/boost",
|
||||
"tag": "boost-%VERSION%",
|
||||
"artifact": "%TAG%-cmake.tar.xz",
|
||||
"hash": "4fb7f6fde92762305aad8754d7643cd918dd1f3f67e104e9ab385b18c73178d72a17321354eb203b790b6702f2cf6d725a5d6e2dfbc63b1e35f9eb59fb42ece9",
|
||||
"git_version": "1.89.0",
|
||||
"hash": "6ae6e94664fe7f2fb01976b59b276ac5df8085c7503fa829d810fbfe495960cfec44fa2c36e2cb23480bc19c956ed199d4952b02639a00a6c07625d4e7130c2d",
|
||||
"git_version": "1.90.0",
|
||||
"version": "1.57",
|
||||
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
||||
"patches": [
|
||||
"0001-clang-cl.patch",
|
||||
"0002-use-marmasm.patch",
|
||||
"0003-armasm-options.patch"
|
||||
"0001-clang-cl.patch"
|
||||
]
|
||||
},
|
||||
"fmt": {
|
||||
@@ -48,9 +46,9 @@
|
||||
"package": "ZLIB",
|
||||
"repo": "madler/zlib",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "8c9642495bafd6fad4ab9fb67f09b268c69ff9af0f4f20cf15dfc18852ff1f312bd8ca41de761b3f8d8e90e77d79f2ccacd3d4c5b19e475ecf09d021fdfe9088",
|
||||
"hash": "06eaa3a1eaaeb31f461a2283b03a91ed8eb2406e62cd97ea1c69836324909edeecd93edd03ff0bf593d9dde223e3376149134c5b1fe2e8688c258cadf8cd60ff",
|
||||
"version": "1.2",
|
||||
"git_version": "1.3.1",
|
||||
"git_version": "1.3.1.2",
|
||||
"options": [
|
||||
"ZLIB_BUILD_SHARED OFF",
|
||||
"ZLIB_INSTALL OFF"
|
||||
@@ -103,5 +101,24 @@
|
||||
"git_version": "1.4.335.0",
|
||||
"artifact": "android-binaries-%VERSION%.zip",
|
||||
"hash": "48167c4a17736301bd08f9290f41830443e1f18cce8ad867fc6f289b49e18b40e93c9850b377951af82f51b5b6d7313aa6a884fc5df79f5ce3df82696c1c1244"
|
||||
},
|
||||
"quazip": {
|
||||
"package": "QuaZip-Qt6",
|
||||
"repo": "stachenov/quazip",
|
||||
"sha": "2e95c9001b",
|
||||
"hash": "609c240c7f029ac26a37d8fbab51bc16284e05e128b78b9b9c0e95d083538c36047a67d682759ac990e4adb0eeb90f04f1ea7fe2253bbda7e7e3bcce32e53dd8",
|
||||
"version": "1.3",
|
||||
"git_version": "1.5",
|
||||
"options": [
|
||||
"QUAZIP_QT_MAJOR_VERSION 6",
|
||||
"QUAZIP_INSTALL OFF",
|
||||
"QUAZIP_ENABLE_QTEXTCODEC OFF"
|
||||
]
|
||||
},
|
||||
"frozen": {
|
||||
"package": "frozen",
|
||||
"repo": "serge-sans-paille/frozen",
|
||||
"sha": "61dce5ae18",
|
||||
"hash": "b8dfe741c82bc178dfc9749d4ab5a130cee718d9ee7b71d9b547cf5f7f23027ed0152ad250012a8546399fcc1e12187efc68d89d6731256c4d2df7d04eef8d5c"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+3
-2
@@ -83,8 +83,9 @@ endif()
|
||||
# mcl
|
||||
AddJsonPackage(mcl)
|
||||
|
||||
# VulkanUtilityHeaders - pulls in headers and utility libs
|
||||
AddJsonPackage(vulkan-utility-headers)
|
||||
# Vulkan stuff
|
||||
AddJsonPackage(vulkan-headers)
|
||||
AddJsonPackage(vulkan-utility-libraries)
|
||||
|
||||
# small hack
|
||||
if (NOT VulkanUtilityLibraries_ADDED)
|
||||
|
||||
Vendored
+19
-13
@@ -28,8 +28,8 @@
|
||||
"httplib": {
|
||||
"repo": "yhirose/cpp-httplib",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "e7a8877d489c97669a8ee536e1498575be921e558ed947253013fe6b67a49d4569eedd01f543caa70183b92d8ac0e8687d662a70d880954412e387317008a239",
|
||||
"git_version": "0.28.0",
|
||||
"hash": "a229e24cca4afe78e5c0aa2e482f15108ac34101fd8dbd927365f15e8c37dec4de38c5277d635017d692a5b320e1b929f8bfcc076f52b8e4dcdab8fe53bfdf2e",
|
||||
"git_version": "0.30.1",
|
||||
"find_args": "MODULE GLOBAL",
|
||||
"patches": [
|
||||
"0001-mingw.patch"
|
||||
@@ -118,15 +118,6 @@
|
||||
"git_version": "1.3.18",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"vulkan-utility-headers": {
|
||||
"package": "VulkanUtilityLibraries",
|
||||
"repo": "scripts/VulkanUtilityHeaders",
|
||||
"tag": "%VERSION%",
|
||||
"git_version": "1.4.335",
|
||||
"artifact": "VulkanUtilityHeaders.tar.zst",
|
||||
"git_host": "git.crueter.xyz",
|
||||
"hash": "16dac0e6586702580c4279e4cd37ffe3cf909c93eb31b5069da7af36436d47b270a9cbaac953bb66c22ed12ed67ffa096688599267f307dfb62be1bc09f79833"
|
||||
},
|
||||
"spirv-tools": {
|
||||
"package": "SPIRV-Tools",
|
||||
"repo": "KhronosGroup/SPIRV-Tools",
|
||||
@@ -174,9 +165,9 @@
|
||||
"package": "Catch2",
|
||||
"repo": "catchorg/Catch2",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "a95495142f915d6e9c2a23e80fe360343e9097680066a2f9d3037a070ba5f81ee5559a0407cc9e972dc2afae325873f1fc7ea07a64012c0f01aac6e549f03e3f",
|
||||
"hash": "acb3f463a7404d6a3bce52e474075cdadf9bb241d93feaf147c182d756e5a2f8bd412f4658ca186d15ab8fed36fc587d79ec311f55642d8e4ded16df9e213656",
|
||||
"version": "3.0.1",
|
||||
"git_version": "3.11.0",
|
||||
"git_version": "3.12.0",
|
||||
"patches": [
|
||||
"0001-solaris-isnan-fix.patch"
|
||||
]
|
||||
@@ -281,5 +272,20 @@
|
||||
"tag": "%VERSION%",
|
||||
"hash": "dc37a189a44ce8b5c988ca550582431a6c7eadfd3c6e709bee6277116ee803e714333e85c9e6cbb5c69346a14d6f2cc7ed96e8aa09cc5fb8a89f945059651db6",
|
||||
"version": "121125"
|
||||
},
|
||||
"vulkan-headers": {
|
||||
"repo": "KhronosGroup/Vulkan-Headers",
|
||||
"package": "VulkanHeaders",
|
||||
"version": "1.3.274",
|
||||
"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%"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,4 @@ pkgs.mkShellNoCC {
|
||||
# optional components
|
||||
discord-rpc gamemode
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,6 @@ import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||
|
||||
class QuickSettings(val emulationFragment: EmulationFragment) {
|
||||
// Kinda a crappy workaround to get a title from setting keys
|
||||
// Idk how to do this witthout hardcoding every single one
|
||||
private fun getSettingTitle(settingKey: String): String {
|
||||
return settingKey.replace("_", " ").split(" ")
|
||||
.joinToString(" ") { it.replaceFirstChar { c -> c.uppercase() } }
|
||||
|
||||
}
|
||||
|
||||
private fun saveSettings() {
|
||||
if (emulationFragment.shouldUseCustom) {
|
||||
NativeConfig.savePerGameConfig()
|
||||
@@ -60,6 +52,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
||||
// settings
|
||||
|
||||
fun addIntSetting(
|
||||
name: Int,
|
||||
container: ViewGroup,
|
||||
setting: IntSetting,
|
||||
namesArrayId: Int,
|
||||
@@ -73,7 +66,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
||||
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.expand_icon)
|
||||
val radioGroup = itemView.findViewById<RadioGroup>(R.id.radio_group)
|
||||
|
||||
titleView.text = getSettingTitle(setting.key)
|
||||
titleView.text = YuzuApplication.appContext.getString(name)
|
||||
|
||||
val names = emulationFragment.resources.getStringArray(namesArrayId)
|
||||
val values = emulationFragment.resources.getIntArray(valuesArrayId)
|
||||
@@ -115,6 +108,8 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
||||
}
|
||||
|
||||
fun addBooleanSetting(
|
||||
name: Int,
|
||||
|
||||
container: ViewGroup,
|
||||
setting: BooleanSetting
|
||||
) {
|
||||
@@ -125,7 +120,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
||||
val titleView = itemView.findViewById<TextView>(R.id.switch_title)
|
||||
val switchView = itemView.findViewById<com.google.android.material.materialswitch.MaterialSwitch>(R.id.setting_switch)
|
||||
|
||||
titleView.text = getSettingTitle(setting.key)
|
||||
titleView.text = YuzuApplication.appContext.getString(name)
|
||||
switchContainer.visibility = View.VISIBLE
|
||||
switchView.isChecked = setting.getBoolean()
|
||||
|
||||
@@ -141,6 +136,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
||||
}
|
||||
|
||||
fun addSliderSetting(
|
||||
name: Int,
|
||||
container: ViewGroup,
|
||||
setting: AbstractSetting,
|
||||
minValue: Int = 0,
|
||||
@@ -156,7 +152,7 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
||||
val slider = itemView.findViewById<com.google.android.material.slider.Slider>(R.id.setting_slider)
|
||||
|
||||
|
||||
titleView.text = getSettingTitle(setting.key)
|
||||
titleView.text = YuzuApplication.appContext.getString(name)
|
||||
sliderContainer.visibility = View.VISIBLE
|
||||
|
||||
slider.valueFrom = minValue.toFloat()
|
||||
|
||||
+2
-1
@@ -82,8 +82,9 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
GPU_LOG_VULKAN_CALLS("gpu_log_vulkan_calls"),
|
||||
GPU_LOG_SHADER_DUMPS("gpu_log_shader_dumps"),
|
||||
GPU_LOG_MEMORY_TRACKING("gpu_log_memory_tracking"),
|
||||
GPU_LOG_DRIVER_DEBUG("gpu_log_driver_debug");
|
||||
GPU_LOG_DRIVER_DEBUG("gpu_log_driver_debug"),
|
||||
|
||||
ENABLE_QUICK_SETTINGS("enable_quick_settings");
|
||||
|
||||
// external fun isFrameSkippingEnabled(): Boolean
|
||||
external fun isFrameInterpolationEnabled(): Boolean
|
||||
|
||||
@@ -16,6 +16,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||
RENDERER_BACKEND("backend"),
|
||||
RENDERER_VRAM_USAGE_MODE("vram_usage_mode"),
|
||||
RENDERER_NVDEC_EMULATION("nvdec_emulation"),
|
||||
RENDERER_ASTC_DECODE_METHOD("accelerate_astc"),
|
||||
RENDERER_ASTC_RECOMPRESSION("astc_recompression"),
|
||||
RENDERER_ACCURACY("gpu_accuracy"),
|
||||
RENDERER_RESOLUTION("resolution_setup"),
|
||||
|
||||
+16
@@ -325,6 +325,15 @@ abstract class SettingsItem(
|
||||
valuesId = R.array.rendererNvdecValues
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.RENDERER_ASTC_DECODE_METHOD,
|
||||
titleId = R.string.accelerate_astc,
|
||||
descriptionId = R.string.accelerate_astc_description,
|
||||
choicesId = R.array.astcDecodingMethodNames,
|
||||
valuesId = R.array.astcDecodingMethodValues
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.RENDERER_ASTC_RECOMPRESSION,
|
||||
@@ -790,6 +799,13 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.enable_update_checks_description,
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.ENABLE_QUICK_SETTINGS,
|
||||
titleId = R.string.enable_quick_settings,
|
||||
descriptionId = R.string.enable_quick_settings_description,
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.ENABLE_FOLDER_BUTTON,
|
||||
|
||||
+3
@@ -268,6 +268,7 @@ class SettingsFragmentPresenter(
|
||||
add(IntSetting.DMA_ACCURACY.key)
|
||||
add(IntSetting.MAX_ANISOTROPY.key)
|
||||
add(IntSetting.RENDERER_VRAM_USAGE_MODE.key)
|
||||
add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key)
|
||||
add(IntSetting.RENDERER_ASTC_RECOMPRESSION.key)
|
||||
|
||||
add(BooleanSetting.SYNC_MEMORY_OPERATIONS.key)
|
||||
@@ -1073,6 +1074,8 @@ class SettingsFragmentPresenter(
|
||||
add(BooleanSetting.ENABLE_UPDATE_CHECKS.key)
|
||||
}
|
||||
|
||||
add(BooleanSetting.ENABLE_QUICK_SETTINGS.key)
|
||||
|
||||
add(HeaderSetting(R.string.theme_and_color))
|
||||
|
||||
|
||||
|
||||
@@ -690,8 +690,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
})
|
||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
|
||||
if (!BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean()) {
|
||||
binding.drawerLayout.setDrawerLockMode(
|
||||
DrawerLayout.LOCK_MODE_LOCKED_CLOSED,
|
||||
binding.quickSettingsSheet
|
||||
)
|
||||
}
|
||||
|
||||
updateGameTitle()
|
||||
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_quick_settings)?.isVisible =
|
||||
BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean()
|
||||
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply {
|
||||
val lockMode = IntSetting.LOCK_DRAWER.getInt()
|
||||
val titleId = if (lockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
|
||||
@@ -749,10 +759,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_quick_settings -> {
|
||||
openQuickSettingsMenu()
|
||||
true
|
||||
}
|
||||
if (BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean())
|
||||
R.id.menu_quick_settings else 0 -> {
|
||||
openQuickSettingsMenu()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_settings_per_game -> {
|
||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
||||
@@ -1045,11 +1056,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
quickSettings.addBooleanSetting(
|
||||
R.string.frame_limit_enable,
|
||||
container,
|
||||
BooleanSetting.RENDERER_USE_SPEED_LIMIT,
|
||||
)
|
||||
|
||||
quickSettings.addSliderSetting(
|
||||
R.string.frame_limit_slider,
|
||||
container,
|
||||
ShortSetting.RENDERER_SPEED_LIMIT,
|
||||
minValue = 0,
|
||||
@@ -1058,6 +1071,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
)
|
||||
|
||||
quickSettings.addBooleanSetting(
|
||||
R.string.use_docked_mode,
|
||||
container,
|
||||
BooleanSetting.USE_DOCKED_MODE,
|
||||
)
|
||||
@@ -1065,6 +1079,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
quickSettings.addDivider(container)
|
||||
|
||||
quickSettings.addIntSetting(
|
||||
R.string.renderer_accuracy,
|
||||
container,
|
||||
IntSetting.RENDERER_ACCURACY,
|
||||
R.array.rendererAccuracyNames,
|
||||
@@ -1073,6 +1088,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
|
||||
quickSettings.addIntSetting(
|
||||
R.string.renderer_scaling_filter,
|
||||
container,
|
||||
IntSetting.RENDERER_SCALING_FILTER,
|
||||
R.array.rendererScalingFilterNames,
|
||||
@@ -1080,6 +1096,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
)
|
||||
|
||||
quickSettings.addSliderSetting(
|
||||
R.string.fsr_sharpness,
|
||||
container,
|
||||
IntSetting.FSR_SHARPENING_SLIDER,
|
||||
minValue = 0,
|
||||
@@ -1088,6 +1105,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
)
|
||||
|
||||
quickSettings.addIntSetting(
|
||||
R.string.renderer_anti_aliasing,
|
||||
container,
|
||||
IntSetting.RENDERER_ANTI_ALIASING,
|
||||
R.array.rendererAntiAliasingNames,
|
||||
|
||||
@@ -202,9 +202,14 @@ namespace AndroidSettings {
|
||||
Settings::Specialization::Default, true, true,
|
||||
&show_soc_overlay};
|
||||
|
||||
// MISC
|
||||
Settings::Setting<bool> dont_show_driver_shader_warning{linkage, false,
|
||||
"dont_show_driver_shader_warning",
|
||||
Settings::Category::Android, Settings::Specialization::Default, true, true};
|
||||
Settings::Setting<bool> enable_quick_settings{linkage, true,
|
||||
"enable_quick_settings",
|
||||
Settings::Category::Android, Settings::Specialization::Default, true,
|
||||
false};
|
||||
};
|
||||
|
||||
extern Values values;
|
||||
|
||||
@@ -123,13 +123,25 @@
|
||||
<item>1</item> <!-- Aggressive -->
|
||||
</integer-array>
|
||||
|
||||
<!-- ASTC Decoding Method Choices -->
|
||||
<string-array name="astcDecodingMethodNames">
|
||||
<item>@string/accelerate_astc_cpu</item>
|
||||
<item>@string/accelerate_astc_gpu</item>
|
||||
<item>@string/accelerate_astc_async</item>
|
||||
</string-array>
|
||||
|
||||
<!-- ASTC Decoding Method Values -->
|
||||
<integer-array name="astcDecodingMethodValues">
|
||||
<item>0</item> <!-- CPU -->
|
||||
<item>1</item> <!-- GPU -->
|
||||
<item>2</item> <!-- CPU Asynchronously -->
|
||||
</integer-array>
|
||||
|
||||
<!-- ASTC Recompression Method Choices -->
|
||||
<string-array name="astcRecompressionMethodNames">
|
||||
<item>@string/astc_recompression_uncompressed</item>
|
||||
<item>@string/astc_recompression_bc1</item>
|
||||
<item>@string/astc_recompression_bc3</item>
|
||||
<item>@string/astc_recompression_bc7</item>
|
||||
<item>@string/astc_recompression_etc2</item>
|
||||
</string-array>
|
||||
|
||||
<!-- ASTC Recompression Method Values -->
|
||||
@@ -137,8 +149,6 @@
|
||||
<item>0</item> <!-- Uncompressed -->
|
||||
<item>1</item> <!-- BC1 -->
|
||||
<item>2</item> <!-- BC3 -->
|
||||
<item>3</item> <!-- BC7 -->
|
||||
<item>4</item> <!-- ETC2 -->
|
||||
</integer-array>
|
||||
|
||||
<!-- NVDEC Emulation Choices -->
|
||||
|
||||
@@ -556,13 +556,11 @@
|
||||
<string name="flush_by_line_description">Flushes debugging logs on each line written, making debugging easier in cases of crashing or freezing.</string>
|
||||
|
||||
<!-- GPU Logging strings -->
|
||||
<string name="gpu_logging">GPU Logging</string>
|
||||
<string name="gpu_logging_header">GPU Logging</string>
|
||||
<string name="gpu_logging_enabled">Enable GPU Logging</string>
|
||||
<string name="gpu_logging_enabled_description">Log GPU operations to eden_gpu.log for debugging Adreno drivers</string>
|
||||
<string name="gpu_log_level">Log Level</string>
|
||||
<string name="gpu_log_level_description">Detail level for GPU logs (higher = more detail, more overhead)</string>
|
||||
<string name="gpu_logging_features">Logging Features</string>
|
||||
<string name="gpu_log_vulkan_calls">Log Vulkan API Calls</string>
|
||||
<string name="gpu_log_vulkan_calls_description">Track all Vulkan API calls in ring buffer</string>
|
||||
<string name="gpu_log_shader_dumps">Dump Shaders</string>
|
||||
@@ -738,6 +736,8 @@
|
||||
<string name="preferences_graphics">Graphics</string>
|
||||
<string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
|
||||
<string name="quick_settings">Quick Settings</string>
|
||||
<string name="enable_quick_settings">Enable Quick Settings</string>
|
||||
<string name="enable_quick_settings_description">Allow access to quick settings menu via swipe and menu button</string>
|
||||
<string name="preferences_audio">Audio</string>
|
||||
<string name="preferences_audio_description">Output engine, volume</string>
|
||||
<string name="preferences_controls">Controls</string>
|
||||
@@ -1033,8 +1033,6 @@
|
||||
<string name="astc_recompression_uncompressed">Uncompressed</string>
|
||||
<string name="astc_recompression_bc1" translatable="false">BC1</string>
|
||||
<string name="astc_recompression_bc3" translatable="false">BC3</string>
|
||||
<string name="astc_recompression_bc7" translatable="false">BC7</string>
|
||||
<string name="astc_recompression_etc2" translatable="false">ETC2</string>
|
||||
|
||||
<!-- ASTC Recompression Method Choices -->
|
||||
<string name="vram_usage_conservative">Conservative</string>
|
||||
|
||||
+10
-1
@@ -430,6 +430,15 @@ struct Values {
|
||||
#endif
|
||||
"max_anisotropy",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
|
||||
#ifdef ANDROID
|
||||
AstcDecodeMode::Cpu,
|
||||
#else
|
||||
AstcDecodeMode::Gpu,
|
||||
#endif
|
||||
"accelerate_astc",
|
||||
Category::RendererAdvanced};
|
||||
|
||||
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
||||
AstcRecompression::Uncompressed,
|
||||
"astc_recompression",
|
||||
@@ -730,7 +739,7 @@ struct Values {
|
||||
Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Debugging};
|
||||
|
||||
// GPU Logging
|
||||
Setting<bool> gpu_logging_enabled{linkage, true, "gpu_logging_enabled", Category::Debugging};
|
||||
Setting<bool> gpu_logging_enabled{linkage, false, "gpu_logging_enabled", Category::Debugging};
|
||||
SwitchableSetting<GpuLogLevel> gpu_log_level{linkage, GpuLogLevel::Standard, "gpu_log_level",
|
||||
Category::Debugging};
|
||||
Setting<bool> gpu_log_vulkan_calls{linkage, true, "gpu_log_vulkan_calls", Category::Debugging};
|
||||
|
||||
@@ -128,7 +128,7 @@ ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt
|
||||
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
|
||||
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16, X32, X64, None);
|
||||
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
|
||||
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3, Bc7, Etc2);
|
||||
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||
ENUM(VramUsageMode, Conservative, Aggressive);
|
||||
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
add_library(qt_common STATIC
|
||||
@@ -78,8 +78,6 @@ target_compile_definitions(qt_common PUBLIC
|
||||
QT_NO_URL_CAST_FROM_STRING
|
||||
)
|
||||
|
||||
add_subdirectory(externals)
|
||||
|
||||
# pass targets
|
||||
find_package(frozen)
|
||||
|
||||
|
||||
@@ -209,6 +209,14 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
||||
tr("Specifies how videos should be decoded.\nIt can either use the CPU or the GPU for "
|
||||
"decoding, or perform no decoding at all (black screen on videos).\n"
|
||||
"In most cases, GPU decoding provides the best performance."));
|
||||
INSERT(Settings,
|
||||
accelerate_astc,
|
||||
tr("ASTC Decoding Method:"),
|
||||
tr("This option controls how ASTC textures should be decoded.\n"
|
||||
"CPU: Use the CPU for decoding.\n"
|
||||
"GPU: Use the GPU's compute shaders to decode ASTC textures (recommended).\n"
|
||||
"CPU Asynchronously: Use the CPU to decode ASTC textures on demand. Eliminates"
|
||||
"ASTC decoding\nstuttering but may present artifacts."));
|
||||
INSERT(
|
||||
Settings,
|
||||
astc_recompression,
|
||||
@@ -482,10 +490,8 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
|
||||
{Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
|
||||
{
|
||||
PAIR(AstcRecompression, Uncompressed, tr("Uncompressed (Best quality)")),
|
||||
PAIR(AstcRecompression, Bc1, tr("BC1")),
|
||||
PAIR(AstcRecompression, Bc3, tr("BC3")),
|
||||
PAIR(AstcRecompression, Bc7, tr("BC7")),
|
||||
PAIR(AstcRecompression, Etc2, tr("ETC2")),
|
||||
PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
|
||||
PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
|
||||
{
|
||||
|
||||
-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"
|
||||
}
|
||||
}
|
||||
@@ -279,6 +279,8 @@ add_library(video_core STATIC
|
||||
texture_cache/types.h
|
||||
texture_cache/util.cpp
|
||||
texture_cache/util.h
|
||||
textures/astc.h
|
||||
textures/astc.cpp
|
||||
textures/bcn.cpp
|
||||
textures/bcn.h
|
||||
textures/decoders.cpp
|
||||
@@ -329,7 +331,7 @@ target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
|
||||
target_link_libraries(video_core PRIVATE sirit::sirit)
|
||||
|
||||
# Header-only stuff needed by all dependent targets
|
||||
target_link_libraries(video_core PUBLIC Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator)
|
||||
target_link_libraries(video_core PUBLIC Vulkan::Headers Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator)
|
||||
|
||||
if (ENABLE_NSIGHT_AFTERMATH)
|
||||
if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
|
||||
|
||||
@@ -90,7 +90,7 @@ if ("${GLSLANGVALIDATOR}" STREQUAL "GLSLANGVALIDATOR-NOTFOUND")
|
||||
message(FATAL_ERROR "Required program `glslangValidator` not found.")
|
||||
endif()
|
||||
|
||||
set(GLSL_FLAGS "-Os")
|
||||
set(GLSL_FLAGS "")
|
||||
set(SPIR_V_VERSION "spirv1.3")
|
||||
set(QUIET_FLAG "--quiet")
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -235,7 +235,9 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
|
||||
[[nodiscard]] bool CanBeAccelerated(const TextureCacheRuntime& runtime,
|
||||
const VideoCommon::ImageInfo& info) {
|
||||
if (IsPixelFormatASTC(info.format) && info.size.depth == 1 && !runtime.HasNativeASTC()) {
|
||||
return true;
|
||||
return Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu &&
|
||||
Settings::values.astc_recompression.GetValue() ==
|
||||
Settings::AstcRecompression::Uncompressed;
|
||||
}
|
||||
// Disable other accelerated uploads for now as they don't implement swizzled uploads
|
||||
return false;
|
||||
@@ -264,6 +266,15 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4
|
||||
return format_info.compatibility_class == store_class;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool CanBeDecodedAsync(const TextureCacheRuntime& runtime,
|
||||
const VideoCommon::ImageInfo& info) {
|
||||
if (IsPixelFormatASTC(info.format) && !runtime.HasNativeASTC()) {
|
||||
return Settings::values.accelerate_astc.GetValue() ==
|
||||
Settings::AstcDecodeMode::CpuAsynchronous;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] CopyOrigin MakeCopyOrigin(VideoCommon::Offset3D offset,
|
||||
VideoCommon::SubresourceLayers subresource, GLenum target) {
|
||||
switch (target) {
|
||||
@@ -432,15 +443,18 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsAstcRecompressionEnabled() {
|
||||
return Settings::values.astc_recompression.GetValue() != Settings::AstcRecompression::Uncompressed;
|
||||
return Settings::values.astc_recompression.GetValue() !=
|
||||
Settings::AstcRecompression::Uncompressed;
|
||||
}
|
||||
|
||||
[[nodiscard]] GLenum SelectAstcFormat(PixelFormat format, bool is_srgb) {
|
||||
switch (Settings::values.astc_recompression.GetValue()) {
|
||||
case Settings::AstcRecompression::Bc1:
|
||||
return is_srgb ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
break;
|
||||
case Settings::AstcRecompression::Bc3:
|
||||
return is_srgb ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
break;
|
||||
default:
|
||||
return is_srgb ? GL_SRGB8_ALPHA8 : GL_RGBA8;
|
||||
}
|
||||
@@ -679,9 +693,12 @@ bool TextureCacheRuntime::HasNativeASTC() const noexcept {
|
||||
return device.HasASTC();
|
||||
}
|
||||
|
||||
Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_, GPUVAddr gpu_addr_, VAddr cpu_addr_)
|
||||
Image::Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info_, GPUVAddr gpu_addr_,
|
||||
VAddr cpu_addr_)
|
||||
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), runtime{&runtime_} {
|
||||
if (CanBeAccelerated(*runtime, info)) {
|
||||
if (CanBeDecodedAsync(*runtime, info)) {
|
||||
flags |= ImageFlagBits::AsynchronousDecode;
|
||||
} else if (CanBeAccelerated(*runtime, info)) {
|
||||
flags |= ImageFlagBits::AcceleratedUpload;
|
||||
}
|
||||
if (IsConverted(runtime->device, info.format, info.type)) {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -28,11 +25,14 @@
|
||||
#include "video_core/texture_cache/accelerated_swizzle.h"
|
||||
#include "video_core/texture_cache/types.h"
|
||||
#include "video_core/texture_cache/util.h"
|
||||
#include "video_core/textures/astc.h"
|
||||
#include "video_core/textures/decoders.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
using namespace HostShaders;
|
||||
using namespace Tegra::Texture::ASTC;
|
||||
|
||||
using VideoCommon::Extent2D;
|
||||
using VideoCommon::Extent3D;
|
||||
using VideoCommon::ImageCopy;
|
||||
@@ -141,8 +141,10 @@ void UtilShaders::BlockLinearUpload2D(Image& image, const StagingBufferMap& map,
|
||||
glUniform1ui(5, params.x_shift);
|
||||
glUniform1ui(6, params.block_height);
|
||||
glUniform1ui(7, params.block_height_mask);
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset, image.guest_size_bytes - swizzle.buffer_offset);
|
||||
glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0, GL_WRITE_ONLY, store_format);
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_INPUT_BUFFER, map.buffer, input_offset,
|
||||
image.guest_size_bytes - swizzle.buffer_offset);
|
||||
glBindImageTexture(BINDING_OUTPUT_IMAGE, image.StorageHandle(), swizzle.level, GL_TRUE, 0,
|
||||
GL_WRITE_ONLY, store_format);
|
||||
glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
|
||||
}
|
||||
program_manager.RestoreGuestCompute();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -251,12 +251,6 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with
|
||||
case Settings::AstcRecompression::Bc3:
|
||||
tuple.format = is_srgb ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK;
|
||||
break;
|
||||
case Settings::AstcRecompression::Bc7:
|
||||
tuple.format = is_srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK;
|
||||
break;
|
||||
case Settings::AstcRecompression::Etc2:
|
||||
tuple.format = is_srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Transcode on hardware that doesn't support BCn natively
|
||||
|
||||
@@ -538,16 +538,16 @@ ASTCDecoderPass::ASTCDecoderPass(const Device& device_, Scheduler& scheduler_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_,
|
||||
MemoryAllocator& memory_allocator_)
|
||||
: ComputePass(device_, descriptor_pool_, ASTC_DESCRIPTOR_SET_BINDINGS,
|
||||
ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO,
|
||||
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(AstcPushConstants)>, ASTC_DECODER_COMP_SPV)
|
||||
, scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_}
|
||||
, compute_pass_descriptor_queue{compute_pass_descriptor_queue_}, memory_allocator{memory_allocator_}
|
||||
{}
|
||||
ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY, ASTC_BANK_INFO,
|
||||
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(AstcPushConstants)>, ASTC_DECODER_COMP_SPV),
|
||||
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
|
||||
compute_pass_descriptor_queue{compute_pass_descriptor_queue_}, memory_allocator{
|
||||
memory_allocator_} {}
|
||||
|
||||
ASTCDecoderPass::~ASTCDecoderPass() = default;
|
||||
|
||||
void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
ASSERT(image.info.size.depth == 1);
|
||||
void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles) {
|
||||
using namespace VideoCommon::Accelerated;
|
||||
const std::array<u32, 2> block_dims{
|
||||
VideoCore::Surface::DefaultBlockWidth(image.info.format),
|
||||
@@ -558,11 +558,13 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, std::s
|
||||
const VkImageAspectFlags aspect_mask = image.AspectMask();
|
||||
const VkImage vk_image = image.Handle();
|
||||
const bool is_initialized = image.ExchangeInitialization();
|
||||
scheduler.Record([vk_pipeline, vk_image, aspect_mask, is_initialized](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([vk_pipeline, vk_image, aspect_mask,
|
||||
is_initialized](vk::CommandBuffer cmdbuf) {
|
||||
const VkImageMemoryBarrier image_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VkAccessFlags(is_initialized ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_NONE),
|
||||
.srcAccessMask = static_cast<VkAccessFlags>(is_initialized ? VK_ACCESS_SHADER_WRITE_BIT
|
||||
: VK_ACCESS_NONE),
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
@@ -577,17 +579,20 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, std::s
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
|
||||
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
|
||||
: VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
|
||||
});
|
||||
for (const VideoCommon::SwizzleParameters& swizzle : swizzles) {
|
||||
const size_t input_offset = swizzle.buffer_offset + map.offset;
|
||||
const u32 num_dispatches_x = Common::DivCeil(swizzle.num_tiles.width, 8U);
|
||||
const u32 num_dispatches_y = Common::DivCeil(swizzle.num_tiles.height, 8U);
|
||||
const u32 num_dispatches_x = swizzle.num_tiles.width;
|
||||
const u32 num_dispatches_y = swizzle.num_tiles.height;
|
||||
const u32 num_dispatches_z = image.info.resources.layers;
|
||||
|
||||
compute_pass_descriptor_queue.Acquire();
|
||||
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset, image.guest_size_bytes - swizzle.buffer_offset);
|
||||
compute_pass_descriptor_queue.AddBuffer(map.buffer, input_offset,
|
||||
image.guest_size_bytes - swizzle.buffer_offset);
|
||||
compute_pass_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
|
||||
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
||||
|
||||
@@ -596,7 +601,8 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, std::s
|
||||
ASSERT(params.origin == (std::array<u32, 3>{0, 0, 0}));
|
||||
ASSERT(params.destination == (std::array<s32, 3>{0, 0, 0}));
|
||||
ASSERT(params.bytes_per_block_log2 == 4);
|
||||
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, block_dims, params, descriptor_data](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, block_dims,
|
||||
params, descriptor_data](vk::CommandBuffer cmdbuf) {
|
||||
const AstcPushConstants uniforms{
|
||||
.blocks_dims = block_dims,
|
||||
.layer_stride = params.layer_stride,
|
||||
@@ -631,7 +637,8 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, std::s
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, image_barrier);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, image_barrier);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -848,11 +848,13 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched
|
||||
RenderPassCache& render_pass_cache_,
|
||||
DescriptorPool& descriptor_pool,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue)
|
||||
: device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_}
|
||||
, staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_}
|
||||
, render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info}
|
||||
{
|
||||
astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, compute_pass_descriptor_queue, memory_allocator);
|
||||
: device{device_}, scheduler{scheduler_}, memory_allocator{memory_allocator_},
|
||||
staging_buffer_pool{staging_buffer_pool_}, blit_image_helper{blit_image_helper_},
|
||||
render_pass_cache{render_pass_cache_}, resolution{Settings::values.resolution_info} {
|
||||
if (Settings::values.accelerate_astc.GetValue() == Settings::AstcDecodeMode::Gpu) {
|
||||
astc_decoder_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool,
|
||||
compute_pass_descriptor_queue, memory_allocator);
|
||||
}
|
||||
if (device.IsStorageImageMultisampleSupported()) {
|
||||
msaa_copy_pass.emplace(device, scheduler, descriptor_pool, staging_buffer_pool, compute_pass_descriptor_queue);
|
||||
}
|
||||
@@ -1560,8 +1562,20 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
|
||||
runtime->ViewFormats(info.format))),
|
||||
aspect_mask(ImageAspectMask(info.format)) {
|
||||
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
|
||||
ASSERT(info.size.depth == 1 && "ASTC Image depth >1 isn't supported");
|
||||
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
|
||||
switch (Settings::values.accelerate_astc.GetValue()) {
|
||||
case Settings::AstcDecodeMode::Gpu:
|
||||
if (Settings::values.astc_recompression.GetValue() ==
|
||||
Settings::AstcRecompression::Uncompressed &&
|
||||
info.size.depth == 1) {
|
||||
flags |= VideoCommon::ImageFlagBits::AcceleratedUpload;
|
||||
}
|
||||
break;
|
||||
case Settings::AstcDecodeMode::CpuAsynchronous:
|
||||
flags |= VideoCommon::ImageFlagBits::AsynchronousDecode;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
flags |= VideoCommon::ImageFlagBits::Converted;
|
||||
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
|
||||
}
|
||||
@@ -1574,10 +1588,13 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
|
||||
}
|
||||
current_image = &Image::original_image;
|
||||
storage_image_views.resize(info.resources.levels);
|
||||
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
|
||||
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported() &&
|
||||
Settings::values.astc_recompression.GetValue() ==
|
||||
Settings::AstcRecompression::Uncompressed) {
|
||||
const auto& device = runtime->device.GetLogical();
|
||||
for (s32 level = 0; level < info.resources.levels; ++level) {
|
||||
storage_image_views[level] = MakeStorageView(device, level, *original_image, VK_FORMAT_A8B8G8R8_UNORM_PACK32);
|
||||
storage_image_views[level] =
|
||||
MakeStorageView(device, level, *original_image, VK_FORMAT_A8B8G8R8_UNORM_PACK32);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2435,16 +2452,19 @@ void TextureCacheRuntime::AccelerateImageUpload(
|
||||
std::span<const VideoCommon::SwizzleParameters> swizzles,
|
||||
u32 z_start, u32 z_count) {
|
||||
|
||||
if (IsPixelFormatASTC(image.info.format)
|
||||
&& image.info.type == ImageType::e2D) {
|
||||
if (IsPixelFormatASTC(image.info.format)) {
|
||||
return astc_decoder_pass->Assemble(image, map, swizzles);
|
||||
}
|
||||
if (IsPixelFormatBCn(image.info.format)
|
||||
&& image.info.type == ImageType::e3D
|
||||
&& image.info.resources.levels == 1
|
||||
&& image.info.resources.layers == 1) {
|
||||
|
||||
if (bl3d_unswizzle_pass &&
|
||||
IsPixelFormatBCn(image.info.format) &&
|
||||
image.info.type == ImageType::e3D &&
|
||||
image.info.resources.levels == 1 &&
|
||||
image.info.resources.layers == 1) {
|
||||
|
||||
return bl3d_unswizzle_pass->Unswizzle(image, map, swizzles, z_start, z_count);
|
||||
}
|
||||
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
@@ -444,17 +444,15 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
|
||||
|
||||
u64 TranscodedAstcSize(u64 base_size, PixelFormat format) {
|
||||
constexpr u64 RGBA8_PIXEL_SIZE = 4;
|
||||
const u64 base_block_size = u64(DefaultBlockWidth(format)) * u64(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE;
|
||||
const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) *
|
||||
static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE;
|
||||
const u64 uncompressed_size = (base_size * base_block_size) / BytesPerBlock(format);
|
||||
|
||||
switch (Settings::values.astc_recompression.GetValue()) {
|
||||
case Settings::AstcRecompression::Bc1:
|
||||
return uncompressed_size / 8;
|
||||
case Settings::AstcRecompression::Bc3:
|
||||
return uncompressed_size / 4;
|
||||
case Settings::AstcRecompression::Bc7:
|
||||
return uncompressed_size / 4;
|
||||
case Settings::AstcRecompression::Etc2:
|
||||
return uncompressed_size / 4; //6=RGB, 4=RGBA
|
||||
default:
|
||||
return uncompressed_size;
|
||||
}
|
||||
|
||||
@@ -2317,10 +2317,13 @@ ImageViewId TextureCache<P>::FindOrEmplaceImageView(ImageId image_id, const Imag
|
||||
template <class P>
|
||||
void TextureCache<P>::RegisterImage(ImageId image_id) {
|
||||
ImageBase& image = slot_images[image_id];
|
||||
ASSERT(False(image.flags & ImageFlagBits::Registered) && "Trying to register an already registered image");
|
||||
ASSERT_MSG(False(image.flags & ImageFlagBits::Registered),
|
||||
"Trying to register an already registered image");
|
||||
image.flags |= ImageFlagBits::Registered;
|
||||
u64 tentative_size = (std::max)(image.guest_size_bytes, image.unswizzled_size_bytes);
|
||||
if ((IsPixelFormatASTC(image.info.format) && True(image.flags & ImageFlagBits::AcceleratedUpload)) || True(image.flags & ImageFlagBits::Converted)) {
|
||||
if ((IsPixelFormatASTC(image.info.format) &&
|
||||
True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
|
||||
True(image.flags & ImageFlagBits::Converted)) {
|
||||
tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
|
||||
}
|
||||
total_used_memory += Common::AlignUp(tentative_size, 1024);
|
||||
@@ -2492,7 +2495,9 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) {
|
||||
total_used_memory -= GetScaledImageSizeBytes(image);
|
||||
}
|
||||
u64 tentative_size = (std::max)(image.guest_size_bytes, image.unswizzled_size_bytes);
|
||||
if ((IsPixelFormatASTC(image.info.format) && True(image.flags & ImageFlagBits::AcceleratedUpload)) || True(image.flags & ImageFlagBits::Converted)) {
|
||||
if ((IsPixelFormatASTC(image.info.format) &&
|
||||
True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
|
||||
True(image.flags & ImageFlagBits::Converted)) {
|
||||
tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
|
||||
}
|
||||
total_used_memory -= Common::AlignUp(tentative_size, 1024);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "video_core/texture_cache/formatter.h"
|
||||
#include "video_core/texture_cache/samples_helper.h"
|
||||
#include "video_core/texture_cache/util.h"
|
||||
#include "video_core/textures/astc.h"
|
||||
#include "video_core/textures/bcn.h"
|
||||
#include "video_core/textures/decoders.h"
|
||||
|
||||
@@ -607,18 +608,23 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept {
|
||||
return info.size.width * BytesPerBlock(info.format);
|
||||
}
|
||||
static constexpr Extent2D TILE_SIZE{1, 1};
|
||||
if (IsPixelFormatASTC(info.format) && Settings::values.astc_recompression.GetValue() != Settings::AstcRecompression::Uncompressed) {
|
||||
const u32 bpp_div = Settings::values.astc_recompression.GetValue() == Settings::AstcRecompression::Bc1 ? 2 : 1;
|
||||
if (IsPixelFormatASTC(info.format) && Settings::values.astc_recompression.GetValue() !=
|
||||
Settings::AstcRecompression::Uncompressed) {
|
||||
const u32 bpp_div =
|
||||
Settings::values.astc_recompression.GetValue() == Settings::AstcRecompression::Bc1 ? 2
|
||||
: 1;
|
||||
// NumBlocksPerLayer doesn't account for this correctly, so we have to do it manually.
|
||||
u32 output_size = 0;
|
||||
for (s32 i = 0; i < info.resources.levels; i++) {
|
||||
const auto mip_size = AdjustMipSize(info.size, i);
|
||||
const u32 plane_dim = Common::AlignUp(mip_size.width, 4U) * Common::AlignUp(mip_size.height, 4U);
|
||||
const u32 plane_dim =
|
||||
Common::AlignUp(mip_size.width, 4U) * Common::AlignUp(mip_size.height, 4U);
|
||||
output_size += (plane_dim * info.size.depth * info.resources.layers) / bpp_div;
|
||||
}
|
||||
return output_size;
|
||||
}
|
||||
return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * ConvertedBytesPerBlock(info.format);
|
||||
return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers *
|
||||
ConvertedBytesPerBlock(info.format);
|
||||
}
|
||||
|
||||
u32 CalculateLayerStride(const ImageInfo& info) noexcept {
|
||||
@@ -916,7 +922,8 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
|
||||
return copies;
|
||||
}
|
||||
|
||||
void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output, std::span<BufferImageCopy> copies) {
|
||||
void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8> output,
|
||||
std::span<BufferImageCopy> copies) {
|
||||
u32 output_offset = 0;
|
||||
Common::ScratchBuffer<u8> decode_scratch;
|
||||
|
||||
@@ -932,9 +939,56 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
|
||||
|
||||
const auto input_offset = input.subspan(copy.buffer_offset);
|
||||
copy.buffer_offset = output_offset;
|
||||
ASSERT(!IsPixelFormatASTC(info.format) && "CPU ASTC decoder is phased out");
|
||||
DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format);
|
||||
output_offset += copy.image_extent.width * copy.image_extent.height * copy.image_subresource.num_layers * ConvertedBytesPerBlock(info.format);
|
||||
|
||||
const auto recompression_setting = Settings::values.astc_recompression.GetValue();
|
||||
const bool astc = IsPixelFormatASTC(info.format);
|
||||
|
||||
if (astc && recompression_setting == Settings::AstcRecompression::Uncompressed) {
|
||||
Tegra::Texture::ASTC::Decompress(
|
||||
input_offset, copy.image_extent.width, copy.image_extent.height,
|
||||
copy.image_subresource.num_layers * copy.image_extent.depth, tile_size.width,
|
||||
tile_size.height, output.subspan(output_offset));
|
||||
|
||||
output_offset += copy.image_extent.width * copy.image_extent.height *
|
||||
copy.image_subresource.num_layers *
|
||||
BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
|
||||
} else if (astc) {
|
||||
// BC1 uses 0.5 bytes per texel
|
||||
// BC3 uses 1 byte per texel
|
||||
const auto compress = recompression_setting == Settings::AstcRecompression::Bc1
|
||||
? Tegra::Texture::BCN::CompressBC1
|
||||
: Tegra::Texture::BCN::CompressBC3;
|
||||
const auto bpp_div = recompression_setting == Settings::AstcRecompression::Bc1 ? 2 : 1;
|
||||
|
||||
const u32 plane_dim = copy.image_extent.width * copy.image_extent.height;
|
||||
const u32 level_size = plane_dim * copy.image_extent.depth *
|
||||
copy.image_subresource.num_layers *
|
||||
BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
|
||||
decode_scratch.resize_destructive(level_size);
|
||||
|
||||
Tegra::Texture::ASTC::Decompress(
|
||||
input_offset, copy.image_extent.width, copy.image_extent.height,
|
||||
copy.image_subresource.num_layers * copy.image_extent.depth, tile_size.width,
|
||||
tile_size.height, decode_scratch);
|
||||
|
||||
compress(decode_scratch, copy.image_extent.width, copy.image_extent.height,
|
||||
copy.image_subresource.num_layers * copy.image_extent.depth,
|
||||
output.subspan(output_offset));
|
||||
|
||||
const u32 aligned_plane_dim = Common::AlignUp(copy.image_extent.width, 4) *
|
||||
Common::AlignUp(copy.image_extent.height, 4);
|
||||
|
||||
copy.buffer_size =
|
||||
(aligned_plane_dim * copy.image_extent.depth * copy.image_subresource.num_layers) /
|
||||
bpp_div;
|
||||
output_offset += static_cast<u32>(copy.buffer_size);
|
||||
} else {
|
||||
DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format);
|
||||
output_offset += copy.image_extent.width * copy.image_extent.height *
|
||||
copy.image_subresource.num_layers *
|
||||
ConvertedBytesPerBlock(info.format);
|
||||
}
|
||||
|
||||
copy.buffer_row_length = mip_size.width;
|
||||
copy.buffer_image_height = mip_size.height;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Tegra::Texture::ASTC {
|
||||
|
||||
void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
|
||||
uint32_t block_width, uint32_t block_height, std::span<uint8_t> output);
|
||||
|
||||
} // namespace Tegra::Texture::ASTC
|
||||
+126
-41
@@ -1,7 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "yuzu/game_list.h"
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
@@ -11,22 +10,28 @@
|
||||
#include <QJsonObject>
|
||||
#include <QList>
|
||||
#include <QMenu>
|
||||
#include <QScroller>
|
||||
#include <QScrollBar>
|
||||
#include <QThreadPool>
|
||||
#include <QToolButton>
|
||||
#include <QVariantAnimation>
|
||||
#include <fmt/ranges.h>
|
||||
#include <qnamespace.h>
|
||||
#include <qscroller.h>
|
||||
#include <qscrollerproperties.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "qt_common/util/game.h"
|
||||
#include "qt_common/config/uisettings.h"
|
||||
#include "qt_common/util/game.h"
|
||||
#include "yuzu/compatibility_list.h"
|
||||
#include "yuzu/game_list.h"
|
||||
#include "yuzu/game_list_p.h"
|
||||
#include "yuzu/game_list_worker.h"
|
||||
#include "yuzu/main_window.h"
|
||||
#include "yuzu/util/controller_navigation.h"
|
||||
#include <fmt/ranges.h>
|
||||
#include <regex>
|
||||
|
||||
GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent)
|
||||
: QObject(parent), gamelist{gamelist_} {}
|
||||
@@ -328,6 +333,22 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
|
||||
item_model = new QStandardItemModel(tree_view);
|
||||
tree_view->setModel(item_model);
|
||||
|
||||
SetupScrollAnimation();
|
||||
tree_view->viewport()->installEventFilter(this);
|
||||
|
||||
// touch gestures
|
||||
tree_view->viewport()->grabGesture(Qt::SwipeGesture);
|
||||
tree_view->viewport()->grabGesture(Qt::PanGesture);
|
||||
|
||||
// TODO: touch?
|
||||
QScroller::grabGesture(tree_view->viewport(), QScroller::LeftMouseButtonGesture);
|
||||
|
||||
auto scroller = QScroller::scroller(tree_view->viewport());
|
||||
QScrollerProperties props;
|
||||
props.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
|
||||
props.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
|
||||
scroller->setScrollerProperties(props);
|
||||
|
||||
tree_view->setAlternatingRowColors(true);
|
||||
tree_view->setSelectionMode(QHeaderView::SingleSelection);
|
||||
tree_view->setSelectionBehavior(QHeaderView::SelectRows);
|
||||
@@ -352,7 +373,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
|
||||
connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
|
||||
connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
|
||||
connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded);
|
||||
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
|
||||
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, this,
|
||||
[this](Qt::Key key) {
|
||||
// Avoid pressing buttons while playing
|
||||
if (system.IsPoweredOn()) {
|
||||
@@ -477,7 +498,7 @@ void GameList::DonePopulating(const QStringList& watch_list) {
|
||||
UISettings::values.favorited_ids.size() == 0);
|
||||
tree_view->setExpanded(item_model->invisibleRootItem()->child(0)->index(),
|
||||
UISettings::values.favorites_expanded.GetValue());
|
||||
for (const auto id : UISettings::values.favorited_ids) {
|
||||
for (const auto id : std::as_const(UISettings::values.favorited_ids)) {
|
||||
AddFavorite(id);
|
||||
}
|
||||
|
||||
@@ -613,73 +634,73 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
|
||||
navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0);
|
||||
|
||||
connect(favorite, &QAction::triggered, [this, program_id]() { ToggleFavorite(program_id); });
|
||||
connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(favorite, &QAction::triggered, this, [this, program_id]() { ToggleFavorite(program_id); });
|
||||
connect(open_save_location, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
|
||||
});
|
||||
connect(start_game, &QAction::triggered,
|
||||
connect(start_game, &QAction::triggered, this,
|
||||
[this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Normal); });
|
||||
connect(start_game_global, &QAction::triggered,
|
||||
connect(start_game_global, &QAction::triggered, this,
|
||||
[this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Global); });
|
||||
connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(open_mod_location, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
|
||||
});
|
||||
connect(open_transferable_shader_cache, &QAction::triggered,
|
||||
connect(open_transferable_shader_cache, &QAction::triggered, this,
|
||||
[this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); });
|
||||
connect(remove_all_content, &QAction::triggered, [this, program_id]() {
|
||||
connect(remove_all_content, &QAction::triggered, this, [this, program_id]() {
|
||||
emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Game);
|
||||
});
|
||||
connect(remove_update, &QAction::triggered, [this, program_id]() {
|
||||
connect(remove_update, &QAction::triggered, this, [this, program_id]() {
|
||||
emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Update);
|
||||
});
|
||||
connect(remove_dlc, &QAction::triggered, [this, program_id]() {
|
||||
connect(remove_dlc, &QAction::triggered, this, [this, program_id]() {
|
||||
emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::AddOnContent);
|
||||
});
|
||||
connect(remove_gl_shader_cache, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(remove_gl_shader_cache, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::GlShaderCache, path);
|
||||
});
|
||||
connect(remove_vk_shader_cache, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(remove_vk_shader_cache, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::VkShaderCache, path);
|
||||
});
|
||||
connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(remove_shader_cache, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::AllShaderCache, path);
|
||||
});
|
||||
connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(remove_custom_config, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CustomConfiguration, path);
|
||||
});
|
||||
connect(set_play_time, &QAction::triggered,
|
||||
connect(set_play_time, &QAction::triggered, this,
|
||||
[this, program_id]() { emit SetPlayTimeRequested(program_id); });
|
||||
connect(remove_play_time_data, &QAction::triggered,
|
||||
connect(remove_play_time_data, &QAction::triggered, this,
|
||||
[this, program_id]() { emit RemovePlayTimeRequested(program_id); });
|
||||
connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] {
|
||||
connect(remove_cache_storage, &QAction::triggered, this, [this, program_id, path] {
|
||||
emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CacheStorage, path);
|
||||
});
|
||||
connect(dump_romfs, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(dump_romfs, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal);
|
||||
});
|
||||
connect(dump_romfs_sdmc, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(dump_romfs_sdmc, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::SDMC);
|
||||
});
|
||||
connect(verify_integrity, &QAction::triggered,
|
||||
connect(verify_integrity, &QAction::triggered, this,
|
||||
[this, path]() { emit VerifyIntegrityRequested(path); });
|
||||
connect(copy_tid, &QAction::triggered,
|
||||
connect(copy_tid, &QAction::triggered, this,
|
||||
[this, program_id]() { emit CopyTIDRequested(program_id); });
|
||||
connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {
|
||||
connect(navigate_to_gamedb_entry, &QAction::triggered, this, [this, program_id]() {
|
||||
emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
|
||||
});
|
||||
// TODO: Implement shortcut creation for macOS
|
||||
#if !defined(__APPLE__)
|
||||
connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(create_desktop_shortcut, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Desktop);
|
||||
});
|
||||
connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() {
|
||||
connect(create_applications_menu_shortcut, &QAction::triggered, this, [this, program_id, path]() {
|
||||
emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Applications);
|
||||
});
|
||||
#endif
|
||||
connect(properties, &QAction::triggered,
|
||||
connect(properties, &QAction::triggered, this,
|
||||
[this, path]() { emit OpenPerGameGeneralRequested(path); });
|
||||
|
||||
connect(ryujinx, &QAction::triggered, [this, program_id]() { emit LinkToRyujinxRequested(program_id);
|
||||
connect(ryujinx, &QAction::triggered, this, [this, program_id]() { emit LinkToRyujinxRequested(program_id);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -693,11 +714,11 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
deep_scan->setCheckable(true);
|
||||
deep_scan->setChecked(game_dir.deep_scan);
|
||||
|
||||
connect(deep_scan, &QAction::triggered, [this, &game_dir] {
|
||||
connect(deep_scan, &QAction::triggered, this, [this, &game_dir] {
|
||||
game_dir.deep_scan = !game_dir.deep_scan;
|
||||
PopulateAsync(UISettings::values.game_dirs);
|
||||
});
|
||||
connect(delete_dir, &QAction::triggered, [this, &game_dir, selected] {
|
||||
connect(delete_dir, &QAction::triggered, this, [this, &game_dir, selected] {
|
||||
UISettings::values.game_dirs.removeOne(game_dir);
|
||||
item_model->invisibleRootItem()->removeRow(selected.row());
|
||||
OnTextChanged(search_field->filterText());
|
||||
@@ -716,7 +737,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
move_up->setEnabled(row > 1);
|
||||
move_down->setEnabled(row < item_model->rowCount() - 2);
|
||||
|
||||
connect(move_up, &QAction::triggered, [this, selected, row, game_dir_index] {
|
||||
connect(move_up, &QAction::triggered, this, [this, selected, row, game_dir_index] {
|
||||
const int other_index = selected.sibling(row - 1, 0).data(GameListDir::GameDirRole).toInt();
|
||||
// swap the items in the settings
|
||||
std::swap(UISettings::values.game_dirs[game_dir_index],
|
||||
@@ -732,7 +753,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
UISettings::values.game_dirs[other_index].expanded);
|
||||
});
|
||||
|
||||
connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] {
|
||||
connect(move_down, &QAction::triggered, this, [this, selected, row, game_dir_index] {
|
||||
const int other_index = selected.sibling(row + 1, 0).data(GameListDir::GameDirRole).toInt();
|
||||
// swap the items in the settings
|
||||
std::swap(UISettings::values.game_dirs[game_dir_index],
|
||||
@@ -748,7 +769,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
UISettings::values.game_dirs[other_index].expanded);
|
||||
});
|
||||
|
||||
connect(open_directory_location, &QAction::triggered, [this, game_dir_index] {
|
||||
connect(open_directory_location, &QAction::triggered, this, [this, game_dir_index] {
|
||||
emit OpenDirectory(
|
||||
QString::fromStdString(UISettings::values.game_dirs[game_dir_index].path));
|
||||
});
|
||||
@@ -757,8 +778,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
void GameList::AddFavoritesPopup(QMenu& context_menu) {
|
||||
QAction* clear = context_menu.addAction(tr("Clear"));
|
||||
|
||||
connect(clear, &QAction::triggered, [this] {
|
||||
for (const auto id : UISettings::values.favorited_ids) {
|
||||
connect(clear, &QAction::triggered, this, [this] {
|
||||
for (const auto id : std::as_const(UISettings::values.favorited_ids)) {
|
||||
RemoveFavorite(id);
|
||||
}
|
||||
UISettings::values.favorited_ids.clear();
|
||||
@@ -788,7 +809,7 @@ void GameList::LoadCompatibilityList() {
|
||||
const QJsonDocument json = QJsonDocument::fromJson(content);
|
||||
const QJsonArray arr = json.array();
|
||||
|
||||
for (const QJsonValue value : arr) {
|
||||
for (const QJsonValue &value : arr) {
|
||||
const QJsonObject game = value.toObject();
|
||||
const QString compatibility_key = QStringLiteral("compatibility");
|
||||
|
||||
@@ -800,7 +821,7 @@ void GameList::LoadCompatibilityList() {
|
||||
const QString directory = game[QStringLiteral("directory")].toString();
|
||||
const QJsonArray ids = game[QStringLiteral("releases")].toArray();
|
||||
|
||||
for (const QJsonValue id_ref : ids) {
|
||||
for (const QJsonValue &id_ref : ids) {
|
||||
const QJsonObject id_object = id_ref.toObject();
|
||||
const QString id = id_object[QStringLiteral("id")].toString();
|
||||
|
||||
@@ -919,7 +940,7 @@ void GameList::ToggleFavorite(u64 program_id) {
|
||||
tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true);
|
||||
}
|
||||
}
|
||||
SaveConfig();
|
||||
emit SaveConfig();
|
||||
}
|
||||
|
||||
void GameList::AddFavorite(u64 program_id) {
|
||||
@@ -989,6 +1010,70 @@ void GameListPlaceholder::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||
emit GameListPlaceholder::AddDirectory();
|
||||
}
|
||||
|
||||
void GameList::SetupScrollAnimation() {
|
||||
auto setup = [this](QVariantAnimation* anim, QScrollBar* bar) {
|
||||
// animation handles moving the bar instead of Qt's built in crap
|
||||
anim->setEasingCurve(QEasingCurve::OutCubic);
|
||||
anim->setDuration(200);
|
||||
connect(anim, &QVariantAnimation::valueChanged, this, [bar](const QVariant& value) {
|
||||
bar->setValue(value.toInt());
|
||||
});
|
||||
};
|
||||
|
||||
vertical_scroll = new QVariantAnimation(this);
|
||||
horizontal_scroll = new QVariantAnimation(this);
|
||||
|
||||
setup(vertical_scroll, tree_view->verticalScrollBar());
|
||||
setup(horizontal_scroll, tree_view->horizontalScrollBar());
|
||||
}
|
||||
|
||||
bool GameList::eventFilter(QObject* obj, QEvent* event) {
|
||||
if (obj == tree_view->viewport() && event->type() == QEvent::Wheel) {
|
||||
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
|
||||
|
||||
bool horizontal = wheelEvent->modifiers() & Qt::ShiftModifier;
|
||||
|
||||
int deltaX = wheelEvent->angleDelta().x();
|
||||
int deltaY = wheelEvent->angleDelta().y();
|
||||
|
||||
// if shift is held do a horizontal scroll
|
||||
if (horizontal && deltaY != 0 && deltaX == 0) {
|
||||
deltaX = deltaY;
|
||||
deltaY = 0;
|
||||
}
|
||||
|
||||
// TODO(crueter): dedup this
|
||||
if (deltaY != 0) {
|
||||
if (vertical_scroll->state() == QAbstractAnimation::Stopped)
|
||||
vertical_scroll_target = tree_view->verticalScrollBar()->value();
|
||||
|
||||
vertical_scroll_target -= deltaY;
|
||||
vertical_scroll_target = qBound(0, vertical_scroll_target, tree_view->verticalScrollBar()->maximum());
|
||||
|
||||
vertical_scroll->stop();
|
||||
vertical_scroll->setStartValue(tree_view->verticalScrollBar()->value());
|
||||
vertical_scroll->setEndValue(vertical_scroll_target);
|
||||
vertical_scroll->start();
|
||||
}
|
||||
|
||||
if (deltaX != 0) {
|
||||
if (horizontal_scroll->state() == QAbstractAnimation::Stopped)
|
||||
horizontal_scroll_target = tree_view->horizontalScrollBar()->value();
|
||||
|
||||
horizontal_scroll_target -= deltaX;
|
||||
horizontal_scroll_target = qBound(0, horizontal_scroll_target, tree_view->horizontalScrollBar()->maximum());
|
||||
|
||||
horizontal_scroll->stop();
|
||||
horizontal_scroll->setStartValue(tree_view->horizontalScrollBar()->value());
|
||||
horizontal_scroll->setEndValue(horizontal_scroll_target);
|
||||
horizontal_scroll->start();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void GameListPlaceholder::changeEvent(QEvent* event) {
|
||||
if (event->type() == QEvent::LanguageChange) {
|
||||
RetranslateUI();
|
||||
|
||||
+10
-1
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "yuzu/compatibility_list.h"
|
||||
#include "frontend_common/play_time_manager.h"
|
||||
|
||||
class QVariantAnimation;
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
@@ -162,6 +163,14 @@ private:
|
||||
ControllerNavigation* controller_navigation = nullptr;
|
||||
CompatibilityList compatibility_list;
|
||||
|
||||
QVariantAnimation* vertical_scroll = nullptr;
|
||||
QVariantAnimation* horizontal_scroll = nullptr;
|
||||
int vertical_scroll_target = 0;
|
||||
int horizontal_scroll_target = 0;
|
||||
|
||||
void SetupScrollAnimation();
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
|
||||
friend class GameListSearchField;
|
||||
|
||||
const PlayTime::PlayTimeManager& play_time_manager;
|
||||
|
||||
Reference in New Issue
Block a user