Compare commits

..

4 Commits

Author SHA1 Message Date
lizzie d336341c8d 2026-09-27 17:50:19
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-27 17:50:19 +00:00
lizzie a4fd5c6b0b 2026-09-27 17:15:36
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-27 17:15:37 +00:00
lizzie ef7e9c00b0 2026-09-27 16:59:33
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-27 16:59:33 +00:00
lizzie 3be0db1266 2026-09-27 15:50:47
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-27 16:58:25 +00:00
88 changed files with 13442 additions and 13276 deletions
+1 -1
View File
@@ -79,7 +79,7 @@
"name": "ffmpeg", "name": "ffmpeg",
"package": "FFmpeg", "package": "FFmpeg",
"repo": "crueter-ci/FFmpeg", "repo": "crueter-ci/FFmpeg",
"version": "9.0.2-1790726865-946fcce07b" "version": "9.0.1-1788120736-bf1b838f2a"
}, },
"fmt": { "fmt": {
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2", "hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
+587 -558
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+477 -443
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+470 -442
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+470 -442
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+470 -443
View File
File diff suppressed because it is too large Load Diff
+470 -442
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+477 -443
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+470 -442
View File
File diff suppressed because it is too large Load Diff
+470 -442
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+477 -443
View File
File diff suppressed because it is too large Load Diff
+474 -444
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+474 -447
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
+477 -443
View File
File diff suppressed because it is too large Load Diff
+469 -442
View File
File diff suppressed because it is too large Load Diff
@@ -16,8 +16,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_USE_SPEED_LIMIT("use_speed_limit"), RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"), USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"), SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
NCE_INVALIDATION_GPU_READBACK("nce_invalidation_gpu_readback"),
NCE_RUNTIME_NRO_PATCH("nce_runtime_nro_patch"),
FIX_BLOOM_EFFECTS("fix_bloom_effects"), FIX_BLOOM_EFFECTS("fix_bloom_effects"),
EMULATE_BGR565("emulate_bgr565"), EMULATE_BGR565("emulate_bgr565"),
RESCALE_HACK("rescale_hack"), RESCALE_HACK("rescale_hack"),
@@ -866,20 +866,6 @@ abstract class SettingsItem(
descriptionId = R.string.skip_cpu_inner_invalidation_description descriptionId = R.string.skip_cpu_inner_invalidation_description
) )
) )
put(
SwitchSetting(
BooleanSetting.NCE_INVALIDATION_GPU_READBACK,
titleId = R.string.nce_invalidation_gpu_readback,
descriptionId = R.string.nce_invalidation_gpu_readback_description
)
)
put(
SwitchSetting(
BooleanSetting.NCE_RUNTIME_NRO_PATCH,
titleId = R.string.nce_runtime_nro_patch,
descriptionId = R.string.nce_runtime_nro_patch_description
)
)
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.FIX_BLOOM_EFFECTS, BooleanSetting.FIX_BLOOM_EFFECTS,
@@ -554,8 +554,6 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.hacks)) add(HeaderSetting(R.string.hacks))
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key) add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
add(BooleanSetting.NCE_INVALIDATION_GPU_READBACK.key)
add(BooleanSetting.NCE_RUNTIME_NRO_PATCH.key)
add(BooleanSetting.FIX_BLOOM_EFFECTS.key) add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
add(BooleanSetting.EMULATE_BGR565.key) add(BooleanSetting.EMULATE_BGR565.key)
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
@@ -23,7 +23,6 @@ import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import java.io.File import java.io.File
@@ -147,11 +146,11 @@ class DriverViewModel : ViewModel() {
private fun wipeGameShaders(game: Game) { private fun wipeGameShaders(game: Game) {
viewModelScope.launch { viewModelScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val userDirectory = DirectoryInitialization.userDirectory val externalFilesDir = YuzuApplication.appContext.getExternalFilesDir(null)
?: return@withContext ?: return@withContext
val shaderDir = File( val shaderDir = File(
userDirectory + externalFilesDir.absolutePath +
"/cache/shader/" + game.settingsName.lowercase() "/shader/" + game.settingsName.lowercase()
) )
if (shaderDir.exists()) { if (shaderDir.exists()) {
shaderDir.deleteRecursively() shaderDir.deleteRecursively()
@@ -28,7 +28,7 @@
<string name="input_overlay_behavior">السلوك</string> <string name="input_overlay_behavior">السلوك</string>
<string name="overlay_auto_hide">إخفاء الطبقة تلقائيًا</string> <string name="overlay_auto_hide">إخفاء الطبقة تلقائيًا</string>
<string name="overlay_auto_hide_description">إخفاء طبقة ذراع التحكم باللمس تلقائيًا بعد مرور الوقت المحدد من عدم النشاط.</string> <string name="overlay_auto_hide_description">إخفاء طبقة ذراع التحكم باللمس تلقائيًا بعد مرور الوقت المحدد من عدم النشاط.</string>
<string name="enable_input_overlay_auto_hide">تفعيل إخفاء الطبقة تلقائيًا</string> <string name="enable_input_overlay_auto_hide">تمكين إخفاء الطبقة تلقائيًا</string>
<string name="hide_overlay_on_controller_input">إخفاء الطبقة عند إدخال ذراع التحكم</string> <string name="hide_overlay_on_controller_input">إخفاء الطبقة عند إدخال ذراع التحكم</string>
<string name="hide_overlay_on_controller_input_description">إخفاء تلقائي لطبقة عناصر التحكم باللمس عند استخدام ذراع تحكم فعلية. تظهر الطبقة مرة أخرى عند فصل ذراع التحكم.</string> <string name="hide_overlay_on_controller_input_description">إخفاء تلقائي لطبقة عناصر التحكم باللمس عند استخدام ذراع تحكم فعلية. تظهر الطبقة مرة أخرى عند فصل ذراع التحكم.</string>
<string name="invert_confirm_back_controller_buttons">عكس أزرار التأكيد/الرجوع في وحدة التحكم</string> <string name="invert_confirm_back_controller_buttons">عكس أزرار التأكيد/الرجوع في وحدة التحكم</string>
@@ -51,7 +51,7 @@
<string name="stats_overlay_customization">التخصيص</string> <string name="stats_overlay_customization">التخصيص</string>
<string name="stats_overlay_items">الرؤية</string> <string name="stats_overlay_items">الرؤية</string>
<string name="stats_overlay_options">طبقة الأداء</string> <string name="stats_overlay_options">طبقة الأداء</string>
<string name="enable_stats_overlay_">تفعيل طبقة إحصائيات الأداء</string> <string name="enable_stats_overlay_">تمكين طبقة إحصائيات الأداء</string>
<string name="stats_overlay_options_description">ضبط المعلومات التي يتم عرضها في طبقة إحصائيات الأداء</string> <string name="stats_overlay_options_description">ضبط المعلومات التي يتم عرضها في طبقة إحصائيات الأداء</string>
<string name="show_fps">عرض معدل الإطارات</string> <string name="show_fps">عرض معدل الإطارات</string>
<string name="show_fps_description">عرض معدل الإطارات الحالي</string> <string name="show_fps_description">عرض معدل الإطارات الحالي</string>
@@ -81,7 +81,7 @@
<!-- Device Overlay settings --> <!-- Device Overlay settings -->
<string name="show_soc_overlay">عرض طبقة معلومات الجهاز</string> <string name="show_soc_overlay">عرض طبقة معلومات الجهاز</string>
<string name="enable_soc_overlay">تفعيل طبقة الجهاز</string> <string name="enable_soc_overlay">تمكين طبقة الجهاز</string>
<string name="soc_overlay_options">طبقة الجهاز</string> <string name="soc_overlay_options">طبقة الجهاز</string>
<string name="soc_overlay_options_description">ضبط المعلومات التي يتم عرضها في طبقة الجهاز</string> <string name="soc_overlay_options_description">ضبط المعلومات التي يتم عرضها في طبقة الجهاز</string>
@@ -98,8 +98,8 @@
<string name="use_sync_core">مزامنة سرعة النواة</string> <string name="use_sync_core">مزامنة سرعة النواة</string>
<string name="use_sync_core_description">قم بمزامنة سرعة النواة مع النسبة المئوية للسرعة القصوى لتحسين الأداء دون تغيير السرعة الفعلية للعبة.</string> <string name="use_sync_core_description">قم بمزامنة سرعة النواة مع النسبة المئوية للسرعة القصوى لتحسين الأداء دون تغيير السرعة الفعلية للعبة.</string>
<string name="cpuopt_unsafe_host_mmu">تفعيل محاكاة MMU المضيف</string> <string name="cpuopt_unsafe_host_mmu">تمكين محاكاة MMU المضيف</string>
<string name="cpuopt_unsafe_host_mmu_description">يعمل هذا التحسين على تسريع وصول الذاكرة بواسطة البرنامج الضيف. يؤدي تفعيله إلى إجراء عمليات قراءة/كتابة ذاكرة الضيف مباشرة في الذاكرة والاستفادة من MMU المضيف. يؤدي تعطيل هذا إلى إجبار جميع عمليات الوصول إلى الذاكرة على استخدام محاكاة MMU البرمجية.</string> <string name="cpuopt_unsafe_host_mmu_description">يعمل هذا التحسين على تسريع وصول الذاكرة بواسطة البرنامج الضيف. يؤدي تمكينه إلى إجراء عمليات قراءة/كتابة ذاكرة الضيف مباشرة في الذاكرة والاستفادة من MMU المضيف. يؤدي تعطيل هذا إلى إجبار جميع عمليات الوصول إلى الذاكرة على استخدام محاكاة MMU البرمجية.</string>
<string name="debug_knobs">مقابض تصحيح الأخطاء</string> <string name="debug_knobs">مقابض تصحيح الأخطاء</string>
<string name="debug_knobs_description">للإستخدام في التطوير فقط.</string> <string name="debug_knobs_description">للإستخدام في التطوير فقط.</string>
<string name="debug_knobs_hint">0 إلى 65535</string> <string name="debug_knobs_hint">0 إلى 65535</string>
@@ -342,7 +342,7 @@
<string name="frame_gen_flow_scale_description">دقة مسار التدفق البصري، كجزء من الناتج. ويُعد خفض هذه القيمة أرخص طريقة لاستعادة الأداء.</string> <string name="frame_gen_flow_scale_description">دقة مسار التدفق البصري، كجزء من الناتج. ويُعد خفض هذه القيمة أرخص طريقة لاستعادة الأداء.</string>
<string name="frame_gen_unsupported">توليد الإطار غير متاح</string> <string name="frame_gen_unsupported">توليد الإطار غير متاح</string>
<string name="frame_gen_unsupported_description">يفتقر برنامج تشغيل وحدة معالجة الرسومات هذا إلى نموذج ذاكرة Vulkan أو دعم الدقة النصفية (float16) التي تتطلبها برامج التظليل الخاصة بـ «Lossless Scaling».</string> <string name="frame_gen_unsupported_description">يفتقر برنامج تشغيل وحدة معالجة الرسومات هذا إلى نموذج ذاكرة Vulkan أو دعم الدقة النصفية (float16) التي تتطلبها برامج التظليل الخاصة بـ «Lossless Scaling».</string>
<string name="lossless_scaling_setup_description">اختياري. قم بتوفير ملف Lossless.dll الخاص بك لتفعيل إنشاء الإطارات لاحقًا</string> <string name="lossless_scaling_setup_description">اختياري. قم بتوفير ملف Lossless.dll الخاص بك لتمكين إنشاء الإطارات لاحقًا</string>
<string name="lossless_scaling_install">تثبيت ملف Lossless.dll</string> <string name="lossless_scaling_install">تثبيت ملف Lossless.dll</string>
<string name="lossless_scaling_install_description">يتطلب إنشاء الإطارات أن تكون لديك نسخة قانونية خاصة بك من ملف Lossless.dll المأخوذ من برنامج Lossless Scaling</string> <string name="lossless_scaling_install_description">يتطلب إنشاء الإطارات أن تكون لديك نسخة قانونية خاصة بك من ملف Lossless.dll المأخوذ من برنامج Lossless Scaling</string>
<string name="lossless_scaling_replace_description">اختر نسخة أخرى من ملف Lossless.dll</string> <string name="lossless_scaling_replace_description">اختر نسخة أخرى من ملف Lossless.dll</string>
@@ -350,7 +350,7 @@
<string name="frame_generation_supported">مدعوم</string> <string name="frame_generation_supported">مدعوم</string>
<string name="frame_generation_unsupported">غير مدعوم (لا يتوفر نموذج ذاكرة Vulkan أو float16)</string> <string name="frame_generation_unsupported">غير مدعوم (لا يتوفر نموذج ذاكرة Vulkan أو float16)</string>
<string name="lossless_scaling">Lossless Scaling</string> <string name="lossless_scaling">Lossless Scaling</string>
<string name="lossless_scaling_description">قم بتوفير نسختك الخاصة من ملف Lossless.dll لتفعيل توليد الإطارات</string> <string name="lossless_scaling_description">قم بتوفير نسختك الخاصة من ملف Lossless.dll لتمكين توليد الإطارات</string>
<string name="lossless_scaling_installed">مثبت</string> <string name="lossless_scaling_installed">مثبت</string>
<string name="lossless_scaling_not_installed">غير مثبت</string> <string name="lossless_scaling_not_installed">غير مثبت</string>
<string name="lossless_scaling_replace">استبدل</string> <string name="lossless_scaling_replace">استبدل</string>
@@ -502,9 +502,9 @@
<string name="frame_limit_slider">نسبة الحد الأقصى للسرعة</string> <string name="frame_limit_slider">نسبة الحد الأقصى للسرعة</string>
<string name="frame_limit_slider_description">يحدد النسبة المئوية للحد من سرعة المحاكاة. %100 هي السرعة الطبيعية. القيم الأعلى أو الأقل ستزيد أو تقلل من الحد الأقصى للسرعة.</string> <string name="frame_limit_slider_description">يحدد النسبة المئوية للحد من سرعة المحاكاة. %100 هي السرعة الطبيعية. القيم الأعلى أو الأقل ستزيد أو تقلل من الحد الأقصى للسرعة.</string>
<string name="turbo_speed_limit">سرعة تيربو</string> <string name="turbo_speed_limit">سرعة تيربو</string>
<string name="turbo_speed_limit_description">عند تفعيل وضع التيربو، سيتم تشغيل المحاكاة بهذه السرعة.</string> <string name="turbo_speed_limit_description">عند تمكين وضع التيربو، سيتم تشغيل المحاكاة بهذه السرعة.</string>
<string name="slow_speed_limit">سرعة بطيئة</string> <string name="slow_speed_limit">سرعة بطيئة</string>
<string name="slow_speed_limit_description">عند تفعيل الوضع البطيء، سيتم تشغيل المحاكاة بهذه السرعة.</string> <string name="slow_speed_limit_description">عند تمكين الوضع البطيء، سيتم تشغيل المحاكاة بهذه السرعة.</string>
<string name="cpu_backend">خلفية وحدة المعالجة المركزية</string> <string name="cpu_backend">خلفية وحدة المعالجة المركزية</string>
<string name="cpu_accuracy">دقة وحدة المعالجة المركزية</string> <string name="cpu_accuracy">دقة وحدة المعالجة المركزية</string>
<string name="value_with_units">%1$s%2$s</string> <string name="value_with_units">%1$s%2$s</string>
@@ -578,7 +578,7 @@
<string name="renderer_async_presentation_description">يمكن لهذه الحيلة أن تزيد من الأداء عن طريق نقل عملية العرض إلى خيط معالجة منفصل على حساب مشاكل الرسوميات.</string> <string name="renderer_async_presentation_description">يمكن لهذه الحيلة أن تزيد من الأداء عن طريق نقل عملية العرض إلى خيط معالجة منفصل على حساب مشاكل الرسوميات.</string>
<string name="renderer_reactive_flushing">استخدم التنظيف التفاعلي</string> <string name="renderer_reactive_flushing">استخدم التنظيف التفاعلي</string>
<string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string> <string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string>
<string name="enable_buffer_history">تفعيل سجل التخزين المؤقت</string> <string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
<string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string> <string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string>
<string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string> <string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string>
<string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string> <string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string>
@@ -616,7 +616,7 @@
<string name="dyna_state_description">يتحكم هذا الخيار في عدد الميزات التي يمكن استخدامها في ExtendedDynamicState (EDS). كلما زادت القيمة، قلّ عدد عمليات تجميع خط الأنابيب بناءً على الحالة الديناميكية التي يدعمها برنامج التشغيل.</string> <string name="dyna_state_description">يتحكم هذا الخيار في عدد الميزات التي يمكن استخدامها في ExtendedDynamicState (EDS). كلما زادت القيمة، قلّ عدد عمليات تجميع خط الأنابيب بناءً على الحالة الديناميكية التي يدعمها برنامج التشغيل.</string>
<string name="disabled">معطل</string> <string name="disabled">معطل</string>
<string name="vertex_input_dynamic_state">حالة ديناميكية لإدخال الرأس</string> <string name="vertex_input_dynamic_state">حالة ديناميكية لإدخال الرأس</string>
<string name="vertex_input_dynamic_state_description">يتيح تفعيل هذه الميزة معالجة أكثر مرونة لمدخلات الرؤوس، مما قد يقلل من وقت تجميع خط الأنابيب في vertex/buffer.</string> <string name="vertex_input_dynamic_state_description">يتيح تمكين هذه الميزة معالجة أكثر مرونة لمدخلات الرؤوس، مما قد يقلل من وقت تجميع خط الأنابيب في vertex/buffer.</string>
<string name="sample_shading_fraction">تظليل العينة</string> <string name="sample_shading_fraction">تظليل العينة</string>
<string name="sample_shading_fraction_description">يسمح هذا الخيار بتنفيذ مُظلل الأجزاء لكل عينة في جزء متعدد العينات بدلاً من تنفيذه مرة واحدة لكل جزء. يُحسّن هذا من جودة الرسومات على حساب بعض الأداء.</string> <string name="sample_shading_fraction_description">يسمح هذا الخيار بتنفيذ مُظلل الأجزاء لكل عينة في جزء متعدد العينات بدلاً من تنفيذه مرة واحدة لكل جزء. يُحسّن هذا من جودة الرسومات على حساب بعض الأداء.</string>
@@ -825,9 +825,9 @@
<string name="preferences_system">النظام</string> <string name="preferences_system">النظام</string>
<string name="preferences_system_description">وضع الإرساء، المنطقة، اللغة</string> <string name="preferences_system_description">وضع الإرساء، المنطقة، اللغة</string>
<string name="preferences_graphics">الرسومات</string> <string name="preferences_graphics">الرسومات</string>
<string name="preferences_graphics_description">مستوى دقة المحاكاة، الدقة، ذاكرة التخزين المؤقتة للتظليل</string> <string name="preferences_graphics_description">مستوى الدقة، الدقة، ذاكرة التخزين المؤقتة للتظليل</string>
<string name="quick_settings">الإعدادات السريعة</string> <string name="quick_settings">الإعدادات السريعة</string>
<string name="enable_quick_settings">تفعيل الإعدادات السريعة</string> <string name="enable_quick_settings">تمكين الإعدادات السريعة</string>
<string name="enable_quick_settings_description">السماح بالوصول إلى قائمة الإعدادات السريعة عن طريق التمرير و زر القائمة</string> <string name="enable_quick_settings_description">السماح بالوصول إلى قائمة الإعدادات السريعة عن طريق التمرير و زر القائمة</string>
<string name="preferences_audio">الصوت</string> <string name="preferences_audio">الصوت</string>
<string name="preferences_audio_description">محرك الإخراج، مستوى الصوت</string> <string name="preferences_audio_description">محرك الإخراج، مستوى الصوت</string>
@@ -1223,8 +1223,8 @@
<string name="airplane_mode">وضع الطيران</string> <string name="airplane_mode">وضع الطيران</string>
<string name="airplane_mode_description">يمرر وضع الطيران إلى نظام تشغيل Switch</string> <string name="airplane_mode_description">يمرر وضع الطيران إلى نظام تشغيل Switch</string>
<string name="enable_overlay">تفعيل التطبيق الصغير للطبقة</string> <string name="enable_overlay">تمكين التطبيق الصغير للطبقة</string>
<string name="enable_overlay_description">تفعيل التطبيق الصغير المدمج في Horizon. اضغط مع الاستمرار على زر الشاشة الرئيسية لمدة 1 ثانية لإظهاره.</string> <string name="enable_overlay_description">تمكين التطبيق الصغير المدمج في Horizon. اضغط مع الاستمرار على زر الشاشة الرئيسية لمدة 1 ثانية لإظهاره.</string>
<!-- Profile Management --> <!-- Profile Management -->
<string name="profile_manager">إدارة ملف التعريف</string> <string name="profile_manager">إدارة ملف التعريف</string>
@@ -16,7 +16,7 @@
<string name="value_too_high">範圍最大必須為%1$d</string> <string name="value_too_high">範圍最大必須為%1$d</string>
<string name="invalid_value">無效的範圍</string> <string name="invalid_value">無效的範圍</string>
<string name="using_per_game_config">使用個別遊戲設定中</string> <string name="using_per_game_config">使用個別設定中</string>
<!-- Input Overlay --> <!-- Input Overlay -->
<string name="show_input_overlay">顯示虛擬按鍵</string> <string name="show_input_overlay">顯示虛擬按鍵</string>
@@ -67,7 +67,7 @@
<string name="show_shaders_building">當著色器在編譯時顯示</string> <string name="show_shaders_building">當著色器在編譯時顯示</string>
<string name="show_shaders_building_description">顯示正在編譯的著色器數量</string> <string name="show_shaders_building_description">顯示正在編譯的著色器數量</string>
<string name="pipeline_worker_cores">管線工作執行緒</string> <string name="pipeline_worker_cores">管線工作執行緒</string>
<string name="pipeline_worker_cores_description">設定用於建置Vulkan管線的CPU核心數量,設定的數值越大效能越好,但溫度也會上升更快</string> <string name="pipeline_worker_cores_description">設定用於建置 Vulkan 管線的 CPU 核心數量,設定的數值越大效能越好,但溫度也會上升更快</string>
<string name="overlay_position">疊加層位置</string> <string name="overlay_position">疊加層位置</string>
<string name="overlay_position_description">選擇疊加層在畫面上的顯示位置</string> <string name="overlay_position_description">選擇疊加層在畫面上的顯示位置</string>
<string name="overlay_position_top_left">左上</string> <string name="overlay_position_top_left">左上</string>
@@ -98,15 +98,15 @@
<string name="use_sync_core">同步核心速度</string> <string name="use_sync_core">同步核心速度</string>
<string name="use_sync_core_description">將核心速度與最大速度百分比同步,在不改變遊戲實際速度的情況下提高效能</string> <string name="use_sync_core_description">將核心速度與最大速度百分比同步,在不改變遊戲實際速度的情況下提高效能</string>
<string name="cpuopt_unsafe_host_mmu">啟用主機MMU模擬</string> <string name="cpuopt_unsafe_host_mmu">啟用主機 MMU 模擬</string>
<string name="cpuopt_unsafe_host_mmu_description">此最佳化可加速客體程式的記憶體存取。啟用後,客體記憶體讀取/寫入將直接在記憶體中執行並利用主機的MMU。停用此功能將強制所有記憶體存取使用軟體MMU模擬</string> <string name="cpuopt_unsafe_host_mmu_description">此最佳化可加速客體程式的記憶體存取。啟用後,客體記憶體讀取/寫入將直接在記憶體中執行並利用主機的 MMU。停用此功能將強制所有記憶體存取使用軟體 MMU 模擬。</string>
<string name="debug_knobs">偵錯開關</string> <string name="debug_knobs">偵錯開關</string>
<string name="debug_knobs_description">僅限開發用途</string> <string name="debug_knobs_description">僅限開發用途</string>
<string name="debug_knobs_hint">0到65535</string> <string name="debug_knobs_hint">0到65535</string>
<!-- NVDEC Emulation --> <!-- NVDEC Emulation -->
<string name="nvdec_emulation">NVDEC模擬</string> <string name="nvdec_emulation">NVDEC模擬</string>
<string name="nvdec_emulation_description">若在過場動畫中當機請切換成CPU</string> <string name="nvdec_emulation_description">若在過場動畫中當機請切換成 CPU</string>
<string name="nvdec_emulation_none">無</string> <string name="nvdec_emulation_none">無</string>
<!-- Optimize SPIRV output --> <!-- Optimize SPIRV output -->
@@ -151,7 +151,7 @@
<string name="multiplayer_member_leave">%1$s 離開</string> <string name="multiplayer_member_leave">%1$s 離開</string>
<string name="multiplayer_member_kicked">%1$s 被踢出</string> <string name="multiplayer_member_kicked">%1$s 被踢出</string>
<string name="multiplayer_member_banned">%1$s 被封鎖</string> <string name="multiplayer_member_banned">%1$s 被封鎖</string>
<string name="multiplayer_address_unbanned">IP位址已解封</string> <string name="multiplayer_address_unbanned">位址已解封</string>
<string name="multiplayer_kick_member">踢出成員</string> <string name="multiplayer_kick_member">踢出成員</string>
<string name="multiplayer_password">密碼</string> <string name="multiplayer_password">密碼</string>
<string name="multiplayer_joining">正在加入…</string> <string name="multiplayer_joining">正在加入…</string>
@@ -173,7 +173,7 @@
<string name="multiplayer_ban">封鎖使用者</string> <string name="multiplayer_ban">封鎖使用者</string>
<string name="multiplayer_room_browser">公開房間</string> <string name="multiplayer_room_browser">公開房間</string>
<string name="multiplayer_no_rooms_found">未找到公開房間</string> <string name="multiplayer_no_rooms_found">未找到公開房間</string>
<string name="multiplayer_password_required">請輸入密碼</string> <string name="multiplayer_password_required">需要輸入密碼</string>
<string name="multiplayer_player_count">:%1$d/%2$d</string> <string name="multiplayer_player_count">:%1$d/%2$d</string>
<string name="multiplayer_game">遊戲</string> <string name="multiplayer_game">遊戲</string>
<string name="multiplayer_no_game_info">任意遊戲</string> <string name="multiplayer_no_game_info">任意遊戲</string>
@@ -189,7 +189,7 @@
<string name="multiplayer_token_required">需要Web令牌,請前往進階設定 -> 系統 -> 網路</string> <string name="multiplayer_token_required">需要Web令牌,請前往進階設定 -> 系統 -> 網路</string>
<string name="multiplayer_ip_error">IP格式無效</string> <string name="multiplayer_ip_error">IP格式無效</string>
<string name="multiplayer_username_error">必須介於4-20個字元之間,並且僅能使用英文字母、數字、句點、破折號、底線和空格(標點符號須為英文格式)</string> <string name="multiplayer_username_error">必須介於4-20個字元之間,並且僅能使用英文字母、數字、句點、破折號、底線和空格(標點符號須為英文格式)</string>
<string name="multiplayer_nickname_invalid">使用者名稱無效,請在系統 -&gt; 網路中檢查設定</string> <string name="multiplayer_nickname_invalid">使用者名稱無效,請在系統→網路中檢查設定</string>
<string name="multiplayer_token_error">必須為48個字元,且僅包含小寫字母a-z</string> <string name="multiplayer_token_error">必須為48個字元,且僅包含小寫字母a-z</string>
<string name="multiplayer_port_error">埠號需為1-65535</string> <string name="multiplayer_port_error">埠號需為1-65535</string>
<string name="cancel">取消</string> <string name="cancel">取消</string>
@@ -201,16 +201,16 @@
<!-- Setup strings --> <!-- Setup strings -->
<string name="welcome">歡迎!</string> <string name="welcome">歡迎!</string>
<string name="welcome_description">瞭解如何設定 <b>Eden</b> 並開始模擬</string> <string name="welcome_description">瞭解如何設定 <b>Eden</b> 並開始模擬。</string>
<string name="get_started">開始使用</string> <string name="get_started">開始使用</string>
<string name="keys">金鑰</string> <string name="keys">金鑰</string>
<string name="keys_description">使用下方的按鈕安裝您的 <b>prod.keys</b> 檔案</string> <string name="keys_description">使用下方的按鈕安裝您的 <b>prod.keys</b> 檔案。</string>
<string name="firmware">韌體</string> <string name="firmware">韌體</string>
<string name="firmware_description">使用下方的按鈕安裝您的<b>firmware.zip</b>檔案</string> <string name="firmware_description">使用下方的按鈕安裝您的<b>firmware.zip</b>檔案</string>
<string name="games">遊戲資料夾</string> <string name="games">遊戲資料夾</string>
<string name="games_description">使用下方的按鈕選擇您的<b>遊戲</b>資料夾。</string> <string name="games_description">使用下方的按鈕選擇您的<b>遊戲</b>資料夾。</string>
<string name="done">完成</string> <string name="done">完成</string>
<string name="done_description">您已準備就緒\n盡情遊玩您的遊戲!</string> <string name="done_description">您已準備就緒。\n盡情遊玩您的遊戲!</string>
<string name="next">下一步</string> <string name="next">下一步</string>
<string name="back">上一步</string> <string name="back">上一步</string>
<string name="add_games">新增遊戲</string> <string name="add_games">新增遊戲</string>
@@ -237,7 +237,7 @@
<string name="update_install_failed">更新安裝失敗:%1$s</string> <string name="update_install_failed">更新安裝失敗:%1$s</string>
<string name="home_search">搜尋</string> <string name="home_search">搜尋</string>
<string name="home_settings">設定</string> <string name="home_settings">設定</string>
<string name="empty_gamelist">找不到遊戲檔案,或者尚未選取遊戲目錄</string> <string name="empty_gamelist">找不到檔案,或者尚未選取遊戲目錄</string>
<string name="manage_game_folders">管理遊戲資料夾</string> <string name="manage_game_folders">管理遊戲資料夾</string>
<string name="select_games_folder_description">允許 Eden 尋找您的遊戲檔案</string> <string name="select_games_folder_description">允許 Eden 尋找您的遊戲檔案</string>
<string name="add_games_warning">跳過選擇遊戲資料夾?</string> <string name="add_games_warning">跳過選擇遊戲資料夾?</string>
@@ -287,9 +287,9 @@
<string name="warning_skip">跳過</string> <string name="warning_skip">跳過</string>
<string name="warning_cancel">取消</string> <string name="warning_cancel">取消</string>
<string name="install_amiibo_keys">安裝 Amiibo 金鑰</string> <string name="install_amiibo_keys">安裝 Amiibo 金鑰</string>
<string name="install_amiibo_keys_description">需要先安裝才能在遊戲中使用Amiibo</string> <string name="install_amiibo_keys_description">若要在遊戲中使用 Amiibo 得先安裝</string>
<string name="gpu_driver_fetcher">GPU驅動程式下載器</string> <string name="gpu_driver_fetcher">GPU驅動程式下載器</string>
<string name="gpu_driver_manager">GPU驅動程式管理員</string> <string name="gpu_driver_manager">GPU 驅動程式管理員</string>
<string name="install_gpu_driver_description">安裝替代驅動程式以取得潛在的更佳效能或準確度</string> <string name="install_gpu_driver_description">安裝替代驅動程式以取得潛在的更佳效能或準確度</string>
<string name="post_processing">後製處理效果</string> <string name="post_processing">後製處理效果</string>
<string name="post_processing_description">在渲染完成後套用 ReShade FX 效果</string> <string name="post_processing_description">在渲染完成後套用 ReShade FX 效果</string>
@@ -299,7 +299,7 @@
<string name="post_processing_open_list">開啟清單</string> <string name="post_processing_open_list">開啟清單</string>
<string name="post_processing_close_list">收起清單</string> <string name="post_processing_close_list">收起清單</string>
<string name="post_processing_remove_all">移除效果</string> <string name="post_processing_remove_all">移除效果</string>
<string name="post_processing_preset_locked">濾鏡已啟用。請在開啟遊戲前於\"後製處理效果\"中調整</string> <string name="post_processing_preset_locked">濾鏡已啟用。請在開啟遊戲前於 後製處理效果 中調整</string>
<string name="post_processing_preset_modified">數值已變更,與原始濾鏡設定不同</string> <string name="post_processing_preset_modified">數值已變更,與原始濾鏡設定不同</string>
<string name="post_processing_presets">濾鏡</string> <string name="post_processing_presets">濾鏡</string>
<string name="post_processing_preset_new">新增濾鏡</string> <string name="post_processing_preset_new">新增濾鏡</string>
@@ -312,102 +312,93 @@
<string name="post_processing_empty">找不到設定檔。請將濾鏡效果的 .fx 檔案放置於此資料夾:</string> <string name="post_processing_empty">找不到設定檔。請將濾鏡效果的 .fx 檔案放置於此資料夾:</string>
<string name="frame_gen">影格生成</string> <string name="frame_gen">影格生成</string>
<string name="frame_gen_per_game_description">調整此遊戲的影格生成設定</string> <string name="frame_gen_per_game_description">調整此遊戲的影格生成設定</string>
<string name="frame_gen_description">使用Lossless Scaling在已渲染的影格之間插入補間影格。啟用此功能時,會強制採用FIFO垂直同步</string> <string name="frame_gen_description">使用 Lossless Scaling 在已渲染的影格之間插入補間影格。啟用此功能時,會強制採用 FIFO 垂直同步</string>
<string name="frame_gen_multiplier">影格倍率</string> <string name="frame_gen_multiplier">影格倍率</string>
<string name="frame_gen_multiplier_description">設定在每個已渲染的影格中要顯示的影格數,數值越高所需的GPU運算時間也會按比例增加。若要求的影格數超過裝置顯示器能呈現的數量將會降低模擬速度</string> <string name="frame_gen_multiplier_description">設定在每個已渲染的影格中要顯示的影格數。數值越高所需的 GPU 運算時間也會按比例增加。若要求的影格數超過裝置顯示器能呈現的數量將會降低模擬速度</string>
<string name="frame_gen_multiplier_2x">2x</string> <string name="frame_gen_multiplier_2x">2x</string>
<string name="frame_gen_multiplier_3x">3x</string> <string name="frame_gen_multiplier_3x">3x</string>
<string name="frame_gen_multiplier_4x">4x</string> <string name="frame_gen_multiplier_4x">4x</string>
<string name="frame_gen_target_rate">目標影格率</string> <string name="frame_gen_target_rate">目標影格率</string>
<string name="frame_gen_target_rate_description">選擇裝置顯示器能實際呈現的影格率,之後倍率器會自動升高或降低以維持影格率。如果某個調整導致遊戲本身運作變慢,則會自動復原該設定</string> <string name="frame_gen_target_rate_description">選擇裝置顯示器能實際呈現的影格率。之後倍率器會自動升高或降低以維持影格率。如果某個調整導致遊戲本身運作變慢,則會自動復原該設定</string>
<string name="frame_gen_target_rate_off">使用固定倍率</string> <string name="frame_gen_target_rate_off">使用固定倍率</string>
<string name="frame_gen_target_rate_60">60 FPS</string> <string name="frame_gen_target_rate_60">60 FPS</string>
<string name="frame_gen_target_rate_90">90 FPS</string> <string name="frame_gen_target_rate_90">90 FPS</string>
<string name="frame_gen_target_rate_120">120 FPS</string> <string name="frame_gen_target_rate_120">120 FPS</string>
<string name="frame_gen_on">開啟</string>
<string name="frame_gen_off">關閉</string>
<string name="frame_gen_fixed">固定</string>
<string name="frame_gen_flow_auto">自動</string>
<string name="frame_gen_quick_description">開啟或關閉影格生成後選擇影格倍率</string>
<string name="frame_gen_target_rate_quick_description">選擇要生成的目標影格率,倍率器會自動調整</string>
<string name="frame_gen_flow_scale_quick_description">用來預測影格之間動態的解析度,較低的數值可以減少GPU運算時間</string>
<string name="frame_gen_queue_target">影格佇列目標</string> <string name="frame_gen_queue_target">影格佇列目標</string>
<string name="frame_gen_queue_target_description">最多允許多少個已完成的影格在顯示器前等待,較大的佇列可以吸收 GPU 突發負載,但會增加輸入延遲</string> <string name="frame_gen_queue_target_description">最多允許多少個已完成的影格在顯示器前等待,較大的佇列可以吸收 GPU 突發負載,但會增加輸入延遲</string>
<string name="frame_gen_queue_target_0">最低延遲(無緩衝)</string> <string name="frame_gen_queue_target_0">最低延遲(無緩衝)</string>
<string name="frame_gen_queue_target_1">平衡(1影格)</string> <string name="frame_gen_queue_target_1">平衡(1影格)</string>
<string name="frame_gen_queue_target_2">最流暢(2影格)</string> <string name="frame_gen_queue_target_2">最流暢(2影格)</string>
<string name="frame_gen_flow_scale_auto">配合遊戲調整運動預測</string> <string name="frame_gen_flow_scale_auto">配合遊戲調整運動預測</string>
<string name="frame_gen_flow_scale_auto_description">以遊戲實際渲染的解析度而非升頻後的輸出進行運動預測,由於升頻後不會增加任何動態細節,因此不會影響準確度</string> <string name="frame_gen_flow_scale_auto_description">以遊戲實際渲染的解析度而非升頻後的輸出進行運動預測。由於升頻後不會增加任何動態細節,因此不會影響準確度</string>
<string name="frame_gen_flow_scale">運動預測解析度</string> <string name="frame_gen_flow_scale">運動預測解析度</string>
<string name="frame_gen_flow_scale_description">光流處理的解析度,以輸出解析度的比例表示,降低此設定值是減少效能負載最有效的方法</string> <string name="frame_gen_flow_scale_description">光流處理的解析度,以輸出解析度的比例表示。降低此設定值是減少效能負載最有效的方法</string>
<string name="frame_gen_unsupported">無法使用影格生成</string> <string name="frame_gen_unsupported">無法使用影格生成</string>
<string name="frame_gen_unsupported_description">此GPU驅動程式缺少Lossless Scaling著色器所需的Vulkan記憶體模型或半精度浮點數(float16)支援</string>
<string name="lossless_scaling_setup_description">可選擇安裝自己擁有的 Lossless.dll 以在之後啟用影格生成功能</string> <string name="lossless_scaling_setup_description">可選擇安裝自己擁有的 Lossless.dll 以在之後啟用影格生成功能</string>
<string name="lossless_scaling_install">安裝 Lossless.dll</string> <string name="lossless_scaling_install">安裝 Lossless.dll</string>
<string name="lossless_scaling_install_description">您需要擁有從合法管道獲得的 Lossless Scaling 並從該軟體的資料夾中取得 Lossless.dll 檔案才能使用影格生成功能</string> <string name="lossless_scaling_install_description">您需要擁有從合法管道獲得的 Lossless Scaling 並從該軟體的資料夾中取得 Lossless.dll 檔案才能使用影格生成功能</string>
<string name="lossless_scaling_replace_description">安裝不同的 Lossless.dll 檔案</string> <string name="lossless_scaling_replace_description">安裝不同的 Lossless.dll 檔案</string>
<string name="frame_generation_support">影格生成</string> <string name="frame_generation_support">影格生成</string>
<string name="frame_generation_supported">支援</string> <string name="frame_generation_supported">支援</string>
<string name="frame_generation_unsupported">不支援(無Vulkan記憶體模型或float16)</string>
<string name="lossless_scaling">Lossless Scaling</string> <string name="lossless_scaling">Lossless Scaling</string>
<string name="lossless_scaling_description">安裝您擁有的Lossless.dll檔案以使用影格生成</string> <string name="lossless_scaling_description">安裝您擁有的 Lossless.dll 檔案以使用影格生成</string>
<string name="lossless_scaling_installed">已安裝</string> <string name="lossless_scaling_installed">已安裝</string>
<string name="lossless_scaling_not_installed">未安裝</string> <string name="lossless_scaling_not_installed">未安裝</string>
<string name="lossless_scaling_replace">更換</string> <string name="lossless_scaling_replace">替換</string>
<string name="lossless_scaling_remove">刪除</string> <string name="lossless_scaling_remove">刪除</string>
<string name="lossless_scaling_remove_description">刪除已安裝的Lossless.dll及預先編譯的著色器</string> <string name="lossless_scaling_remove_description">刪除已安裝的 Lossless.dll 及預先編譯的著色器</string>
<string name="lossless_scaling_remove_confirmation">影格生成功能會停止運作直到您重新安裝Lossless.dll,您的Lossless.dll原始檔不會被 Eden 修改</string> <string name="lossless_scaling_remove_confirmation">影格生成功能會停止運作直到您重新安裝 Lossless.dll 。您的 Lossless.dll 原始檔並不會被 Eden 修改</string>
<string name="lossless_scaling_missing">Lossless.dll 未安裝</string> <string name="lossless_scaling_missing">Lossless.dll 未安裝</string>
<string name="lossless_scaling_missing_description">前往 設定 -&gt; Lossless Scaling 安裝以使用影格生成功能</string> <string name="lossless_scaling_missing_description">前往 設定 -&gt; Lossless Scaling 安裝以使用影格生成功能</string>
<string name="lossless_scaling_locked">請先關閉遊戲</string> <string name="lossless_scaling_locked">請先關閉遊戲</string>
<string name="lossless_scaling_locked_description">Lossless.dll無法在遊戲執行時進行更換</string> <string name="lossless_scaling_locked_description">Lossless.dll 無法在遊戲執行時進行更換</string>
<string name="lossless_scaling_remove_unavailable">沒有東西可以刪除</string> <string name="lossless_scaling_remove_unavailable">沒有東西可以刪除</string>
<string name="lossless_scaling_remove_unavailable_description">尚未安裝Lossless.dll</string> <string name="lossless_scaling_remove_unavailable_description">尚未安裝 Lossless.dll</string>
<string name="lossless_scaling_installing">準備影格生成著色器中...</string> <string name="lossless_scaling_installing">準備影格生成著色器中...</string>
<string name="lossless_scaling_install_success">成功安裝Lossless.dll</string> <string name="lossless_scaling_install_success">成功安裝 Lossless.dll</string>
<string name="lossless_scaling_install_failed">無法安裝Lossless.dll</string> <string name="lossless_scaling_install_failed">無法安裝 Lossless.dll</string>
<string name="error_lossless_copy_failed">無法複製選取的檔案</string> <string name="error_lossless_copy_failed">無法複製選取的檔案</string>
<string name="error_lossless_unreadable">無法讀取選取的檔案</string> <string name="error_lossless_unreadable">無法讀取選取的檔案</string>
<string name="error_lossless_not_pe">選取的檔案並不是Windows程式庫。請在Lossless Scaling的安裝位置(資料夾)中選擇Lossless.dll</string> <string name="error_lossless_not_pe">選取的檔案並不是 Windows 程式庫。請在 Lossless Scaling 的安裝位置(資料夾)中選擇 Lossless.dll</string>
<string name="error_lossless_missing_shaders">這個Lossless.dll的副本並未包含影格生成著色器。請更新Lossless Scaling後重試</string> <string name="error_lossless_missing_shaders">這個 Lossless.dll 的副本並未包含影格生成著色器。請更新 Lossless Scaling 後再試一次</string>
<string name="error_lossless_translation_failed">無法轉譯影格生成著色器,尚不支援此Lossless Scaling版本</string> <string name="error_lossless_translation_failed">無法轉譯影格生成著色器。尚不支援此 Lossless Scaling 版本</string>
<string name="error_lossless_cache_failed">轉譯的著色器無法寫入到儲存空間,請確認手機容量是否充足</string> <string name="error_lossless_cache_failed">轉譯的著色器無法寫入到儲存空間。請確認手機容量是否充足</string>
<string name="advanced_settings">進階設定</string> <string name="advanced_settings">進階設定</string>
<string name="settings_description">調整模擬器設定</string> <string name="settings_description">調整模擬器設定</string>
<string name="search_recently_played">最近遊玩</string> <string name="search_recently_played">最近遊玩</string>
<string name="search_recently_added">最近新增</string> <string name="search_recently_added">最近新增</string>
<string name="open_user_folder">開啟Eden資料夾</string> <string name="open_user_folder">開啟 Eden 資料夾</string>
<string name="open_user_folder_description">管理Eden的內部檔案</string> <string name="open_user_folder_description">管理 Eden 的內部檔案</string>
<string name="app_settings_description">自訂Eden的主題與介面</string> <string name="app_settings_description">自訂Eden的主題與介面</string>
<string name="no_file_manager">找不到檔案管理員</string> <string name="no_file_manager">找不到檔案管理員</string>
<string name="notification_no_directory_link">無法開啟Eden目錄</string> <string name="notification_no_directory_link">無法開啟 Eden 目錄</string>
<string name="notification_no_directory_link_description">請使用檔案管理員的側邊面板手動定位到使用者資料夾</string> <string name="notification_no_directory_link_description">請使用檔案管理員的側邊面板手動定位到使用者資料夾</string>
<string name="manage_save_data">管理儲存資料</string> <string name="manage_save_data">管理儲存資料</string>
<string name="manage_save_data_description">導入/導出遊戲的儲存資料\n壓縮檔必須為.zip格式\n壓縮檔中首個子資料夾名稱必須為遊戲ID</string> <string name="manage_save_data_description">導入/導出遊戲的儲存資料\n壓縮檔必須為.zip格式\n壓縮檔中首個子資料夾名稱必須為遊戲 ID</string>
<string name="import_save_warning">導入儲存資料</string> <string name="import_save_warning">導入儲存資料</string>
<string name="import_save_warning_description">這將會以提供的檔案覆寫現有的該遊戲儲存資料,您確定要繼續嗎?</string> <string name="import_save_warning_description">這將會以提供的檔案覆寫現有的該遊戲儲存資料,您確定要繼續嗎?</string>
<string name="save_files_importing">正在導入儲存資料…</string> <string name="save_files_importing">正在導入儲存資料…</string>
<string name="save_files_exporting">正在導出儲存資料…</string> <string name="save_files_exporting">正在導出儲存資料…</string>
<string name="save_file_imported_success">已成功導入</string> <string name="save_file_imported_success">已成功導入</string>
<string name="save_file_invalid_zip_structure">無效的儲存目錄結構</string> <string name="save_file_invalid_zip_structure">無效的儲存目錄結構</string>
<string name="save_file_invalid_zip_structure_description">首個子資料夾名稱必須為遊戲ID</string> <string name="save_file_invalid_zip_structure_description">首個子資料夾名稱必須為遊戲 ID</string>
<string name="install_firmware">安裝韌體</string> <string name="install_firmware">安裝韌體</string>
<string name="install_firmware_description">韌體必須為ZIP壓縮檔,將會用於部分遊戲的啟動</string> <string name="install_firmware_description">韌體必須為 ZIP 壓縮檔,將會用於部分遊戲的啟動</string>
<string name="firmware_installing">正在安裝韌體</string> <string name="firmware_installing">正在安裝韌體</string>
<string name="firmware_installed_failure">韌體安裝失敗</string> <string name="firmware_installed_failure">韌體安裝失敗</string>
<string name="firmware_installed_failure_description">請確保韌體nca檔案位於zip壓縮檔的根目錄後再試一次</string> <string name="firmware_installed_failure_description">請確保韌體 nca 檔案位於 zip 壓縮檔的根目錄,然後再試一次。</string>
<string name="firmware_uninstalled_failure">韌體解除安裝失敗</string> <string name="firmware_uninstalled_failure">韌體解除安裝失敗</string>
<string name="share_log">分享偵錯記錄</string> <string name="share_log">分享偵錯記錄</string>
<string name="share_log_description">分享Eden的記錄檔以便對相關問題進行偵錯</string> <string name="share_log_description">分享 Eden 的記錄檔以便對相關問題進行偵錯</string>
<string name="share_log_missing">找不到日誌檔案</string> <string name="share_log_missing">找不到日誌檔案</string>
<string name="share_gpu_log">分享GPU日誌</string> <string name="share_gpu_log">分享 GPU 日誌</string>
<string name="share_gpu_log_description">分享Eden的GPU日誌以對圖形問題進行偵錯</string> <string name="share_gpu_log_description">分享 Eden 的 GPU 日誌以對圖形問題進行偵錯</string>
<string name="share_gpu_log_missing">找不到GPU日誌檔案</string> <string name="share_gpu_log_missing">找不到 GPU 日誌檔案</string>
<string name="install_game_content">安裝遊戲內容</string> <string name="install_game_content">安裝遊戲內容</string>
<string name="install_game_content_description">安裝遊戲更新或DLC</string> <string name="install_game_content_description">安裝遊戲更新或 DLC</string>
<string name="installing_game_content">正在安裝內容…</string> <string name="installing_game_content">正在安裝內容…</string>
<string name="install_game_content_failure">安裝檔案至NAND時發生錯誤</string> <string name="install_game_content_failure">安裝檔案至 NAND 時發生錯誤</string>
<string name="install_game_content_failure_description">請確保內容有效並且prod.keys檔案已安裝</string> <string name="install_game_content_failure_description">請確保內容有效並且 prod.keys 檔案已安裝</string>
<string name="install_game_content_failure_base">為避免產生衝突,無法直接安裝遊戲本體</string> <string name="install_game_content_failure_base">為避免產生衝突,無法直接安裝遊戲本體</string>
<string name="install_game_content_failed_count">%1$d 安裝錯誤</string> <string name="install_game_content_failed_count">%1$d 安裝錯誤</string>
<string name="install_game_content_success">遊戲內容已成功安裝</string> <string name="install_game_content_success">遊戲內容已成功安裝</string>
@@ -415,8 +406,8 @@
<string name="install_game_content_success_overwrite">%1$d 覆寫成功</string> <string name="install_game_content_success_overwrite">%1$d 覆寫成功</string>
<string name="install_game_content_help_link">https://yuzu-mirror.github.io/help/quickstart/#dumping-installed-updates</string> <string name="install_game_content_help_link">https://yuzu-mirror.github.io/help/quickstart/#dumping-installed-updates</string>
<string name="custom_driver_not_supported">您的裝置不支援自訂驅動程式</string> <string name="custom_driver_not_supported">您的裝置不支援自訂驅動程式</string>
<string name="custom_driver_not_supported_description">此裝置不支援注入自訂驅動程式\n請以後再來查看是否已新增支援!</string> <string name="custom_driver_not_supported_description">此裝置不支援注入自訂驅動程式。\n請以後再來查看是否已新增支援!</string>
<string name="manage_yuzu_data">管理Eden資料</string> <string name="manage_yuzu_data">管理 Eden 資料</string>
<string name="manage_yuzu_data_description">安裝韌體、金鑰,導入/導出使用者資料及安裝其它項目!</string> <string name="manage_yuzu_data_description">安裝韌體、金鑰,導入/導出使用者資料及安裝其它項目!</string>
<string name="game_folders">遊戲資料夾</string> <string name="game_folders">遊戲資料夾</string>
<string name="deep_scan">深度掃描</string> <string name="deep_scan">深度掃描</string>
@@ -433,7 +424,7 @@
<string name="verify_installed_content">驗證已安裝內容的完整性</string> <string name="verify_installed_content">驗證已安裝內容的完整性</string>
<string name="verify_installed_content_description">檢查所有已安裝的內容是否有損壞</string> <string name="verify_installed_content_description">檢查所有已安裝的內容是否有損壞</string>
<string name="keys_missing">缺少prod.keys</string> <string name="keys_missing">缺少 prod.keys</string>
<string name="keys_missing_description">無法解密韌體和零售遊戲</string> <string name="keys_missing_description">無法解密韌體和零售遊戲</string>
<string name="keys_missing_help">https://yuzu-mirror.github.io/help/quickstart/#dumping-decryption-keys</string> <string name="keys_missing_help">https://yuzu-mirror.github.io/help/quickstart/#dumping-decryption-keys</string>
@@ -446,8 +437,8 @@
<string name="keys_failed">金鑰安裝失敗</string> <string name="keys_failed">金鑰安裝失敗</string>
<string name="keys_install_success">金鑰安裝成功</string> <string name="keys_install_success">金鑰安裝成功</string>
<string name="error_keys_copy_failed">一個或多個金鑰安裝失敗</string> <string name="error_keys_copy_failed">一個或多個金鑰安裝失敗</string>
<string name="error_keys_invalid_filename">請確保金鑰檔案具有.keys副檔名後重試</string> <string name="error_keys_invalid_filename">請確保金鑰檔案具有.keys副檔名後重試。</string>
<string name="error_keys_failed_init">金鑰初始化失敗,請檢查您的轉儲工具是否為最新版本並重新轉儲金鑰</string> <string name="error_keys_failed_init">金鑰初始化失敗。請檢查您的轉儲工具是否為最新版本並重新轉儲金鑰。</string>
<!-- Applet launcher strings --> <!-- Applet launcher strings -->
<string name="qlaunch_applet">Qlaunch</string> <string name="qlaunch_applet">Qlaunch</string>
@@ -459,48 +450,48 @@
<string name="applets_error_description"><![CDATA[請確定您的<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a>檔案和<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-system-firmware\">韌體</a>已安裝並重試]]></string> <string name="applets_error_description"><![CDATA[請確定您的<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a>檔案和<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-system-firmware\">韌體</a>已安裝並重試]]></string>
<string name="album_applet">相簿</string> <string name="album_applet">相簿</string>
<string name="album_applet_description">使用系統相片檢視器查看儲存在使用者螢幕截圖資料夾中的影像</string> <string name="album_applet_description">使用系統相片檢視器查看儲存在使用者螢幕截圖資料夾中的影像</string>
<string name="mii_edit_applet">Mii編輯</string> <string name="mii_edit_applet">Mii 編輯</string>
<string name="mii_edit_applet_description">使用系統編輯器來檢視並編輯Mii</string> <string name="mii_edit_applet_description">使用系統編輯器來檢視並編輯 Mii</string>
<string name="cabinet_applet">Cabinet</string> <string name="cabinet_applet">Cabinet</string>
<string name="cabinet_applet_description">編輯、刪除儲存在amiibo上的資料</string> <string name="cabinet_applet_description">編輯、刪除儲存在 amiibo 上的資料</string>
<string name="cabinet_launcher">Cabinet啟動器</string> <string name="cabinet_launcher">Cabinet 啟動器</string>
<string name="cabinet_nickname_and_owner">暱稱和擁有者設定</string> <string name="cabinet_nickname_and_owner">暱稱和擁有者設定</string>
<string name="cabinet_game_data_eraser">刪除遊戲資料</string> <string name="cabinet_game_data_eraser">刪除遊戲資料</string>
<string name="cabinet_restorer">還原程式</string> <string name="cabinet_restorer">還原程式</string>
<string name="cabinet_formatter">格式化程式</string> <string name="cabinet_formatter">格式化程式</string>
<!-- About screen strings --> <!-- About screen strings -->
<string name="gaia_is_not_real">Gaia不存在</string> <string name="gaia_is_not_real">Gaia 不存在</string>
<string name="copied_to_clipboard">已複製到剪貼簿</string> <string name="copied_to_clipboard">已複製到剪貼簿</string>
<string name="about_app_description">一個開放原始碼的Switch模擬器</string> <string name="about_app_description">一個開放原始碼的 Switch 模擬器</string>
<string name="contributors">參與者</string> <string name="contributors">參與者</string>
<string name="contributors_description">這些人讓Eden Android版成為可能</string> <string name="contributors_description">這些人讓 Eden Android 版成為可能</string>
<string name="licenses_description">這些專案使Eden Android版成為可能</string> <string name="licenses_description">這些專案使 Eden Android 版成為可能</string>
<string name="build">組建版本</string> <string name="build">組建版本</string>
<string name="user_data">使用者資料</string> <string name="user_data">使用者資料</string>
<string name="user_data_description">導入/導出所有應用程式資料\n\n導入使用者資料時,現有的使用者資料將被取代!\n\n直接從 Citron 導入使用者資料可能會出現問題,建議手動導入所有所需資料</string> <string name="user_data_description">導入/導出所有應用程式資料。\n\n導入使用者資料時,現有的使用者資料將被取代!\n\n直接從 Citron 導入使用者資料可能會出現問題,建議手動導入所有所需資料。</string>
<string name="exporting_user_data">正在導出使用者資料…</string> <string name="exporting_user_data">正在導出使用者資料…</string>
<string name="importing_user_data">正在導入使用者資料…</string> <string name="importing_user_data">正在導入使用者資料…</string>
<string name="invalid_yuzu_backup">無效的Eden備份</string> <string name="invalid_yuzu_backup">無效的 Eden 備份</string>
<string name="user_data_export_success">使用者資料導出成功</string> <string name="user_data_export_success">使用者資料導出成功</string>
<string name="user_data_import_success">使用者資料導入成功</string> <string name="user_data_import_success">使用者資料導入成功</string>
<string name="user_data_export_cancelled">導出已取消</string> <string name="user_data_export_cancelled">導出已取消</string>
<string name="user_data_import_failed_description">請確保使用者資料夾位於zip壓縮檔的根目錄,並在 config/config.ini 路徑中包含組態檔案後重試</string> <string name="user_data_import_failed_description">請確保使用者資料夾位於 zip 壓縮檔的根目錄,並在 config/config.ini 路徑中包含組態檔案,並再試一次</string>
<!-- General settings strings --> <!-- General settings strings -->
<string name="frame_limit_enable">限制模擬速度</string> <string name="frame_limit_enable">限制模擬速度</string>
<string name="frame_limit_enable_description">將模擬速度限制在標準速度的指定百分比</string> <string name="frame_limit_enable_description">將模擬速度限制在標準速度的指定百分比</string>
<string name="frame_limit_slider">限制速度百分比</string> <string name="frame_limit_slider">限制速度百分比</string>
<string name="frame_limit_slider_description">指定模擬速度的百分比,100%為標準速度,更高或更低的值將會減少或增加速度限制</string> <string name="frame_limit_slider_description">指定模擬速度的百分比。100% 為標準速度,更高或更低的值將會減少或增加速度限制</string>
<string name="turbo_speed_limit">加速模式</string> <string name="turbo_speed_limit">加速模式</string>
<string name="turbo_speed_limit_description">當開啟加速模式時,模擬器將以此速度執行</string> <string name="turbo_speed_limit_description">當開啟加速模式時,模擬器將以此速度執行</string>
<string name="slow_speed_limit">慢速模式</string> <string name="slow_speed_limit">慢速模式</string>
<string name="slow_speed_limit_description">當慢速模式開啟時,模擬器將會以此速度執行</string> <string name="slow_speed_limit_description">當慢速模式開啟時,模擬器將會以此速度執行</string>
<string name="cpu_backend">CPU後端</string> <string name="cpu_backend">CPU 後端</string>
<string name="cpu_accuracy">CPU準確度</string> <string name="cpu_accuracy">CPU 準確度</string>
<string name="value_with_units">%1$s%2$s</string> <string name="value_with_units">%1$s%2$s</string>
<string name="program_args">Homebrew參數</string> <string name="program_args">Homebrew 參數</string>
<string name="program_args_description">在啟動時傳遞給Homebrew的命令列參數(例如:-noglsl)</string> <string name="program_args_description">在啟動時傳遞給 Homebrew 的命令列參數(例如:-noglsl)</string>
<!-- System settings strings --> <!-- System settings strings -->
<string name="device_name">裝置名稱</string> <string name="device_name">裝置名稱</string>
@@ -508,26 +499,26 @@
<string name="use_docked_mode_description">提高解析度,降低效能。停用後將會使用手提模式,會降低解析度並提高效能</string> <string name="use_docked_mode_description">提高解析度,降低效能。停用後將會使用手提模式,會降低解析度並提高效能</string>
<string name="emulated_region">模擬區域</string> <string name="emulated_region">模擬區域</string>
<string name="emulated_language">模擬語言</string> <string name="emulated_language">模擬語言</string>
<string name="select_rtc_date">選擇RTC日期</string> <string name="select_rtc_date">選擇 RTC 日期</string>
<string name="select_rtc_time">選擇RTC時間</string> <string name="select_rtc_time">選擇 RTC 時間</string>
<string name="use_custom_rtc">自訂RTC</string> <string name="use_custom_rtc">自訂 RTC</string>
<string name="use_custom_rtc_description">允許您設定與您的目前系統時間相互獨立的自訂時間</string> <string name="use_custom_rtc_description">允許您設定與您的目前系統時間相互獨立的自訂時間</string>
<string name="set_custom_rtc">設定自訂RTC</string> <string name="set_custom_rtc">設定自訂 RTC</string>
<!-- CPU --> <!-- CPU -->
<string name="fast_cpu_time">CPU時脈</string> <string name="fast_cpu_time">CPU 時脈</string>
<string name="fast_cpu_time_description">提高模擬CPU回報的時脈,可以減少某些FPS限制。較弱的CPU可能會出現效能下降的情況,部分遊戲可能會出現異常</string> <string name="fast_cpu_time_description">提高模擬 CPU 回報的時脈,可以減少某些 FPS 限制。較弱的 CPU 可能會出現效能下降的情況,部分遊戲可能會出現異常</string>
<string name="custom_cpu_ticks">自訂CPU時脈</string> <string name="custom_cpu_ticks">自訂CPU時脈</string>
<string name="custom_cpu_ticks_description">自訂CPU時脈,更高的值可能提高效能,但也可能導致遊戲卡死。建議範圍為77-21000</string> <string name="custom_cpu_ticks_description">自訂CPU時脈。更高的值可能提高效能,但也可能導致遊戲卡死。建議範圍為77-21000。</string>
<string name="cpu_ticks">時脈</string> <string name="cpu_ticks">時脈</string>
<string name="memory_layout">記憶體布局</string> <string name="memory_layout">記憶體佈局</string>
<string name="memory_layout_description">(實驗性)更改模擬記憶體布局,此設定不會提高效能,但可能有助於使用模組來提高解析度的遊戲的載入。不要在RAM為8GB或更少的手機上使用。若遊戲崩潰請將進階設定裡偵錯選項中的CPU後端改為Dynarmic (JIT)</string> <string name="memory_layout_description">(實驗性)更改模擬記憶體佈局。此設定不會提高效能,但可能有助於使用模組來提高解析度的遊戲的載入。不要在 RAM 為 8GB 或更少的手機上使用。若遊戲崩潰請將進階設定裡偵錯選項中的CPU後端改為 Dynarmic (JIT)</string>
<string name="generate">生成</string> <string name="generate">生成</string>
<!-- Network settings strings --> <!-- Network settings strings -->
<string name="web_token">網路令牌</string> <string name="web_token">網路令牌</string>
<string name="web_token_description">用於建立公開大廳的網路令牌,由48個小寫字母a-z組成</string> <string name="web_token_description">用於建立公開大廳的網路令牌。由48個小寫字母a-z組成</string>
<string name="web_username">網路使用者名稱</string> <string name="web_username">網路使用者名稱</string>
<string name="web_username_description">多人遊戲房間中顯示的使用者名稱。必須為4-20個字元,僅能使用英文字母、數字、句點、破折號、底線和空格(標點符號須為英文格式)</string> <string name="web_username_description">多人遊戲房間中顯示的使用者名稱。必須為4-20個字元,僅能使用英文字母、數字、句點、破折號、底線和空格(標點符號須為英文格式)</string>
<string name="network">網路</string> <string name="network">網路</string>
@@ -536,19 +527,19 @@
<string name="renderer_resolution">解析度 (手提/底座)</string> <string name="renderer_resolution">解析度 (手提/底座)</string>
<string name="renderer_vsync">垂直同步</string> <string name="renderer_vsync">垂直同步</string>
<string name="renderer_scaling_filter">視窗自適應濾波器</string> <string name="renderer_scaling_filter">視窗自適應濾波器</string>
<string name="fsr_sharpness">FSR/SGSR銳化度</string> <string name="fsr_sharpness">FSR/SGSR 銳化度</string>
<string name="fsr_sharpness_description">使用FSR/SGSR時圖片的銳化程度</string> <string name="fsr_sharpness_description">使用 FSR/SGSR 時圖片的銳化程度</string>
<string name="renderer_anti_aliasing">抗鋸齒</string> <string name="renderer_anti_aliasing">抗鋸齒</string>
<string name="advanced">進階</string> <string name="advanced">進階</string>
<string name="renderer_accuracy">GPU模式</string> <string name="renderer_accuracy">GPU 模式</string>
<string name="renderer_accuracy_description">設定GPU模擬的準確度,大多數遊戲在設定為快速時即可正常渲染,但有些需要渲染粒子的遊戲仍需設為準確來避免圖形錯誤</string> <string name="renderer_accuracy_description">設定 GPU 模擬的準確度。大多數遊戲在設定為快速時即可正常渲染,但有些需要渲染粒子的遊戲仍需設為準確來避免圖形錯誤</string>
<string name="dma_accuracy">DMA準確度</string> <string name="dma_accuracy">DMA 準確度</string>
<string name="dma_accuracy_description">控制DMA準確度,將準確度設為穩定可以修復某些遊戲中的問題,但在某些情況下也可能影響效能。如果不確定,請保留為預設</string> <string name="dma_accuracy_description">控制 DMA 準確度。將準確度設為穩定可以修復某些遊戲中的問題,但在某些情況下也可能影響效能。如果不確定,請保留為預設</string>
<string name="gpu_fence_behavior">GPU 同步柵欄模式</string> <string name="gpu_fence_behavior">GPU 同步柵欄模式</string>
<string name="gpu_fence_behavior_description">控制 GPU 同步柵欄模式,即時是速度最快的選項,但可能會導致一些問題;使用平衡可以提供更好的相容性並修復某些遊戲中的錯誤;準確則是在犧牲部分效能的情況下進一步提升相容性;嚴格是最慢的選項,但可以修復那些對同步要求更嚴格的遊戲中的問題;預設則會依照 GPU 準確度設定</string> <string name="gpu_fence_behavior_description">控制 GPU 同步柵欄模式。即時是速度最快的選項,但可能會導致一些問題。使用平衡可以提供更好的相容性並修復某些遊戲中的錯誤。準確則是在犧牲部分效能的情況下進一步提升相容性。嚴格是最慢的選項,但可以修復那些對同步要求更嚴格的遊戲中的問題。預設則會依照 GPU 準確度設定</string>
<string name="anisotropic_filtering">各向異性過濾</string> <string name="anisotropic_filtering">各向異性過濾</string>
<string name="anisotropic_filtering_description">改善斜角檢視時的紋理品質</string> <string name="anisotropic_filtering_description">改善斜角檢視時的紋理品質</string>
<string name="vram_usage_mode">VRAM使用模式</string> <string name="vram_usage_mode">VRAM使用模式</string>
@@ -557,53 +548,53 @@
<string name="accelerate_astc_description">選擇ASTC壓縮紋理的解碼方式:CPU(慢速、穩定)、GPU(快速、推薦)或CPU非同步(無卡頓,可能導致問題)</string> <string name="accelerate_astc_description">選擇ASTC壓縮紋理的解碼方式:CPU(慢速、穩定)、GPU(快速、推薦)或CPU非同步(無卡頓,可能導致問題)</string>
<string name="sync_memory_operations">同步記憶體操作</string> <string name="sync_memory_operations">同步記憶體操作</string>
<string name="sync_memory_operations_description">確保計算和記憶體操作之間的資料一致性,此選項應能修復某些遊戲中的問題,但在某些情況下可能會降低效能。使用Unreal Engine 4的遊戲似乎受影響最大</string> <string name="sync_memory_operations_description">確保計算和記憶體操作之間的資料一致性。 此選項應能修復某些遊戲中的問題,但在某些情況下可能會降低效能。 使用Unreal Engine 4的遊戲似乎受影響最大</string>
<string name="use_disk_shader_cache">磁碟著色器快取</string> <string name="use_disk_shader_cache">磁碟著色器快取</string>
<string name="use_disk_shader_cache_description">將產生的著色器快取儲存至硬碟以減少中斷</string> <string name="use_disk_shader_cache_description">將產生的著色器快取儲存至硬碟以減少中斷</string>
<string name="renderer_force_max_clock">強制使用最大時脈(僅限Adreno)</string> <string name="renderer_force_max_clock">強制使用最大時脈 (僅限Adreno)</string>
<string name="renderer_force_max_clock_description">強制GPU以可能的最大時脈運作(熱溫限制仍會被套用)</string> <string name="renderer_force_max_clock_description">強制 GPU 以可能的最大時脈執行 (熱溫限制仍會被套用)</string>
<string name="renderer_asynchronous_gpu_emulation">GPU非同步模擬</string> <string name="renderer_asynchronous_gpu_emulation">GPU 非同步模擬</string>
<string name="renderer_asynchronous_gpu_emulation_description">此修改可透過使用GPU非同步模擬來提升性能,不過可能會導致圖形問題且會提高在進行時序相關操作時當機的機率</string> <string name="renderer_asynchronous_gpu_emulation_description">此修改可透過使用 GPU 非同步模擬來提升性能,不過可能會導致圖形問題且會提高在進行時序相關操作時當機的機率</string>
<string name="renderer_async_presentation">非同步呈現</string> <string name="renderer_async_presentation">非同步呈現</string>
<string name="renderer_async_presentation_description">此修改可以透過將渲染移至單獨的CPU執行緒來提升性能,但可能會導致圖形問題</string> <string name="renderer_async_presentation_description">此修改可以透過將渲染移至單獨的 CPU 執行緒來提升性能,但可能會導致圖形問題</string>
<string name="renderer_reactive_flushing">使用重新啟用排清</string> <string name="renderer_reactive_flushing">使用重新啟用排清</string>
<string name="renderer_reactive_flushing_description">犧牲效能以改善部分遊戲的轉譯準確度</string> <string name="renderer_reactive_flushing_description">犧牲效能,以改善部分遊戲的轉譯準確度</string>
<string name="enable_buffer_history">啟用緩衝區歷史</string> <string name="enable_buffer_history">啟用緩衝區歷史</string>
<string name="enable_buffer_history_description">允許存取先前的緩衝區狀態,此選項可能會改善部分遊戲的渲染品質與效能穩定性</string> <string name="enable_buffer_history_description">允許存取先前的緩衝區狀態。此選項可能會改善部分遊戲的渲染品質與效能穩定性</string>
<string name="use_optimized_vertex_buffers">最佳化頂點緩衝區</string> <string name="use_optimized_vertex_buffers">最佳化頂點緩衝區</string>
<string name="use_optimized_vertex_buffers_description">啟用最佳化的頂點緩衝區綁定,需要安裝 Mesa 26.0+ Turnip drivers/Qualcomm drivers。使用舊版 Turnip drivers 會導致當機(25.3版和更低的版本)</string> <string name="use_optimized_vertex_buffers_description">啟用最佳化的頂點緩衝區綁定。需要安裝 Mesa 26.0+ Turnip drivers/Qualcomm drivers。使用舊版 Turnip drivers 會導致當機 (25.3版和更低的版本)</string>
<string name="hacks">修改</string> <string name="hacks">修改</string>
<string name="fast_gpu_time">GPU時脈</string> <string name="fast_gpu_time">GPU 時脈</string>
<string name="fast_gpu_time_description">讓遊戲誤以為GPU工作能更快完成,避免遊戲為了配合Switch的時脈而降低解析度與渲染距離</string> <string name="fast_gpu_time_description">讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離</string>
<string name="skip_cpu_inner_invalidation">跳過CPU內部失效處理</string> <string name="skip_cpu_inner_invalidation">跳過CPU內部失效處理</string>
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些CPU端快取的失效處理,減少CPU使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string> <string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些CPU端快取的失效處理,減少CPU使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string>
<string name="fix_bloom_effects">修正光暈特效</string> <string name="fix_bloom_effects">修正光暈特效</string>
<string name="fix_bloom_effects_description">在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string> <string name="fix_bloom_effects_description">在 薩爾達傳說:織夢島 和 薩爾達傳說:智慧的再現 中 減少光暈模糊的問題並移除 橫衝直撞:狂飆樂園重製版 中的光暈效果 (Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
<string name="emulate_bgr565">模擬BGR565</string> <string name="emulate_bgr565">模擬 BGR565</string>
<string name="emulate_bgr565_description">修正遊戲中出現的色彩反轉、圖形異常或陰影異常</string> <string name="emulate_bgr565_description">修正遊戲中出現的顏色反轉、圖形異常或陰影異常</string>
<string name="rescale_hack">啟用舊版重新縮放處理</string> <string name="rescale_hack">啟用舊版重新縮放處理</string>
<string name="rescale_hack_description">透過快速重新縮放處理來啟用遊戲重新縮放設定階段的舊版處理方式</string> <string name="rescale_hack_description">透過快速重新縮放處理來啟用遊戲重新縮放設定階段的舊版處理方式</string>
<string name="renderer_asynchronous_shaders">使用非同步著色器</string> <string name="renderer_asynchronous_shaders">使用非同步著色器</string>
<string name="renderer_asynchronous_shaders_description">使用非同步編譯著色器,這可能會減少卡頓,但也可能導致圖形錯誤</string> <string name="renderer_asynchronous_shaders_description">使用非同步編譯著色器。這可能會減少卡頓,但也可能導致圖形錯誤。</string>
<string name="gpu_unswizzle_settings">GPU Unswizzle設定</string> <string name="gpu_unswizzle_settings">GPU Unswizzle 設定</string>
<string name="gpu_unswizzle_settings_description">設定基於GPU的Unswizzling參數或完全停用此功能,調整此設定以在性能與紋理載入品質中取得平衡</string> <string name="gpu_unswizzle_settings_description">設定基於 GPU 的 Unswizzling 參數或完全停用此功能。調整此設定以在性能與紋理載入品質中取得平衡</string>
<string name="gpu_unswizzle_enable">啟用GPU Unswizzle</string> <string name="gpu_unswizzle_enable">啟用 GPU Unswizzle</string>
<string name="gpu_unswizzle_disabled">停用</string> <string name="gpu_unswizzle_disabled">停用</string>
<string name="gpu_unswizzle_texture_size">GPU Unswizzle最大紋理尺寸</string> <string name="gpu_unswizzle_texture_size">GPU Unswizzle 最大紋理尺寸</string>
<string name="gpu_unswizzle_texture_size_description">設定 GPU 紋理 Unswizzling 的最大值(MB),雖然 GPU 處理中型和大型紋理的速度較快,但 CPU 處理非常小的紋理可能更有效率。調整此設定以在GPU加速與CPU負載之間取得平衡</string> <string name="gpu_unswizzle_texture_size_description">設定 GPU 紋理 Unswizzling 的最大值 (MB)。雖然 GPU 處理中型和大型紋理的速度較快,但 CPU 處理非常小的紋理可能更有效率。整此設定以在 GPU 加速與 CPU 負載之間取得平衡</string>
<string name="gpu_unswizzle_stream_size">GPU Unswizzle Stream大小</string> <string name="gpu_unswizzle_stream_size">GPU Unswizzle 流大小</string>
<string name="gpu_unswizzle_stream_size_description">設定每個影格處理大型紋理Unswizzling的資料上限,數值越高載入紋理的速度越快,但會增加畫面延遲;數值較低則能降低 GPU 負載,不過有可能導致至紋理載入不完全甚至突然出現</string> <string name="gpu_unswizzle_stream_size_description">設定每個影格處理大型紋理 Unswizzling 的資料上限。數值越高載入紋理的速度越快,但會增加畫面延遲;數值較低則能降低 GPU 負載,不過有可能導致至紋理載入不完全甚至突然出現</string>
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle Chunk大小</string> <string name="gpu_unswizzle_chunk_size">GPU Unswizzle 塊大小</string>
<string name="gpu_unswizzle_chunk_size_description">設定 3D 紋理每批次處理的深度切片數量,增加此數值可提升規格較佳GPU的處理效率,但在較低規格的硬體上可能導致卡頓或驅動程式逾時</string> <string name="gpu_unswizzle_chunk_size_description">設定 3D 紋理每批次處理的深度切片數量。增加此數值可提升規格較佳 GPU 的處理效率,但在較低規格的硬體上可能導致卡頓或驅動程式逾時</string>
<string name="gpu_unswizzle_default_button">預設</string> <string name="gpu_unswizzle_default_button">預設</string>
<string name="extensions">擴充功能</string> <string name="extensions">擴充功能</string>
<string name="dyna_state">擴展動態狀態</string> <string name="dyna_state">擴展動態狀態</string>
<string name="dyna_state_description">控制擴展動態狀態中可使用的功能數量,較高的數值可根據驅動程式支援的動態狀態減少管線編譯的次數</string> <string name="dyna_state_description">控制擴展動態狀態中可使用的功能數量。較高的數值可根據驅動程式支援的動態狀態減少管線編譯的次數。</string>
<string name="disabled">停用</string> <string name="disabled">停用</string>
<string name="vertex_input_dynamic_state">頂點輸入動態狀態</string> <string name="vertex_input_dynamic_state">頂點輸入動態狀態</string>
<string name="vertex_input_dynamic_state_description">啟用此功能可提供更彈性的頂點輸入處理方式,並可能減少頂點/緩衝區的管線編譯時間</string> <string name="vertex_input_dynamic_state_description">啟用此功能可提供更彈性的頂點輸入處理方式,並可能減少頂點/緩衝區的管線編譯時間</string>
@@ -625,43 +616,43 @@
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="clocks">時脈</string> <string name="clocks">時脈</string>
<string name="use_auto_stub">使用自動存根</string> <string name="use_auto_stub">使用自動存根</string>
<string name="use_auto_stub_description">自動補上缺少的服務和功能,可提高相容性但可能導致當機和穩定性問題</string> <string name="use_auto_stub_description">自動補上缺少的服務和功能。可提高相容性但可能導致當機和穩定性問題。</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">圖形偵錯</string> <string name="renderer_debug">圖形偵錯</string>
<string name="renderer_debug_description">將圖形API設為慢速偵錯模式</string> <string name="renderer_debug_description">將圖形 API 設為慢速偵錯模式</string>
<string name="patch_old_qcom_drivers">BCn區塊壓縮紋理修補</string> <string name="patch_old_qcom_drivers">BCn 區塊壓縮紋理修補</string>
<string name="patch_old_qcom_drivers_description">覆寫Adreno GPU的BCn紋理格式自動偵測。通常會根據Android版本自動偵測(會在API 28以上的裝置自動啟用)</string> <string name="patch_old_qcom_drivers_description">覆寫 Adreno GPU 的 BCn 紋理格式自動偵測。通常會根據 Android 版本自動偵測(會在API 28 以上自動啟用)</string>
<string name="fastmem">Fastmem</string> <string name="fastmem">Fastmem</string>
<string name="log">日誌</string> <string name="log">日誌</string>
<string name="flush_by_line">按行寫入偵錯日誌</string> <string name="flush_by_line">按行寫入偵錯日誌</string>
<string name="flush_by_line_description">在寫入一行日誌就立刻更新偵錯記錄,讓程式在當機或閃退時更容易偵錯</string> <string name="flush_by_line_description">在每行寫入時重新整理偵錯日誌,讓程式在當機或閃退時更容易偵錯。</string>
<string name="extended_logging">啟用更詳細的日誌記錄</string> <string name="extended_logging">啟用更詳細的日誌記錄</string>
<string name="extended_logging_description">將日誌檔的最大檔案限制從100MB提高到1GB</string> <string name="extended_logging_description">將日誌檔的最大檔案限制從 100MB 提高到 1GB</string>
<string name="log_filter">日誌過濾器</string> <string name="log_filter">日誌過濾器</string>
<string name="log_filter_description">控制 Eden 日誌的紀錄類別。例如: *:Info Service.LM:Debug</string> <string name="log_filter_description">控制 Eden 日誌的紀錄類別。例如: *:Info Service.LM:Debug</string>
<!-- GPU Logging strings --> <!-- GPU Logging strings -->
<string name="gpu_logging_header">GPU日誌</string> <string name="gpu_logging_header">GPU 日誌</string>
<string name="gpu_log_level">記錄層級</string> <string name="gpu_log_level">記錄層級</string>
<string name="gpu_log_level_description">GPU日誌的詳細層級(越高日誌越詳細,不過會更容易過熱)</string> <string name="gpu_log_level_description">GPU 日誌的詳細層級 (越高日誌越詳細,不過會更容易過熱)</string>
<string name="gpu_log_vulkan_calls">記錄Vulkan API呼叫</string> <string name="gpu_log_vulkan_calls">記錄 Vulkan API 呼叫</string>
<string name="gpu_log_vulkan_calls_description">在環形緩衝區中記錄所有Vulkan API呼叫</string> <string name="gpu_log_vulkan_calls_description">在環形緩衝區中記錄所有 Vulkan API 呼叫</string>
<string name="gpu_log_shader_dumps">傾印SPIR-V著色器</string> <string name="gpu_log_shader_dumps">傾印 SPIR-V 著色器</string>
<string name="gpu_log_shader_dumps_description">將重新編譯後的SPIR-V二進位檔案(.spv)儲存至Eden資料夾裡的dump資料夾中。可使用 spirv-dis/spirv-cross/spirv-val 進行檢查</string> <string name="gpu_log_shader_dumps_description">將重新編譯後的 SPIR-V 二進位檔案 (.spv) 儲存至 Eden 資料夾裡的 dump 資料夾中。可使用 spirv-dis/spirv-cross/spirv-val 進行檢查</string>
<string name="dump_guest_shaders">傾印客體(Maxwell)著色器</string> <string name="dump_guest_shaders">傾印客體(Maxwell)著色器</string>
<string name="dump_guest_shaders_description">將Maxwell客體著色器位元組碼檔案(.ash)儲存至Eden資料夾裡的dump資料夾中。可使用 nvdisasm 進行檢查</string> <string name="dump_guest_shaders_description">將 Maxwell 客體著色器位元組碼檔案 (.ash) 儲存至 Eden 資料夾裡的 dump 資料夾中。可使用 nvdisasm 進行檢查</string>
<string name="dump_macros">傾印Maxwell巨集</string> <string name="dump_macros">傾印 Maxwell 巨集</string>
<string name="dump_macros_description">將Maxwell巨集程式檔案(.macro)儲存至Eden資料夾裡的dump資料夾中。可使用 envydis 進行檢查</string> <string name="dump_macros_description">將 Maxwell 巨集程式檔案 (.macro) 儲存至 Eden 資料夾裡的 dump 資料夾中。可使用 envydis 進行檢查</string>
<string name="gpu_log_memory_tracking">追蹤GPU記憶體</string> <string name="gpu_log_memory_tracking">追蹤 GPU 記憶體</string>
<string name="gpu_log_memory_tracking_description">監控GPU記憶體的分配和釋放</string> <string name="gpu_log_memory_tracking_description">監控 GPU 記憶體的分配和釋放</string>
<string name="gpu_log_driver_debug">驅動程式偵錯資料</string> <string name="gpu_log_driver_debug">驅動程式偵錯資料</string>
<string name="gpu_log_driver_debug_description">擷取驅動程式的特定偵錯資料(例如 Turnip breadcrumbs)</string> <string name="gpu_log_driver_debug_description">擷取驅動程式的特定偵錯資料(例如 Turnip breadcrumbs)</string>
<string name="gpu_log_ring_buffer_size">環形緩衝區大小</string> <string name="gpu_log_ring_buffer_size">環形緩衝區大小</string>
<string name="gpu_log_ring_buffer_size_description">追蹤的近期Vulkan呼叫數量(預設為512)</string> <string name="gpu_log_ring_buffer_size_description">追蹤的近期 Vulkan 呼叫數量(預設為 512 )</string>
<string name="gpu_log_ring_buffer_size_hint">64至4096個項目</string> <string name="gpu_log_ring_buffer_size_hint">64 至 4096 個項目</string>
<string name="general">一般</string> <string name="general">一般</string>
@@ -685,17 +676,17 @@
<string name="left_stick">左搖桿</string> <string name="left_stick">左搖桿</string>
<string name="control_stick">控制搖桿</string> <string name="control_stick">控制搖桿</string>
<string name="right_stick">右搖桿</string> <string name="right_stick">右搖桿</string>
<string name="c_stick">C搖桿</string> <string name="c_stick">C 搖桿</string>
<string name="pressed">按壓</string> <string name="pressed">按壓</string>
<string name="range">靈敏度</string> <string name="range">靈敏度</string>
<string name="deadzone">無感帶</string> <string name="deadzone">無感帶</string>
<string name="modifier">用按鈕、按鍵來模擬搖桿</string> <string name="modifier">用按鈕、按鍵來模擬搖桿</string>
<string name="modifier_range">修改按鈕模擬左/右搖桿的值,視遊戲不同而有所差異\n(模擬左搖桿時,若將此數值設為50,則按下按鈕時遊戲裡的人物可能只會走動而不是奔跑;模擬右搖桿時所使用的值則是會影響到轉視角的速度,數值越高代表使用的模擬值越大)</string> <string name="modifier_range">修改按鈕模擬左/右搖桿的值,視遊戲不同而有所差異\n(模擬左搖桿時,若將此數值設為50,則按下按鈕時遊戲裡的人物可能只會走動而不是奔跑;模擬右搖桿時所使用的值則是會影響到轉視角的速度,數值越高代表使用的模擬值越大)</string>
<string name="triggers">肩部按鍵</string> <string name="triggers">肩部按鍵</string>
<string name="button_sl_left">左SL</string> <string name="button_sl_left">左 SL</string>
<string name="button_sr_left">左SR</string> <string name="button_sr_left">左 SR</string>
<string name="button_sl_right">右SL</string> <string name="button_sl_right">右 SL</string>
<string name="button_sr_right">右SR</string> <string name="button_sr_right">右 SR</string>
<string name="invalid">無效</string> <string name="invalid">無效</string>
<string name="not_set">無</string> <string name="not_set">無</string>
<string name="unknown">未知</string> <string name="unknown">未知</string>
@@ -710,12 +701,12 @@
<string name="auto_map_description">選擇一個控制器以嘗試自動配對按鈕、搖桿</string> <string name="auto_map_description">選擇一個控制器以嘗試自動配對按鈕、搖桿</string>
<string name="attempted_auto_map">嘗試為 %1$s 自動配對</string> <string name="attempted_auto_map">嘗試為 %1$s 自動配對</string>
<string name="controller_type">控制器類型</string> <string name="controller_type">控制器類型</string>
<string name="pro_controller">Pro手把</string> <string name="pro_controller">Pro 手把</string>
<string name="handheld">掌機模式</string> <string name="handheld">掌機模式</string>
<string name="dual_joycons">雙Joycon手把</string> <string name="dual_joycons">雙 Joycon 手把</string>
<string name="left_joycon">左Joycon手把</string> <string name="left_joycon">左 Joycon 手把</string>
<string name="right_joycon">右Joycon手把</string> <string name="right_joycon">右 Joycon 手把</string>
<string name="gamecube_controller">GameCube手把</string> <string name="gamecube_controller">GameCube 手把</string>
<string name="invert_axis">方向反轉</string> <string name="invert_axis">方向反轉</string>
<string name="invert_button">反轉按鈕</string> <string name="invert_button">反轉按鈕</string>
<string name="toggle_button">切換按鍵</string> <string name="toggle_button">切換按鍵</string>
@@ -808,7 +799,7 @@
<string name="recommended_driver">推薦驅動程式:</string> <string name="recommended_driver">推薦驅動程式:</string>
<string name="gpu_model">GPU型號</string> <string name="gpu_model">GPU型號</string>
<string name="unsupported_gpu">不支援的GPU</string> <string name="unsupported_gpu">不支援的GPU</string>
<string name="unsupported_gpu_warning">您的GPU不支援驅動程式注入,不建議嘗試設定自訂驅動程式</string> <string name="unsupported_gpu_warning">您的GPU不支援驅動程式注入。不建議嘗試設定自訂驅動程式。</string>
<!-- Preferences Screen --> <!-- Preferences Screen -->
<string name="preferences_settings">設定</string> <string name="preferences_settings">設定</string>
@@ -595,10 +595,6 @@
<string name="fast_gpu_time_description">Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch\'s clocks.</string> <string name="fast_gpu_time_description">Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch\'s clocks.</string>
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string> <string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string> <string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
<string name="nce_invalidation_gpu_readback">GPU Readback Before NCE Invalidation</string>
<string name="nce_invalidation_gpu_readback_description">Temporary. Fix Ender Magnolia (and other UE titles) crashes. May reduce performance. Improvement in progress.</string>
<string name="nce_runtime_nro_patch">Patch Runtime NROs for NCE</string>
<string name="nce_runtime_nro_patch_description">Temporary. Fix Biomutant boot. May impact performance. Improvement in progress.</string>
<string name="fix_bloom_effects">Fix Bloom Effects</string> <string name="fix_bloom_effects">Fix Bloom Effects</string>
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string> <string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
<string name="emulate_bgr565">Emulate BGR565</string> <string name="emulate_bgr565">Emulate BGR565</string>
-1
View File
@@ -62,7 +62,6 @@ add_library(
fs/fs_util.h fs/fs_util.h
fs/path_util.cpp fs/path_util.cpp
fs/path_util.h fs/path_util.h
hash.h
heap_tracker.cpp heap_tracker.cpp
heap_tracker.h heap_tracker.h
hex_util.cpp hex_util.cpp
+252 -251
View File
@@ -12,93 +12,94 @@
#include "common/android/multiplayer/multiplayer.h" #include "common/android/multiplayer/multiplayer.h"
#include <network/network.h> #include <network/network.h>
static struct {
JavaVM *java_vm;
jclass native_library_class;
jclass disk_cache_progress_class;
jclass load_callback_stage_class;
jclass game_dir_class;
jmethodID game_dir_constructor;
jmethodID exit_emulation_activity;
jmethodID disk_cache_load_progress;
jmethodID on_emulation_started;
jmethodID on_emulation_stopped;
jmethodID on_program_changed;
jmethodID copy_to_storage;
jmethodID file_exists;
jmethodID file_extension;
static JavaVM *s_java_vm; jclass game_class;
static jclass s_native_library_class; jmethodID game_constructor;
static jclass s_disk_cache_progress_class; jfieldID game_title_field;
static jclass s_load_callback_stage_class; jfieldID game_path_field;
static jclass s_game_dir_class; jfieldID game_program_id_field;
static jmethodID s_game_dir_constructor; jfieldID game_developer_field;
static jmethodID s_exit_emulation_activity; jfieldID game_version_field;
static jmethodID s_disk_cache_load_progress; jfieldID game_is_homebrew_field;
static jmethodID s_on_emulation_started;
static jmethodID s_on_emulation_stopped;
static jmethodID s_on_program_changed;
static jmethodID s_copy_to_storage;
static jmethodID s_file_exists;
static jmethodID s_file_extension;
static jclass s_game_class; jclass string_class;
static jmethodID s_game_constructor; jclass pair_class;
static jfieldID s_game_title_field; jmethodID pair_constructor;
static jfieldID s_game_path_field; jfieldID pair_first_field;
static jfieldID s_game_program_id_field; jfieldID pair_second_field;
static jfieldID s_game_developer_field;
static jfieldID s_game_version_field;
static jfieldID s_game_is_homebrew_field;
static jclass s_string_class; jclass overlay_control_data_class;
static jclass s_pair_class; jmethodID overlay_control_data_constructor;
static jmethodID s_pair_constructor; jfieldID overlay_control_data_id_field;
static jfieldID s_pair_first_field; jfieldID overlay_control_data_enabled_field;
static jfieldID s_pair_second_field; jfieldID overlay_control_data_individual_scale_field;
jfieldID overlay_control_data_landscape_position_field;
jfieldID overlay_control_data_portrait_position_field;
jfieldID overlay_control_data_foldable_position_field;
static jclass s_overlay_control_data_class; jclass patch_class;
static jmethodID s_overlay_control_data_constructor; jmethodID patch_constructor;
static jfieldID s_overlay_control_data_id_field; jfieldID patch_enabled_field;
static jfieldID s_overlay_control_data_enabled_field; jfieldID patch_name_field;
static jfieldID s_overlay_control_data_individual_scale_field; jfieldID patch_version_field;
static jfieldID s_overlay_control_data_landscape_position_field; jfieldID patch_type_field;
static jfieldID s_overlay_control_data_portrait_position_field; jfieldID patch_program_id_field;
static jfieldID s_overlay_control_data_foldable_position_field; jfieldID patch_title_id_field;
static jclass s_patch_class; jclass double_class;
static jmethodID s_patch_constructor; jmethodID double_constructor;
static jfieldID s_patch_enabled_field; jmethodID double_value_method;
static jfieldID s_patch_name_field;
static jfieldID s_patch_version_field;
static jfieldID s_patch_type_field;
static jfieldID s_patch_program_id_field;
static jfieldID s_patch_title_id_field;
static jclass s_double_class; jclass integer_class;
static jmethodID s_double_constructor; jmethodID integer_constructor;
static jmethodID s_double_value_method; jmethodID integer_value_method;
static jclass s_integer_class; jclass boolean_class;
static jmethodID s_integer_constructor; jmethodID boolean_constructor;
static jmethodID s_integer_value_method; jmethodID boolean_value_method;
static jclass s_boolean_class; jclass player_input_class;
static jmethodID s_boolean_constructor; jmethodID player_input_constructor;
static jmethodID s_boolean_value_method; jfieldID player_input_connected_field;
jfieldID player_input_buttons_field;
jfieldID player_input_analogs_field;
jfieldID player_input_motions_field;
jfieldID player_input_vibration_enabled_field;
jfieldID player_input_vibration_strength_field;
jfieldID player_input_body_color_left_field;
jfieldID player_input_body_color_right_field;
jfieldID player_input_button_color_left_field;
jfieldID player_input_button_color_right_field;
jfieldID player_input_profile_name_field;
jfieldID player_input_use_system_vibrator_field;
static jclass s_player_input_class; jclass yuzu_input_device_interface;
static jmethodID s_player_input_constructor; jmethodID yuzu_input_device_get_name;
static jfieldID s_player_input_connected_field; jmethodID yuzu_input_device_get_guid;
static jfieldID s_player_input_buttons_field; jmethodID yuzu_input_device_get_port;
static jfieldID s_player_input_analogs_field; jmethodID yuzu_input_device_get_supports_vibration;
static jfieldID s_player_input_motions_field; jmethodID yuzu_input_device_vibrate;
static jfieldID s_player_input_vibration_enabled_field; jmethodID yuzu_input_device_get_axes;
static jfieldID s_player_input_vibration_strength_field; jmethodID yuzu_input_device_has_keys;
static jfieldID s_player_input_body_color_left_field;
static jfieldID s_player_input_body_color_right_field;
static jfieldID s_player_input_button_color_left_field;
static jfieldID s_player_input_button_color_right_field;
static jfieldID s_player_input_profile_name_field;
static jfieldID s_player_input_use_system_vibrator_field;
static jclass s_yuzu_input_device_interface; jmethodID add_netplay_message;
static jmethodID s_yuzu_input_device_get_name; jmethodID clear_chat;
static jmethodID s_yuzu_input_device_get_guid; } state;
static jmethodID s_yuzu_input_device_get_port;
static jmethodID s_yuzu_input_device_get_supports_vibration;
static jmethodID s_yuzu_input_device_vibrate;
static jmethodID s_yuzu_input_device_get_axes;
static jmethodID s_yuzu_input_device_has_keys;
static jmethodID s_add_netplay_message;
static jmethodID s_clear_chat;
static constexpr jint JNI_VERSION = JNI_VERSION_1_6; static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
@@ -106,14 +107,14 @@ namespace Common::Android {
JNIEnv *GetEnvForThread() { JNIEnv *GetEnvForThread() {
thread_local static struct OwnedEnv { thread_local static struct OwnedEnv {
OwnedEnv() { OwnedEnv() {
status = s_java_vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6); status = state.java_vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (status == JNI_EDETACHED) if (status == JNI_EDETACHED)
s_java_vm->AttachCurrentThread(&env, nullptr); state.java_vm->AttachCurrentThread(&env, nullptr);
} }
~OwnedEnv() { ~OwnedEnv() {
if (status == JNI_EDETACHED) if (status == JNI_EDETACHED)
s_java_vm->DetachCurrentThread(); state.java_vm->DetachCurrentThread();
} }
int status; int status;
@@ -123,303 +124,303 @@ namespace Common::Android {
} }
jclass GetNativeLibraryClass() { jclass GetNativeLibraryClass() {
return s_native_library_class; return state.native_library_class;
} }
jclass GetDiskCacheProgressClass() { jclass GetDiskCacheProgressClass() {
return s_disk_cache_progress_class; return state.disk_cache_progress_class;
} }
jclass GetDiskCacheLoadCallbackStageClass() { jclass GetDiskCacheLoadCallbackStageClass() {
return s_load_callback_stage_class; return state.load_callback_stage_class;
} }
jclass GetGameDirClass() { jclass GetGameDirClass() {
return s_game_dir_class; return state.game_dir_class;
} }
jmethodID GetGameDirConstructor() { jmethodID GetGameDirConstructor() {
return s_game_dir_constructor; return state.game_dir_constructor;
} }
jmethodID GetExitEmulationActivity() { jmethodID GetExitEmulationActivity() {
return s_exit_emulation_activity; return state.exit_emulation_activity;
} }
jmethodID GetDiskCacheLoadProgress() { jmethodID GetDiskCacheLoadProgress() {
return s_disk_cache_load_progress; return state.disk_cache_load_progress;
} }
jmethodID GetCopyToStorage() { jmethodID GetCopyToStorage() {
return s_copy_to_storage; return state.copy_to_storage;
} }
jmethodID GetFileExists() { jmethodID GetFileExists() {
return s_file_exists; return state.file_exists;
} }
jmethodID GetFileExtension() { jmethodID GetFileExtension() {
return s_file_extension; return state.file_extension;
} }
jmethodID GetOnEmulationStarted() { jmethodID GetOnEmulationStarted() {
return s_on_emulation_started; return state.on_emulation_started;
} }
jmethodID GetOnEmulationStopped() { jmethodID GetOnEmulationStopped() {
return s_on_emulation_stopped; return state.on_emulation_stopped;
} }
jmethodID GetOnProgramChanged() { jmethodID GetOnProgramChanged() {
return s_on_program_changed; return state.on_program_changed;
} }
jclass GetGameClass() { jclass GetGameClass() {
return s_game_class; return state.game_class;
} }
jmethodID GetGameConstructor() { jmethodID GetGameConstructor() {
return s_game_constructor; return state.game_constructor;
} }
jfieldID GetGameTitleField() { jfieldID GetGameTitleField() {
return s_game_title_field; return state.game_title_field;
} }
jfieldID GetGamePathField() { jfieldID GetGamePathField() {
return s_game_path_field; return state.game_path_field;
} }
jfieldID GetGameProgramIdField() { jfieldID GetGameProgramIdField() {
return s_game_program_id_field; return state.game_program_id_field;
} }
jfieldID GetGameDeveloperField() { jfieldID GetGameDeveloperField() {
return s_game_developer_field; return state.game_developer_field;
} }
jfieldID GetGameVersionField() { jfieldID GetGameVersionField() {
return s_game_version_field; return state.game_version_field;
} }
jfieldID GetGameIsHomebrewField() { jfieldID GetGameIsHomebrewField() {
return s_game_is_homebrew_field; return state.game_is_homebrew_field;
} }
jclass GetStringClass() { jclass GetStringClass() {
return s_string_class; return state.string_class;
} }
jclass GetPairClass() { jclass GetPairClass() {
return s_pair_class; return state.pair_class;
} }
jmethodID GetPairConstructor() { jmethodID GetPairConstructor() {
return s_pair_constructor; return state.pair_constructor;
} }
jfieldID GetPairFirstField() { jfieldID GetPairFirstField() {
return s_pair_first_field; return state.pair_first_field;
} }
jfieldID GetPairSecondField() { jfieldID GetPairSecondField() {
return s_pair_second_field; return state.pair_second_field;
} }
jclass GetOverlayControlDataClass() { jclass GetOverlayControlDataClass() {
return s_overlay_control_data_class; return state.overlay_control_data_class;
} }
jmethodID GetOverlayControlDataConstructor() { jmethodID GetOverlayControlDataConstructor() {
return s_overlay_control_data_constructor; return state.overlay_control_data_constructor;
} }
jfieldID GetOverlayControlDataIdField() { jfieldID GetOverlayControlDataIdField() {
return s_overlay_control_data_id_field; return state.overlay_control_data_id_field;
} }
jfieldID GetOverlayControlDataEnabledField() { jfieldID GetOverlayControlDataEnabledField() {
return s_overlay_control_data_enabled_field; return state.overlay_control_data_enabled_field;
} }
jfieldID GetOverlayControlDataIndividualScaleField() { jfieldID GetOverlayControlDataIndividualScaleField() {
return s_overlay_control_data_individual_scale_field; return state.overlay_control_data_individual_scale_field;
} }
jfieldID GetOverlayControlDataLandscapePositionField() { jfieldID GetOverlayControlDataLandscapePositionField() {
return s_overlay_control_data_landscape_position_field; return state.overlay_control_data_landscape_position_field;
} }
jfieldID GetOverlayControlDataPortraitPositionField() { jfieldID GetOverlayControlDataPortraitPositionField() {
return s_overlay_control_data_portrait_position_field; return state.overlay_control_data_portrait_position_field;
} }
jfieldID GetOverlayControlDataFoldablePositionField() { jfieldID GetOverlayControlDataFoldablePositionField() {
return s_overlay_control_data_foldable_position_field; return state.overlay_control_data_foldable_position_field;
} }
jclass GetPatchClass() { jclass GetPatchClass() {
return s_patch_class; return state.patch_class;
} }
jmethodID GetPatchConstructor() { jmethodID GetPatchConstructor() {
return s_patch_constructor; return state.patch_constructor;
} }
jfieldID GetPatchEnabledField() { jfieldID GetPatchEnabledField() {
return s_patch_enabled_field; return state.patch_enabled_field;
} }
jfieldID GetPatchNameField() { jfieldID GetPatchNameField() {
return s_patch_name_field; return state.patch_name_field;
} }
jfieldID GetPatchVersionField() { jfieldID GetPatchVersionField() {
return s_patch_version_field; return state.patch_version_field;
} }
jfieldID GetPatchTypeField() { jfieldID GetPatchTypeField() {
return s_patch_type_field; return state.patch_type_field;
} }
jfieldID GetPatchProgramIdField() { jfieldID GetPatchProgramIdField() {
return s_patch_program_id_field; return state.patch_program_id_field;
} }
jfieldID GetPatchTitleIdField() { jfieldID GetPatchTitleIdField() {
return s_patch_title_id_field; return state.patch_title_id_field;
} }
jclass GetDoubleClass() { jclass GetDoubleClass() {
return s_double_class; return state.double_class;
} }
jmethodID GetDoubleConstructor() { jmethodID GetDoubleConstructor() {
return s_double_constructor; return state.double_constructor;
} }
jmethodID GetDoubleValueMethod() { jmethodID GetDoubleValueMethod() {
return s_double_value_method; return state.double_value_method;
} }
jclass GetIntegerClass() { jclass GetIntegerClass() {
return s_integer_class; return state.integer_class;
} }
jmethodID GetIntegerConstructor() { jmethodID GetIntegerConstructor() {
return s_integer_constructor; return state.integer_constructor;
} }
jmethodID GetIntegerValueMethod() { jmethodID GetIntegerValueMethod() {
return s_integer_value_method; return state.integer_value_method;
} }
jclass GetBooleanClass() { jclass GetBooleanClass() {
return s_boolean_class; return state.boolean_class;
} }
jmethodID GetBooleanConstructor() { jmethodID GetBooleanConstructor() {
return s_boolean_constructor; return state.boolean_constructor;
} }
jmethodID GetBooleanValueMethod() { jmethodID GetBooleanValueMethod() {
return s_boolean_value_method; return state.boolean_value_method;
} }
jclass GetPlayerInputClass() { jclass GetPlayerInputClass() {
return s_player_input_class; return state.player_input_class;
} }
jmethodID GetPlayerInputConstructor() { jmethodID GetPlayerInputConstructor() {
return s_player_input_constructor; return state.player_input_constructor;
} }
jfieldID GetPlayerInputConnectedField() { jfieldID GetPlayerInputConnectedField() {
return s_player_input_connected_field; return state.player_input_connected_field;
} }
jfieldID GetPlayerInputButtonsField() { jfieldID GetPlayerInputButtonsField() {
return s_player_input_buttons_field; return state.player_input_buttons_field;
} }
jfieldID GetPlayerInputAnalogsField() { jfieldID GetPlayerInputAnalogsField() {
return s_player_input_analogs_field; return state.player_input_analogs_field;
} }
jfieldID GetPlayerInputMotionsField() { jfieldID GetPlayerInputMotionsField() {
return s_player_input_motions_field; return state.player_input_motions_field;
} }
jfieldID GetPlayerInputVibrationEnabledField() { jfieldID GetPlayerInputVibrationEnabledField() {
return s_player_input_vibration_enabled_field; return state.player_input_vibration_enabled_field;
} }
jfieldID GetPlayerInputVibrationStrengthField() { jfieldID GetPlayerInputVibrationStrengthField() {
return s_player_input_vibration_strength_field; return state.player_input_vibration_strength_field;
} }
jfieldID GetPlayerInputBodyColorLeftField() { jfieldID GetPlayerInputBodyColorLeftField() {
return s_player_input_body_color_left_field; return state.player_input_body_color_left_field;
} }
jfieldID GetPlayerInputBodyColorRightField() { jfieldID GetPlayerInputBodyColorRightField() {
return s_player_input_body_color_right_field; return state.player_input_body_color_right_field;
} }
jfieldID GetPlayerInputButtonColorLeftField() { jfieldID GetPlayerInputButtonColorLeftField() {
return s_player_input_button_color_left_field; return state.player_input_button_color_left_field;
} }
jfieldID GetPlayerInputButtonColorRightField() { jfieldID GetPlayerInputButtonColorRightField() {
return s_player_input_button_color_right_field; return state.player_input_button_color_right_field;
} }
jfieldID GetPlayerInputProfileNameField() { jfieldID GetPlayerInputProfileNameField() {
return s_player_input_profile_name_field; return state.player_input_profile_name_field;
} }
jfieldID GetPlayerInputUseSystemVibratorField() { jfieldID GetPlayerInputUseSystemVibratorField() {
return s_player_input_use_system_vibrator_field; return state.player_input_use_system_vibrator_field;
} }
jclass GetYuzuInputDeviceInterface() { jclass GetYuzuInputDeviceInterface() {
return s_yuzu_input_device_interface; return state.yuzu_input_device_interface;
} }
jmethodID GetYuzuDeviceGetName() { jmethodID GetYuzuDeviceGetName() {
return s_yuzu_input_device_get_name; return state.yuzu_input_device_get_name;
} }
jmethodID GetYuzuDeviceGetGUID() { jmethodID GetYuzuDeviceGetGUID() {
return s_yuzu_input_device_get_guid; return state.yuzu_input_device_get_guid;
} }
jmethodID GetYuzuDeviceGetPort() { jmethodID GetYuzuDeviceGetPort() {
return s_yuzu_input_device_get_port; return state.yuzu_input_device_get_port;
} }
jmethodID GetYuzuDeviceGetSupportsVibration() { jmethodID GetYuzuDeviceGetSupportsVibration() {
return s_yuzu_input_device_get_supports_vibration; return state.yuzu_input_device_get_supports_vibration;
} }
jmethodID GetYuzuDeviceVibrate() { jmethodID GetYuzuDeviceVibrate() {
return s_yuzu_input_device_vibrate; return state.yuzu_input_device_vibrate;
} }
jmethodID GetYuzuDeviceGetAxes() { jmethodID GetYuzuDeviceGetAxes() {
return s_yuzu_input_device_get_axes; return state.yuzu_input_device_get_axes;
} }
jmethodID GetYuzuDeviceHasKeys() { jmethodID GetYuzuDeviceHasKeys() {
return s_yuzu_input_device_has_keys; return state.yuzu_input_device_has_keys;
} }
jmethodID GetAddNetPlayMessage() { jmethodID GetAddNetPlayMessage() {
return s_add_netplay_message; return state.add_netplay_message;
} }
jmethodID ClearChat() { jmethodID ClearChat() {
return s_clear_chat; return state.clear_chat;
} }
#ifdef __cplusplus #ifdef __cplusplus
@@ -436,20 +437,20 @@ namespace Common::Android {
// UnInitialize Android Storage // UnInitialize Android Storage
Common::FS::Android::UnRegisterCallbacks(); Common::FS::Android::UnRegisterCallbacks();
env->DeleteGlobalRef(s_native_library_class); env->DeleteGlobalRef(state.native_library_class);
env->DeleteGlobalRef(s_disk_cache_progress_class); env->DeleteGlobalRef(state.disk_cache_progress_class);
env->DeleteGlobalRef(s_load_callback_stage_class); env->DeleteGlobalRef(state.load_callback_stage_class);
env->DeleteGlobalRef(s_game_dir_class); env->DeleteGlobalRef(state.game_dir_class);
env->DeleteGlobalRef(s_game_class); env->DeleteGlobalRef(state.game_class);
env->DeleteGlobalRef(s_string_class); env->DeleteGlobalRef(state.string_class);
env->DeleteGlobalRef(s_pair_class); env->DeleteGlobalRef(state.pair_class);
env->DeleteGlobalRef(s_overlay_control_data_class); env->DeleteGlobalRef(state.overlay_control_data_class);
env->DeleteGlobalRef(s_patch_class); env->DeleteGlobalRef(state.patch_class);
env->DeleteGlobalRef(s_double_class); env->DeleteGlobalRef(state.double_class);
env->DeleteGlobalRef(s_integer_class); env->DeleteGlobalRef(state.integer_class);
env->DeleteGlobalRef(s_boolean_class); env->DeleteGlobalRef(state.boolean_class);
env->DeleteGlobalRef(s_player_input_class); env->DeleteGlobalRef(state.player_input_class);
env->DeleteGlobalRef(s_yuzu_input_device_interface); env->DeleteGlobalRef(state.yuzu_input_device_interface);
// UnInitialize applets // UnInitialize applets
SoftwareKeyboard::CleanupJNI(env); SoftwareKeyboard::CleanupJNI(env);
@@ -463,7 +464,7 @@ namespace Common::Android {
#endif #endif
void Initialize(JavaVM* vm, JNIEnv *env) { void Initialize(JavaVM* vm, JNIEnv *env) {
s_java_vm = vm; state.java_vm = vm;
InitFFmpegOnLoad(vm); InitFFmpegOnLoad(vm);
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
@@ -472,169 +473,169 @@ void Initialize(JavaVM* vm, JNIEnv *env) {
// Initialize Java classes // Initialize Java classes
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary"); const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class)); state.native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef( state.disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress"))); env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass( state.load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage"))); "org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir"); const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class)); state.game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>", state.game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
"(Ljava/lang/String;Z)V"); "(Ljava/lang/String;Z)V");
env->DeleteLocalRef(game_dir_class); env->DeleteLocalRef(game_dir_class);
// Initialize methods // Initialize methods
s_exit_emulation_activity = state.exit_emulation_activity =
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); env->GetStaticMethodID(state.native_library_class, "exitEmulationActivity", "(I)V");
s_disk_cache_load_progress = state.disk_cache_load_progress =
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V"); env->GetStaticMethodID(state.disk_cache_progress_class, "loadProgress", "(III)V");
s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage", state.copy_to_storage = env->GetStaticMethodID(state.native_library_class, "copyFileToStorage",
"(Ljava/lang/String;Ljava/lang/String;)Z"); "(Ljava/lang/String;Ljava/lang/String;)Z");
s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists", state.file_exists = env->GetStaticMethodID(state.native_library_class, "exists",
"(Ljava/lang/String;)Z"); "(Ljava/lang/String;)Z");
s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension", state.file_extension = env->GetStaticMethodID(state.native_library_class, "getFileExtension",
"(Ljava/lang/String;)Ljava/lang/String;"); "(Ljava/lang/String;)Ljava/lang/String;");
s_on_emulation_started = state.on_emulation_started =
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V"); env->GetStaticMethodID(state.native_library_class, "onEmulationStarted", "()V");
s_on_emulation_stopped = state.on_emulation_stopped =
env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V"); env->GetStaticMethodID(state.native_library_class, "onEmulationStopped", "(I)V");
s_on_program_changed = state.on_program_changed =
env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V"); env->GetStaticMethodID(state.native_library_class, "onProgramChanged", "(I)V");
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game"); const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class)); state.game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
s_game_constructor = env->GetMethodID(game_class, "<init>", state.game_constructor = env->GetMethodID(game_class, "<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/" "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
"String;Ljava/lang/String;Ljava/lang/String;Z)V"); "String;Ljava/lang/String;Ljava/lang/String;Z)V");
s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;"); state.game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;"); state.game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;"); state.game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;"); state.game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;"); state.game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z"); state.game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
env->DeleteLocalRef(game_class); env->DeleteLocalRef(game_class);
const jclass string_class = env->FindClass("java/lang/String"); const jclass string_class = env->FindClass("java/lang/String");
s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class)); state.string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
env->DeleteLocalRef(string_class); env->DeleteLocalRef(string_class);
const jclass pair_class = env->FindClass("kotlin/Pair"); const jclass pair_class = env->FindClass("kotlin/Pair");
s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class)); state.pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
s_pair_constructor = state.pair_constructor =
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V"); env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;"); state.pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;"); state.pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
env->DeleteLocalRef(pair_class); env->DeleteLocalRef(pair_class);
const jclass overlay_control_data_class = const jclass overlay_control_data_class =
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData"); env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
s_overlay_control_data_class = state.overlay_control_data_class =
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class)); reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
s_overlay_control_data_constructor = state.overlay_control_data_constructor =
env->GetMethodID(overlay_control_data_class, "<init>", env->GetMethodID(overlay_control_data_class, "<init>",
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V"); "(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
s_overlay_control_data_id_field = state.overlay_control_data_id_field =
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;"); env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
s_overlay_control_data_enabled_field = state.overlay_control_data_enabled_field =
env->GetFieldID(overlay_control_data_class, "enabled", "Z"); env->GetFieldID(overlay_control_data_class, "enabled", "Z");
s_overlay_control_data_landscape_position_field = state.overlay_control_data_landscape_position_field =
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;"); env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
s_overlay_control_data_portrait_position_field = state.overlay_control_data_portrait_position_field =
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;"); env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
s_overlay_control_data_foldable_position_field = state.overlay_control_data_foldable_position_field =
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;"); env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
s_overlay_control_data_individual_scale_field = state.overlay_control_data_individual_scale_field =
env->GetFieldID(overlay_control_data_class, "individualScale", "F"); env->GetFieldID(overlay_control_data_class, "individualScale", "F");
env->DeleteLocalRef(overlay_control_data_class); env->DeleteLocalRef(overlay_control_data_class);
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch"); const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class)); state.patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
s_patch_constructor = env->GetMethodID( state.patch_constructor = env->GetMethodID(
patch_class, "<init>", patch_class, "<init>",
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V"); "(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z"); state.patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;"); state.patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;"); state.patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
s_patch_type_field = env->GetFieldID(patch_class, "type", "I"); state.patch_type_field = env->GetFieldID(patch_class, "type", "I");
s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;"); state.patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;"); state.patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
env->DeleteLocalRef(patch_class); env->DeleteLocalRef(patch_class);
const jclass double_class = env->FindClass("java/lang/Double"); const jclass double_class = env->FindClass("java/lang/Double");
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class)); state.double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V"); state.double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
s_double_value_method = env->GetMethodID(double_class, "doubleValue", "()D"); state.double_value_method = env->GetMethodID(double_class, "doubleValue", "()D");
env->DeleteLocalRef(double_class); env->DeleteLocalRef(double_class);
const jclass int_class = env->FindClass("java/lang/Integer"); const jclass int_class = env->FindClass("java/lang/Integer");
s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class)); state.integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V"); state.integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
s_integer_value_method = env->GetMethodID(int_class, "intValue", "()I"); state.integer_value_method = env->GetMethodID(int_class, "intValue", "()I");
env->DeleteLocalRef(int_class); env->DeleteLocalRef(int_class);
const jclass boolean_class = env->FindClass("java/lang/Boolean"); const jclass boolean_class = env->FindClass("java/lang/Boolean");
s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class)); state.boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V"); state.boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
s_boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z"); state.boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z");
env->DeleteLocalRef(boolean_class); env->DeleteLocalRef(boolean_class);
const jclass player_input_class = const jclass player_input_class =
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput"); env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class)); state.player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
s_player_input_constructor = env->GetMethodID( state.player_input_constructor = env->GetMethodID(
player_input_class, "<init>", player_input_class, "<init>",
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V"); "(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z"); state.player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
s_player_input_buttons_field = state.player_input_buttons_field =
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;"); env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
s_player_input_analogs_field = state.player_input_analogs_field =
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;"); env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
s_player_input_motions_field = state.player_input_motions_field =
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;"); env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
s_player_input_vibration_enabled_field = state.player_input_vibration_enabled_field =
env->GetFieldID(player_input_class, "vibrationEnabled", "Z"); env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
s_player_input_vibration_strength_field = state.player_input_vibration_strength_field =
env->GetFieldID(player_input_class, "vibrationStrength", "I"); env->GetFieldID(player_input_class, "vibrationStrength", "I");
s_player_input_body_color_left_field = state.player_input_body_color_left_field =
env->GetFieldID(player_input_class, "bodyColorLeft", "J"); env->GetFieldID(player_input_class, "bodyColorLeft", "J");
s_player_input_body_color_right_field = state.player_input_body_color_right_field =
env->GetFieldID(player_input_class, "bodyColorRight", "J"); env->GetFieldID(player_input_class, "bodyColorRight", "J");
s_player_input_button_color_left_field = state.player_input_button_color_left_field =
env->GetFieldID(player_input_class, "buttonColorLeft", "J"); env->GetFieldID(player_input_class, "buttonColorLeft", "J");
s_player_input_button_color_right_field = state.player_input_button_color_right_field =
env->GetFieldID(player_input_class, "buttonColorRight", "J"); env->GetFieldID(player_input_class, "buttonColorRight", "J");
s_player_input_profile_name_field = state.player_input_profile_name_field =
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;"); env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
s_player_input_use_system_vibrator_field = state.player_input_use_system_vibrator_field =
env->GetFieldID(player_input_class, "useSystemVibrator", "Z"); env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
env->DeleteLocalRef(player_input_class); env->DeleteLocalRef(player_input_class);
const jclass yuzu_input_device_interface = const jclass yuzu_input_device_interface =
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice"); env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
s_yuzu_input_device_interface = state.yuzu_input_device_interface =
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface)); reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
s_yuzu_input_device_get_name = state.yuzu_input_device_get_name =
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;"); env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
s_yuzu_input_device_get_guid = state.yuzu_input_device_get_guid =
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;"); env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort", state.yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
"()I"); "()I");
s_yuzu_input_device_get_supports_vibration = state.yuzu_input_device_get_supports_vibration =
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z"); env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate", state.yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
"(F)V"); "(F)V");
s_yuzu_input_device_get_axes = state.yuzu_input_device_get_axes =
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;"); env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
s_yuzu_input_device_has_keys = state.yuzu_input_device_has_keys =
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z"); env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
env->DeleteLocalRef(yuzu_input_device_interface); env->DeleteLocalRef(yuzu_input_device_interface);
s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage", state.add_netplay_message = env->GetStaticMethodID(state.native_library_class, "addNetPlayMessage",
"(ILjava/lang/String;)V"); "(ILjava/lang/String;)V");
s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V"); state.clear_chat = env->GetStaticMethodID(state.native_library_class, "clearChat", "()V");
// Initialize Android Storage // Initialize Android Storage
Common::FS::Android::RegisterCallbacks(env, s_native_library_class); Common::FS::Android::RegisterCallbacks(env, state.native_library_class);
// Initialize applets // Initialize applets
Common::Android::SoftwareKeyboard::InitJNI(env); Common::Android::SoftwareKeyboard::InitJNI(env);
+4 -18
View File
@@ -22,36 +22,22 @@ template <typename T>
return std::size_t(sizeof(T) * CHAR_BIT); return std::size_t(sizeof(T) * CHAR_BIT);
} }
template<typename T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr u32 MostSignificantBit(const T value) {
return u32(sizeof(T) * CHAR_BIT - 1 - std::countl_zero(value));
}
template<typename T> template<typename T>
requires std::is_integral_v<T> requires std::is_integral_v<T>
[[nodiscard]] constexpr T Log2Floor(const T value) { [[nodiscard]] constexpr T Log2Floor(const T value) {
return T(MostSignificantBit<T>(value)); return std::bit_width(value) - 1;
} }
template<typename T> template<typename T>
requires std::is_integral_v<T> requires std::is_integral_v<T>
[[nodiscard]] constexpr T Log2Ceil(const T value) { [[nodiscard]] constexpr T Log2Ceil(const T value) {
const T log2_f = Log2Floor<T>(value); return std::bit_width(value - 1);
return T(log2_f + T((value ^ (T(1ULL) << log2_f)) != T(0ULL)));
}
template <typename T>
requires std::is_integral_v<T>
[[nodiscard]] T NextPow2(T value) {
return T(1ULL << (sizeof(T) * CHAR_BIT - std::countl_zero(value - 1U)));
} }
template <size_t bit_index, typename T> template <size_t bit_index, typename T>
requires std::is_integral_v<T> requires (std::is_integral_v<T> && bit_index < BitSize<T>())
[[nodiscard]] constexpr bool Bit(const T value) { [[nodiscard]] constexpr bool Bit(const T value) {
static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T"); return (T(value >> bit_index) & T(1)) == T(1);
return ((value >> bit_index) & T(1)) == T(1);
} }
} // namespace Common } // namespace Common
+5 -13
View File
@@ -25,26 +25,18 @@ template <typename T>
requires std::is_unsigned_v<T> requires std::is_unsigned_v<T>
inline std::size_t HashValue(T val) { inline std::size_t HashValue(T val) {
const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits; const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits;
const unsigned int length = const unsigned int length = (std::numeric_limits<T>::digits - 1) / static_cast<unsigned int>(size_t_bits);
(std::numeric_limits<T>::digits - 1) / static_cast<unsigned int>(size_t_bits);
std::size_t seed = 0; std::size_t seed = 0;
for (unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
for (unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits) { seed ^= std::size_t(val >> i) + (seed << 6) + (seed >> 2);
seed ^= static_cast<size_t>(val >> i) + (seed << 6) + (seed >> 2); return seed ^= std::size_t(val) + (seed << 6) + (seed >> 2);
}
seed ^= static_cast<size_t>(val) + (seed << 6) + (seed >> 2);
return seed;
} }
template <size_t Bits> template <size_t Bits>
struct HashCombineImpl { struct HashCombineImpl {
template <typename T> template <typename T>
static inline T fn(T seed, T value) { static inline T fn(T seed, T value) {
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
} }
}; };
+5 -2
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -12,14 +15,14 @@ namespace Common {
template <typename N, typename D> template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D> requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeil(N number, D divisor) { [[nodiscard]] constexpr N DivCeil(N number, D divisor) {
return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor); return N((D(number) + divisor - 1) / divisor);
} }
/// Ceiled integer division with logarithmic divisor in base 2 /// Ceiled integer division with logarithmic divisor in base 2
template <typename N, typename D> template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D> requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) { [[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2); return N((D(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
} }
} // namespace Common } // namespace Common
-28
View File
@@ -1,28 +0,0 @@
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <cstddef>
#include <utility>
#include <boost/functional/hash.hpp>
namespace Common {
struct PairHash {
template <class T1, class T2>
std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
std::size_t seed = std::hash<T1>()(pair.first);
boost::hash_combine(seed, std::hash<T2>()(pair.second));
return seed;
}
};
template <typename T>
struct IdentityHash {
[[nodiscard]] size_t operator()(T value) const noexcept {
return static_cast<size_t>(value);
}
};
} // namespace Common
+10 -16
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -16,14 +19,12 @@ namespace Common {
[[nodiscard]] constexpr u8 ToHexNibble(char c) { [[nodiscard]] constexpr u8 ToHexNibble(char c) {
if (c >= 65 && c <= 70) { if (c >= 65 && c <= 70) {
return static_cast<u8>(c - 55); return u8(c - 55);
} }
if (c >= 97 && c <= 102) { if (c >= 97 && c <= 102) {
return static_cast<u8>(c - 87); return u8(c - 87);
} }
return u8(c - 48);
return static_cast<u8>(c - 48);
} }
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian); [[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
@@ -31,35 +32,28 @@ namespace Common {
template <std::size_t Size, bool le = false> template <std::size_t Size, bool le = false>
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) { [[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size"); ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size");
std::array<u8, Size> out{}; std::array<u8, Size> out{};
if constexpr (le) { if constexpr (le) {
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1])); out[i / 2] = u8((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
} }
} else { } else {
for (std::size_t i = 0; i < 2 * Size; i += 2) { for (std::size_t i = 0; i < 2 * Size; i += 2) {
out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1])); out[i / 2] = u8((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
} }
} }
return out; return out;
} }
template <typename ContiguousContainer> template <typename ContiguousContainer>
requires std::is_same_v<typename ContiguousContainer::value_type, u8>
[[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) { [[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) {
static_assert(std::is_same_v<typename ContiguousContainer::value_type, u8>,
"Underlying type within the contiguous container must be u8.");
constexpr std::size_t pad_width = 2; constexpr std::size_t pad_width = 2;
std::string out; std::string out;
out.reserve(std::size(data) * pad_width); out.reserve(std::size(data) * pad_width);
const auto format_str = fmt::runtime(upper ? "{:02X}" : "{:02x}"); const auto format_str = fmt::runtime(upper ? "{:02X}" : "{:02x}");
for (const u8 c : data) { for (const u8 c : data)
out += fmt::format(format_str, c); out += fmt::format(format_str, c);
}
return out; return out;
} }
+10 -6
View File
@@ -10,6 +10,7 @@
#include <cstdlib> #include <cstdlib>
#include <regex> #include <regex>
#include <thread> #include <thread>
#include <boost/algorithm/string/predicate.hpp>
#if defined(__ANDROID__) #if defined(__ANDROID__)
#include <android/log.h> #include <android/log.h>
@@ -95,9 +96,10 @@ std::string FormatLogMessage(const Entry& entry) noexcept {
template <typename It> template <typename It>
Level GetLevelByName(const It begin, const It end) { Level GetLevelByName(const It begin, const It end) {
std::string_view const sv{begin, end};
for (u32 i = 0; i < u32(Level::Count); ++i) { for (u32 i = 0; i < u32(Level::Count); ++i) {
const char* level_name = GetLevelName(Level(i)); auto const level_name = GetLevelName(Level(i));
if (Common::ComparePartialString(begin, end, level_name)) if (boost::iequals(sv, level_name))
return Level(i); return Level(i);
} }
return Level::Count; return Level::Count;
@@ -105,9 +107,10 @@ Level GetLevelByName(const It begin, const It end) {
template <typename It> template <typename It>
Class GetClassByName(const It begin, const It end) { Class GetClassByName(const It begin, const It end) {
std::string_view const sv{begin, end};
for (u32 i = 0; i < u32(Class::Count); ++i) { for (u32 i = 0; i < u32(Class::Count); ++i) {
const char* level_name = GetLogClassName(Class(i)); auto const level_name = GetLogClassName(Class(i));
if (Common::ComparePartialString(begin, end, level_name)) if (boost::iequals(sv, level_name))
return Class(i); return Class(i);
} }
return Class::Count; return Class::Count;
@@ -120,12 +123,13 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}", std::string(begin, end)); LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}", std::string(begin, end));
return false; return false;
} }
const Level level = GetLevelByName(level_separator + 1, end); auto const sv = std::string_view{begin, level_separator};
auto const level = GetLevelByName(level_separator + 1, end);
if (level == Level::Count) { if (level == Level::Count) {
LOG_ERROR(Log, "Unknown log level in filter: {}", std::string(begin, end)); LOG_ERROR(Log, "Unknown log level in filter: {}", std::string(begin, end));
return false; return false;
} }
if (Common::ComparePartialString(begin, level_separator, "*")) { if (boost::iequals(sv, "*")) {
instance.class_levels.fill(level); instance.class_levels.fill(level);
return true; return true;
} }
+20 -18
View File
@@ -8,6 +8,9 @@
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include "common/logging.h" #include "common/logging.h"
#include "common/param_package.h" #include "common/param_package.h"
@@ -15,17 +18,16 @@
namespace Common { namespace Common {
constexpr char KEY_VALUE_SEPARATOR = ':'; constexpr auto KEY_VALUE_SEPARATOR = ":";
constexpr char PARAM_SEPARATOR = ','; constexpr auto PARAM_SEPARATOR = ",";
constexpr auto ESCAPE_CHARACTER = "$";
constexpr char ESCAPE_CHARACTER = '$'; constexpr auto KEY_VALUE_SEPARATOR_ESCAPE = "$0";
constexpr char KEY_VALUE_SEPARATOR_ESCAPE[] = "$0"; constexpr auto PARAM_SEPARATOR_ESCAPE = "$1";
constexpr char PARAM_SEPARATOR_ESCAPE[] = "$1"; constexpr auto ESCAPE_CHARACTER_ESCAPE = "$2";
constexpr char ESCAPE_CHARACTER_ESCAPE[] = "$2";
/// A placeholder for empty param packages to avoid empty strings /// A placeholder for empty param packages to avoid empty strings
/// (they may be recognized as "not set" by some frontend libraries like qt) /// (they may be recognized as "not set" by some frontend libraries like qt)
constexpr char EMPTY_PLACEHOLDER[] = "[empty]"; constexpr auto EMPTY_PLACEHOLDER = "[empty]";
ParamPackage::ParamPackage(const std::string& serialized) { ParamPackage::ParamPackage(const std::string& serialized) {
if (serialized == EMPTY_PLACEHOLDER) { if (serialized == EMPTY_PLACEHOLDER) {
@@ -33,20 +35,20 @@ ParamPackage::ParamPackage(const std::string& serialized) {
} }
std::vector<std::string> pairs; std::vector<std::string> pairs;
Common::SplitString(serialized, PARAM_SEPARATOR, pairs); boost::split(pairs, serialized, boost::is_any_of(PARAM_SEPARATOR));
for (const std::string& pair : pairs) { for (const std::string& pair : pairs) {
std::vector<std::string> key_value; std::vector<std::string> key_value;
Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value); boost::split(key_value, pair, boost::is_any_of(KEY_VALUE_SEPARATOR));
if (key_value.size() != 2) { if (key_value.size() != 2) {
LOG_ERROR(Common, "invalid key pair {}", pair); LOG_ERROR(Common, "invalid key pair {}", pair);
continue; continue;
} }
for (std::string& part : key_value) { for (auto& part : key_value) {
part = Common::ReplaceAll(part, KEY_VALUE_SEPARATOR_ESCAPE, {KEY_VALUE_SEPARATOR}); boost::replace_all(part, KEY_VALUE_SEPARATOR_ESCAPE, KEY_VALUE_SEPARATOR);
part = Common::ReplaceAll(part, PARAM_SEPARATOR_ESCAPE, {PARAM_SEPARATOR}); boost::replace_all(part, PARAM_SEPARATOR_ESCAPE, PARAM_SEPARATOR);
part = Common::ReplaceAll(part, ESCAPE_CHARACTER_ESCAPE, {ESCAPE_CHARACTER}); boost::replace_all(part, ESCAPE_CHARACTER_ESCAPE, ESCAPE_CHARACTER);
} }
Set(key_value[0], std::move(key_value[1])); Set(key_value[0], std::move(key_value[1]));
@@ -63,10 +65,10 @@ std::string ParamPackage::Serialize() const {
for (const auto& pair : data) { for (const auto& pair : data) {
std::array<std::string, 2> key_value{{pair.first, pair.second}}; std::array<std::string, 2> key_value{{pair.first, pair.second}};
for (std::string& part : key_value) { for (auto& part : key_value) {
part = Common::ReplaceAll(part, {ESCAPE_CHARACTER}, ESCAPE_CHARACTER_ESCAPE); boost::replace_all(part, ESCAPE_CHARACTER, ESCAPE_CHARACTER_ESCAPE);
part = Common::ReplaceAll(part, {PARAM_SEPARATOR}, PARAM_SEPARATOR_ESCAPE); boost::replace_all(part, PARAM_SEPARATOR, PARAM_SEPARATOR_ESCAPE);
part = Common::ReplaceAll(part, {KEY_VALUE_SEPARATOR}, KEY_VALUE_SEPARATOR_ESCAPE); boost::replace_all(part, KEY_VALUE_SEPARATOR, KEY_VALUE_SEPARATOR_ESCAPE);
} }
result += key_value[0] + KEY_VALUE_SEPARATOR + key_value[1] + PARAM_SEPARATOR; result += key_value[0] + KEY_VALUE_SEPARATOR + key_value[1] + PARAM_SEPARATOR;
} }
-4
View File
@@ -639,10 +639,6 @@ struct Values {
Specialization::Default, Specialization::Default,
true, true,
true}; true};
SwitchableSetting<bool> nce_invalidation_gpu_readback{
linkage, false, "nce_invalidation_gpu_readback", Category::RendererHacks};
SwitchableSetting<bool> nce_runtime_nro_patch{
linkage, false, "nce_runtime_nro_patch", Category::RendererHacks};
SwitchableSetting<bool> async_presentation{linkage, SwitchableSetting<bool> async_presentation{linkage,
#ifdef __ANDROID__ #ifdef __ANDROID__
false, false,
+1 -1
View File
@@ -150,7 +150,7 @@ ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, Scale
ENUM(AntiAliasing, None, Fxaa, Smaa); ENUM(AntiAliasing, None, Fxaa, Smaa);
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch); ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
ENUM(ConsoleMode, Handheld, Docked); ENUM(ConsoleMode, Handheld, Docked);
ENUM(AppletMode, HLE, LLE, Disabled); ENUM(AppletMode, HLE, LLE);
ENUM(SpirvOptimizeMode, Never, OnLoad, Always); ENUM(SpirvOptimizeMode, Never, OnLoad, Always);
ENUM(GpuClock, Normal, Boost, Overclock) ENUM(GpuClock, Normal, Boost, Overclock)
ENUM(GpuUnswizzleSize, VerySmall, Small, Normal, Large, VeryLarge) ENUM(GpuUnswizzleSize, VerySmall, Small, Normal, Large, VeryLarge)
-51
View File
@@ -24,22 +24,6 @@
namespace Common { namespace Common {
/// Make a string lowercase
std::string ToLower(const std::string_view sv) {
std::string str{sv};
std::transform(str.begin(), str.end(), str.begin(),
[](auto const c) { return char(std::tolower(c)); });
return str;
}
/// Make a string uppercase
std::string ToUpper(const std::string_view sv) {
std::string str{sv};
std::transform(str.begin(), str.end(), str.begin(),
[](auto const c) { return char(std::toupper(c)); });
return str;
}
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
std::string* _pExtension) { std::string* _pExtension) {
if (full_path.empty()) if (full_path.empty())
@@ -80,41 +64,6 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
return true; return true;
} }
void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) {
std::istringstream iss(str);
output.resize(1);
while (std::getline(iss, *output.rbegin(), delim)) {
output.emplace_back();
}
output.pop_back();
}
std::string TabsToSpaces(int tab_size, std::string in) {
std::size_t i = 0;
while ((i = in.find('\t')) != std::string::npos) {
in.replace(i, 1, tab_size, ' ');
}
return in;
}
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) {
std::size_t pos = 0;
if (src == dest)
return result;
while ((pos = result.find(src, pos)) != std::string::npos) {
result.replace(pos, src.size(), dest);
pos += dest.length();
}
return result;
}
std::string UTF16ToUTF8(std::u16string_view input) { std::string UTF16ToUTF8(std::u16string_view input) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.to_bytes(input.data(), input.data() + input.size()); return convert.to_bytes(input.data(), input.data() + input.size());
+4 -56
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
@@ -16,12 +16,6 @@
namespace Common { namespace Common {
/// Make a string lowercase
[[nodiscard]] std::string ToLower(const std::string_view sv);
/// Make a string uppercase
[[nodiscard]] std::string ToUpper(const std::string_view sv);
[[nodiscard]] inline std::string StringFromBuffer(std::span<const u8> data) noexcept { [[nodiscard]] inline std::string StringFromBuffer(std::span<const u8> data) noexcept {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
} }
@@ -29,37 +23,8 @@ namespace Common {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
} }
/// Turns " hej " into "hej". Also handles tabs.
[[nodiscard]] inline std::string StripSpaces(const std::string_view str) noexcept {
const std::size_t s = str.find_first_not_of(" \t\r\n");
if (str.npos != s)
return std::string{str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1)};
return {};
}
/// "\"hello\"" is turned to "hello"
/// This one assumes that the string has already been space stripped in both
/// ends, as done by StripSpaces above, for example.
[[nodiscard]] inline std::string StripQuotes(const std::string_view s) noexcept {
if (s.size() && '\"' == s[0] && '\"' == *s.rbegin())
return std::string{s.substr(1, s.size() - 2)};
return std::string{s};
}
[[nodiscard]] inline std::string StringFromBool(bool value) noexcept {
return value ? "True" : "False";
}
[[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in);
void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" // "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe"
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension);
std::string* _pExtension);
[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
const std::string& dest);
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input); [[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input); [[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
@@ -73,30 +38,13 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
[[nodiscard]] std::u16string U16StringFromBuffer(const u16* input, std::size_t length); [[nodiscard]] std::u16string U16StringFromBuffer(const u16* input, std::size_t length);
/**
* Compares the string defined by the range [`begin`, `end`) to the null-terminated C-string
* `other` for equality.
*/
template <typename InIt>
[[nodiscard]] inline bool ComparePartialString(InIt begin, InIt end, const char* other) noexcept {
for (; begin != end && *other != '\0'; ++begin, ++other) {
if (*begin != *other) {
return false;
}
}
// Only return true if both strings finished at the same point
return (begin == end) == (*other == '\0');
}
/// Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't /// Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
/// NUL-terminated then the string ends at max_len characters. /// NUL-terminated then the string ends at max_len characters.
[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, [[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, std::size_t max_len);
std::size_t max_len);
/// Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't /// Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
/// null-terminated, then the string ends at the greatest multiple of two less then or equal to /// null-terminated, then the string ends at the greatest multiple of two less then or equal to
/// max_len_bytes. /// max_len_bytes.
[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, [[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, std::size_t max_len);
std::size_t max_len);
} // namespace Common } // namespace Common
-1
View File
@@ -13,7 +13,6 @@
#include <dynarmic/interface/A64/a64.h> #include <dynarmic/interface/A64/a64.h>
#include <dynarmic/interface/code_page.h> #include <dynarmic/interface/code_page.h>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/hash.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "dynarmic/interface/A64/config.h" #include "dynarmic/interface/A64/config.h"
+12 -19
View File
@@ -168,7 +168,7 @@ void CpuManager::ShutdownThread(Kernel::KernelCore& kernel) {
UNREACHABLE(); UNREACHABLE();
} }
void CpuManager::RunThread(std::stop_token token, std::size_t core) { void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
/// Initialization /// Initialization
system.RegisterCoreThread(core); system.RegisterCoreThread(core);
std::string name = is_multicore ? ("CPUCore_" + std::to_string(core)) : std::string{"CPUThread"}; std::string name = is_multicore ? ("CPUCore_" + std::to_string(core)) : std::string{"CPUThread"};
@@ -178,26 +178,19 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
auto& data = core_data[core]; auto& data = core_data[core];
data.host_context = Common::Fiber::ThreadToFiber(); data.host_context = Common::Fiber::ThreadToFiber();
// Cleanup
SCOPE_EXIT {
data.host_context->Exit();
};
// Running // Running
if (!gpu_barrier->Sync(token)) { gpu_barrier->arrive_and_wait();
return; if (!stop_token.stop_requested()) {
if (!is_async_gpu && !is_multicore) {
system.GPU().ObtainContext();
}
auto& kernel = system.Kernel();
auto& scheduler = *kernel.CurrentScheduler();
auto* thread = scheduler.GetSchedulerCurrentThread();
Kernel::SetCurrentThread(kernel, thread);
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
} }
data.host_context->Exit();
if (!is_async_gpu && !is_multicore) {
system.GPU().ObtainContext();
}
auto& kernel = system.Kernel();
auto& scheduler = *kernel.CurrentScheduler();
auto* thread = scheduler.GetSchedulerCurrentThread();
Kernel::SetCurrentThread(kernel, thread);
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
} }
} // namespace Core } // namespace Core
+3 -2
View File
@@ -8,6 +8,7 @@
#include <array> #include <array>
#include <atomic> #include <atomic>
#include <barrier>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <thread> #include <thread>
@@ -52,7 +53,7 @@ public:
} }
void OnGpuReady() { void OnGpuReady() {
gpu_barrier->Sync(); gpu_barrier->arrive_and_wait();
} }
void Initialize(); void Initialize();
@@ -95,7 +96,7 @@ private:
static constexpr std::size_t max_cycle_runs = 5; static constexpr std::size_t max_cycle_runs = 5;
std::optional<Common::Barrier> gpu_barrier{}; std::optional<std::barrier<>> gpu_barrier{};
struct CoreData { struct CoreData {
std::shared_ptr<Common::Fiber> host_context; std::shared_ptr<Common::Fiber> host_context;
std::jthread host_thread; std::jthread host_thread;
+2 -1
View File
@@ -14,6 +14,7 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include <boost/algorithm/string/case_conv.hpp>
#include <openssl/evp.h> #include <openssl/evp.h>
#include "common/fs/file.h" #include "common/fs/file.h"
@@ -622,7 +623,7 @@ void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_ti
Key128 key = Common::HexStringToArray<16>(out[1]); Key128 key = Common::HexStringToArray<16>(out[1]);
s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key; s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key;
} else { } else {
out[0] = Common::ToLower(out[0]); boost::algorithm::to_lower(out[0]);
if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) { if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) {
const auto& index = iter128->second; const auto& index = iter128->second;
const Key128 key = Common::HexStringToArray<16>(out[1]); const Key128 key = Common::HexStringToArray<16>(out[1]);
+3 -5
View File
@@ -6,6 +6,7 @@
#include <array> #include <array>
#include <cstring> #include <cstring>
#include <boost/algorithm/string/case_conv.hpp>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/hex_util.h" #include "common/hex_util.h"
@@ -41,16 +42,13 @@ static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect siz
const u8 PartitionDataManager::MAX_KEYBLOB_SOURCE_HASH = 32; const u8 PartitionDataManager::MAX_KEYBLOB_SOURCE_HASH = 32;
static FileSys::VirtualFile FindFileInDirWithNames(const FileSys::VirtualDir& dir, static FileSys::VirtualFile FindFileInDirWithNames(const FileSys::VirtualDir& dir, const std::string& name) {
const std::string& name) { const auto upper = boost::algorithm::to_upper_copy(name);
const auto upper = Common::ToUpper(name);
for (const auto& fname : {name, name + ".bin", upper, upper + ".BIN"}) { for (const auto& fname : {name, name + ".bin", upper, upper + ".BIN"}) {
if (dir->GetFile(fname) != nullptr) { if (dir->GetFile(fname) != nullptr) {
return dir->GetFile(fname); return dir->GetFile(fname);
} }
} }
return nullptr; return nullptr;
} }
+2 -3
View File
@@ -8,6 +8,7 @@
#include <array> #include <array>
#include <cstddef> #include <cstddef>
#include <cstring> #include <cstring>
#include <boost/algorithm/string/case_conv.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/hex_util.h" #include "common/hex_util.h"
@@ -73,12 +74,10 @@ VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name)
#else #else
const auto subdirs = dir->GetSubdirectories(); const auto subdirs = dir->GetSubdirectories();
for (const auto& subdir : subdirs) { for (const auto& subdir : subdirs) {
std::string dir_name = Common::ToLower(subdir->GetName()); if (name == boost::algorithm::to_lower_copy(subdir->GetName())) {
if (dir_name == name) {
return subdir; return subdir;
} }
} }
return nullptr; return nullptr;
#endif #endif
} }
+4 -4
View File
@@ -8,6 +8,7 @@
#include <limits> #include <limits>
#include <random> #include <random>
#include <regex> #include <regex>
#include <boost/algorithm/string/case_conv.hpp>
#include <openssl/evp.h> #include <openssl/evp.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
@@ -1414,11 +1415,10 @@ void ExternalContentProvider::ScanDirectory(const VirtualDir& dir) {
continue; continue;
} }
const auto extension = Common::ToLower(filename.substr(dot_pos + 1)); const auto ext = boost::to_lower_copy(filename.substr(dot_pos + 1));
if (ext == "nsp") {
if (extension == "nsp") {
ProcessNSP(file); ProcessNSP(file);
} else if (extension == "xci") { } else if (ext == "xci") {
ProcessXCI(file); ProcessXCI(file);
} }
} }
+3 -2
View File
@@ -9,6 +9,7 @@
#include <regex> #include <regex>
#include <string> #include <string>
#include <boost/algorithm/string/case_conv.hpp>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/evp.h> #include <openssl/evp.h>
@@ -63,8 +64,8 @@ NAX::NAX(VirtualFile file_)
return; return;
} }
const std::string two_dir = Common::ToUpper(std::string{match[1]}); const std::string two_dir = boost::algorithm::to_upper_copy(std::string{match[1]});
const std::string nca_id = Common::ToLower(std::string{match[2]}); const std::string nca_id = boost::algorithm::to_lower_copy(std::string{match[2]});
status = Parse(fmt::format("/registered/{}/{}.nca", two_dir, nca_id)); status = Parse(fmt::format("/registered/{}/{}.nca", two_dir, nca_id));
} }
+11 -2
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -19,8 +22,14 @@ constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores - sync wit
// Virtual to Physical core map. // Virtual to Physical core map.
constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{ constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 3,
}; };
static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>(); static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>();
+2 -3
View File
@@ -250,10 +250,9 @@ std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<
return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer); return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer);
case AppletId::NetConnect: case AppletId::NetConnect:
return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect); return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect);
case AppletId::None:
return nullptr;
default: default:
UNIMPLEMENTED_MSG("No frontend implementation exists for applet_id={:02X} program_id={:016X}! Using stub applet.", static_cast<u8>(id), applet->program_id); LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X} program_id={:016X}"
"Falling back to stub applet", static_cast<u8>(id), applet->program_id);
return std::make_shared<StubApplet>(system, applet, id, mode); return std::make_shared<StubApplet>(system, applet, id, mode);
} }
} }
+2 -32
View File
@@ -16,10 +16,6 @@
#include "core/hle/service/ro/ro_types.h" #include "core/hle/service/ro/ro_types.h"
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#ifdef HAS_NCE
#include "core/arm/nce/patcher.h"
#include "core/hle/kernel/k_shared_memory.h"
#endif
namespace Service::RO { namespace Service::RO {
@@ -390,7 +386,7 @@ public:
R_SUCCEED(); R_SUCCEED();
} }
Result MapManualLoadModuleMemory(Kernel::KernelCore& kernel, u64* out_address, size_t context_id, u64 nro_address, Result MapManualLoadModuleMemory(u64* out_address, size_t context_id, u64 nro_address,
u64 nro_size, u64 bss_address, u64 bss_size) { u64 nro_size, u64 bss_address, u64 bss_size) {
// Get context. // Get context.
ProcessContext* context = this->GetContextById(context_id); ProcessContext* context = this->GetContextById(context_id);
@@ -425,33 +421,7 @@ public:
R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size), R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size),
std::addressof(ro_size), std::addressof(rw_size), std::addressof(ro_size), std::addressof(rw_size),
nro_info->base_address, nro_size, bss_size)); nro_info->base_address, nro_size, bss_size));
#ifdef HAS_NCE
if (Settings::values.nce_runtime_nro_patch.GetValue()) {
if (Settings::IsNceEnabled()) {
auto* process = context->GetProcess();
auto& memory = process->GetMemory();
std::vector<u8> image(total_size);
memory.ReadBlock(nro_info->base_address, image.data(), rx_size);
Kernel::CodeSet::Segment code{.size = static_cast<u32>(rx_size)};
Core::NCE::Patcher patch;
patch.PatchText(image, code);
patch.RelocateAndCopy(nro_info->base_address, code, image, nullptr);
const u64 patch_address = nro_info->base_address + total_size;
const size_t patch_size = patch.GetSectionSize();
constexpr auto permission = Kernel::Svc::MemoryPermission::ReadExecute;
auto* patch_memory = Kernel::KSharedMemory::Create(kernel);
R_TRY(patch_memory->Initialize(kernel, kernel.System().DeviceMemory(), process, permission, permission, patch_size));
std::memcpy(patch_memory->GetPointer(), image.data() + total_size, patch_size);
R_TRY(process->AddSharedMemory(kernel, patch_memory, patch_address, patch_size));
R_TRY(patch_memory->Map(*process, patch_address, patch_size, permission));
memory.WriteBlock(nro_info->base_address, image.data(), rx_size);
}
}
#endif
// Set NRO perms. // Set NRO perms.
R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size, R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size,
rw_size + bss_size)); rw_size + bss_size));
@@ -561,7 +531,7 @@ public:
Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid, Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid,
u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
R_RETURN(m_ro->MapManualLoadModuleMemory(system.Kernel(), out_load_address.Get(), m_context_id, nro_address, R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address.Get(), m_context_id, nro_address,
nro_size, bss_address, bss_size)); nro_size, bss_address, bss_size));
} }
+2 -2
View File
@@ -10,6 +10,7 @@
#include <string> #include <string>
#include <concepts> #include <concepts>
#include <algorithm> #include <algorithm>
#include <boost/algorithm/string/case_conv.hpp>
#include "common/concepts.h" #include "common/concepts.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
#include "common/logging.h" #include "common/logging.h"
@@ -170,8 +171,7 @@ FileType GuessFromFilename(const std::string& name) {
else if (name == "00") else if (name == "00")
return FileType::NCA; return FileType::NCA;
auto const extension = auto const extension = boost::algorithm::to_lower_copy(std::string(Common::FS::GetExtensionFromFilename(name)));
Common::ToLower(std::string(Common::FS::GetExtensionFromFilename(name)));
if (extension == "nro") if (extension == "nro")
return FileType::NRO; return FileType::NRO;
else if (extension == "nso") else if (extension == "nso")
+1 -1
View File
@@ -757,7 +757,7 @@ struct Memory::Impl {
}; };
auto& gpu = system.GPU(); auto& gpu = system.GPU();
gpu_device_memory->ApplyOpOnPointer( gpu_device_memory->ApplyOpOnPointer(
p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size, true); }); p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); });
} }
Core::System& system; Core::System& system;
+2 -1
View File
@@ -14,6 +14,7 @@
#include <regex> #include <regex>
#include <string> #include <string>
#include <thread> #include <thread>
#include <boost/algorithm/string/trim.hpp>
#ifdef _WIN32 #ifdef _WIN32
// windows.h needs to be included before shellapi.h // windows.h needs to be included before shellapi.h
@@ -132,7 +133,7 @@ static Network::Room::BanList LoadBanList(const std::string& path) {
std::string line; std::string line;
std::getline(file, line); std::getline(file, line);
line.erase(std::remove(line.begin(), line.end(), '\0'), line.end()); line.erase(std::remove(line.begin(), line.end(), '\0'), line.end());
line = Common::StripSpaces(line); boost::trim(line);
if (line.empty()) { if (line.empty()) {
// An empty line marks start of the IP ban list // An empty line marks start of the IP ban list
ban_list_type = true; ban_list_type = true;
+3 -9
View File
@@ -194,14 +194,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"), INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"),
tr("Skips certain cache invalidations during memory updates, reducing CPU usage and " tr("Skips certain cache invalidations during memory updates, reducing CPU usage and "
"improving latency. This may cause soft-crashes.")); "improving latency. This may cause soft-crashes."));
INSERT(Settings, nce_invalidation_gpu_readback,
tr("GPU Readback Before NCE Invalidation"),
tr("Flushes GPU buffer data back to guest memory before NCE invalidates the whole "
"guest page, preserving it while the CPU store proceeds."));
INSERT(Settings, nce_runtime_nro_patch,
tr("Patch Runtime NROs for NCE"),
tr("Applies NCE code patches to runtime-loaded NRO modules."
"This is required for some games to run correctly."));
INSERT(Settings, vsync_mode, tr("VSync Mode:"), INSERT(Settings, vsync_mode, tr("VSync Mode:"),
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
"refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n" "refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n"
@@ -350,6 +342,9 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
"it bypasses such prompts and directly exits the emulation.")); "it bypasses such prompts and directly exits the emulation."));
INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"),
tr("Hides the mouse after 2.5s of inactivity.")); tr("Hides the mouse after 2.5s of inactivity."));
INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"),
tr("Forcibly disables the use of the controller applet in emulated programs.\n"
"When a program attempts to open the controller applet, it is immediately closed."));
INSERT(UISettings, check_for_updates, tr("Check for updates"), INSERT(UISettings, check_for_updates, tr("Check for updates"),
tr("Whether or not to check for updates upon startup.")); tr("Whether or not to check for updates upon startup."));
@@ -385,7 +380,6 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent) {
{ {
PAIR(AppletMode, HLE, tr("Custom frontend")), PAIR(AppletMode, HLE, tr("Custom frontend")),
PAIR(AppletMode, LLE, tr("Real applet")), PAIR(AppletMode, LLE, tr("Real applet")),
PAIR(AppletMode, Disabled, tr("Disabled")),
}}); }});
translations->insert({Settings::EnumMetadata<Settings::SpirvOptimizeMode>::Index(), translations->insert({Settings::EnumMetadata<Settings::SpirvOptimizeMode>::Index(),
+2
View File
@@ -127,6 +127,8 @@ struct Values {
Setting<bool> hide_mouse{ Setting<bool> hide_mouse{
linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default, linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
true, true}; true, true};
Setting<bool> controller_applet_disabled{linkage, false, "disableControllerApplet",
Category::UiGeneral};
// Set when Vulkan is known to crash the application // Set when Vulkan is known to crash the application
bool has_broken_vulkan = false; bool has_broken_vulkan = false;
+2 -1
View File
@@ -8,6 +8,7 @@
#include <string> #include <string>
#include <QEventLoop> #include <QEventLoop>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include "common/httplib.h" #include "common/httplib.h"
@@ -45,7 +46,7 @@ void DiscordImpl::Pause() {
std::string DiscordImpl::GetGameString(const std::string& title) { std::string DiscordImpl::GetGameString(const std::string& title) {
// Convert to lowercase // Convert to lowercase
std::string icon_name = Common::ToLower(title); std::string icon_name = boost::algorithm::to_lower_copy(title);
// Replace spaces with dashes // Replace spaces with dashes
std::replace(icon_name.begin(), icon_name.end(), ' ', '-'); std::replace(icon_name.begin(), icon_name.end(), ' ', '-');
-1
View File
@@ -172,7 +172,6 @@ add_library(shader_recompiler STATIC
ir_opt/constant_propagation_pass.cpp ir_opt/constant_propagation_pass.cpp
ir_opt/dead_code_elimination_pass.cpp ir_opt/dead_code_elimination_pass.cpp
ir_opt/dual_vertex_pass.cpp ir_opt/dual_vertex_pass.cpp
ir_opt/geometry_compaction_pass.cpp
ir_opt/global_memory_to_storage_buffer_pass.cpp ir_opt/global_memory_to_storage_buffer_pass.cpp
ir_opt/identity_removal_pass.cpp ir_opt/identity_removal_pass.cpp
ir_opt/layer_pass.cpp ir_opt/layer_pass.cpp
@@ -4,7 +4,6 @@
// 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
#include <algorithm>
#include <span> #include <span>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
@@ -440,13 +439,10 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
ctx.AddCapability(spv::Capability::DrawParameters); ctx.AddCapability(spv::Capability::DrawParameters);
} }
if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id || if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id ||
info.uses_subgroup_shuffles || info.uses_subgroup_mask) && info.uses_subgroup_shuffles) &&
profile.support_vote && profile.SupportsSubgroupStage(ctx.stage)) { profile.support_vote && profile.SupportsSubgroupStage(ctx.stage)) {
ctx.AddCapability(spv::Capability::GroupNonUniformBallot); ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
ctx.AddCapability(spv::Capability::GroupNonUniformShuffle); ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);
if (info.uses_subgroup_shuffles && profile.support_shuffle_relative) {
ctx.AddCapability(spv::Capability::GroupNonUniformShuffleRelative);
}
if (!profile.warp_size_potentially_larger_than_guest) { if (!profile.warp_size_potentially_larger_than_guest) {
// vote ops are only used when not taking the long path // vote ops are only used when not taking the long path
ctx.AddCapability(spv::Capability::GroupNonUniformVote); ctx.AddCapability(spv::Capability::GroupNonUniformVote);
@@ -525,29 +521,6 @@ void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
return { ctx.Def(phi->Arg(phi_arg)), parent }; return { ctx.Def(phi->Arg(phi_arg)), parent };
}); });
} }
void RewriteOpcodes(std::vector<u32>& code, std::span<const std::pair<u32, spv::Op>> rewrites) {
if (rewrites.empty()) {
return;
}
size_t offset = 5;
while (offset + 2 < code.size()) {
const u32 word_count{code[offset] >> 16};
const auto opcode{static_cast<spv::Op>(code[offset] & 0xFFFFu)};
if (word_count == 0) {
return;
}
if (opcode == spv::Op::OpGroupNonUniformShuffleXor ||
opcode == spv::Op::OpGroupNonUniformQuadBroadcast) {
const auto it{std::ranges::find(rewrites, code[offset + 2],
&std::pair<u32, spv::Op>::first)};
if (it != rewrites.end()) {
code[offset] = (code[offset] & 0xFFFF0000u) | static_cast<u32>(it->second);
}
}
offset += word_count;
}
}
} // Anonymous namespace } // Anonymous namespace
std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, Bindings& bindings) { std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program, Bindings& bindings) {
@@ -562,9 +535,7 @@ std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in
SetupCapabilities(profile, program.info, ctx); SetupCapabilities(profile, program.info, ctx);
SetupTransformFeedbackCapabilities(ctx, main); SetupTransformFeedbackCapabilities(ctx, main);
PatchPhiNodes(program, ctx); PatchPhiNodes(program, ctx);
std::vector<u32> code{ctx.Assemble()}; return ctx.Assemble();
RewriteOpcodes(code, ctx.opcode_rewrites);
return code;
} }
Id EmitPhi(EmitContext& ctx, IR::Inst* inst) { Id EmitPhi(EmitContext& ctx, IR::Inst* inst) {
@@ -77,57 +77,20 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask
return ComputeMaxThreadId(ctx, min_thread_id, clamp, not_seg_mask); return ComputeMaxThreadId(ctx, min_thread_id, clamp, not_seg_mask);
} }
Id HostThreadId(EmitContext& ctx, Id thread_id) { Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) {
if (!ctx.profile.warp_size_potentially_larger_than_guest) { if (!StageSupportsSubgroups(ctx)) {
return thread_id; return value;
} }
return ctx.OpSelect(
ctx.U32[1], in_range,
ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value);
}
Id AddPartitionBase(EmitContext& ctx, Id thread_id) {
const Id partition_idx{ctx.OpShiftRightLogical(ctx.U32[1], GetThreadId(ctx), ctx.Const(5u))}; const Id partition_idx{ctx.OpShiftRightLogical(ctx.U32[1], GetThreadId(ctx), ctx.Const(5u))};
const Id partition_base{ctx.OpShiftLeftLogical(ctx.U32[1], partition_idx, ctx.Const(5u))}; const Id partition_base{ctx.OpShiftLeftLogical(ctx.U32[1], partition_idx, ctx.Const(5u))};
return ctx.OpIAdd(ctx.U32[1], thread_id, partition_base); return ctx.OpIAdd(ctx.U32[1], thread_id, partition_base);
} }
Id GuestLane(EmitContext& ctx, Id index) {
return ctx.OpBitwiseAnd(ctx.U32[1], index, ctx.Const(31U));
}
Id ShuffleAbsolute(EmitContext& ctx, Id value, Id src_thread_id) {
if (!ctx.profile.has_broken_spirv_subgroup_shuffle) {
return ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id);
}
Id result{ctx.u32_zero_value};
for (u32 lane = 0; lane < ctx.profile.max_subgroup_size; ++lane) {
const Id read{
ctx.OpGroupNonUniformBroadcast(ctx.U32[1], SubgroupScope(ctx), value, ctx.Const(lane))};
const Id matches{ctx.OpIEqual(ctx.U1, src_thread_id, ctx.Const(lane))};
result = ctx.OpSelect(ctx.U32[1], matches, read, result);
}
return result;
}
Id ShuffleRelative(EmitContext& ctx, Id value, Id delta, Id src_thread_id, spv::Op op) {
if (!ctx.profile.support_shuffle_relative) {
return ShuffleAbsolute(ctx, value, HostThreadId(ctx, src_thread_id));
}
const Id result{ctx.OpGroupNonUniformShuffleXor(ctx.U32[1], SubgroupScope(ctx), value, delta)};
ctx.opcode_rewrites.emplace_back(result.value, op);
return result;
}
Id BroadcastLane(EmitContext& ctx, Id value, u32 lane) {
Id result{
ctx.OpGroupNonUniformBroadcast(ctx.U32[1], SubgroupScope(ctx), value, ctx.Const(lane))};
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
return result;
}
const Id partition_idx{ctx.OpShiftRightLogical(ctx.U32[1], GetThreadId(ctx), ctx.Const(5u))};
for (u32 base = 32; base < ctx.profile.max_subgroup_size; base += 32) {
const Id read{ctx.OpGroupNonUniformBroadcast(ctx.U32[1], SubgroupScope(ctx), value,
ctx.Const(base + lane))};
const Id matches{ctx.OpIEqual(ctx.U1, partition_idx, ctx.Const(base >> 5))};
result = ctx.OpSelect(ctx.U32[1], matches, read, result);
}
return result;
}
} // Anonymous namespace } // Anonymous namespace
Id EmitLaneId(EmitContext& ctx) { Id EmitLaneId(EmitContext& ctx) {
@@ -240,75 +203,61 @@ Id EmitShuffleIndex(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id cla
const Id min_thread_id{ComputeMinThreadId(ctx, thread_id, segmentation_mask)}; const Id min_thread_id{ComputeMinThreadId(ctx, thread_id, segmentation_mask)};
const Id max_thread_id{ComputeMaxThreadId(ctx, min_thread_id, clamp, not_seg_mask)}; const Id max_thread_id{ComputeMaxThreadId(ctx, min_thread_id, clamp, not_seg_mask)};
const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], GuestLane(ctx, index), not_seg_mask)}; const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], index, not_seg_mask)};
const Id src_thread_id{ctx.OpBitwiseOr(ctx.U32[1], lhs, min_thread_id)}; Id src_thread_id{ctx.OpBitwiseOr(ctx.U32[1], lhs, min_thread_id)};
const Id in_range{ctx.OpSLessThanEqual(ctx.U1, src_thread_id, max_thread_id)}; const Id in_range{ctx.OpSLessThanEqual(ctx.U1, src_thread_id, max_thread_id)};
if (ctx.profile.warp_size_potentially_larger_than_guest) {
src_thread_id = AddPartitionBase(ctx, src_thread_id);
}
SetInBoundsFlag(inst, in_range); SetInBoundsFlag(inst, in_range);
if (!StageSupportsSubgroups(ctx)) { return SelectValue(ctx, in_range, value, src_thread_id);
return value;
}
const IR::Value lane{inst->Arg(1).Resolve()};
const IR::Value segment{inst->Arg(3).Resolve()};
if (lane.IsImmediate() && segment.IsImmediate() && segment.U32() == 0) {
return ctx.OpSelect(ctx.U32[1], in_range, BroadcastLane(ctx, value, lane.U32() & 31),
value);
}
const Id shuffled{ShuffleAbsolute(ctx, value, HostThreadId(ctx, src_thread_id))};
return ctx.OpSelect(ctx.U32[1], in_range, shuffled, value);
} }
Id EmitShuffleUp(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp, Id EmitShuffleUp(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
Id segmentation_mask) { Id segmentation_mask) {
if (!StageSupportsSubgroups(ctx)) {
SetInBoundsFlag(inst, ctx.false_value);
return value;
}
const Id delta{GuestLane(ctx, index)};
const Id thread_id{EmitLaneId(ctx)}; const Id thread_id{EmitLaneId(ctx)};
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)}; const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
const Id src_thread_id{ctx.OpISub(ctx.U32[1], thread_id, delta)}; Id src_thread_id{ctx.OpISub(ctx.U32[1], thread_id, index)};
const Id in_range{ctx.OpSGreaterThanEqual(ctx.U1, src_thread_id, max_thread_id)}; const Id in_range{ctx.OpSGreaterThanEqual(ctx.U1, src_thread_id, max_thread_id)};
if (ctx.profile.warp_size_potentially_larger_than_guest) {
src_thread_id = AddPartitionBase(ctx, src_thread_id);
}
SetInBoundsFlag(inst, in_range); SetInBoundsFlag(inst, in_range);
const Id shuffled{ShuffleRelative(ctx, value, delta, src_thread_id, return SelectValue(ctx, in_range, value, src_thread_id);
spv::Op::OpGroupNonUniformShuffleUp)};
return ctx.OpSelect(ctx.U32[1], in_range, shuffled, value);
} }
Id EmitShuffleDown(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp, Id EmitShuffleDown(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
Id segmentation_mask) { Id segmentation_mask) {
if (!StageSupportsSubgroups(ctx)) {
SetInBoundsFlag(inst, ctx.false_value);
return value;
}
const Id delta{GuestLane(ctx, index)};
const Id thread_id{EmitLaneId(ctx)}; const Id thread_id{EmitLaneId(ctx)};
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)}; const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
const Id src_thread_id{ctx.OpIAdd(ctx.U32[1], thread_id, delta)}; Id src_thread_id{ctx.OpIAdd(ctx.U32[1], thread_id, index)};
const Id in_range{ctx.OpSLessThanEqual(ctx.U1, src_thread_id, max_thread_id)}; const Id in_range{ctx.OpSLessThanEqual(ctx.U1, src_thread_id, max_thread_id)};
if (ctx.profile.warp_size_potentially_larger_than_guest) {
src_thread_id = AddPartitionBase(ctx, src_thread_id);
}
SetInBoundsFlag(inst, in_range); SetInBoundsFlag(inst, in_range);
const Id shuffled{ShuffleRelative(ctx, value, delta, src_thread_id, return SelectValue(ctx, in_range, value, src_thread_id);
spv::Op::OpGroupNonUniformShuffleDown)};
return ctx.OpSelect(ctx.U32[1], in_range, shuffled, value);
} }
Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp, Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id clamp,
Id segmentation_mask) { Id segmentation_mask) {
if (!StageSupportsSubgroups(ctx)) {
SetInBoundsFlag(inst, ctx.false_value);
return value;
}
const Id mask{GuestLane(ctx, index)};
const Id thread_id{EmitLaneId(ctx)}; const Id thread_id{EmitLaneId(ctx)};
const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)}; const Id max_thread_id{GetMaxThreadId(ctx, thread_id, clamp, segmentation_mask)};
const Id src_thread_id{ctx.OpBitwiseXor(ctx.U32[1], thread_id, mask)}; Id src_thread_id{ctx.OpBitwiseXor(ctx.U32[1], thread_id, index)};
const Id in_range{ctx.OpSLessThanEqual(ctx.U1, src_thread_id, max_thread_id)}; const Id in_range{ctx.OpSLessThanEqual(ctx.U1, src_thread_id, max_thread_id)};
if (ctx.profile.warp_size_potentially_larger_than_guest) {
src_thread_id = AddPartitionBase(ctx, src_thread_id);
}
SetInBoundsFlag(inst, in_range); SetInBoundsFlag(inst, in_range);
const Id shuffled{ctx.OpGroupNonUniformShuffleXor(ctx.U32[1], SubgroupScope(ctx), value, mask)}; return SelectValue(ctx, in_range, value, src_thread_id);
return ctx.OpSelect(ctx.U32[1], in_range, shuffled, value);
} }
Id EmitQuadBroadcast(EmitContext& ctx, Id value, Id lane) { Id EmitQuadBroadcast(EmitContext& ctx, Id value, Id lane) {
@@ -318,16 +267,10 @@ Id EmitQuadBroadcast(EmitContext& ctx, Id value, Id lane) {
const Id base{ctx.OpBitwiseAnd(ctx.U32[1], GetThreadId(ctx), ctx.Const(~3u))}; const Id base{ctx.OpBitwiseAnd(ctx.U32[1], GetThreadId(ctx), ctx.Const(~3u))};
const Id local_lane{ctx.OpBitwiseAnd(ctx.U32[1], lane, ctx.Const(3u))}; const Id local_lane{ctx.OpBitwiseAnd(ctx.U32[1], lane, ctx.Const(3u))};
const Id src_thread_id{ctx.OpBitwiseOr(ctx.U32[1], base, local_lane)}; const Id src_thread_id{ctx.OpBitwiseOr(ctx.U32[1], base, local_lane)};
return ShuffleAbsolute(ctx, value, src_thread_id); return ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id);
} }
Id EmitQuadSwap(EmitContext& ctx, Id value, Id direction) { Id EmitQuadSwap(EmitContext& ctx, Id value, Id direction) {
if (ctx.profile.support_quad_shuffles) {
const Id result{
ctx.OpGroupNonUniformQuadBroadcast(ctx.U32[1], SubgroupScope(ctx), value, direction)};
ctx.opcode_rewrites.emplace_back(result.value, spv::Op::OpGroupNonUniformQuadSwap);
return result;
}
const Id xor_mask{ctx.OpIAdd(ctx.U32[1], direction, ctx.Const(1u))}; const Id xor_mask{ctx.OpIAdd(ctx.U32[1], direction, ctx.Const(1u))};
return ctx.OpGroupNonUniformShuffleXor(ctx.U32[1], SubgroupScope(ctx), value, xor_mask); return ctx.OpGroupNonUniformShuffleXor(ctx.U32[1], SubgroupScope(ctx), value, xor_mask);
} }
@@ -361,7 +361,6 @@ public:
Id frag_depth{}; Id frag_depth{};
std::vector<Id> interfaces; std::vector<Id> interfaces;
std::vector<std::pair<u32, spv::Op>> opcode_rewrites;
Id load_const_func_u8{}; Id load_const_func_u8{};
Id load_const_func_u16{}; Id load_const_func_u16{};
@@ -5,10 +5,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm> #include <algorithm>
#include <array>
#include <bitset>
#include <memory> #include <memory>
#include <optional>
#include <vector> #include <vector>
#include <queue> #include <queue>
@@ -175,17 +172,7 @@ std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings(
void EmitGeometryPassthrough(IR::IREmitter& ir, const IR::Program& program, void EmitGeometryPassthrough(IR::IREmitter& ir, const IR::Program& program,
const Shader::VaryingState& passthrough_mask, const Shader::VaryingState& passthrough_mask,
bool passthrough_position, bool passthrough_position,
std::optional<IR::Attribute> passthrough_layer_attr, std::optional<IR::Attribute> passthrough_layer_attr) {
std::optional<IR::Reg> viewport_mask_reg) {
constexpr std::array CULLED_POSITION{2.0f, 2.0f, 2.0f, 1.0f};
IR::U1 culled{ir.Imm1(false)};
IR::U32 viewport{ir.Imm32(0)};
if (viewport_mask_reg) {
const IR::U32 mask{ir.GetReg(*viewport_mask_reg)};
const IR::U32 lowest_bit{ir.BitwiseAnd(mask, IR::U32{ir.INeg(mask)})};
culled = ir.IEqual(mask, ir.Imm32(0));
viewport = IR::U32{ir.Select(culled, ir.Imm32(0), ir.FindUMsb(lowest_bit))};
}
for (u32 i = 0; i < program.output_vertices; i++) { for (u32 i = 0; i < program.output_vertices; i++) {
// Assign generics from input // Assign generics from input
for (u32 j = 0; j < 32; j++) { for (u32 j = 0; j < 32; j++) {
@@ -203,19 +190,10 @@ void EmitGeometryPassthrough(IR::IREmitter& ir, const IR::Program& program,
if (passthrough_position) { if (passthrough_position) {
// Assign position from input // Assign position from input
const IR::Attribute attr = IR::Attribute::PositionX; const IR::Attribute attr = IR::Attribute::PositionX;
for (u32 component = 0; component < 4; ++component) { ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0));
IR::F32 value{ir.GetAttribute(attr + component, ir.Imm32(i))}; ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0));
if (viewport_mask_reg) { ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0));
value = IR::F32{ ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0));
ir.Select(culled, ir.Imm32(CULLED_POSITION[component]), value)};
}
ir.SetAttribute(attr + component, value, ir.Imm32(0));
}
}
if (viewport_mask_reg) {
ir.SetAttribute(IR::Attribute::ViewportIndex, ir.BitCast<IR::F32>(viewport),
ir.Imm32(0));
} }
if (passthrough_layer_attr) { if (passthrough_layer_attr) {
@@ -241,91 +219,19 @@ u32 GetOutputTopologyVertices(OutputTopology output_topology) {
} }
} }
std::optional<IR::Reg> FindFreeRegister(const IR::Program& program) {
std::bitset<IR::NUM_REGS> used;
for (IR::Block* const block : program.blocks) {
for (const IR::Inst& inst : block->Instructions()) {
const IR::Opcode opcode{inst.GetOpcode()};
if (opcode == IR::Opcode::GetRegister || opcode == IR::Opcode::SetRegister) {
used.set(IR::RegIndex(inst.Arg(0).Reg()));
}
}
}
for (size_t index = IR::NUM_USER_REGS; index-- > 0;) {
if (!used.test(index)) {
return static_cast<IR::Reg>(index);
}
}
return std::nullopt;
}
std::optional<IR::Reg> LowerViewportMask(const IR::Program& program) {
const std::optional<IR::Reg> reg{FindFreeRegister(program)};
if (!reg || program.blocks.empty()) {
return std::nullopt;
}
bool stores_mask{};
for (IR::Block* const block : program.blocks) {
for (IR::Inst& inst : block->Instructions()) {
if (inst.GetOpcode() != IR::Opcode::SetAttribute ||
inst.Arg(0).Attribute() != IR::Attribute::ViewportMask) {
continue;
}
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
ir.SetReg(*reg, ir.BitCast<IR::U32>(IR::F32{inst.Arg(1)}));
inst.Invalidate();
stores_mask = true;
}
}
if (!stores_mask) {
return std::nullopt;
}
IR::Block& entry{*program.blocks.front()};
IR::IREmitter ir{entry, entry.begin()};
ir.SetReg(*reg, ir.Imm32(1));
return reg;
}
void LowerGeometryPassthrough(const IR::Program& program, const HostTranslateInfo& host_info) { void LowerGeometryPassthrough(const IR::Program& program, const HostTranslateInfo& host_info) {
std::optional<IR::Reg> viewport_mask_reg;
if (!host_info.support_viewport_mask) {
viewport_mask_reg = LowerViewportMask(program);
}
for (IR::Block* const block : program.blocks) { for (IR::Block* const block : program.blocks) {
for (IR::Inst& inst : block->Instructions()) { for (IR::Inst& inst : block->Instructions()) {
if (inst.GetOpcode() == IR::Opcode::Epilogue) { if (inst.GetOpcode() == IR::Opcode::Epilogue) {
IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)}; IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
EmitGeometryPassthrough( EmitGeometryPassthrough(
ir, program, program.info.passthrough, ir, program, program.info.passthrough,
program.info.passthrough.AnyComponent(IR::Attribute::PositionX), {}, program.info.passthrough.AnyComponent(IR::Attribute::PositionX), {});
viewport_mask_reg);
} }
} }
} }
} }
void TightenOutputVertices(IR::Program& program) {
if (program.stage != Stage::Geometry || program.is_geometry_passthrough) {
return;
}
const bool has_loops = std::ranges::any_of(program.syntax_list, [](const auto& node) {
return node.type == IR::AbstractSyntaxNode::Type::Loop;
});
if (has_loops) {
return;
}
u32 num_emits = 0;
for (IR::Block* const block : program.blocks) {
for (const IR::Inst& inst : block->Instructions()) {
if (inst.GetOpcode() == IR::Opcode::EmitVertex) {
++num_emits;
}
}
}
if (num_emits != 0) {
program.output_vertices = (std::min)(program.output_vertices, num_emits);
}
}
} // Anonymous namespace } // Anonymous namespace
IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool, IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
@@ -393,14 +299,12 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
Optimization::PositionPass(env, program); Optimization::PositionPass(env, program);
Optimization::GlobalMemoryToStorageBufferPass(program, normalized_host_info); Optimization::GlobalMemoryToStorageBufferPass(program, normalized_host_info);
Optimization::GeometryCompactionPass(program, normalized_host_info);
Optimization::TexturePass(env, program, normalized_host_info); Optimization::TexturePass(env, program, normalized_host_info);
if (Settings::values.resolution_info.active || Settings::values.rescale_hack.GetValue()) { if (Settings::values.resolution_info.active || Settings::values.rescale_hack.GetValue()) {
Optimization::RescalingPass(program); Optimization::RescalingPass(program);
} }
Optimization::DeadCodeEliminationPass(program); Optimization::DeadCodeEliminationPass(program);
TightenOutputVertices(program);
if (Settings::values.renderer_debug) { if (Settings::values.renderer_debug) {
Optimization::VerificationPass(program); Optimization::VerificationPass(program);
} }
@@ -529,7 +433,7 @@ IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool,
IR::IREmitter ir{*current_block}; IR::IREmitter ir{*current_block};
EmitGeometryPassthrough(ir, program, program.info.stores, true, EmitGeometryPassthrough(ir, program, program.info.stores, true,
source_program.info.emulated_layer, std::nullopt); source_program.info.emulated_layer);
IR::Block* return_block{block_pool.Create(inst_pool)}; IR::Block* return_block{block_pool.Create(inst_pool)};
IR::IREmitter{*return_block}.Epilogue(); IR::IREmitter{*return_block}.Epilogue();
@@ -34,12 +34,10 @@ struct HostTranslateInfo {
bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered
bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers
bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS
bool support_viewport_mask{};
bool support_geometry_shader_passthrough{}; ///< True when the device supports geometry bool support_geometry_shader_passthrough{}; ///< True when the device supports geometry
///< passthrough shaders ///< passthrough shaders
bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional
///< control flow ///< control flow
bool single_lane_geometry_subgroups{};
void ApplyDescriptorLimitPolicy() noexcept { void ApplyDescriptorLimitPolicy() noexcept {
if (min_ssbo_alignment == 0) { if (min_ssbo_alignment == 0) {
@@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -651,29 +651,6 @@ IR::Value GetThroughCast(IR::Value value, IR::Opcode expected_cast) {
return value; return value;
} }
u32 QuadButterflyMask(const IR::Inst& inst) {
if (inst.GetOpcode() == IR::Opcode::QuadSwap) {
const IR::Value direction{inst.Arg(1)};
if (!direction.IsImmediate()) {
return 0;
}
return direction.U32() + 1;
}
if (inst.GetOpcode() != IR::Opcode::ShuffleButterfly) {
return 0;
}
const IR::Value index{inst.Arg(1)};
const IR::Value clamp{inst.Arg(2)};
const IR::Value segmentation_mask{inst.Arg(3)};
if (!index.IsImmediate() || !clamp.IsImmediate() || !segmentation_mask.IsImmediate()) {
return 0;
}
if (clamp.U32() != 3 || segmentation_mask.U32() != 28) {
return 0;
}
return index.U32();
}
void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) { void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
const IR::Value swizzle{inst.Arg(2)}; const IR::Value swizzle{inst.Arg(2)};
if (!swizzle.IsImmediate()) { if (!swizzle.IsImmediate()) {
@@ -689,8 +666,7 @@ void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
return; return;
} }
IR::Inst* const inst2{value_1.InstRecursive()}; IR::Inst* const inst2{value_1.InstRecursive()};
const u32 lane_mask{QuadButterflyMask(*inst2)}; if (inst2->GetOpcode() != IR::Opcode::ShuffleButterfly) {
if (lane_mask == 0) {
return; return;
} }
const IR::Value value_3{GetThroughCast(inst2->Arg(0).Resolve(), IR::Opcode::BitCastU32F32)}; const IR::Value value_3{GetThroughCast(inst2->Arg(0).Resolve(), IR::Opcode::BitCastU32F32)};
@@ -702,15 +678,24 @@ void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
return; return;
} }
} }
const IR::Value index{inst2->Arg(1)};
const IR::Value clamp{inst2->Arg(2)};
const IR::Value segmentation_mask{inst2->Arg(3)};
if (!index.IsImmediate() || !clamp.IsImmediate() || !segmentation_mask.IsImmediate()) {
return;
}
if (clamp.U32() != 3 || segmentation_mask.U32() != 28) {
return;
}
if (swizzle_value == 0x99) { if (swizzle_value == 0x99) {
// DPdxFine // DPdxFine
if (lane_mask == 1) { if (index.U32() == 1) {
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
inst.ReplaceUsesWith(ir.DPdxFine(IR::F32{inst.Arg(1)})); inst.ReplaceUsesWith(ir.DPdxFine(IR::F32{inst.Arg(1)}));
} }
} else if (swizzle_value == 0xA5) { } else if (swizzle_value == 0xA5) {
// DPdyFine // DPdyFine
if (lane_mask == 2) { if (index.U32() == 2) {
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
inst.ReplaceUsesWith(ir.DPdyFine(IR::F32{inst.Arg(1)})); inst.ReplaceUsesWith(ir.DPdyFine(IR::F32{inst.Arg(1)}));
} }
@@ -724,13 +709,6 @@ bool FindGradient3DDerivatives(std::array<IR::Value, 3>& results, IR::Value coor
const auto check_through_shuffle = [](IR::Value input, IR::Value& result) { const auto check_through_shuffle = [](IR::Value input, IR::Value& result) {
const IR::Value value_1{GetThroughCast(input.Resolve(), IR::Opcode::BitCastF32U32)}; const IR::Value value_1{GetThroughCast(input.Resolve(), IR::Opcode::BitCastF32U32)};
IR::Inst* const inst2{value_1.InstRecursive()}; IR::Inst* const inst2{value_1.InstRecursive()};
if (inst2->GetOpcode() == IR::Opcode::QuadBroadcast) {
if (!inst2->Arg(1).Resolve().IsImmediate()) {
return false;
}
result = GetThroughCast(inst2->Arg(0).Resolve(), IR::Opcode::BitCastU32F32);
return true;
}
if (inst2->GetOpcode() != IR::Opcode::ShuffleIndex) { if (inst2->GetOpcode() != IR::Opcode::ShuffleIndex) {
return false; return false;
} }
@@ -1,129 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <boost/container/small_vector.hpp>
#include "shader_recompiler/frontend/ir/ir_emitter.h"
#include "shader_recompiler/host_translate_info.h"
#include "shader_recompiler/ir_opt/passes.h"
namespace Shader::Optimization {
namespace {
constexpr int MAX_BALLOT_DEPTH = 8;
struct SlotAtomic {
IR::Block* block;
IR::Inst* atomic;
IR::Inst* ballot;
};
IR::Inst* FindBallot(const IR::Value& value, int depth) {
if (depth > MAX_BALLOT_DEPTH || value.IsImmediate()) {
return nullptr;
}
IR::Inst* const inst{value.InstRecursive()};
if (inst->GetOpcode() == IR::Opcode::SubgroupBallot) {
return inst;
}
if (inst->GetOpcode() == IR::Opcode::Phi) {
return nullptr;
}
for (size_t index = 0; index < inst->NumArgs(); ++index) {
if (IR::Inst* const ballot{FindBallot(inst->Arg(index), depth + 1)}) {
return ballot;
}
}
return nullptr;
}
bool IsShuffle(IR::Opcode opcode) {
switch (opcode) {
case IR::Opcode::ShuffleIndex:
case IR::Opcode::ShuffleUp:
case IR::Opcode::ShuffleDown:
case IR::Opcode::ShuffleButterfly:
return true;
default:
return false;
}
}
IR::U32 PrimitiveSlot(IR::IREmitter& ir, u32 invocations, const IR::U32& amount) {
IR::U32 key{ir.GetAttributeU32(IR::Attribute::PrimitiveId)};
if (invocations > 1) {
key = ir.IAdd(ir.IMul(key, ir.Imm32(invocations)), ir.InvocationId());
}
return ir.IMul(key, amount);
}
bool MergesAtomic(const IR::Inst& phi, const IR::Block& block, const IR::Inst& atomic) {
for (size_t index = 0; index < phi.NumArgs(); ++index) {
const IR::Value arg{phi.Arg(index)};
if (phi.PhiBlock(index) == &block && !arg.IsImmediate() &&
arg.InstRecursive() == &atomic) {
return true;
}
}
return false;
}
void RewriteMergedSlots(IR::Block& block, IR::Inst& atomic, u32 invocations) {
for (IR::Block* const successor : block.ImmSuccessors()) {
for (IR::Inst& phi : successor->Instructions()) {
if (phi.GetOpcode() != IR::Opcode::Phi || !MergesAtomic(phi, block, atomic)) {
continue;
}
for (size_t index = 0; index < phi.NumArgs(); ++index) {
const IR::Value arg{phi.Arg(index)};
if (arg.IsImmediate() || !IsShuffle(arg.InstRecursive()->GetOpcode())) {
continue;
}
IR::IREmitter ir{*phi.PhiBlock(index)};
const IR::U32 amount{arg.InstRecursive()->Arg(0)};
phi.SetArg(index, PrimitiveSlot(ir, invocations, amount));
}
}
}
}
void RewriteAtomic(IR::Block& block, IR::Inst& atomic, u32 invocations) {
const auto insert_point{IR::Block::InstructionList::s_iterator_to(atomic)};
IR::IREmitter ir{block, insert_point};
const IR::U32 amount{atomic.Arg(2)};
const IR::U32 slot{PrimitiveSlot(ir, invocations, amount)};
block.PrependNewInst(insert_point, IR::Opcode::StorageAtomicUMax32,
{atomic.Arg(0), atomic.Arg(1), ir.IAdd(slot, amount)});
atomic.ReplaceUsesWith(slot);
}
void NeutralizePredicate(IR::Inst& ballot) {
const IR::Value pred{ballot.Arg(0)};
if (!pred.IsImmediate()) {
pred.InstRecursive()->ReplaceUsesWith(IR::Value{true});
}
}
}
void GeometryCompactionPass(IR::Program& program, const HostTranslateInfo& host_info) {
if (program.stage != Stage::Geometry || !host_info.single_lane_geometry_subgroups) {
return;
}
boost::container::small_vector<SlotAtomic, 4> slot_atomics;
for (IR::Block* const block : program.post_order_blocks) {
for (IR::Inst& inst : block->Instructions()) {
if (inst.GetOpcode() != IR::Opcode::StorageAtomicIAdd32) {
continue;
}
if (IR::Inst* const ballot{FindBallot(inst.Arg(2), 0)}) {
slot_atomics.push_back({block, &inst, ballot});
}
}
}
for (const SlotAtomic& slot_atomic : slot_atomics) {
RewriteMergedSlots(*slot_atomic.block, *slot_atomic.atomic, program.invocations);
RewriteAtomic(*slot_atomic.block, *slot_atomic.atomic, program.invocations);
NeutralizePredicate(*slot_atomic.ballot);
}
}
}
-4
View File
@@ -1,6 +1,3 @@
// 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
@@ -19,7 +16,6 @@ void CollectShaderInfoPass(Environment& env, IR::Program& program);
void ConditionalBarrierPass(IR::Program& program); void ConditionalBarrierPass(IR::Program& program);
void ConstantPropagationPass(Environment& env, IR::Program& program); void ConstantPropagationPass(Environment& env, IR::Program& program);
void DeadCodeEliminationPass(IR::Program& program); void DeadCodeEliminationPass(IR::Program& program);
void GeometryCompactionPass(IR::Program& program, const HostTranslateInfo& host_info);
void GlobalMemoryToStorageBufferPass(IR::Program& program, const HostTranslateInfo& host_info); void GlobalMemoryToStorageBufferPass(IR::Program& program, const HostTranslateInfo& host_info);
void IdentityRemovalPass(IR::Program& program); void IdentityRemovalPass(IR::Program& program);
void LowerFp64ToFp32(IR::Program& program); void LowerFp64ToFp32(IR::Program& program);
-3
View File
@@ -40,7 +40,6 @@ struct Profile {
bool support_shader_quad_control{}; bool support_shader_quad_control{};
bool support_quad_shuffles{}; bool support_quad_shuffles{};
bool support_vote{}; bool support_vote{};
bool support_shuffle_relative{};
u32 supported_subgroup_stages{0x7F}; u32 supported_subgroup_stages{0x7F};
bool support_viewport_index_layer_non_geometry{}; bool support_viewport_index_layer_non_geometry{};
bool support_viewport_mask{}; bool support_viewport_mask{};
@@ -103,8 +102,6 @@ struct Profile {
bool ignore_nan_fp_comparisons{}; bool ignore_nan_fp_comparisons{};
/// Some drivers have broken support for OpVectorExtractDynamic on subgroup mask inputs /// Some drivers have broken support for OpVectorExtractDynamic on subgroup mask inputs
bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{}; bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{};
bool has_broken_spirv_subgroup_shuffle{};
u32 max_subgroup_size{};
u32 gl_max_compute_smem_size{}; u32 gl_max_compute_smem_size{};
+3 -15
View File
@@ -226,19 +226,7 @@ struct GPU::Impl {
} }
/// Notify rasterizer that any caches of the specified region should be invalidated /// Notify rasterizer that any caches of the specified region should be invalidated
void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) { void InvalidateRegion(DAddr addr, u64 size) {
if (Settings::values.nce_invalidation_gpu_readback.GetValue()) {
VideoCore::RasterizerInterface* rasterizer = renderer->ReadRasterizer();
if (preserve_gpu_writes && rasterizer->MustFlushRegion(addr, size, VideoCommon::CacheType::BufferCache)) {
const u64 fence = RequestSyncOperation([rasterizer, addr, size] {
rasterizer->FlushRegion(addr, size, VideoCommon::CacheType::BufferCache);
rasterizer->OnCacheInvalidation(addr, size);
});
gpu_thread.TickGPU(is_async);
WaitForSyncOperation(fence);
return;
}
}
gpu_thread.InvalidateRegion(addr, size); gpu_thread.InvalidateRegion(addr, size);
} }
@@ -530,8 +518,8 @@ void GPU::FlushRegion(DAddr addr, u64 size) {
impl->FlushRegion(addr, size); impl->FlushRegion(addr, size);
} }
void GPU::InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) { void GPU::InvalidateRegion(DAddr addr, u64 size) {
impl->InvalidateRegion(addr, size, preserve_gpu_writes); impl->InvalidateRegion(addr, size);
} }
bool GPU::OnCPUWrite(DAddr addr, u64 size) { bool GPU::OnCPUWrite(DAddr addr, u64 size) {
+1 -1
View File
@@ -248,7 +248,7 @@ public:
void FlushRegion(DAddr addr, u64 size); void FlushRegion(DAddr addr, u64 size);
/// Notify rasterizer that any caches of the specified region should be invalidated /// Notify rasterizer that any caches of the specified region should be invalidated
void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes = false); void InvalidateRegion(DAddr addr, u64 size);
/// Notify rasterizer that CPU is trying to write this area. It returns true if the area is /// Notify rasterizer that CPU is trying to write this area. It returns true if the area is
/// sensible, false otherwise, addr and size must be a valid combination /// sensible, false otherwise, addr and size must be a valid combination
@@ -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
@@ -55,7 +55,7 @@ size_t StagingBuffers::RequestBuffer(size_t requested_size) {
} }
StagingBufferAlloc alloc; StagingBufferAlloc alloc;
alloc.buffer.Create(); alloc.buffer.Create();
const auto next_pow2_size = Common::NextPow2(requested_size); const auto next_pow2_size = std::bit_ceil(requested_size);
glNamedBufferStorage(alloc.buffer.handle, next_pow2_size, nullptr, glNamedBufferStorage(alloc.buffer.handle, next_pow2_size, nullptr,
storage_flags | GL_MAP_PERSISTENT_BIT); storage_flags | GL_MAP_PERSISTENT_BIT);
alloc.map = static_cast<u8*>(glMapNamedBufferRange(alloc.buffer.handle, 0, next_pow2_size, alloc.map = static_cast<u8*>(glMapNamedBufferRange(alloc.buffer.handle, 0, next_pow2_size,
@@ -1404,7 +1404,7 @@ void FormatConversionPass::ConvertImage(Image& dst_image, Image& src_image,
const u32 copy_size = region.width * region.height * region.depth * img_bpp; const u32 copy_size = region.width * region.height * region.depth * img_bpp;
if (pbo_size < copy_size) { if (pbo_size < copy_size) {
intermediate_pbo.Create(); intermediate_pbo.Create();
pbo_size = Common::NextPow2(copy_size); pbo_size = std::bit_ceil(copy_size);
glNamedBufferData(intermediate_pbo.handle, pbo_size, nullptr, GL_STREAM_COPY); glNamedBufferData(intermediate_pbo.handle, pbo_size, nullptr, GL_STREAM_COPY);
} }
// Copy from source to PBO // Copy from source to PBO
@@ -362,7 +362,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
const auto subgroup_stage_bit{[subgroup_stages](VkShaderStageFlags flag, Shader::Stage stage) { const auto subgroup_stage_bit{[subgroup_stages](VkShaderStageFlags flag, Shader::Stage stage) {
return (subgroup_stages & flag) != 0 ? (1u << static_cast<u32>(stage)) : 0u; return (subgroup_stages & flag) != 0 ? (1u << static_cast<u32>(stage)) : 0u;
}}; }};
u32 supported_subgroup_stages{ const u32 supported_subgroup_stages{
subgroup_stage_bit(VK_SHADER_STAGE_VERTEX_BIT, Shader::Stage::VertexA) | subgroup_stage_bit(VK_SHADER_STAGE_VERTEX_BIT, Shader::Stage::VertexA) |
subgroup_stage_bit(VK_SHADER_STAGE_VERTEX_BIT, Shader::Stage::VertexB) | subgroup_stage_bit(VK_SHADER_STAGE_VERTEX_BIT, Shader::Stage::VertexB) |
subgroup_stage_bit(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, subgroup_stage_bit(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
@@ -372,9 +372,6 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
subgroup_stage_bit(VK_SHADER_STAGE_GEOMETRY_BIT, Shader::Stage::Geometry) | subgroup_stage_bit(VK_SHADER_STAGE_GEOMETRY_BIT, Shader::Stage::Geometry) |
subgroup_stage_bit(VK_SHADER_STAGE_FRAGMENT_BIT, Shader::Stage::Fragment) | subgroup_stage_bit(VK_SHADER_STAGE_FRAGMENT_BIT, Shader::Stage::Fragment) |
subgroup_stage_bit(VK_SHADER_STAGE_COMPUTE_BIT, Shader::Stage::Compute)}; subgroup_stage_bit(VK_SHADER_STAGE_COMPUTE_BIT, Shader::Stage::Compute)};
if (driver_id == VK_DRIVER_ID_MESA_TURNIP) {
supported_subgroup_stages &= ~(1u << static_cast<u32>(Shader::Stage::Geometry));
}
profile = Shader::Profile{ profile = Shader::Profile{
.supported_spirv = device.SupportedSpirvVersion(), .supported_spirv = device.SupportedSpirvVersion(),
.unified_descriptor_binding = true, .unified_descriptor_binding = true,
@@ -412,8 +409,6 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
.support_shader_quad_control = device.IsKhrShaderQuadControlSupported(), .support_shader_quad_control = device.IsKhrShaderQuadControlSupported(),
.support_quad_shuffles = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_QUAD_BIT), .support_quad_shuffles = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_QUAD_BIT),
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT), .support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
.support_shuffle_relative =
device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT),
.supported_subgroup_stages = supported_subgroup_stages, .supported_subgroup_stages = supported_subgroup_stages,
.support_viewport_index_layer_non_geometry = .support_viewport_index_layer_non_geometry =
device.IsExtShaderViewportIndexLayerSupported(), device.IsExtShaderViewportIndexLayerSupported(),
@@ -449,17 +444,13 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA, driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA,
.has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS,
.has_broken_spirv_position_input = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY, .has_broken_spirv_position_input = driver_id == false,
.has_broken_unsigned_image_offsets = false, .has_broken_unsigned_image_offsets = false,
.has_broken_signed_operations = false, .has_broken_signed_operations = false,
.has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY, .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,
.has_broken_fp32_denorm_flush = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY, .has_broken_fp32_denorm_flush = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
.ignore_nan_fp_comparisons = false, .ignore_nan_fp_comparisons = false,
.has_broken_spirv_subgroup_mask_vector_extract_dynamic = .has_broken_spirv_subgroup_mask_vector_extract_dynamic = false,
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY &&
device.GetDriverVersion() < VK_MAKE_VERSION(512, 672, 0),
.has_broken_spirv_subgroup_shuffle = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
.max_subgroup_size = device.GetMaxSubgroupSize(),
.has_broken_robust = .has_broken_robust =
device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal, device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal,
.min_ssbo_alignment = device.GetStorageBufferAlignment(), .min_ssbo_alignment = device.GetStorageBufferAlignment(),
@@ -486,10 +477,8 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
driver_id == VK_DRIVER_ID_SAMSUNG_PROPRIETARY, driver_id == VK_DRIVER_ID_SAMSUNG_PROPRIETARY,
.support_snorm_render_buffer = true, .support_snorm_render_buffer = true,
.support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(), .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(),
.support_viewport_mask = device.IsNvViewportArray2Supported(),
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
.support_conditional_barrier = device.SupportsConditionalBarriers(), .support_conditional_barrier = device.SupportsConditionalBarriers(),
.single_lane_geometry_subgroups = !profile.SupportsSubgroupStage(Shader::Stage::Geometry),
}; };
host_info.ApplyDescriptorLimitPolicy(); host_info.ApplyDescriptorLimitPolicy();
@@ -1011,7 +1011,7 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
if (buffers[level]) { if (buffers[level]) {
return *buffers[level]; return *buffers[level];
} }
const auto new_size = Common::NextPow2(needed_size); const auto new_size = std::bit_ceil(needed_size);
static constexpr VkBufferUsageFlags flags = static constexpr VkBufferUsageFlags flags =
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+1 -1
View File
@@ -2190,7 +2190,7 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) {
image.flags &= ~ImageFlagBits::BadOverlap; image.flags &= ~ImageFlagBits::BadOverlap;
lru_cache.Free(image.lru_index); lru_cache.Free(image.lru_index);
const auto& clear_page_table = const auto& clear_page_table =
[image_id](u64 page, ::Common::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>& selected_page_table) { [image_id](u64 page, ::Common::unordered_map<u64, std::vector<ImageId>>& selected_page_table) {
const auto page_it = selected_page_table.find(page); const auto page_it = selected_page_table.find(page);
if (page_it == selected_page_table.end()) { if (page_it == selected_page_table.end()) {
ASSERT_MSG(false, "Unregistering unregistered page={:#x}", page << YUZU_PAGEBITS); ASSERT_MSG(false, "Unregistering unregistered page={:#x}", page << YUZU_PAGEBITS);
@@ -22,7 +22,6 @@
#include <queue> #include <queue>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/hash.h"
#include "common/literals.h" #include "common/literals.h"
#include "common/lru_cache.h" #include "common/lru_cache.h"
#include <ranges> #include <ranges>
@@ -69,7 +68,7 @@ struct AsyncDecodeContext {
std::atomic_bool complete; std::atomic_bool complete;
}; };
using TextureCacheGPUMap = ::Common::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>>; using TextureCacheGPUMap = ::Common::unordered_map<u64, std::vector<ImageId>>;
class TextureCacheChannelInfo : public ChannelInfo { class TextureCacheChannelInfo : public ChannelInfo {
public: public:
@@ -443,7 +442,7 @@ private:
u64 last_framebuffer_serial = 0; u64 last_framebuffer_serial = 0;
::Common::unordered_map<RenderTargets, FramebufferId> framebuffers; ::Common::unordered_map<RenderTargets, FramebufferId> framebuffers;
::Common::unordered_map<u64, std::vector<ImageMapId>, Common::IdentityHash<u64>> page_table; ::Common::unordered_map<u64, std::vector<ImageMapId>> page_table;
::Common::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views; ::Common::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views;
DAddr virtual_invalid_space{}; DAddr virtual_invalid_space{};
@@ -483,11 +483,6 @@ FN_MAX_LIMIT_LIST
return properties.subgroup_properties.supportedStages; return properties.subgroup_properties.supportedStages;
} }
u32 GetMaxSubgroupSize() const {
return (std::max)(properties.subgroup_properties.subgroupSize,
properties.subgroup_size_control.maxSubgroupSize);
}
/// Returns the maximum number of push descriptors. /// Returns the maximum number of push descriptors.
u32 MaxPushDescriptors() const { u32 MaxPushDescriptors() const {
return properties.push_descriptor.maxPushDescriptors; return properties.push_descriptor.maxPushDescriptors;
+1 -3
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project // SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,6 +8,7 @@
class QCheckBox; class QCheckBox;
class QLineEdit; class QLineEdit;
class QComboBox;
class QDateTimeEdit; class QDateTimeEdit;
namespace Core { namespace Core {
class System; class System;
+4 -8
View File
@@ -140,12 +140,7 @@ QWidget* Widget::CreateCombobox(std::function<std::string()>& serializer,
if (combobox_enumerations.contains(type)) { if (combobox_enumerations.contains(type)) {
enumeration = &combobox_enumerations.at(type); enumeration = &combobox_enumerations.at(type);
for (const auto& [id, name] : *enumeration) { for (const auto& [id, name] : *enumeration) {
if (type == Settings::EnumMetadata<Settings::AppletMode>::Index() && combobox->addItem(name);
id == static_cast<u32>(Settings::AppletMode::Disabled) &&
setting.Id() != Settings::values.controller_applet_mode.Id()) {
continue;
}
combobox->addItem(name, id);
} }
} else { } else {
return combobox; return combobox;
@@ -163,8 +158,9 @@ QWidget* Widget::CreateCombobox(std::function<std::string()>& serializer,
const u32 setting_value = std::strtoul(setting.ToString().c_str(), nullptr, 0); const u32 setting_value = std::strtoul(setting.ToString().c_str(), nullptr, 0);
combobox->setCurrentIndex(find_index(setting_value)); combobox->setCurrentIndex(find_index(setting_value));
serializer = [this]() { serializer = [this, enumeration]() {
return std::to_string(combobox->currentData().toUInt()); int current = combobox->currentIndex();
return std::to_string(enumeration->at(current).first);
}; };
restore_func = [this, find_index]() { restore_func = [this, find_index]() {
+11 -15
View File
@@ -12,29 +12,25 @@ namespace Yuzu {
inline bool ContainsAllWords(const QString& haystack, const QString& userinput) { inline bool ContainsAllWords(const QString& haystack, const QString& userinput) {
const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts); const QStringList userinput_split = userinput.split(QLatin1Char{' '}, Qt::SkipEmptyParts);
return std::all_of(userinput_split.begin(), userinput_split.end(), [&haystack](const QString& s) { return std::all_of(userinput_split.begin(), userinput_split.end(),
return haystack.contains(s); [&haystack](const QString& s) { return haystack.contains(s); });
});
} }
inline bool FilterMatches(const QString& filter, const QStandardItem* item) { inline bool FilterMatches(const QString& filter, const QStandardItem* item) {
if (filter.isEmpty()) if (filter.isEmpty())
return true; return true;
auto const sluggify = [](const QString& s) {
QString o(s.normalized(QString::NormalizationForm_D).toLower());
return o.replace(QRegularExpression(QStringLiteral("[^a-z\\s]")), QStringLiteral(""));
};
const auto norm_filter = sluggify(filter);
const auto program_id = item->data(GameListItemPath::ProgramIdRole).toULongLong(); const auto program_id = item->data(GameListItemPath::ProgramIdRole).toULongLong();
const QString file_path = sluggify(item->data(GameListItemPath::FullPathRole).toString());
const QString file_title = sluggify(item->data(GameListItemPath::TitleRole).toString()); const QString file_path = item->data(GameListItemPath::FullPathRole).toString().toLower();
const QString file_title = item->data(GameListItemPath::TitleRole).toString().toLower();
const QString file_program_id = QStringLiteral("%1").arg(program_id, 16, 16, QLatin1Char{'0'}); const QString file_program_id = QStringLiteral("%1").arg(program_id, 16, 16, QLatin1Char{'0'});
const QString file_name = sluggify(file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} + file_title);
return (ContainsAllWords(file_name, norm_filter) const QString file_name =
|| ContainsAllWords(file_title, norm_filter)) file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} + file_title;
|| (file_program_id.size() == 16 && file_program_id.contains(norm_filter));
return Yuzu::ContainsAllWords(file_name, filter) ||
(file_program_id.size() == 16 && file_program_id.contains(filter));
} }
} // namespace Yuzu } // namespace Yuzu
+1 -1
View File
@@ -1786,7 +1786,7 @@ bool MainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPar
QtCommon::system->SetFrontendAppletSet({ QtCommon::system->SetFrontendAppletSet({
std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings
(Settings::values.controller_applet_mode.GetValue() == Settings::AppletMode::Disabled) (UISettings::values.controller_applet_disabled.GetValue() == true)
? nullptr ? nullptr
: std::make_unique<QtControllerSelector>(*this), // Controller Selector : std::make_unique<QtControllerSelector>(*this), // Controller Selector
std::make_unique<QtErrorDisplay>(*this), // Error Display std::make_unique<QtErrorDisplay>(*this), // Error Display