From 797b6ca8fef00f5cb17e67eda82008df7806d16a Mon Sep 17 00:00:00 2001 From: Aleksandr Popovich Date: Thu, 3 Jul 2025 12:22:16 -0400 Subject: [PATCH 01/20] [android] Snapdragon 865 patches - fixes vram usage, textures and vulkan memory Signed-off-by: Aleksandr Popovich --- src/common/microprofile.h | 17 +++++++++++++++-- src/core/arm/nce/arm_nce.cpp | 2 +- src/core/hle/service/sockets/sfdnsres.cpp | 15 ++++++++++++--- .../maxwell/translate/impl/warp_shuffle.cpp | 17 ++++++++++++++++- src/video_core/buffer_cache/buffer_cache.h | 10 ++++++++-- .../buffer_cache/buffer_cache_base.h | 18 +++++++++++++++++- src/video_core/host1x/host1x.cpp | 2 ++ src/video_core/host1x/host1x.h | 2 ++ .../texture_cache/texture_cache_base.h | 11 +++++++++++ .../vulkan_common/vulkan_memory_allocator.cpp | 5 ++++- 10 files changed, 88 insertions(+), 11 deletions(-) diff --git a/src/common/microprofile.h b/src/common/microprofile.h index 56ef0a2dcf..5d4c54852f 100644 --- a/src/common/microprofile.h +++ b/src/common/microprofile.h @@ -3,9 +3,16 @@ #pragma once -// Uncomment this to disable microprofile. This will get you cleaner profiles when using +// Use this to disable microprofile. This will get you cleaner profiles when using // external sampling profilers like "Very Sleepy", and will improve performance somewhat. -// #define MICROPROFILE_ENABLED 0 +#ifdef ANDROID +#define MICROPROFILE_ENABLED 0 +#define MICROPROFILEUI_ENABLED 0 +#define MicroProfileOnThreadExit() do{}while(0) +#define MICROPROFILE_TOKEN(x) 0 +#define MicroProfileEnter(x) 0 +#define MicroProfileLeave(x, y) ignore_all(x, y) +#endif // Customized Citra settings. // This file wraps the MicroProfile header so that these are consistent everywhere. @@ -19,6 +26,12 @@ typedef void* HANDLE; #endif +#include +template +void ignore_all(Args&&... args) { + (static_cast(std::ignore = args), ...); +} + #include #define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0) diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index 877e8ac3c7..0e0d72fc8a 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp @@ -227,7 +227,7 @@ HaltReason ArmNce::RunThread(Kernel::KThread* thread) { if (auto it = post_handlers.find(m_guest_ctx.pc); it != post_handlers.end()) { hr = ReturnToRunCodeByTrampoline(thread_params, &m_guest_ctx, it->second); } else { - hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); + hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); // Android: Use "process handle SIGUSR2 -n true -p true -s false" (and SIGURG) in LLDB when debugging } // Critical section for thread cleanup diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index b07bd3e58e..d9f01a65b8 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -53,6 +53,16 @@ enum class NetDbError : s32 { NoData = 4, }; +const std::vector blockedDomains = {"srv.nintendo.net", "battle.net", + "microsoft.com", "mojang.com", + "xboxlive.com", "minecraftservices.com"}; + +static bool IsBlockedHost(const std::string& host) { + return std::any_of( + blockedDomains.begin(), blockedDomains.end(), + [&host](const std::string& domain) { return host.find(domain) != std::string::npos; }); +} + static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) { // These combinations have been verified on console (but are not // exhaustive). @@ -154,7 +164,7 @@ static std::pair GetHostByNameRequestImpl(HLERequestConte // For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions. // Prevent resolution of Nintendo servers - if (host.find("srv.nintendo.net") != std::string::npos) { + if (IsBlockedHost(host)) { LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host); return {0, GetAddrInfoError::AGAIN}; } @@ -271,7 +281,7 @@ static std::pair GetAddrInfoRequestImpl(HLERequestContext const std::string host = Common::StringFromBuffer(host_buffer); // Prevent resolution of Nintendo servers - if (host.find("srv.nintendo.net") != std::string::npos) { + if (IsBlockedHost(host)) { LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host); return {0, GetAddrInfoError::AGAIN}; } @@ -359,5 +369,4 @@ void SFDNSRES::ResolverSetOptionRequest(HLERequestContext& ctx) { rb.Push(ResultSuccess); rb.Push(0); // bsd errno } - } // namespace Service::Sockets diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp index 972eec8276..b904821619 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp @@ -7,6 +7,7 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" +#include namespace Shader::Maxwell { namespace { @@ -36,6 +37,17 @@ enum class ShuffleMode : u64 { } } +bool IsKONA() { + std::ifstream machineFile("/sys/devices/soc0/machine"); + if (machineFile.is_open()) { + std::string line; + std::getline(machineFile, line); + if (line == "KONA") + return true; + } + return false; +} + void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32& mask) { union { u64 insn; @@ -47,7 +59,10 @@ void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32 const IR::U32 result{ShuffleOperation(v.ir, v.X(shfl.src_reg), index, mask, shfl.mode)}; v.ir.SetPred(shfl.pred, v.ir.GetInBoundsFromOp(result)); - v.X(shfl.dest_reg, result); + if (IsKONA()) + v.X(shfl.dest_reg, v.ir.Imm32(0xffffffff)); // This fixes the freeze for Retroid / Snapdragon SD865 + else + v.X(shfl.dest_reg, result); } } // Anonymous namespace diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 0ce2abc627..e134e26e66 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -26,7 +26,9 @@ BufferCache

::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, R void(slot_buffers.insert(runtime, NullBufferParams{})); gpu_modified_ranges.Clear(); inline_buffer_id = NULL_BUFFER_ID; - +#ifdef ANDROID + immediately_free = (Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Aggressive); +#endif if (!runtime.CanReportMemoryUsage()) { minimum_memory = DEFAULT_EXPECTED_MEMORY; critical_memory = DEFAULT_CRITICAL_MEMORY; @@ -1383,6 +1385,8 @@ void BufferCache

::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, }); new_buffer.MarkUsage(copies[0].dst_offset, copies[0].size); runtime.CopyBuffer(new_buffer, overlap, copies, true); + if (immediately_free) + runtime.Finish(); DeleteBuffer(overlap_id, true); } @@ -1674,7 +1678,9 @@ void BufferCache

::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { } Unregister(buffer_id); - delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id])); + + if (!do_not_mark || !immediately_free) + delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id])); slot_buffers.erase(buffer_id); if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index d45f595ea8..dbe44c875f 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -159,7 +159,11 @@ template class BufferCache : public VideoCommon::ChannelSetupCaches { // Page size for caching purposes. // This is unrelated to the CPU page size and it can be changed as it seems optimal. +#ifdef ANDROID + static constexpr u32 CACHING_PAGEBITS = 12; +#else static constexpr u32 CACHING_PAGEBITS = 16; +#endif static constexpr u64 CACHING_PAGESIZE = u64{1} << CACHING_PAGEBITS; static constexpr bool IS_OPENGL = P::IS_OPENGL; @@ -173,9 +177,15 @@ class BufferCache : public VideoCommon::ChannelSetupCaches slot_buffers; - DelayedDestructionRing delayed_destruction_ring; +#ifdef ANDROID + static constexpr size_t TICKS_TO_DESTROY = 6; +#else + static constexpr size_t TICKS_TO_DESTROY = 8; +#endif + DelayedDestructionRing delayed_destruction_ring; const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{}; @@ -483,6 +498,7 @@ private: u64 minimum_memory = 0; u64 critical_memory = 0; BufferId inline_buffer_id; + bool immediately_free = false; std::array> CACHING_PAGEBITS)> page_table; Common::ScratchBuffer tmp_buffer; diff --git a/src/video_core/host1x/host1x.cpp b/src/video_core/host1x/host1x.cpp index 293bca6d79..6256cd8af2 100644 --- a/src/video_core/host1x/host1x.cpp +++ b/src/video_core/host1x/host1x.cpp @@ -18,9 +18,11 @@ Host1x::~Host1x() = default; void Host1x::StartDevice(s32 fd, ChannelType type, u32 syncpt) { switch (type) { case ChannelType::NvDec: + std::call_once(nvdec_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer devices[fd] = std::make_unique(*this, fd, syncpt, frame_queue); break; case ChannelType::VIC: + std::call_once(vic_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer devices[fd] = std::make_unique(*this, fd, syncpt, frame_queue); break; default: diff --git a/src/video_core/host1x/host1x.h b/src/video_core/host1x/host1x.h index 8debac93dd..bddb489438 100644 --- a/src/video_core/host1x/host1x.h +++ b/src/video_core/host1x/host1x.h @@ -201,6 +201,8 @@ private: std::unique_ptr> allocator; FrameQueue frame_queue; std::unordered_map> devices; + std::once_flag nvdec_first_init; + std::once_flag vic_first_init; }; } // namespace Tegra::Host1x diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index cbc27344b0..3f67828b86 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -110,10 +110,17 @@ class TextureCache : public VideoCommon::ChannelSetupCaches::max()}; + #ifdef ANDROID + static constexpr s64 TARGET_THRESHOLD = 3_GiB; + static constexpr s64 DEFAULT_EXPECTED_MEMORY = 1_GiB + 125_MiB; + static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB + 625_MiB; + static constexpr size_t GC_EMERGENCY_COUNTS = 2; + #else static constexpr s64 TARGET_THRESHOLD = 4_GiB; static constexpr s64 DEFAULT_EXPECTED_MEMORY = 1_GiB + 125_MiB; static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB + 625_MiB; static constexpr size_t GC_EMERGENCY_COUNTS = 2; + #endif using Runtime = typename P::Runtime; using Image = typename P::Image; @@ -479,7 +486,11 @@ private: }; Common::LeastRecentlyUsedCache lru_cache; + #ifdef ANDROID + static constexpr size_t TICKS_TO_DESTROY = 6; + #else static constexpr size_t TICKS_TO_DESTROY = 8; +#endif DelayedDestructionRing sentenced_images; DelayedDestructionRing sentenced_image_view; DelayedDestructionRing sentenced_framebuffers; diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index e80808621b..04b362f9b0 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -271,7 +271,10 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsa VmaAllocation allocation{}; VkMemoryPropertyFlags property_flags{}; - vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info)); + VkResult result = vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info); + if (result == VK_ERROR_OUT_OF_DEVICE_MEMORY) { + LOG_ERROR(Render_Vulkan, "Out of memory creating buffer (size: {})", ci.size); + } vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags); u8* data = reinterpret_cast(alloc_info.pMappedData); -- 2.39.5 From 5d4c6e085d04fd8ecf31613af757841913f3f3cb Mon Sep 17 00:00:00 2001 From: PavelBARABANOV Date: Thu, 3 Jul 2025 16:35:02 +0000 Subject: [PATCH 02/20] [vk, frontend] RAII Toggle (#247) Co-authored-by: Pavel Barabanov Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/247 --- .../features/settings/model/BooleanSetting.kt | 5 +- .../settings/model/view/SettingsItem.kt | 8 +- .../settings/ui/SettingsFragmentPresenter.kt | 1 + .../app/src/main/res/values-ar/strings.xml | 27 ++++- .../app/src/main/res/values-ckb/strings.xml | 27 ++++- .../app/src/main/res/values-cs/strings.xml | 27 ++++- .../app/src/main/res/values-de/strings.xml | 26 ++++- .../app/src/main/res/values-es/strings.xml | 26 ++++- .../app/src/main/res/values-fa/strings.xml | 84 ++++++++++----- .../app/src/main/res/values-fr/strings.xml | 26 ++++- .../app/src/main/res/values-he/strings.xml | 26 ++++- .../app/src/main/res/values-hu/strings.xml | 26 ++++- .../app/src/main/res/values-id/strings.xml | 100 ++++++++++++------ .../app/src/main/res/values-it/strings.xml | 26 ++++- .../app/src/main/res/values-ja/strings.xml | 26 ++++- .../app/src/main/res/values-ko/strings.xml | 26 ++++- .../app/src/main/res/values-nb/strings.xml | 26 ++++- .../app/src/main/res/values-pl/strings.xml | 26 ++++- .../src/main/res/values-pt-rBR/strings.xml | 26 ++++- .../src/main/res/values-pt-rPT/strings.xml | 26 ++++- .../app/src/main/res/values-ru/strings.xml | 27 ++++- .../app/src/main/res/values-sr/strings.xml | 34 ++++++ .../app/src/main/res/values-uk/strings.xml | 32 +++++- .../app/src/main/res/values-vi/strings.xml | 26 ++++- .../src/main/res/values-zh-rCN/strings.xml | 26 ++++- .../src/main/res/values-zh-rTW/strings.xml | 26 ++++- .../app/src/main/res/values/strings.xml | 2 + src/common/settings.h | 3 +- .../renderer_vulkan/renderer_vulkan.cpp | 46 ++++---- src/yuzu/configuration/shared_translation.cpp | 6 ++ 30 files changed, 708 insertions(+), 111 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index cdfbe88152..21dc51513d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -46,6 +46,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { SOC_OVERLAY_BACKGROUND("soc_overlay_background"), + ENABLE_RAII("enable_raii"), FRAME_INTERPOLATION("frame_interpolation"), // FRAME_SKIPPING("frame_skipping"), @@ -60,7 +61,9 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { SHOW_SHADERS_BUILDING("show_shaders_building"), DEBUG_FLUSH_BY_LINE("flush_lines"), USE_LRU_CACHE("use_lru_cache"),; -// external fun isFrameSkippingEnabled(): Boolean + + external fun isRaiiEnabled(): Boolean +// external fun isFrameSkippingEnabled(): Boolean external fun isFrameInterpolationEnabled(): Boolean diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 91675414a2..6ec678717b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -220,7 +220,13 @@ abstract class SettingsItem( override fun reset() = BooleanSetting.USE_DOCKED_MODE.reset() } - + put( + SwitchSetting( + BooleanSetting.ENABLE_RAII, + titleId = R.string.enable_raii, + descriptionId = R.string.enable_raii_description + ) + ) put( SwitchSetting( BooleanSetting.FRAME_INTERPOLATION, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index b09a611506..a6110a354a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -446,6 +446,7 @@ class SettingsFragmentPresenter( add(BooleanSetting.RENDERER_SAMPLE_SHADING.key) add(HeaderSetting(R.string.veil_renderer)) + add(BooleanSetting.ENABLE_RAII.key) add(BooleanSetting.FRAME_INTERPOLATION.key) add(BooleanSetting.RENDERER_FAST_GPU.key) add(IntSetting.FAST_GPU_TIME.key) diff --git a/src/android/app/src/main/res/values-ar/strings.xml b/src/android/app/src/main/res/values-ar/strings.xml index 075479286e..fba704d516 100644 --- a/src/android/app/src/main/res/values-ar/strings.xml +++ b/src/android/app/src/main/res/values-ar/strings.xml @@ -54,10 +54,14 @@ عرض طراز GPU المضيف عرض طراز SoC عرض طراز SoC المضيف + إظهار إصدار البرنامج الثابت + عرض إصدار البرنامج الثابت المثبت امتدادات GPU العارض + RAII + طريقة لإدارة الموارد تلقائيًا في فولكان تضمن الإفراج الصحيح عن الموارد عندما لا تكون هناك حاجة إليها، ولكن قد تسبب تعطل الألعاب المجمعة. متنوع حجاب عدن إعدادات تجريبية لتحسين الأداء والقدرة. قد تسبب هذه الإعدادات شاشات سوداء أو مشاكل أخرى في اللعبة. @@ -93,6 +97,11 @@ استخدم Boost (1700MHz) للتشغيل بأعلى سرعة أصلية لـ Switch، أو Fast (2000MHz) للتشغيل بضعف السرعة. تخطيط الذاكرة (تجريبي) تغيير تخطيط الذاكرة المحاكاة. هذا الإعداد لن يزيد الأداء، ولكن قد يساعد في الألعاب التي تستخدم دقة عالية عبر التعديلات. لا تستخدم على الهواتف التي تحتوي على 8 جيجابايت من الذاكرة العشوائية أو أقل. + تظليل العينة + يسمح لمُظلل الأجزاء بالتنفيذ لكل عينة في جزء متعدد العينات بدلاً من مرة واحدة لكل جزء. يحسن جودة الرسومات على حساب بعض الأداء. تدعم فقط أجهزة Vulkan 1.1+ هذا الامتداد. + تخصيص دورات المعالج + تعيين قيمة مخصصة لدورات المعالج. القيم الأعلى قد تزيد الأداء، ولكن قد تتسبب أيضًا في تجمد اللعبة. يوصى بنطاق 77-21000. + دورات 4 جيجابايت (موصى به) @@ -238,12 +247,17 @@ يجب أن يكون بين 3 و20 حرفًا مطلوب تنسيق IP غير صالح - يجب أن يكون 5 أحرف على الأقل + يجب أن يكون بين 4-20 حرفًا يجب أن يكون بين 1 و65535 + يجب أن يتكون من 48 حرفًا، وأحرف صغيرة من a-z فقط + نوع الغرفة + عام + غير مدرج إلغاء موافق تحديث قائمة الغرف + مطلوب رمز ويب، انتقل إلى الإعدادات المتقدمة -> النظام -> الشبكة لون السمة @@ -279,6 +293,7 @@ أبجدي قائمة شبكة + عرض دائري مجلد برنامج أولي تحذير: هذا الإصدار غير مكتمل وقد يحتوي على أخطاء @@ -429,11 +444,17 @@ تعيين ساعة مخصصة في الوقت الحقيقي + توليد + اسم مستخدم الويب + اسم المستخدم الذي سيظهر في غرف اللعب الجماعي. يجب أن يكون بين 4-20 حرفًا. رمز الويب رمز الويب المستخدم لإنشاء غرف عامة. وهو سلسلة من 48 حرفًا تحتوي فقط على أحرف صغيرة من a-z. الشبكة + الخلفية + العرض + المعالجة اللاحقة مستوى الدقة (Handheld/Docked) الدقة VSync وضع @@ -445,6 +466,7 @@ استخدم التنظيف التفاعلي تحسين دقة العرض في بعض الألعاب على حساب الأداء يقلل من التأتأة عن طريق تخزين وتحميل التظليلات التي تم إنشاؤها محليًا. + وحدة المعالج المركزية تصحيح أخطاء وحدة المعالجة المركزية @@ -750,6 +772,9 @@ لوحة المفاتيح البرمجية + وضع الطيران + يمرر وضع الطيران إلى نظام التشغيل Switch + التراخيص AMD ترقية عالية الجودة من diff --git a/src/android/app/src/main/res/values-ckb/strings.xml b/src/android/app/src/main/res/values-ckb/strings.xml index cbe3aaa7cb..014e6f724a 100644 --- a/src/android/app/src/main/res/values-ckb/strings.xml +++ b/src/android/app/src/main/res/values-ckb/strings.xml @@ -55,10 +55,14 @@ نیشاندانی مۆدێلی GPUی میواندار نیشاندانی مۆدێلی SoC نیشاندانی مۆدێلی SoCی میواندار + نیشاندانی وەشانی فریموێر + وەشانی فریموێری نەصبکراو پیشان بدە پاشکۆکانی GPU رێندرەر + RAII + ڕێگایەکی بەڕێوەبردنی سەرچاوەکان بە خۆکار لە ڤولکان کە دڵنیای دەکاتەوە لە ئازادکردنی گونجاوی سەرچاوەکان کاتێک کە چیتر پێویستیان نییە، بەڵام لەوانەیە ببێتە هۆی کەوتنی یارییە کۆکراوەکان. جۆراوجۆر حجاب عدن ڕێکخستنە تاقیکارییەکان بۆ باشترکردنی کارایی و توانا. ئەم ڕێکخستنانە لەوانەیە ببێتە هۆی شاشە ڕەشەکان یان کێشەیتری یاری. @@ -97,6 +101,12 @@ Boost (1700MHz) بەکاربهێنە بۆ کارکردن بە بەرزترین کاتژمێری نەیتیڤی سوویچ، یان Fast (2000MHz) بۆ کارکردن بە دوو هێندەی کاتژمێر. ڕێکخستنی بیرگە (تاقیکاری) گۆڕینی ڕێکخستنی بیرگەی شبیهسازیکراو. ئەم ڕێکخستنە کارایی زیاد ناکات، بەڵام لەوانەیە یارمەتی یارییەکان بدات کە بەرزی ڕێزۆلۆشن بەکاردهێنن بە هۆی مۆدەکان. لەسەر مۆبایلەکانی کە 8GB یان کەمتر RAMیان هەیە بەکارمەهێنە. + سێبەندی نمونە + ڕێگە بە شێدەری پارچە دەدات کە بۆ هەر نمونەیەک لە پارچەی فرە نمونەیدا جێبەجێ بکات لە جیاتی جێبەجێکردنی بۆ هەر پارچەیەک. جۆرایی گرافیک باشتر دەکات بە بەهای هەندێک لە کارایی. تەنها ئامێرەکانی Vulkan 1.1+ پشتگیری ئەم درێژکراوە دەکەن. + تیکی CPU هەڵبژێردراو + بەهای هەڵبژێردراوی تیکی CPU دابنێ. بەهای زیاتر دەتوانن کارایی زیاد بکەن، بەڵام لەوانەیە بووەستانی یاریش دروست بکەن. ئامۆژگاری بە نێوان 77-21000 دەکرێت. + تیک + 4GB (پێشنیارکراو) 6GB (نائاسایش) 8GB (نائاسایش) @@ -234,12 +244,17 @@ دەبێت لە نێوان 3 بۆ 20 پیت بێت پێویستە فۆرماتی IP نادروستە - دەبێت لانیکەم 5 پیت بێت + دەبێت لە نێوان 4-20 پیتدا بێت دەبێت لە نێوان 1 بۆ 65535 بێت + دەبێت 48 پیت بێت، و تەنها پیتی بچووکی a-z + جۆری لۆبی + گشتی + نەناسراو پاشگەزبوونەوە باشە نوێکردنەوە لیستی ژوورەکان + تۆکنی وێب پێویستە، بڕۆ بۆ ڕێکخستنە پێشکەوتووەکان -> سیستەم -> تۆڕ ڕەنگی پۆل @@ -273,6 +288,7 @@ پێنووس لیست تۆڕ + کارۆسێل فۆڵدەر نەرمەکاڵای پێش-ئەلفا "ئاگاداری: ئەم وەشانە بۆ بڵاوکردنەوە یان پیشاندانی گشتی نییە. ئەم نەرمەکاڵایە لە قۆناغی پێش-ئەلفادایە و لەوانەیە هەڵەی تێدا بێت." @@ -397,11 +413,17 @@ دانانی RTCی تایبەتمەند + بەرهەم هێنان + ناوی بەکارهێنەری وێب + ناوی بەکارهێنەر کە لە لۆبی یاری فرە یاریکەردا دەر دەکەوێت. دەبێت 4-20 پیت بێت. نیشانەی وێب نیشانەی وێب بۆ دروستکردنی ژوورە گشتییەکان. زنجیرەیەکی 48 پیتییە تەنها پیتی a-z بچووک لەخۆدەگرێت. تۆڕ + پاشبنەما + پیشاندان + پاشپڕۆسەکردن ئاستی وردبینی ڕوونی (دۆخی دەستی/دۆخی دۆک) دۆخی VSync @@ -706,6 +728,9 @@ کلیلەبۆردی نەرمەکاڵا + دۆخی فڕۆکە + دۆخی فڕۆکە بۆ سیستەمی کارپێکەری Switch دەگوازێتەوە + مۆڵەتەکان بەرزکردنەوەی کوالێتی بەرز لە کۆمپانیای AMD diff --git a/src/android/app/src/main/res/values-cs/strings.xml b/src/android/app/src/main/res/values-cs/strings.xml index da044122a3..27e2bd5c6b 100644 --- a/src/android/app/src/main/res/values-cs/strings.xml +++ b/src/android/app/src/main/res/values-cs/strings.xml @@ -54,10 +54,14 @@ Zobrazit model hostitelské GPU Zobrazit model SoC Zobrazit model hostitelského SoC + Zobrazit verzi firmwaru + Zobrazí nainstalovanou verzi firmwaru Rozšíření GPU Renderer + RAII + Metoda automatické správy prostředků ve Vulkanu, která zajišťuje správné uvolnění prostředků, když již nejsou potřeba, ale může způsobit pády v balených hrách. Různé Edenův závoj Experimentální nastavení pro zlepšení výkonu a schopností. Tato nastavení mohou způsobit černé obrazovky nebo další herní problémy. @@ -96,6 +100,12 @@ Použijte Boost (1700MHz) pro běh na nejvyšším nativním taktu Switch nebo Fast (2000MHz) pro běh na dvojnásobném taktu. Rozložení paměti (EXPERIMENTÁLNÍ) Změna emulovaného rozložení paměti. Toto nastavení nezvyšuje výkon, ale může pomoci hrám využívajícím vysoké rozlišení pomocí modů. Nepoužívejte na telefonech s 8GB RAM nebo méně. + Vzorkovací stínování + Umožňuje fragment shaderu provádět výpočty pro každý vzorek ve fragmentu s více vzorky namísto jednou pro fragment. Zlepšuje kvalitu grafiky na úkor výkonu. Tuto funkci podporují pouze zařízení s Vulkan 1.1+. + Vlastní CPU takty + Nastavte vlastní hodnotu CPU taktů. Vyšší hodnoty mohou zvýšit výkon, ale mohou také způsobit zamrznutí hry. Doporučuje se rozsah 77–21000. + Takty + 4GB (Doporučeno) 6GB (Nebezpečné) 8GB (Nebezpečné) @@ -233,12 +243,17 @@ Musí mít 3 až 20 znaků Povinné Neplatný formát IP - Musí mít alespoň 5 znaků + Musí mít 4–20 znaků Musí být mezi 1 a 65535 + Musí mít 48 znaků a pouze malá písmena a-z + Typ místnosti + Veřejné + Neveřejné Zrušit OK Obnovit Seznam místností + Vyžadován webový token, přejděte do Pokročilá nastavení -> Systém -> Síť Barva motivu @@ -270,6 +285,7 @@ Abecedně Seznam Mřížka + Kolotoč Složka Předběžná verze Varování: Tato verze není určena pro veřejnost. Může obsahovat chyby. @@ -392,11 +408,17 @@ Nastavit vlastní RTC + Generovat + Webové uživatelské jméno + Uživatelské jméno zobrazené v multiplayerových místnostech. Musí mít 4–20 znaků. Webový token Webový token používaný k vytváření veřejných místností. Jedná se o řetězec o délce 48 znaků obsahující pouze malá písmena a-z. Síť + Backend + Zobrazení + Postprocesing Úroveň přesnosti Rozlišení (Handheld/Docked) VSync režim @@ -625,6 +647,9 @@ Softwarová klávesnice + Režim letadla + Předává režim letadla do systému Switch + Licence diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index 321913a1db..2349c70c89 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml @@ -55,10 +55,14 @@ Modell der Host-GPU anzeigen SoC-Modell anzeigen Modell des Host-SoC anzeigen + Firmware-Version anzeigen + Zeigt die installierte Firmware-Version an GPU-Erweiterungen Renderer + RAII + Eine Methode zur automatischen Ressourcenverwaltung in Vulkan, die eine ordnungsgemäße Freigabe von Ressourcen gewährleistet, wenn sie nicht mehr benötigt werden, aber bei gebündelten Spielen Abstürze verursachen kann. Verschiedenes Edens Schleier Experimentelle Einstellungen zur Verbesserung der Leistung und Funktionalität. Diese Einstellungen können schwarze Bildschirme oder andere Spielprobleme verursachen. @@ -97,6 +101,11 @@ Verwenden Sie Boost (1700MHz), um mit der höchsten nativen Taktrate des Switch zu laufen, oder Fast (2000MHz), um mit der doppelten Taktrate zu laufen. Speicherlayout (EXPERIMENTELL) Ändert das emulierte Speicherlayout. Diese Einstellung erhöht nicht die Leistung, kann aber bei Spielen helfen, die hohe Auflösungen über Mods nutzen. Nicht auf Telefonen mit 8 GB RAM oder weniger verwenden. + Sample Shading + Ermöglicht dem Fragment-Shader, pro Sample in einem mehrfach gesampleten Fragment ausgeführt zu werden, anstatt einmal pro Fragment. Verbessert die Grafikqualität auf Kosten der Leistung. Nur Vulkan 1.1+-Geräte unterstützen diese Erweiterung. + Benutzerdefinierte CPU-Ticks + Legen Sie einen benutzerdefinierten Wert für CPU-Ticks fest. Höhere Werte können die Leistung steigern, aber auch zum Einfrieren des Spiels führen. Ein Bereich von 77–21000 wird empfohlen. + Ticks 4 GB (Empfohlen) 6 GB (Unsicher) 8 GB (Unsicher) @@ -234,12 +243,17 @@ Muss 3-20 Zeichen lang sein Erforderlich Ungültiges IP-Format - Mindestens 5 Zeichen + Muss zwischen 4–20 Zeichen lang sein Muss zwischen 1-65535 liegen + Muss 48 Zeichen lang sein und nur Kleinbuchstaben a-z enthalten + Lobby-Typ + Öffentlich + Unlisted Abbrechen OK Aktualisieren Raumliste + Web-Token erforderlich, gehen Sie zu Erweiterte Einstellungen -> System -> Netzwerk Designfarbe @@ -275,6 +289,7 @@ Alphabetisch Liste Raster + Karussell Ordner Pre-Alpha Software WARNUNG: Diese Version ist nicht für die Öffentlichkeit bestimmt. @@ -420,11 +435,17 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die Benutzerdefinierte Echtzeituhr + Generieren + Web-Benutzername + Benutzername, der in Multiplayer-Lobbys angezeigt wird. Muss 4–20 Zeichen lang sein. Web-Token Web-Token zum Erstellen öffentlicher Räume. Es handelt sich um eine 48-stellige Zeichenfolge, die nur Kleinbuchstaben a-z enthält. Netzwerk + Backend + Anzeige + Nachbearbeitung Genauigkeitsstufe Auflösung (Handheld/Gedockt) VSync-Modus @@ -794,6 +815,9 @@ Wirklich fortfahren? Software-Tastatur + Flugmodus + Übergibt den Flugmodus an das Switch-Betriebssystem + Lizenzen Hochwertiges Upscaling von AMD diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 447fdfbe47..27bbb35cae 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -55,10 +55,14 @@ Mostrar el modelo de GPU del anfitrión Mostrar modelo de SoC Mostrar el modelo de SoC del anfitrión + Mostrar versión de firmware + Muestra la versión de firmware instalada Extensiones de GPU Renderizador + RAII + Un método de gestión automática de recursos en Vulkan que garantiza la liberación adecuada de recursos cuando ya no son necesarios, pero puede causar fallos en juegos empaquetados. Misceláneos Velo de Edén Configuraciones experimentales para mejorar el rendimiento y la capacidad. Estas configuraciones pueden causar pantallas negras u otros problemas en el juego. @@ -97,6 +101,11 @@ Usa Boost (1700MHz) para funcionar a la velocidad nativa más alta de Switch, o Fast (2000MHz) para funcionar al doble de velocidad. Distribución de memoria (EXPERIMENTAL) Cambia la distribución de memoria emulada. Esta configuración no aumenta el rendimiento, pero puede ayudar en juegos que utilizan altas resoluciones mediante mods. No usar en teléfonos con 8GB de RAM o menos. + Muestreo de sombreado + Permite que el fragment shader se ejecute por muestra en un fragmento multisample en lugar de una vez por fragmento. Mejora la calidad gráfica a costa de algo de rendimiento. Solo los dispositivos Vulkan 1.1+ admiten esta extensión. + Ticks de CPU personalizados + Establece un valor personalizado de ticks de CPU. Valores más altos pueden aumentar el rendimiento, pero también pueden hacer que el juego se congele. Se recomienda un rango de 77–21000. + Ticks 4GB (Recomendado) 6GB (Inseguro) 8GB (Inseguro) @@ -234,12 +243,17 @@ باید بین 3 تا 20 کاراکتر باشد الزامی فرمت IP نامعتبر - حداقل 5 کاراکتر + Debe tener entre 4–20 caracteres باید بین 1 تا 65535 باشد + Debe tener 48 caracteres y solo letras minúsculas a-z + Tipo de lobby + Público + No listado انصراف تایید تازه‌سازی لیست اتاق‌ها + Se requiere un token web, ve a Configuración avanzada -> Sistema -> Red Color del tema @@ -275,6 +289,7 @@ Alfabético Lista Cuadrícula + Carrusel Carpeta Software Pre-Alfa ADVERTENCIA: Versión inestable. No para uso público. @@ -455,11 +470,17 @@ Configurar RTC personalizado + Generar + Nombre de usuario web + Nombre de usuario que se mostrará en los lobbies multijugador. Debe tener entre 4 y 20 caracteres. Token web Token web utilizado para crear salas públicas. Es una cadena de 48 caracteres que solo contiene letras minúsculas a-z. Red + Backend + Pantalla + Postprocesado Nivel de precisión Resolución (Portátil/Sobremesa) Modo VSync @@ -872,6 +893,9 @@ Teclado de software + Modo avión + Pasa el modo avión al sistema operativo Switch + Licencias Upscaling de alta calidad de AMD diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml index 8bd2f82aad..da78876baf 100644 --- a/src/android/app/src/main/res/values-fa/strings.xml +++ b/src/android/app/src/main/res/values-fa/strings.xml @@ -55,10 +55,14 @@ نمایش مدل GPU میزبان نمایش مدل SoC نمایش مدل SoC میزبان + نمایش نسخه فریمور + نسخه نصب شده فریمور را نمایش می‌دهد افزونه‌های GPU رندرر + RAII + روشی برای مدیریت خودکار منابع در ولکان که تضمین می‌کند منابع به درستی آزاد شوند وقتی دیگر مورد نیاز نیستند، اما ممکن است باعث کرش شدن بازی‌های بسته‌بندی شده شود. متفرقه پرده عدن تنظیمات آزمایشی برای بهبود عملکرد و قابلیت. این تنظیمات ممکن است باعث نمایش صفحه سیاه یا سایر مشکلات بازی شود. @@ -97,6 +101,11 @@ از Boost (1700MHz) برای کار با بالاترین سرعت کلاک بومی سوئیچ یا Fast (2000MHz) برای کار با دو برابر سرعت استفاده کنید. چیدمان حافظه (آزمایشی) چیدمان حافظه شبیه‌سازی شده را تغییر می‌دهد. این تنظیم عملکرد را افزایش نمی‌دهد، اما ممکن است به بازی‌هایی که از رزولوشن بالا با استفاده از مادها استفاده می‌کنند کمک کند. در تلفن‌های با 8 گیگابایت رم یا کمتر استفاده نشود. + سایه‌زنی نمونه + اجازه می‌دهد شیدر قطعه در هر نمونه از یک قطعه چندنمونه‌ای اجرا شود به جای یک بار برای هر قطعه. کیفیت گرافیک را به بهای کاهش عملکرد بهبود می‌بخشد. فقط دستگاه‌های Vulkan 1.1+ از این افزونه پشتیبانی می‌کنند. + تیک‌های CPU سفارشی + مقدار سفارشی برای تیک‌های CPU تنظیم کنید. مقادیر بالاتر ممکن است عملکرد را افزایش دهند، اما ممکن است باعث یخ زدن بازی شوند. محدوده 77-21000 توصیه می‌شود. + تیک‌ها 4 گیگابایت (توصیه شده) 6 گیگابایت (ناامن) 8 گیگابایت (ناامن) @@ -148,7 +157,7 @@ چندنفره - اتاق بازی خود را بسازید یا به یک اتاق موجود بپیوندید تا با دیگران بازی کنید + اتاق بازی خود را میزبانی کنید یا به یک اتاق موجود بپیوندید تا با دیگران بازی کنید اتاق: %1$s شناسه کنسول: %1$s ایجاد @@ -157,42 +166,45 @@ نام کاربری آدرس IP پورت - اتاق با موفقیت ایجاد شد! - با موفقیت به اتاق پیوستید! - ایجاد اتاق ناموفق بود! - پیوستن به اتاق ناموفق بود! - پورت نامعتبر است! + اتاق با موفقیت ایجاد شد + با موفقیت به اتاق پیوستید + ایجاد اتاق ناموفق بود + پیوستن به اتاق ناموفق بود + نام خیلی کوتاه است + آدرس نامعتبر + پورت نامعتبر! خروج از اتاق خطای شبکه اتصال قطع شد - تداخل نام - تداخل MAC - تداخل شناسه کنسول + تضاد نام + تضاد آدرس MAC + تضاد شناسه کنسول نسخه نادرست رمز عبور نادرست اتصال برقرار نشد اتاق پر است میزبان مسدود شده دسترسی رد شد - چنین کاربری وجود ندارد + کاربری وجود ندارد قبلاً در اتاق هستید خطا در ایجاد اتاق میزبان اخراج شد خطای ناشناخته اتاق راه‌اندازی نشده - اتاق بیکار - در حال عضویت - عضو شد + اتاق غیرفعال + در حال پیوستن به اتاق + به اتاق پیوستید ناظر اتاق - %1$s عضو شد + %1$s پیوست %1$s خارج شد %1$s اخراج شد %1$s مسدود شد آدرس آزاد شد اخراج - ارسال پیام… + ارسال پیام... رمز عبور در حال پیوستن... + در حال ایجاد... نام اتاق نام اتاق باید بین 3 تا 20 کاراکتر باشد حداکثر بازیکنان (16) @@ -202,36 +214,46 @@ آدرس IP در حافظه موقت کپی شد آدرس سرور چت - پیام بنویسید… + پیام را بنویسید... ارسال ارسال پیام مدیریت لیست مسدودها - هیچ کاربر مسدود شده‌ای وجود ندارد + کاربر مسدود شده‌ای وجود ندارد آزاد کردن کاربر آزاد کردن - آیا مطمئنید که می‌خواهید %1$s را آزاد کنید؟ + آیا مطمئن هستید که می‌خواهید %1$s را آزاد کنید؟ مسدود کردن کاربر اتاق‌های عمومی - هیچ اتاق عمومی یافت نشد - رمز عبور مورد نیاز است + اتاق عمومی یافت نشد + رمز عبور مورد نیاز : %1$d/%2$d بازی هر بازی - اتاق با رمز عبور محافظت شده - مخفی کردن اتاق‌های پر - مخفی کردن اتاق‌های خالی + اتاق با رمز عبور + پنهان کردن اتاق‌های پر + پنهان کردن اتاق‌های خالی برای بررسی مجدد، تازه‌سازی را لمس کنید - جستجوی اتاق‌ها… + جستجوی لابی‌ها... چندنفره بازی‌های ترجیحی بازی ترجیحی - هیچ بازی یافت نشد + نوع لابی + بازی یافت نشد برای میزبانی اتاق باید یک بازی ترجیحی انتخاب کنید. + باید بین 3 تا 20 کاراکتر باشد + الزامی + توکن وب مورد نیاز است، به تنظیمات پیشرفته -> سیستم -> شبکه بروید + فرمت IP نامعتبر + باید بین 4-20 کاراکتر باشد + باید 48 کاراکتر باشد و فقط حروف کوچک a-z + باید بین 1 تا 65535 باشد انصراف - تأیید + تایید تازه‌سازی لیست اتاق‌ها + عمومی + فهرست نشده رنگ تم @@ -267,6 +289,7 @@ الفبایی لیست گرید + کاروسل پوشه نرم‌افزار پیش‌آلفا هشدار: این نسخه برای استفاده عمومی نیست. ممکن است دارای اشکالات باشد. @@ -445,11 +468,17 @@ تنظیم زمان سفارشی + تولید + نام کاربری وب + نام کاربری که در لابی‌های چندنفره نمایش داده می‌شود. باید بین 4 تا 20 کاراکتر باشد. توکن وب توکن وب برای ایجاد اتاق‌های عمومی استفاده می‌شود. این یک رشته 48 کاراکتری است که فقط شامل حروف کوچک a-z می‌شود. شبکه + بک‌اند + نمایش + پس‌پردازش سطح دقت وضوح تصویر (دستی/متصل) حالت VSync @@ -863,6 +892,9 @@ صفحه کلید نرم‌افزاری + حالت هواپیما + حالت هواپیما را به سیستم عامل Switch منتقل می‌کند + مجوزها High-quality upscaling from AMD diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index cc5179169f..452f43bd6d 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -55,10 +55,14 @@ Afficher le modèle du GPU hôte Afficher le modèle du SoC Afficher le modèle du SoC hôte + Afficher la version du firmware + Affiche la version du firmware installé Extensions GPU Rendu + RAII + Une méthode de gestion automatique des ressources dans Vulkan qui assure la libération correcte des ressources lorsqu\'elles ne sont plus nécessaires, mais peut provoquer des plantages dans les jeux regroupés. Divers Voile d`Éden Paramètres expérimentaux pour améliorer les performances et les capacités. Ces paramètres peuvent causer des écrans noirs ou d\'autres problèmes de jeu. @@ -97,6 +101,11 @@ Utilisez Boost (1700MHz) pour fonctionner à la fréquence native la plus élevée de la Switch, ou Fast (2000MHz) pour fonctionner à double fréquence. Disposition de la mémoire (EXPÉRIMENTAL) Change la disposition de la mémoire émulée. Ce paramètre n\'augmente pas les performances, mais peut aider les jeux utilisant des résolutions élevées via des mods. Ne pas utiliser sur les téléphones avec 8 Go de RAM ou moins. + Échantillonnage de shading + Permet au fragment shader de s\'exécuter par échantillon dans un fragment multi-échantillonné au lieu d\'une fois par fragment. Améliore la qualité graphique au détriment des performances. Seuls les appareils Vulkan 1.1+ prennent en charge cette extension. + Ticks CPU personnalisés + Définissez une valeur personnalisée de ticks CPU. Des valeurs plus élevées peuvent améliorer les performances, mais peuvent aussi provoquer des gels du jeu. Une plage de 77 à 21000 est recommandée. + Ticks 4 Go (Recommandé) 6 Go (Dangereux) 8 Go (Dangereux) @@ -234,12 +243,17 @@ Doit contenir entre 3 et 20 caractères Requis Format IP invalide - Doit contenir au moins 5 caractères + Doit contenir entre 4 et 20 caractères Doit être entre 1 et 65535 + Doit contenir 48 caractères, uniquement des lettres minuscules a-z + Type de lobby + Public + Non listé Annuler OK Actualiser Liste des salons + Token web requis, allez dans Paramètres avancés -> Système -> Réseau Couleur du thème @@ -275,6 +289,7 @@ Alphabétique Liste Grille + Carrousel Dossier Logiciel Pré-Alpha AVERTISSEMENT : Cette version ne doit pas être partagée ou montrée au public. Ce logiciel est en phase pré-alpha et peut contenir des bugs et des fonctionnalités incomplètes.\nSi vous avez obtenu un accès non autorisé à cette version, il est fortement recommandé de la désinstaller immédiatement. @@ -455,11 +470,17 @@ Définir l\'horloge RTC personnalisée + Générer + Nom d\'utilisateur web + Nom d\'utilisateur à afficher dans les lobbys multijoueur. Doit contenir entre 4 et 20 caractères. Jeton Web Jeton Web utilisé pour créer des salles publiques. Il s\'agit d\'une chaîne de 48 caractères ne contenant que des lettres minuscules a-z. Réseau + Backend + Affichage + Post-traitement Niveau de précision Résolution (Mode Portable/Mode TV) Mode VSync @@ -920,6 +941,9 @@ Clavier logiciel + Mode avion + Passe le mode avion au système d\'exploitation Switch + Licences Mise à l\'échelle de haute qualité par AMD. diff --git a/src/android/app/src/main/res/values-he/strings.xml b/src/android/app/src/main/res/values-he/strings.xml index e804b862d4..09952ae0b1 100644 --- a/src/android/app/src/main/res/values-he/strings.xml +++ b/src/android/app/src/main/res/values-he/strings.xml @@ -55,10 +55,14 @@ הצג את דגם ה-GPU המארח הצג דגם SoC הצג את דגם ה-SoC המארח + הצג גרסת קושחה + מציג את גרסת הקושחה המותקנת הרחבות GPU רנדרר + RAII + שיטה לניהול אוטומטי של משאבים ב-Vulkan המבטיחה שחרור נכון של משאבים כאשר הם כבר לא נחוצים, אך עלולה לגרום לקריסות במשחקים מאוגדים. שונות עדן וייל הגדרות ניסיוניות לשיפור ביצועים ויכולות. הגדרות אלו עלולות לגרום למסכים שחורים או לבעיות אחרות במשחק. @@ -98,6 +102,11 @@ השתמש ב-Boost (1700MHz) כדי לפעול במהירות השעון הגבוהה ביותר של ה-Switch, או Fast (2000MHz) כדי לפעול במהירות כפולה. מבנה זיכרון (ניסיוני) שנה את מבנה הזיכרון המדומה. הגדרה זו לא תגדיל את הביצועים, אך עשויה לעזור במשחקים המשתמשים ברזולוציות גבוהות באמצעות מודים. אל תשתמש בטלפונים עם 8GB זיכרון RAM או פחות. + דגימת צל + מאפשר לשברי הצללה לרוץ לכל דגימה בקטע רב-דגימות במקום פעם אחת לקטע. משפר את איכות הגרפיקה במחיר של ביצועים. רק מכשירי Vulkan 1.1+ תומכים בהרחבה זו. + טיקי CPU מותאמים + הגדר ערך מותאם לטיקי CPU. ערכים גבוהים יותר עשויים לשפר ביצועים, אך גם עלולים לגרום להקפאת המשחק. מומלץ טווח של 77-21000. + טיקים 4GB (מומלץ) 6GB (לא בטוח) 8GB (לא בטוח) @@ -235,12 +244,17 @@ חייב להיות בין 3-20 תווים נדרש פורמט IP לא תקין - לפחות 5 תווים + חייב להיות בין 4-20 תווים חייב להיות בין 1-65535 + חייב להיות באורך 48 תווים, ורק אותיות קטנות a-z + סוג לובי + ציבורי + לא רשום ביטול אישור רענון רשימת חדרים + נדרש אסימון אינטרנט, עבור להגדרות מתקדמות -> מערכת -> רשת צבע ערכת עיצוב @@ -276,6 +290,7 @@ אלפביתי רשימה רשת + קרוסלה תיקייה תוכנת טרום-אלפא אזהרה: גרסה זו אינה מיועדת לשימוש ציבורי. התוכנה בשלבי פיתוח מוקדמים ועלולה להכיל באגים. @@ -441,11 +456,17 @@ קבע RTC מותאם אישית + יצירה + שם משתמש באינטרנט + שם המשתמש שיוצג בלובי מרובה משתתפים. חייב להיות באורך 4-20 תווים. אסימון אינטרנט אסימון אינטרנט המשמש ליצירת חדרים ציבוריים. זהו מחרוזת של 48 תווים המכילה רק אותיות קטנות a-z. רשת + בקאנד + תצוגה + עיבוד לאחר רמת דיוק רזולוציה (מעוגן/נייד) מצב VSync @@ -771,6 +792,9 @@ מקלדת תוכנה + מצב טיסה + מעביר את מצב הטיסה למערכת ההפעלה של Switch + רישיונות אפסקיילינג באיכות גבוהה מ AMD diff --git a/src/android/app/src/main/res/values-hu/strings.xml b/src/android/app/src/main/res/values-hu/strings.xml index 6f0913bb7d..121edfdced 100644 --- a/src/android/app/src/main/res/values-hu/strings.xml +++ b/src/android/app/src/main/res/values-hu/strings.xml @@ -55,10 +55,14 @@ A gazda GPU modelljének megjelenítése SoC modell megjelenítése A gazda SoC modelljének megjelenítése + Firmver verzió megjelenítése + A telepített firmver verziójának megjelenítése GPU kiterjesztések Megjelenítő + RAII + A Vulkan erőforrás-kezelési módszere, amely biztosítja az erőforrások megfelelő felszabadítását, ha már nincs rájuk szükség, de csomagolt játékok összeomlását okozhatja. Egyéb Eden Fátyla Kísérleti beállítások a teljesítmény és képesség javításához. Ezek a beállítások fekete képernyőket vagy más játékproblémákat okozhatnak. @@ -97,6 +101,11 @@ Használd a Boost (1700MHz) opciót a Switch legmagasabb natív órajelén való futáshoz, vagy a Fast (2000MHz) opciót a dupla órajelen való futáshoz. Memórialayout (KÍSÉRLETI) Megváltoztatja az emulált memórialayoutot. Ez a beállítás nem növeli a teljesítményt, de segíthet a magas felbontást használó játékokban modok segítségével. Ne használd 8GB RAM vagy kevesebb rendelkező telefonokon. + Mintavételezés árnyékolás + Lehetővé teszi, hogy a fragment shader mintánként fusson egy többmintás fragmentben a fragmentenkénti futtatás helyett. Javítja a grafikai minőséget a teljesítmény rovására. Csak Vulkan 1.1+ eszközök támogatják ezt a kiterjesztést. + Egyéni CPU tick-ek + Egyéni CPU tick érték beállítása. A magasabb értékek növelhetik a teljesítményt, de a játék befagyását is okozhatják. 77–21000 közötti tartomány ajánlott. + Tick-ek 4GB (Ajánlott) 6GB (Nem biztonságos) 8GB (Nem biztonságos) @@ -234,12 +243,17 @@ 3-20 karakter kell Kötelező Érvénytelen IP formátum - Legalább 5 karakter + 4–20 karakter hosszú lehet 1-65535 között legyen + 48 karakter hosszú lehet, és csak kisbetűket (a-z) tartalmazhat + Lobby típusa + Nyilvános + Nem nyilvános Mégse OK Frissítés Szobalista + Web token szükséges, lépj a Speciális beállítások -> Rendszer -> Hálózat menüpontba Téma színe @@ -275,6 +289,7 @@ ABC sorrend Lista Rács + Körhinta Mappa Pre-Alpha szoftver FIGYELMEZTETÉS: Ez a verzió nem nyilvános. A szoftver pre-alpha állapotban van, hibákat és hiányos funkciókat tartalmazhat. @@ -450,11 +465,17 @@ Egyéni RTC beállítása + Generálás + Webes felhasználónév + A többjátékos lobbikban megjelenítendő felhasználónév. 4–20 karakter hosszúságú lehet. Web token Web token nyilvános termek létrehozásához. Ez egy 48 karakter hosszú sztring, amely csak kisbetűket (a-z) tartalmaz. Hálózat + Backend + Kijelző + Utófeldolgozás Pontosság szintje Felbontás (Kézi/Dockolt) VSync mód @@ -904,6 +925,9 @@ Szoftveres billentyűzet + Repülő üzemmód + Átadja a repülő üzemmódot a Switch operációs rendszernek + Licenszek Magas minőségű felskálázás az AMD-től diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index dd67006ff6..83ae800e94 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -55,10 +55,14 @@ Tampilkan model GPU host Tampilkan Model SoC Tampilkan model SoC host + Tampilkan Versi Firmware + Menampilkan versi firmware yang terinstal Ekstensi GPU Renderer + RAII + Metode manajemen sumber daya otomatis di Vulkan yang memastikan pelepasan sumber daya yang tepat ketika tidak lagi diperlukan, tetapi dapat menyebabkan crash pada game yang dibundel. Lain-lain Eden`s Veil Pengaturan eksperimental untuk meningkatkan kinerja dan kemampuan. Pengaturan ini dapat menyebabkan layar hitam atau masalah game lainnya. @@ -97,6 +101,11 @@ Gunakan Boost (1700MHz) untuk berjalan pada kecepatan clock asli tertinggi Switch, atau Fast (2000MHz) untuk berjalan pada kecepatan ganda. Tata Letak Memori (EKSPERIMENTAL) Ubah tata letak memori emulasi. Pengaturan ini tidak meningkatkan kinerja, tetapi dapat membantu game yang menggunakan resolusi tinggi melalui mod. Jangan gunakan pada ponsel dengan RAM 8GB atau kurang. + Pencahayaan Sampel + Memungkinkan fragment shader dieksekusi per sampel dalam fragmen multisampel alih-alih sekali per fragmen. Meningkatkan kualitas grafis dengan mengorbankan kinerja. Hanya perangkat Vulkan 1.1+ yang mendukung ekstensi ini. + Ticks CPU Kustom + Atur nilai ticks CPU kustom. Nilai yang lebih tinggi dapat meningkatkan kinerja, tetapi juga dapat menyebabkan game membeku. Kisaran 77–21000 direkomendasikan. + Ticks 4GB (Direkomendasikan) 6GB (Tidak Aman) 8GB (Tidak Aman) @@ -147,8 +156,8 @@ Selalu - Multipemain - Buat ruang permainan sendiri atau bergabung dengan yang sudah ada untuk bermain dengan orang lain + Multiplayer + Host ruang permainan Anda sendiri atau bergabung dengan yang sudah ada untuk bermain dengan orang lain Ruang: %1$s ID Konsol: %1$s Buat @@ -157,52 +166,55 @@ Nama Pengguna Alamat IP Port - Ruang berhasil dibuat! - Berhasil bergabung dengan ruang! - Gagal membuat ruang! - Gagal bergabung dengan ruang! + Ruang berhasil dibuat + Berhasil bergabung ke ruang + Gagal membuat ruang + Gagal bergabung ke ruang + Nama terlalu pendek + Alamat tidak valid Port tidak valid! - Keluar dari Ruang + Keluar Ruang Kesalahan jaringan Koneksi terputus - Tabrakan nama - Tabrakan MAC - Tabrakan ID Konsol + Nama bentrok + Alamat MAC bentrok + ID Konsol bentrok Versi salah - Kata sandi salah + Password salah Tidak dapat terhubung - Ruang sudah penuh + Ruang penuh Host diblokir Izin ditolak - Tidak ada pengguna tersebut + Pengguna tidak ditemukan Sudah berada di ruang Kesalahan membuat ruang Host dikeluarkan Kesalahan tidak diketahui - Ruang tidak diinisialisasi - Ruang menganggur - Bergabung dengan ruang - Bergabung dengan ruang + Ruang belum diinisialisasi + Ruang tidak aktif + Sedang bergabung ke ruang + Bergabung ke ruang Moderator ruang %1$s bergabung %1$s keluar - %1$s di-kick - %1$s dilarang - Alamat diizinkan - Kick Anggota - Kirim pesan… + %1$s dikeluarkan + %1$s diblokir + Alamat dibuka blokir + Keluarkan + Kirim pesan... Password - Bergabung... + Sedang bergabung... + Sedang membuat... Nama Ruang - Nama ruang harus antara 3 hingga 20 karakter + Nama ruang harus antara 3-20 karakter Pemain Maks (16) Pemain Maks: %d Obrolan Opsi Lainnya Alamat IP disalin ke clipboard Alamat Server - Chat - Ketik pesan… + Obrolan + Ketik pesan... Kirim Kirim Pesan Moderasi @@ -214,24 +226,34 @@ Blokir Pengguna Ruang Publik Tidak ada ruang publik yang ditemukan - Kata sandi diperlukan + Password Diperlukan : %1$d/%2$d Game Game Apa Saja - Ruang dilindungi kata sandi + Ruang dengan password Sembunyikan Ruang Penuh Sembunyikan Ruang Kosong Ketuk segarkan untuk memeriksa lagi - Cari Ruang… - Multipemain - Game Favorit + Cari Lobi... + Multiplayer + Game Pilihan Game Pilihan - Tidak ada game yang ditemukan - Anda harus memilih Game Pilihan untuk membuat ruang. + Jenis Lobi + Game Tidak Ditemukan + Anda harus memilih Game Pilihan untuk menjadi host ruang. + Harus antara 3-20 karakter + Diperlukan + Token Web diperlukan, buka Pengaturan Lanjutan -> Sistem -> Jaringan + Format IP tidak valid + Harus antara 4-20 karakter + Harus 48 karakter, dan hanya huruf kecil a-z + Harus antara 1-65535 Batal - OK + Oke Segarkan Daftar Ruang + Publik + Tidak Terdaftar Warna Tema @@ -267,6 +289,7 @@ Abjad Daftar Grid + Karousel Folder Perangkat Lunak Pre-Alpha "PERINGATAN: Build ini tidak dimaksudkan untuk dibagikan atau ditunjukkan ke publik. Perangkat lunak ini dalam tahap pre-alpha dan mungkin memiliki bug dan fitur yang belum lengkap. \nJika Anda mendapatkan akses tidak sah ke build ini; sangat disarankan untuk mencopotnya segera" @@ -443,11 +466,17 @@ Setel RTC Kustom + Hasilkan + Nama Pengguna Web + Nama pengguna yang akan ditampilkan di lobi multipemain. Harus terdiri dari 4–20 karakter. Token Web Token web digunakan untuk membuat ruang publik. Ini adalah string 48 karakter yang hanya berisi huruf kecil a-z. Jaringan + Backend + Tampilan + Pascaproses Tingkatan Akurasi Resolusi (Handheld/Docked) Mode Sinkronisasi Vertikal @@ -856,6 +885,9 @@ Papan Ketik Perangkat Lunak + Mode Pesawat + Meneruskan Mode Pesawat ke OS Switch + Lisensi Peningkatan kualitas tinggi dari AMD diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index 297205501c..bc0f7996b1 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml @@ -55,10 +55,14 @@ Mostra il modello della GPU host Mostra modello SoC Mostra il modello del SoC host + Mostra versione firmware + Visualizza la versione del firmware installato Estensioni GPU Renderer + RAII + Un metodo di gestione automatica delle risorse in Vulkan che garantisce il corretto rilascio delle risorse quando non sono più necessarie, ma può causare crash nei giochi in bundle. Varie Velo di Eden Impostazioni sperimentali per migliorare prestazioni e capacità. Queste impostazioni possono causare schermate nere o altri problemi di gioco. @@ -97,6 +101,11 @@ Usa Boost (1700MHz) per funzionare alla massima frequenza nativa dello Switch, o Fast (2000MHz) per funzionare al doppio della frequenza. Layout della memoria (SPERIMENTALE) Cambia il layout della memoria emulata. Questa impostazione non aumenta le prestazioni, ma può aiutare nei giochi che utilizzano alte risoluzioni tramite mod. Non usare su telefoni con 8GB di RAM o meno. + Shading campione + Permette al fragment shader di eseguire per campione in un frammento multi-campione invece che una volta per frammento. Migliora la qualità grafica a scapito delle prestazioni. Solo i dispositivi Vulkan 1.1+ supportano questa estensione. + Tick CPU personalizzati + Imposta un valore personalizzato per i tick della CPU. Valori più alti possono aumentare le prestazioni, ma possono anche causare il blocco del gioco. Si consiglia un intervallo di 77–21000. + Tick 4GB (Consigliato) 6GB (Non sicuro) 8GB (Non sicuro) @@ -234,12 +243,17 @@ 3-20 caratteri richiesti Richiesto Formato IP non valido - Minimo 5 caratteri + Deve essere lungo 4–20 caratteri Deve essere tra 1-65535 + Deve essere lungo 48 caratteri e contenere solo lettere minuscole a-z + Tipo di lobby + Pubblico + Non in elenco Annulla OK Aggiorna Lista stanze + Token web richiesto, vai su Impostazioni avanzate -> Sistema -> Rete Colore tema @@ -275,6 +289,7 @@ Alfabetico Lista Griglia + Carosello Cartella Software Pre-Alpha AVVISO: Questa versione non è per uso pubblico. Il software è in fase pre-alpha e può contenere bug e funzionalità incomplete.\nSe hai accesso non autorizzato a questa versione, si consiglia di disinstallarla immediatamente. @@ -443,11 +458,17 @@ Imposta un orologio in tempo reale personalizzato + Genera + Nome utente web + Nome utente da visualizzare nelle lobby multigiocatore. Deve essere lungo 4–20 caratteri. Token web Token web utilizzato per creare stanze pubbliche. È una stringa di 48 caratteri contenente solo lettere minuscole a-z. Rete + Backend + Schermo + Post-elaborazione Livello di accuratezza Risoluzione (Portatile/Docked) Modalità VSync @@ -805,6 +826,9 @@ Tastiera software + Modalità aereo + Passa la modalità aereo al sistema operativo Switch + Licenze Upscaling di alta qualità da parte di AMD diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index 9d95e994fd..1fc162a600 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml @@ -55,10 +55,14 @@ ホストGPUのモデルを表示 SoCモデルを表示 ホストSoCのモデルを表示 + ファームウェアバージョンを表示 + インストールされているファームウェアのバージョンを表示します GPU拡張機能 レンダラー + RAII + Vulkanにおける自動リソース管理の方法で、不要になったリソースを適切に解放しますが、バンドルされたゲームでクラッシュを引き起こす可能性があります。 その他 エデンのベール パフォーマンスと機能を向上させる実験的な設定。これらの設定は黒画面やその他のゲームの問題を引き起こす可能性があります。 @@ -97,6 +101,11 @@ Boost (1700MHz)を使用してSwitchの最高ネイティブクロックで動作させるか、Fast (2000MHz)を使用して2倍のクロックで動作させます。 メモリレイアウト (実験的) エミュレートされたメモリレイアウトを変更します。この設定はパフォーマンスを向上させませんが、modを介して高解像度を利用するゲームに役立つ場合があります。8GB以下のRAMを搭載した電話では使用しないでください。 + サンプルシェーディング + マルチサンプルフラグメントでフラグメントシェーダーをフラグメントごとではなくサンプルごとに実行できるようにします。パフォーマンスを犠牲にしてグラフィック品質を向上させます。Vulkan 1.1+デバイスのみがこの拡張機能をサポートしています。 + カスタムCPUティック + CPUティックのカスタム値を設定します。高い値はパフォーマンスを向上させる可能性がありますが、ゲームがフリーズする可能性もあります。77〜21000の範囲が推奨されます。 + ティック 4GB (推奨) 6GB (安全でない) 8GB (安全でない) @@ -234,12 +243,17 @@ 3〜20文字で入力してください 必須 無効なIP形式 - 5文字以上必要です + Deve essere lungo 4–20 caratteri 1〜65535の間で入力してください + 48文字で、小文字のa-zのみ使用可能 + ロビータイプ + 公開 + 非公開 キャンセル OK 更新 ルーム一覧 + ウェブトークンが必要です。詳細設定 -> システム -> ネットワークに移動してください テーマカラー @@ -275,6 +289,7 @@ アルファベット順 リスト表示 グリッド表示 + カルーセル フォルダ プレアルファ版 警告: このビルドは公開用ではありません。プレアルファ段階でバグや未実装機能が含まれます。\n不正に入手した場合は直ちにアンインストールしてください @@ -421,11 +436,17 @@ カスタムRTCを設定 + 生成 + ウェブユーザー名 + マルチプレイヤーロビーに表示されるユーザー名。4〜20文字でなければなりません。 ウェブトークン 公開ルームを作成するために使用されるウェブトークン。a-zの小文字のみを含む48文字の文字列です。 ネットワーク + バックエンド + ディスプレイ + 後処理 精度 解像度(携帯モード/TVモード) 垂直同期モード @@ -767,6 +788,9 @@ ソフトウェアキーボード + 機内モード + 機内モードをSwitch OSに渡します + ライセンス AMDの高品質アップスケーリング diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index 56a50c083c..d99bc5e92f 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml @@ -55,10 +55,14 @@ 호스트 GPU 모델 표시 SoC 모델 표시 호스트 SoC 모델 표시 + 펌웨어 버전 표시 + 설치된 펌웨어 버전을 표시합니다 GPU 확장 기능 렌더러 + RAII + Vulkan에서 자동 리소스 관리를 위한 방법으로, 더 이상 필요하지 않은 리소스를 적절히 해제하지만 번들된 게임에서 충돌을 일으킬 수 있습니다. 기타 에덴의 장막 성능 및 기능을 향상시키기 위한 실험적 설정. 이 설정은 검은 화면 또는 기타 게임 문제를 일으킬 수 있습니다. @@ -97,6 +101,11 @@ Boost (1700MHz)를 사용하여 Switch의 최고 네이티브 클럭으로 실행하거나 Fast (2000MHz)를 사용하여 2배 클럭으로 실행합니다. 메모리 레이아웃 (실험적) 에뮬레이트된 메모리 레이아웃을 변경합니다. 이 설정은 성능을 높이지 않지만 모드를 통해 고해상도를 사용하는 게임에 도움이 될 수 있습니다. 8GB 이하 RAM의 휴대폰에서는 사용하지 마십시오. + 샘플 쉐이딩 + 멀티샘플 프래그먼트에서 프래그먼트 쉐이더가 프래그먼트당 한 번이 아니라 샘플당 실행되도록 합니다. 성능을 희생하여 그래픽 품질을 향상시킵니다. Vulkan 1.1+ 장치만 이 확장을 지원합니다. + 사용자 정의 CPU 틱 + CPU 틱의 사용자 정의 값을 설정합니다. 높은 값은 성능을 향상시킬 수 있지만 게임이 멈출 수도 있습니다. 77~21000 범위를 권장합니다. + 4GB (권장) 6GB (안전하지 않음) 8GB (안전하지 않음) @@ -233,12 +242,17 @@ 3~20자여야 합니다 필수 잘못된 IP 형식 - 최소 5자 이상 + 4~20자여야 합니다 1~65535 사이여야 합니다 + 48자여야 하며, 소문자 a-z만 사용 가능 + 로비 유형 + 공개 + 비공개 취소 확인 새로 고침 방 목록 + 웹 토큰이 필요합니다. 고급 설정 -> 시스템 -> 네트워크로 이동하세요 테마 색상 @@ -274,6 +288,7 @@ 알파벳순 목록 격자 + 캐러셀 폴더 프리-알파 소프트웨어 "경고: 이 빌드는 공개용이 아닙니다. 이 소프트웨어는 프리-알파 단계이며 버그 및 미완성 기능이 있을 수 있습니다. \n무단으로 이 빌드를 획득한 경우 즉시 삭제하는 것이 좋습니다." @@ -450,11 +465,17 @@ 사용자 지정 RTC 설정 + 생성 + 웹 사용자 이름 + 멀티플레이어 로비에 표시될 사용자 이름. 4~20자여야 합니다. 웹 토큰 공개 방을 만들기 위해 사용되는 웹 토큰. a-z 소문자만 포함된 48자 문자열입니다. 네트워크 + 백엔드 + 디스플레이 + 후처리 정확도 수준 해상도 (휴대 모드/독 모드) 수직동기화 모드 @@ -863,6 +884,9 @@ 소프트웨어 키보드 + 비행기 모드 + 비행기 모드를 Switch OS에 전달합니다 + 라이센스 AMD 고품질 업스케일링 diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index 84b738a4f6..b66d7e3a9f 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml @@ -55,10 +55,14 @@ Vis verts-GPUens modell Vis SoC-modell Vis verts-SoCens modell + Vis firmwareversjon + Viser den installerte firmwareversjonen GPU-utvidelser Renderer + RAII + En metode for automatisk ressurshåndtering i Vulkan som sikrer riktig frigjøring av ressurser når de ikke lenger trengs, men kan føre til krasj i bundlede spill. Diverse Edens slør Eksperimentelle innstillinger for å forbedre ytelse og funksjonalitet. Disse innstillingene kan forårsake svarte skjermer eller andre spillproblemer. @@ -97,6 +101,11 @@ Bruk Boost (1700MHz) for å kjøre med Switch\'s høyeste native klokkehastighet, eller Fast (2000MHz) for å kjøre med dobbel hastighet. Minneoppsett (EKSPERIMENTELL) Endre det emulerte minneoppsettet. Denne innstillingen øker ikke ytelsen, men kan hjelpe spill som bruker høy oppløsning via mods. Ikke bruk på telefoner med 8GB RAM eller mindre. + Prøvegjengivelse + Lar fragment-shaderen kjøres per prøve i et flerprøvefragment i stedet for en gang per fragment. Forbedrer grafikkvaliteten på bekostning av ytelse. Bare Vulkan 1.1+-enheter støtter denne utvidelsen. + Egendefinerte CPU-takter + Angi en egendefinert verdi for CPU-takter. Høyere verdier kan øke ytelsen, men kan også føre til at spret fryser. Et område på 77–21000 anbefales. + Takter 4GB (Anbefalt) 6GB (Usikkert) 8GB (Usikkert) @@ -234,12 +243,17 @@ Må være 3-20 tegn Påkrevd Ugyldig IP-format - Minst 5 tegn + Må være mellom 4–20 tegn Må være mellom 1-65535 + Må være 48 tegn, og kun små bokstaver a-z + Lobbytype + Offentlig + Uoppført Avbryt OK Oppdater Romliste + Webtoken kreves, gå til Avanserte innstillinger -> System -> Nettverk Temafarge @@ -273,6 +287,7 @@ Alfabetisk Liste Rutenett + Karusell Mappe Forhåndsversjon ADVARSEL: Denne versjonen er ikke ment for offentlig bruk. Programvaren er i tidlig utvikling og kan inneholde feil. @@ -397,11 +412,17 @@ Angi tilpasset RTC + Generer + Webbrukernavn + Brukernavn som vises i flerspillerlobbyer. Må være 4–20 tegn langt. Nett-token Nett-token som brukes til å opprette offentlige rom. Det er en 48-tegns streng som kun inneholder små bokstaver a-z. Nettverk + Backend + Skjerm + Etterbehandling Nøyaktighetsnivå Oppløsning (håndholdt/dokket) VSync-modus @@ -716,6 +737,9 @@ Programvare-tastatur + Flymodus + Sender flymodus til Switch OS + Lisenser Oppskalering av høy kvalitet fra AMD diff --git a/src/android/app/src/main/res/values-pl/strings.xml b/src/android/app/src/main/res/values-pl/strings.xml index 935ef3c69f..da5f3c6874 100644 --- a/src/android/app/src/main/res/values-pl/strings.xml +++ b/src/android/app/src/main/res/values-pl/strings.xml @@ -55,10 +55,14 @@ Wyświetl model GPU hosta Pokaż model SoC Wyświetl model SoC hosta + Pokaż wersję firmware + Wyświetla zainstalowaną wersję firmware Rozszerzenia GPU Renderer + RAII + Metoda automatycznego zarządzania zasobami w Vulkanie, która zapewnia prawidłowe zwalnianie zasobów, gdy nie są już potrzebne, ale może powodować awarie w pakietowych grach. Różne Zasłona Edenu Eksperymentalne ustawienia poprawiające wydajność i możliwości. Te ustawienia mogą powodować czarne ekrany lub inne problemy z grą. @@ -97,6 +101,11 @@ Użyj Boost (1700MHz), aby działać z najwyższą natywną częstotliwością Switcha, lub Fast (2000MHz), aby działać z podwójną częstotliwością. Układ pamięci (EKSPERYMENTALNY) Zmienia emulowany układ pamięci. To ustawienie nie zwiększa wydajności, ale może pomóc w grach wykorzystujących wysokie rozdzielczości poprzez mody. Nie używaj na telefonach z 8GB RAM lub mniej. + Cieniowanie próbek + Pozwala shaderowi fragmentów wykonywać się na próbkę w fragmencie wielopróbkowym zamiast raz na fragment. Poprawia jakość grafiki kosztem wydajności. Tylko urządzenia Vulkan 1.1+ obsługują to rozszerzenie. + Niestandardowe takty CPU + Ustaw niestandardową wartość taktów CPU. Wyższe wartości mogą zwiększyć wydajność, ale mogą też powodować zawieszanie się gry. Zalecany zakres to 77–21000. + Takty 4GB (Zalecane) 6GB (Niebezpieczne) 8GB (Niebezpieczne) @@ -234,12 +243,17 @@ 3-20 znaków wymagane Wymagane Nieprawidłowy format IP - Minimum 5 znaków + Musi mieć 4–20 znaków Musi być między 1-65535 + Musi mieć 48 znaków i składać się tylko z małych liter a-z + Typ lobby + Publiczne + Niepubliczne Anuluj OK Odśwież Lista pokoi + Wymagany token internetowy, przejdź do Ustawienia zaawansowane -> System -> Sieć Kolor motywu @@ -273,6 +287,7 @@ Alfabetycznie Lista Siatka + Karuzela Folder Oprogramowanie w fazie pre-alfa UWAGA: Ta wersja nie jest przeznaczona do publicznego udostępniania. Może zawierać błędy i niekompletne funkcje.\nJeśli masz do niej nieautoryzowany dostęp, zaleca się natychmiastową deinstalację. @@ -397,11 +412,17 @@ Ustaw niestandardowy czas RTC + Generuj + Nazwa użytkownika w sieci + Nazwa użytkownika wyświetlana w lobby multiplayer. Musi mieć 4–20 znaków. Token internetowy Token internetowy używany do tworzenia publicznych pokoi. Jest to 48-znakowy ciąg zawierający tylko małe litery a-z. Sieć + Backend + Wyświetlacz + Postprocessing Poziom precyzji emulacji Rozdzielczość (Handheld/Zadokowany) Synchronizacja pionowa VSync @@ -700,6 +721,9 @@ Klawiatura programowa + Tryb samolotowy + Przekazuje tryb samolotowy do systemu operacyjnego Switch + Licencje Rozciąganie wysokiej jakości od AMD diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index 909cb7cc6e..99fd14463a 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml @@ -55,10 +55,14 @@ Exibir o modelo da GPU host Mostrar modelo do SoC Exibir o modelo do SoC host + Mostrar versão do firmware + Exibe a versão do firmware instalado Extensões da GPU Renderizador + RAII + Um método de gerenciamento automático de recursos no Vulkan que garante a liberação adequada de recursos quando não são mais necessários, mas pode causar falhas em jogos empacotados. Diversos Véu do Éden Configurações experimentais para melhorar desempenho e capacidade. Essas configurações podem causar telas pretas ou outros problemas no jogo. @@ -97,6 +101,11 @@ Use Boost (1700MHz) para funcionar na frequência nativa mais alta do Switch, ou Fast (2000MHz) para funcionar em dobro da frequência. Layout de memória (EXPERIMENTAL) Altera o layout de memória emulado. Esta configuração não aumenta o desempenho, mas pode ajudar em jogos que utilizam altas resoluções via mods. Não use em telefones com 8GB de RAM ou menos. + Amostragem de sombreamento + Permite que o fragment shader seja executado por amostra em um fragmento multi-amostrado em vez de uma vez por fragmento. Melhora a qualidade gráfica às custas de desempenho. Apenas dispositivos Vulkan 1.1+ suportam esta extensão. + Ticks de CPU personalizados + Defina um valor personalizado para ticks de CPU. Valores mais altos podem aumentar o desempenho, mas também podem causar travamentos no jogo. Um intervalo de 77–21000 é recomendado. + Ticks 4GB (Recomendado) 6GB (Inseguro) 8GB (Inseguro) @@ -234,12 +243,17 @@ 3-20 caracteres necessários Obrigatório Formato de IP inválido - Mínimo 5 caracteres + Deve ter entre 4–20 caracteres Deve ser entre 1-65535 + Deve ter 48 caracteres e apenas letras minúsculas a-z + Tipo de lobby + Público + Não listado Cancelar OK Atualizar Lista de salas + Token web necessário, vá para Configurações avançadas -> Sistema -> Rede Cor do tema @@ -275,6 +289,7 @@ Alfabético Lista Grade + Carrossel Pasta Software Pré-Alpha "AVISO: Esta versão não deve ser compartilhada. Software em estágio pré-alpha pode conter bugs e recursos incompletos. \nSe você obteve acesso não autorizado a esta versão, é recomendado desinstalá-la imediatamente." @@ -455,11 +470,17 @@ Definir um relógio em tempo real personalizado + Gerar + Nome de usuário web + Nome de usuário a ser exibido nos lobbies multiplayer. Deve ter 4–20 caracteres. Token web Token web usado para criar salas públicas. É uma string de 48 caracteres contendo apenas letras minúsculas a-z. Rede + Backend + Tela + Pós-processamento Nível de precisão Resolução (Portátil/Modo TV) Modo de VSync @@ -921,6 +942,9 @@ uma tentativa de mapeamento automático Teclado de software + Modo avião + Passa o modo avião para o sistema operacional do Switch + Licenças Upscaling de alta qualidade da AMD diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index 38320dadf8..11f331ac15 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml @@ -55,10 +55,14 @@ Exibir o modelo da GPU anfitriã Mostrar modelo do SoC Exibir o modelo do SoC anfitrião + Mostrar versão do firmware + Mostra a versão do firmware instalado Extensões da GPU Renderizador + RAII + Um método de gestão automática de recursos no Vulkan que garante a libertação adequada de recursos quando já não são necessários, mas pode causar falhas em jogos empacotados. Diversos Véu do Éden Definições experimentais para melhorar o desempenho e capacidade. Estas definições podem causar ecrãs pretos ou outros problemas no jogo. @@ -97,6 +101,11 @@ Use Boost (1700MHz) para funcionar à velocidade nativa mais alta do Switch, ou Fast (2000MHz) para funcionar ao dobro da velocidade. Disposição de memória (EXPERIMENTAL) Altera a disposição de memória emulada. Esta definição não aumenta o desempenho, mas pode ajudar em jogos que utilizam altas resoluções via mods. Não use em telemóveis com 8GB de RAM ou menos. + Amostragem de sombreamento + Permite que o fragment shader seja executado por amostra num fragmento multi-amostrado em vez de uma vez por fragmento. Melhora a qualidade gráfica à custa de desempenho. Apenas dispositivos Vulkan 1.1+ suportam esta extensão. + Ticks de CPU personalizados + Defina um valor personalizado para ticks de CPU. Valores mais altos podem aumentar o desempenho, mas também podem causar bloqueios no jogo. Um intervalo de 77–21000 é recomendado. + Ticks 4GB (Recomendado) 6GB (Inseguro) 8GB (Inseguro) @@ -234,12 +243,17 @@ 3-20 caracteres necessários Obrigatório Formato de IP inválido - Mínimo 5 caracteres + Deve ter entre 4–20 caracteres Deve ser entre 1-65535 + Deve ter 48 caracteres e apenas letras minúsculas a-z + Tipo de lobby + Público + Não listado Cancelar OK Atualizar Lista de salas + Token web necessário, vá para Definições avançadas -> Sistema -> Rede Cor do tema @@ -275,6 +289,7 @@ Alfabético Lista Grelha + Carrossel Pasta Software Pré-Alpha AVISO: Esta versão não deve ser partilhada publicamente. O software está em fase pré-alpha e pode conter bugs e funcionalidades incompletas.\nSe obteve acesso não autorizado a esta versão, recomenda-se a desinstalação imediata. @@ -455,11 +470,17 @@ Defina um relógio em tempo real personalizado + Gerar + Nome de utilizador web + Nome de utilizador a ser exibido nos lobbies multiplayer. Deve ter entre 4–20 caracteres. Token web Token web usado para criar salas públicas. É uma string de 48 caracteres contendo apenas letras minúsculas a-z. Rede + Backend + Ecrã + Pós-processamento Nível de precisão Resolução (Portátil/Ancorado) Modo VSync @@ -921,6 +942,9 @@ uma tentativa de mapeamento automático Teclado de software + Modo avião + Passa o modo avião para o sistema operativo do Switch + Licenças Upscaling de alta qualidade da AMD diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index 25b5d3cd31..e8ddf96d17 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -55,6 +55,8 @@ Отобразить модель хостовой GPU Показать модель SoC Отобразить модель хостового SoC + Показать версию прошивки + Отображает установленную версию прошивки Расширения GPU @@ -66,6 +68,8 @@ Настройки в Eden\'s Veil являются экспериментальными и могут вызывать проблемы. Если ваша игра не запускается, отключите все расширения и установите расширенное динамическое состояние на 0. В разработке: Пропуск кадров Включите или отключите пропуск кадров для повышения производительности за счет уменьшения количества отображаемых кадров. Эта функция находится в разработке и будет включена в будущих версиях. + RAII + Метод автоматического управления ресурсами в Vulkan, который обеспечивает правильное освобождение ресурсов при их ненадобности, но может вызывать сбои в бандл-играх. Улучшенная синхронизация кадров Обеспечивает плавную и стабильную подачу кадров за счет синхронизации их времени, уменьшая подтормаживания и неравномерную анимацию. Идеально для игр с нестабильным временем кадров или микро-подтормаживаниями во время игры. Включить LRU-кеш @@ -97,6 +101,11 @@ Используйте Разгон (1700MHz) для работы на максимальной нативной частоте Switch или Быстрая (2000MHz) для работы на удвоенной частоте. Распределение памяти (ЭКСПЕРИМЕНТАЛЬНО) Изменяет эмулируемое распределение памяти. Эта настройка не увеличивает производительность, но может помочь в играх, использующих высокие разрешения через моды. Не используйте на телефонах с 8 ГБ ОЗУ или меньше. + Сэмпловый шейдинг + Позволяет шейдеру фрагментов выполняться на каждый сэмпл в мультисэмпловом фрагменте вместо одного раза на фрагмент. Улучшает качество графики ценой производительности. Только устройства с Vulkan 1.1+ поддерживают это расширение. + Пользовательские такты CPU + Установите пользовательское значение тактов CPU. Более высокие значения могут увеличить производительность, но также могут вызвать зависание игры. Рекомендуется диапазон 77–21000. + Такты 4 ГБ (Рекомендуется) 6 ГБ (Небезопасно) 8 ГБ (Небезопасно) @@ -234,12 +243,17 @@ 3-20 символов Обязательно Неверный IP - Минимум 5 символов + Должно быть от 4 до 20 символов 1-65535 + Должно быть 48 символов и содержать только строчные буквы a-z + Тип лобби + Публичное + Непубличное Отмена OK Обновить Список комнат + Требуется веб-токен, перейдите в Дополнительные настройки -> Система -> Сеть Цвет темы @@ -275,6 +289,7 @@ По алфавиту Список Сетка + Карусель Папка Пре-альфа версия ВНИМАНИЕ: Эта версия не предназначена для публичного использования. Возможны ошибки и неполные функции. @@ -375,6 +390,7 @@ Папки с играми Глубокий анализ Добавить папку с игрой + Новый игровой каталог успешно добавлен Эта папка уже была добавлена! Свойства папки игры @@ -456,11 +472,17 @@ Установить пользовательский RTC + Создать + Веб-имя пользователя + Имя пользователя, которое будет отображаться в мультиплеерных лобби. Должно содержать 4–20 символов. Веб-токен Веб-токен, используемый для создания публичных комнат. Это строка из 48 символов, содержащая только строчные буквы a-z. Сеть + Бэкенд + Дисплей + Постобработка Уровень точности Разрешение (портативное/в док-станции) Режим верт. синхронизации @@ -921,6 +943,9 @@ Программная клавиатура + Режим полета + Передает режим полета в ОС Switch + Лицензии Высококачественное масштабирование от AMD diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index 703429ddd5..5065b7d171 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -57,6 +57,8 @@ Прикажите модел ГПУ-а у хосту Прикажи соц модел Прикажите модел домаћина СоЦ + Прикажи верзију фирмвера + Приказује инсталирану верзију фирмвера Еденова аукција @@ -73,6 +75,8 @@ Побољшава текстуру и руковање међуспремника, као и преводилачки слој Маквелл. Подржани од стране неких Вулкана 1.1 ГПУ-а и сви Вулкан 1.2+ ГПУ. Рендерер + RAII + Метод аутоматског управљања ресурсима у Vulkan-у који осигурава правилно ослобађање ресурса када више нису потребни, али може изазвати падове у пакованим играма. Побољшани оквирни пејсинг Осигурава глатку и доследан испоруку оквира синхронизацијом времена између оквира, смањење муцања и неуједначене анимације. Идеално за игре које доживљавају временски оквир нестабилност или микро-штитнике током играња. Користите ауто-стуб @@ -94,6 +98,12 @@ Изглед меморије (Експериментално) Промените изглед емулираног меморије. Ово постављање неће повећати перформансе, али може помоћи у играма које користе високе резолуције путем модова. Не користите на телефонима са 8 ГБ РАМ-а или мање. Ради само на динамичком (ЈИТ) бацкенд-у. + Семпловање сенчења + Омогућава фрагмент шејдеру да се извршава по узорку у вишеузорачном фрагменту уместо једном по фрагменту. Побољшава квалитет графике на рачун перформанси. Само Vulkan 1.1+ уређаји подржавају ову екстензију. + Прилагођени CPU тактови + Поставите прилагођену вредност CPU тактова. Веће вредности могу повећати перформансе, али могу изазвати залеђивање игре. Препоручује се опсег 77–21000. + Тактови + Схадер Бацкенд Изаберите како се сјеначици саставе и преведете за ваш ГПУ. @@ -194,10 +204,24 @@ Преферирана игра Није пронађена није пронађена игара Морате одабрати преферирану игру да бисте угостили собу. + Мора бити дугачко 48 знакова и садржати само мала слова a-z + Тип лобија + Јавно + Неприказано + Име је прекратко + Неисправна адреса + Мора бити између 4–20 знакова Отказати У реду Освежити Листа соба + Придружујем се… + Креирам… + Обавезно + Потребан је веб токен, идите на Напредне поставке -> Систем -> Мрежа + Неисправан ИП формат + Мора бити између 1 и 65535 + Мора бити између 3 и 20 знакова Добродошли! @@ -221,6 +245,7 @@ Азбучни Списак Мрежа + Карусел Мапа Пре-Алпха софтвер "УПОЗОРЕЊЕ: Овај софтвер је у пре-алфа фази и може имати грешке и непотпуне примене функција." @@ -401,11 +426,17 @@ Подесите прилагођени РТЦ + Генериши + Веб корисничко име + Корисничко име које ће бити приказано у мултиплејер лобијима. Мора бити дугачко 4–20 знакова. Веб токен Веб токен који се користи за стварање јавних лобија. То је низ од 48 знакова који садржи само мала слова А-З. Мрежа + Бекенд + Приказ + Постпроцесирање ВИП: Фрамескип Пребацивање оквира прескакање да бисте побољшали перформансе смањењем броја пружених оквира. Ова функција се и даље ради и биће омогућена у будућим издањима. Ниво тачности @@ -944,6 +975,9 @@ Софтверска тастатура + Авионски режим + Прослеђује авионски режим на Switch OS + Лиценце FidelityFX-FSR diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index 7dd5d5cec7..55d767b384 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -55,12 +55,19 @@ Відобразити модель головної GPU Показати модель SoC Відобразити модель головного SoC + Показати версію прошивки + Відображає встановлену версію прошивки + Розширення GPU + Рендерер + Різне Завіса Eden Експериментальні налаштування для покращення продуктивності та сумісності. Ці налаштування можуть викликати збої, зокрема чорний екран. Експериментальні налаштування Налаштування Завіси Eden (Eden\'s Veil) є дуже експериментальними та можуть спричинити проблеми. Якщо ваша гра не запускається — вимкніть усі розширення та змініть Розширений динамічний стан на 0. + RAII + Метод автоматичного керування ресурсами у Vulkan, який забезпечує правильне звільнення ресурсів, коли вони більше не потрібні, але може спричинити збої в зібраних іграх. В розробці: Пропуск кадрів Увімкніть або вимкніть пропуск кадрів для покращення продуктивності за рахунок зменшення кількості візуалізованих кадрів. Ця функція ще розробляється та буде доступна у майбутніх версіях. Покращена синхронізація кадрів @@ -94,6 +101,11 @@ Використовуйте Прискорену (1700MHz) для роботи на максимальній нативній частоті Switch, або оберіть Швидку (2000MHz) для подвоєння базової частоти. Розподіл пам\'яті (ЕКСПЕРИМЕНТАЛЬНО) Змінює емульований розподіл пам\'яті. Це налаштування не підвищує продуктивність, але може допомогти в іграх, які використовують високу роздільну здатність через моди. Не використовуйте на телефонах з 8 ГБ ОЗУ або менше. + Семплове затінення + Дозволяє шейдеру фрагментів виконуватися на кожен семпл у багатосемпловому фрагменті замість одного разу на фрагмент. Покращує якість графіки за рахунок продуктивності. Лише пристрої з Vulkan 1.1+ підтримують це розширення. + Користувацькі такти CPU + Встановіть користувацьке значення тактів CPU. Вищі значення можуть покращити продуктивність, але також можуть спричинити зависання гри. Рекомендується діапазон 77–21000. + Такти 4 ГБ (Рекомендовано) 6 ГБ (Небезпечно) 8 ГБ (Небезпечно) @@ -228,12 +240,20 @@ 3-20 символів Обов\'язково Невірний IP - Мінімум 5 символів + Ім\'я занадто коротке + Має бути від 4 до 20 символів 1-65535 + Має бути 48 символів і містити лише малі літери a-z + Тип лобі + Публічне + Приховане Скасувати OK Оновити Список кімнат + Приєднуюсь… + Створюю… + Потрібний веб-токен, перейдіть у Розширені налаштування → Система → Мережа Колір теми @@ -267,6 +287,7 @@ За алфавітом Список Сітка + Карусель Тека Попередня версія УВАГА: Ця версія не призначена для публічного використання. Програмне забезпечення знаходиться на ранній стадії розробки та може містити помилки. @@ -378,11 +399,17 @@ Встановити RTC + Створити + Веб-ім\'я користувача + Ім\'я користувача, яке буде відображатися в мультиплеєрних лобі. Має містити 4–20 символів. Веб-токен Веб-токен, що використовується для створення публічних кімнат. Це рядок із 48 символів, що містить лише малі літери a-z. Мережа + Бекенд + Дисплей + Постобробка Рівень точності Роздільна здатність (Портативний/Док) Режим верт. синхронізації @@ -680,6 +707,9 @@ Програмна клавіатура + Режим польоту + Передає режим польоту в ОС Switch + Ліцензії diff --git a/src/android/app/src/main/res/values-vi/strings.xml b/src/android/app/src/main/res/values-vi/strings.xml index 902bac6656..dbe74f18f4 100644 --- a/src/android/app/src/main/res/values-vi/strings.xml +++ b/src/android/app/src/main/res/values-vi/strings.xml @@ -55,10 +55,14 @@ Hiển thị model GPU chủ Hiển thị model SoC Hiển thị model SoC chủ + Hiển thị phiên bản firmware + Hiển thị phiên bản firmware đã cài đặt Tiện ích mở rộng GPU Trình kết xuất + RAII + Phương pháp quản lý tài nguyên tự động trong Vulkan đảm bảo giải phóng tài nguyên đúng cách khi không còn cần thiết, nhưng có thể gây ra sự cố trong các trò chơi được đóng gói. Khác Màn Eden Cài đặt thử nghiệm để cải thiện hiệu suất và khả năng. Những cài đặt này có thể gây ra màn hình đen hoặc các vấn đề khác trong trò chơi. @@ -97,6 +101,11 @@ Sử dụng Boost (1700MHz) để chạy ở tốc độ xung nhịp gốc cao nhất của Switch hoặc Fast (2000MHz) để chạy ở tốc độ gấp đôi. Bố cục bộ nhớ (THỬ NGHIỆM) Thay đổi bố cục bộ nhớ mô phỏng. Cài đặt này không tăng hiệu suất, nhưng có thể giúp ích cho các trò chơi sử dụng độ phân giải cao thông qua mod. Không sử dụng trên điện thoại có 8GB RAM trở xuống. + Tô bóng mẫu + Cho phép fragment shader thực thi trên mỗi mẫu trong một fragment đa mẫu thay vì một lần mỗi fragment. Cải thiện chất lượng đồ họa với chi phí hiệu suất. Chỉ thiết bị Vulkan 1.1+ hỗ trợ tiện ích mở rộng này. + Tích CPU tùy chỉnh + Đặt giá trị tích CPU tùy chỉnh. Giá trị cao hơn có thể tăng hiệu suất, nhưng cũng có thể khiến trò chơi bị đơ. Phạm vi 77–21000 được khuyến nghị. + Tích 4GB (Được đề xuất) 6GB (Không an toàn) 8GB (Không an toàn) @@ -234,12 +243,17 @@ 3-20 ký tự Bắt buộc Sai định dạng IP - Ít nhất 5 ký tự + Phải có từ 4–20 ký tự 1-65535 + Phải có 48 ký tự và chỉ chữ thường a-z + Loại phòng + Công khai + Không công khai Hủy OK Tải lại Danh sách phòng + Yêu cầu mã web, hãy vào Cài đặt nâng cao -> Hệ thống -> Mạng Màu giao diện @@ -273,6 +287,7 @@ A-Z Danh sách Lưới + Băng chuyền Thư mục Phần mềm Pre-Alpha CẢNH BÁO: Phiên bản này chưa hoàn thiện, có thể có lỗi. @@ -397,11 +412,17 @@ Thiết lập RTC tùy chỉnh + Tạo + Tên người dùng web + Tên người dùng hiển thị trong phòng chơi nhiều người. Phải có 4–20 ký tự. Token web Token web dùng để tạo phòng công khai. Đây là chuỗi 48 ký tự chỉ chứa chữ thường a-z. Mạng + Backend + Hiển thị + Hậu xử lý Mức độ chính xác Độ phân giải (Handheld/Docked) Chế độ VSync @@ -708,6 +729,9 @@ Bàn phím phần mềm + Chế độ máy bay + Truyền chế độ máy bay sang hệ điều hành Switch + Giấy phép Upscaling chất lượng cao từ AMD diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index a9c06392e2..2105a95e1e 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -55,10 +55,14 @@ 显示主机GPU型号 显示SoC型号 显示主机SoC型号 + 显示固件版本 + 显示已安装的固件版本 GPU扩展 渲染器 + RAII + Vulkan中的一种自动资源管理方法,确保在不再需要时正确释放资源,但可能导致捆绑游戏崩溃。 杂项 伊甸之幕 实验性设置以提高性能和能力。这些设置可能会导致黑屏或其他游戏问题。 @@ -97,6 +101,11 @@ 使用 Boost (1700MHz) 以 Switch 的最高原生时钟速度运行,或 Fast (2000MHz) 以双倍时钟速度运行。 内存布局 (实验性) 更改模拟内存布局。此设置不会提高性能,但可能有助于通过模组使用高分辨率的游戏。不要在 RAM 为 8GB 或更少的手机上使用。 + 采样着色 + 允许片段着色器在多采样片段中每个样本执行一次,而不是每个片段执行一次。以提高性能为代价改善图形质量。仅Vulkan 1.1+设备支持此扩展。 + 自定义CPU时钟 + 设置自定义的CPU时钟值。更高的值可能提高性能,但也可能导致游戏卡顿。建议范围为77-21000。 + 时钟 4GB (推荐) 6GB (不安全) 8GB (不安全) @@ -234,12 +243,17 @@ 长度需为3-20个字符 必填 IP格式无效 - 至少5个字符 + 必须为4-20个字符 端口需为1-65535 + 必须为48个字符,且仅包含小写字母a-z + 大厅类型 + 公开 + 未列出 取消 确定 刷新 房间列表 + 需要Web令牌,请前往高级设置 -> 系统 -> 网络 主题颜色 @@ -275,6 +289,7 @@ 字母顺序 列表 网格 + 轮播 文件夹 预发布软件 警告:此版本不适用于公开分享或展示。软件处于预发布阶段,可能存在错误和功能不完整。\n如果您未经授权获取此版本,强烈建议立即卸载。 @@ -450,11 +465,17 @@ 设置自定义系统时间 + 生成 + 网络用户名 + 在多人游戏大厅中显示的用户名。必须为4-20个字符。 网络令牌 用于创建公共房间的网络令牌。它是一个48个字符的字符串,仅包含小写字母a-z。 网络 + 后端 + 显示 + 后处理 精度等级 分辨率 (掌机模式/主机模式) 垂直同步模式 @@ -915,6 +936,9 @@ 软件键盘 + 飞行模式 + 将飞行模式传递给Switch操作系统 + 许可证 来自 AMD 的高品质画质升级技术 diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index 0733a91a0b..0226ae0804 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -55,10 +55,14 @@ 顯示主機GPU型號 顯示SoC型號 顯示主機SoC型號 + 顯示韌體版本 + 顯示已安裝的韌體版本 GPU擴充功能 渲染器 + RAII + Vulkan中的一種自動資源管理方法,確保在不再需要時正確釋放資源,但可能導致捆綁遊戲崩潰。 其他 伊甸之幕 實驗性設定以提高效能和能力。這些設定可能會導致黑屏或其他遊戲問題。 @@ -94,6 +98,11 @@ 使用 Boost (1700MHz) 以 Switch 的最高原生時鐘速度運行,或 Fast (2000MHz) 以雙倍時鐘速度運行。 記憶體佈局 (實驗性) 更改模擬記憶體佈局。此設定不會提高效能,但可能有助於通過模組使用高解析度的遊戲。不要在 RAM 為 8GB 或更少的手機上使用。 + 取樣著色 + 允許片段著色器在多取樣片段中每個樣本執行一次,而不是每個片段執行一次。以提高效能為代價改善圖形品質。僅Vulkan 1.1+裝置支援此擴充功能。 + 自訂CPU時脈 + 設定自訂的CPU時脈值。更高的值可能提高效能,但也可能導致遊戲卡頓。建議範圍為77-21000。 + 時脈 4GB (推薦) @@ -239,12 +248,17 @@ 長度需為3-20個字元 必填 IP格式無效 - 至少5個字元 + 必須為4-20個字元 埠號需為1-65535 + 必須為48個字元,且僅包含小寫字母a-z + 大廳類型 + 公開 + 未列出 取消 確定 刷新 房間列表 + 需要Web令牌,請前往進階設定 -> 系統 -> 網路 主題色彩 @@ -280,6 +294,7 @@ 依字母 列表 網格 + 輪播 資料夾 預覽版軟體 警告:此版本不應公開分享或展示。此為預覽版軟體,可能存在錯誤與未完成功能。\n若您未經授權取得此版本,強烈建議立即解除安裝 @@ -456,11 +471,17 @@ 設定自訂 RTC + 生成 + 網路使用者名稱 + 在多人遊戲大廳中顯示的使用者名稱。必須為4-20個字元。 網路令牌 用於建立公開大廳的網路令牌。它是由48個小寫字母a-z組成的字串。 網路 + 後端 + 顯示 + 後處理 準確度層級 解析度 (手提/底座) VSync 模式 @@ -921,6 +942,9 @@ 軟體鍵盤 + 飛航模式 + 將飛航模式傳遞給Switch作業系統 + 授權 來自 AMD 的升級圖像品質 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 9a937b37bb..01d4d83e27 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -78,6 +78,8 @@ Allows the fragment shader to execute per sample in a multi-sampled fragment instead once per fragment. Improves graphics quality at the cost of some performance. Only Vulkan 1.1+ devices support this extension. Renderer + RAII + A method of automatic resource management in Vulkan that ensures proper release of resources when they are no longer needed, but may cause crashes in bundled games. Enhanced Frame Pacing Ensures smooth and consistent frame delivery by synchronizing the timing between frames, reducing stuttering and uneven animation. Ideal for games that experience frame timing instability or micro-stutters during gameplay. Use Auto Stub diff --git a/src/common/settings.h b/src/common/settings.h index d7a8d201f9..2d5a1c4736 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -321,6 +321,7 @@ struct Values { "shader_backend", Category::Renderer, Specialization::RuntimeList}; SwitchableSetting vulkan_device{linkage, 0, "vulkan_device", Category::Renderer, Specialization::RuntimeList}; + SwitchableSetting enable_raii{linkage, false, "enable_raii", Category::Renderer}; #ifdef __ANDROID__ SwitchableSetting frame_interpolation{linkage, true, "frame_interpolation", Category::Renderer, Specialization::RuntimeList}; @@ -469,7 +470,7 @@ struct Values { SwitchableSetting use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders", Category::RendererAdvanced}; SwitchableSetting use_fast_gpu_time{linkage, - false, + true, "use_fast_gpu_time", Category::RendererAdvanced, Specialization::Paired, diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index ae88dfbddb..a91fba6725 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -110,27 +110,18 @@ try , device_memory(device_memory_) , gpu(gpu_) , library(OpenLibrary(context.get())) - , + , dld() // Create raw Vulkan instance first - instance(CreateInstance(*library, + , instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, Settings::values.renderer_debug.GetValue())) - , - // Now create RAII wrappers for the resources in the correct order - managed_instance(MakeManagedInstance(instance, dld)) - , // Create debug messenger if debug is enabled - debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance) + , debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance) : vk::DebugUtilsMessenger{}) - , managed_debug_messenger(Settings::values.renderer_debug - ? MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld) - : ManagedDebugUtilsMessenger{}) - , // Create surface - surface(CreateSurface(instance, render_window.GetWindowInfo())) - , managed_surface(MakeManagedSurface(surface, instance, dld)) + , surface(CreateSurface(instance, render_window.GetWindowInfo())) , device(CreateDevice(instance, dld, *surface)) , memory_allocator(device) , state_tracker() @@ -138,8 +129,8 @@ try , swapchain(*surface, device, scheduler, - render_window.GetFramebufferLayout().width, - render_window.GetFramebufferLayout().height) + render_window.GetFramebufferLayout().width, + render_window.GetFramebufferLayout().height) , present_manager(instance, render_window, device, @@ -171,23 +162,22 @@ try present_manager, scheduler, PresentFiltersForAppletCapture) - , rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, scheduler) - , applet_frame() { + , rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, scheduler) { + + // Initialize RAII wrappers after creating the main objects + if (Settings::values.enable_raii.GetValue()) { + managed_instance = MakeManagedInstance(instance, dld); + if (Settings::values.renderer_debug) { + managed_debug_messenger = MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld); + } + managed_surface = MakeManagedSurface(surface, instance, dld); + } if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { turbo_mode.emplace(instance, dld); scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); }); } -#ifndef ANDROID - // Release ownership from the old instance and surface - instance.release(); - surface.release(); - if (Settings::values.renderer_debug) { - debug_messenger.release(); - } -#endif - Report(); } catch (const vk::Exception& exception) { LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what()); @@ -223,12 +213,12 @@ class BooleanSetting { BooleanSetting BooleanSetting::FRAME_INTERPOLATION(false); // extern "C" JNIEXPORT jboolean JNICALL -// Java_org_uzuy_uzuy_1emu_features_settings_model_BooleanSetting_isFrameSkippingEnabled(JNIEnv* env, jobject /* this */) { +// Java_org_yuzu_yuzu_1emu_features_settings_model_BooleanSetting_isFrameSkippingEnabled(JNIEnv* env, jobject /* this */) { // return static_cast(BooleanSetting::FRAME_SKIPPING.getBoolean()); // } extern "C" JNIEXPORT jboolean JNICALL - Java_org_uzuy_uzuy_1emu_features_settings_model_BooleanSetting_isFrameInterpolationEnabled(JNIEnv* env, jobject /* this */) { + Java_org_yuzu_yuzu_1emu_features_settings_model_BooleanSetting_isFrameInterpolationEnabled(JNIEnv* env, jobject /* this */) { return static_cast(BooleanSetting::FRAME_INTERPOLATION.getBoolean()); } diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 790a693952..2ff2626b6c 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -330,6 +330,12 @@ std::unique_ptr InitializeTranslations(QWidget* parent) tr("Improves rendering of transparency effects in specific games.")); // Renderer (Extensions) + INSERT(Settings, + enable_raii, + tr("RAII"), + tr("A method of automatic resource management in Vulkan " + "that ensures proper release of resources " + "when they are no longer needed, but may cause crashes in bundled games.")); INSERT(Settings, dyna_state, tr("Extended Dynamic State"), -- 2.39.5 From 52fac14d23cd6e819d89aff6383b8ca3126906ff Mon Sep 17 00:00:00 2001 From: Aleksandr Popovich Date: Thu, 3 Jul 2025 13:22:38 -0400 Subject: [PATCH 03/20] Fix license headers --- src/common/microprofile.h | 3 +++ src/video_core/host1x/host1x.cpp | 3 +++ src/video_core/host1x/host1x.h | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/common/microprofile.h b/src/common/microprofile.h index 5d4c54852f..25bf362500 100644 --- a/src/common/microprofile.h +++ b/src/common/microprofile.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/video_core/host1x/host1x.cpp b/src/video_core/host1x/host1x.cpp index 6256cd8af2..652d387031 100644 --- a/src/video_core/host1x/host1x.cpp +++ b/src/video_core/host1x/host1x.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/video_core/host1x/host1x.h b/src/video_core/host1x/host1x.h index bddb489438..5ecffa442c 100644 --- a/src/video_core/host1x/host1x.h +++ b/src/video_core/host1x/host1x.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -- 2.39.5 From 64fe103afd2ed838a741088a51488c04ae359fad Mon Sep 17 00:00:00 2001 From: Bix Date: Thu, 3 Jul 2025 20:13:31 +0000 Subject: [PATCH 04/20] [Android] Updated app name from "eden" to "Eden". (#256) Signed-off-by: Bix Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/256 --- src/android/app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index fb15783426..b235698b22 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -103,7 +103,7 @@ android { signingConfigs.getByName("default") } - resValue("string", "app_name_suffixed", "eden") + resValue("string", "app_name_suffixed", "Eden") isMinifyEnabled = true isDebuggable = false proguardFiles( -- 2.39.5 From cb3521272ffda48f95a689d56e92c4b51dd0868d Mon Sep 17 00:00:00 2001 From: Aleksandr Popovich Date: Fri, 4 Jul 2025 03:14:05 +0000 Subject: [PATCH 05/20] [ir] Align and bias memory stronger Signed-off-by: Aleksandr Popovich Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/229 Co-authored-by: Aleksandr Popovich Co-committed-by: Aleksandr Popovich --- .../global_memory_to_storage_buffer_pass.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp index 2d4feca02c..902cd698ad 100644 --- a/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp +++ b/src/shader_recompiler/ir_opt/global_memory_to_storage_buffer_pass.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -351,7 +354,7 @@ std::optional Track(const IR::Value& value, const Bias* bias) .index = index.U32(), .offset = offset.U32(), }; - const u32 alignment{bias ? bias->alignment : 8U}; + const u32 alignment{bias ? bias->alignment : 16U}; if (!Common::IsAligned(storage_buffer.offset, alignment)) { // The SSBO pointer has to be aligned return std::nullopt; @@ -372,9 +375,9 @@ void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageInfo& info) // avoid getting false positives static constexpr Bias nvn_bias{ .index = 0, - .offset_begin = 0x100, - .offset_end = 0x700, - .alignment = 16, + .offset_begin = 0x110, + .offset_end = 0x800, + .alignment = 32, }; // Track the low address of the instruction const std::optional low_addr_info{TrackLowAddress(&inst)}; @@ -426,7 +429,10 @@ IR::U32 StorageOffset(IR::Block& block, IR::Inst& inst, StorageBufferAddr buffer // Align the offset base to match the host alignment requirements low_cbuf = ir.BitwiseAnd(low_cbuf, ir.Imm32(~(alignment - 1U))); - return ir.ISub(offset, low_cbuf); + + // It aligns the memory strongly + IR::U32 res = ir.ISub(offset, low_cbuf); + return res; } /// Replace a global memory load instruction with its storage buffer equivalent -- 2.39.5 From aeb2aec13b3e15c9c059e91ee37a08360e95bee0 Mon Sep 17 00:00:00 2001 From: Aleksandr Popovich Date: Fri, 4 Jul 2025 20:24:03 +0000 Subject: [PATCH 06/20] [android] fix firmware overlay multiple updates (#252) Signed-off-by: Aleksandr Popovich Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/252 Co-authored-by: Aleksandr Popovich Co-committed-by: Aleksandr Popovich --- .../main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt | 2 +- .../features/settings/ui/SettingsFragmentPresenter.kt | 3 +-- .../settings/ui/viewholder/SwitchSettingViewHolder.kt | 1 + .../java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt | 4 +++- src/android/app/src/main/jni/android_settings.h | 8 ++++---- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt index dc8d5e5761..ede2cfafa4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt @@ -361,7 +361,7 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { // setup listeners etc val roomNameWatcher = object : TextValidatorWatcher( - binding.btnConfirm, // TODO(alekpop, crueter): Figure out a better way to deal with this? + binding.btnConfirm, binding.layoutRoomName, context.getString( R.string.multiplayer_room_name_error diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index a6110a354a..0cf7be74d3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -56,6 +56,7 @@ class SettingsFragmentPresenter( } val pairedSettingKey = item.setting.pairedSettingKey + if (pairedSettingKey.isNotEmpty()) { val pairedSettingValue = NativeConfig.getBoolean( pairedSettingKey, @@ -220,7 +221,6 @@ class SettingsFragmentPresenter( private fun addGraphicsSettings(sl: ArrayList) { sl.apply { - // TODO(crueter): reorganize this, this is awful add(HeaderSetting(R.string.backend)) add(IntSetting.RENDERER_ACCURACY.key) @@ -436,7 +436,6 @@ class SettingsFragmentPresenter( } } - // TODO(alekpop): sort these into headers. private fun addEdenVeilSettings(sl: ArrayList) { sl.apply { add(HeaderSetting(R.string.veil_extensions)) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt index e5763264a4..e4a2a82c9a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt @@ -22,6 +22,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter binding.textSettingDescription.setVisible(setting.description.isNotEmpty()) binding.textSettingDescription.text = setting.description + // TODO(alekpop): A race condition occurs here if the button is clicked too fast binding.switchWidget.setOnCheckedChangeListener(null) binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal) binding.switchWidget.setOnCheckedChangeListener { _: CompoundButton, _: Boolean -> diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 641522de4d..9ba2d9e625 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -105,6 +105,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { private var isInFoldableLayout = false private lateinit var gpuModel: String + private lateinit var fwVersion: String override fun onAttach(context: Context) { super.onAttach(context) @@ -186,6 +187,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } gpuModel = GpuDriverHelper.getGpuModel().toString() + fwVersion = NativeLibrary.firmwareVersion() binding.surfaceEmulation.holder.addCallback(this) binding.doneControlConfig.setOnClickListener { stopConfiguringControls() } @@ -755,7 +757,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { if (BooleanSetting.SHOW_FW_VERSION.getBoolean(NativeConfig.isPerGameConfigLoaded())) { if (sb.isNotEmpty()) sb.append(" | ") - sb.append(NativeLibrary.firmwareVersion()) + sb.append(fwVersion) } binding.showSocOverlayText.text = sb.toString() diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h index 67d70a6adc..e7401a8947 100644 --- a/src/android/app/src/main/jni/android_settings.h +++ b/src/android/app/src/main/jni/android_settings.h @@ -127,22 +127,22 @@ namespace AndroidSettings { Settings::Setting show_device_model{linkage, true, "show_device_model", Settings::Category::Overlay, Settings::Specialization::Default, true, true, - &show_performance_overlay}; + &show_soc_overlay}; Settings::Setting show_gpu_model{linkage, true, "show_gpu_model", Settings::Category::Overlay, Settings::Specialization::Default, true, true, - &show_performance_overlay}; + &show_soc_overlay}; Settings::Setting show_soc_model{linkage, true, "show_soc_model", Settings::Category::Overlay, Settings::Specialization::Default, true, true, - &show_performance_overlay}; + &show_soc_overlay}; Settings::Setting show_fw_version{linkage, true, "show_firmware_version", Settings::Category::Overlay, Settings::Specialization::Default, true, true, - &show_performance_overlay}; + &show_soc_overlay}; Settings::Setting soc_overlay_background{linkage, false, "soc_overlay_background", Settings::Category::Overlay, -- 2.39.5 From b60d0aabf0bddcc0866577d0de2d6a39efdd896b Mon Sep 17 00:00:00 2001 From: Aleksandr Popovich Date: Fri, 4 Jul 2025 20:29:23 +0000 Subject: [PATCH 07/20] [android] improve driver fetcher (#251) - Fix the app compat crash - Fix kimchi sorting - Improve performance in ui thread Signed-off-by: Aleksandr Popovich Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/251 Co-authored-by: Aleksandr Popovich Co-committed-by: Aleksandr Popovich --- .../features/fetcher/DriverGroupAdapter.kt | 57 ++++++--- .../fragments/DriverFetcherFragment.kt | 118 +++++++++++------- .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 8 +- 3 files changed, 118 insertions(+), 65 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt index 06105d2702..14d69cb384 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + package org.yuzu.yuzu_emu.features.fetcher import android.annotation.SuppressLint @@ -17,7 +20,9 @@ import androidx.transition.TransitionManager import androidx.transition.TransitionSet import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.yuzu.yuzu_emu.model.DriverViewModel class DriverGroupAdapter( @@ -25,43 +30,61 @@ class DriverGroupAdapter( private val driverViewModel: DriverViewModel ) : RecyclerView.Adapter() { private var driverGroups: List = emptyList() + private val adapterJobs = mutableMapOf() inner class DriverGroupViewHolder( private val binding: ItemDriverGroupBinding ) : RecyclerView.ViewHolder(binding.root) { fun bind(group: DriverGroup) { + binding.textGroupName.text = group.name + + if (binding.recyclerReleases.layoutManager == null) { + binding.recyclerReleases.layoutManager = LinearLayoutManager(activity) + binding.recyclerReleases.addItemDecoration( + SpacingItemDecoration( + (activity.resources.displayMetrics.density * 8).toInt() + ) + ) + } + val onClick = { + adapterJobs[bindingAdapterPosition]?.cancel() + TransitionManager.beginDelayedTransition( binding.root, TransitionSet().addTransition(Fade()).addTransition(ChangeBounds()) .setDuration(200) ) + val isVisible = binding.recyclerReleases.isVisible + if (!isVisible && binding.recyclerReleases.adapter == null) { + val job = CoroutineScope(Dispatchers.Main).launch { + // It prevents blocking the ui thread. + var adapter: ReleaseAdapter? + + withContext(Dispatchers.IO) { + adapter = ReleaseAdapter(group.releases, activity, driverViewModel) + } + + binding.recyclerReleases.adapter = adapter + } + + adapterJobs[bindingAdapterPosition] = job + } + binding.recyclerReleases.visibility = if (isVisible) View.GONE else View.VISIBLE binding.imageDropdownArrow.rotation = if (isVisible) 0f else 180f - - if (!isVisible && binding.recyclerReleases.adapter == null) { - CoroutineScope(Dispatchers.Main).launch { - binding.recyclerReleases.layoutManager = - LinearLayoutManager(binding.root.context) - binding.recyclerReleases.adapter = - ReleaseAdapter(group.releases, activity, driverViewModel) - - binding.recyclerReleases.addItemDecoration( - SpacingItemDecoration( - (activity.resources.displayMetrics.density * 8).toInt() - ) - ) - } - } } - binding.textGroupName.text = group.name binding.textGroupName.setOnClickListener { onClick() } - binding.imageDropdownArrow.setOnClickListener { onClick() } } + + fun clear() { + adapterJobs[bindingAdapterPosition]?.cancel() + adapterJobs.remove(bindingAdapterPosition) + } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverGroupViewHolder { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt index 7c6dc238e3..0c1e39d095 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt @@ -1,6 +1,8 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + package org.yuzu.yuzu_emu.fragments -import android.app.AlertDialog import android.os.Bundle import androidx.fragment.app.Fragment import android.view.LayoutInflater @@ -28,10 +30,12 @@ import org.yuzu.yuzu_emu.databinding.FragmentDriverFetcherBinding import org.yuzu.yuzu_emu.features.fetcher.DriverGroupAdapter import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.utils.GpuDriverHelper -import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import java.io.IOException import java.net.URL +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId import kotlin.getValue class DriverFetcherFragment : Fragment() { @@ -49,17 +53,22 @@ class DriverFetcherFragment : Fragment() { private val recommendedDriver: String get() = driverMap.firstOrNull { adrenoModel in it.first }?.second ?: "Unsupported" + enum class SortMode { + Default, PublishTime, + } + private data class DriverRepo( val name: String = "", val path: String = "", val sort: Int = 0, - val useTagName: Boolean = false + val useTagName: Boolean = false, + val sortMode: SortMode = SortMode.Default, ) private val repoList: List = listOf( DriverRepo("Mr. Purple Turnip", "MrPurple666/purple-turnip", 0), DriverRepo("GameHub Adreno 8xx", "crueter/GameHub-8Elite-Drivers", 1), - DriverRepo("KIMCHI Turnip", "K11MCH1/AdrenoToolsDrivers", 2, true), + DriverRepo("KIMCHI Turnip", "K11MCH1/AdrenoToolsDrivers", 2, true, SortMode.PublishTime), DriverRepo("Weab-Chan Freedreno", "Weab-chan/freedreno_turnip-CI", 3), ) @@ -78,7 +87,7 @@ class DriverFetcherFragment : Fragment() { private lateinit var driverGroupAdapter: DriverGroupAdapter private val driverViewModel: DriverViewModel by activityViewModels() - fun parseAdrenoModel(): Int { + private fun parseAdrenoModel(): Int { if (gpuModel == null) { return 0 } @@ -115,9 +124,8 @@ class DriverFetcherFragment : Fragment() { } override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { _binding = FragmentDriverFetcherBinding.inflate(inflater) binding.badgeRecommendedDriver.text = recommendedDriver binding.badgeGpuModel.text = gpuModel @@ -150,11 +158,12 @@ class DriverFetcherFragment : Fragment() { val name = driver.name val path = driver.path val useTagName = driver.useTagName + val sortMode = driver.sortMode val sort = driver.sort + CoroutineScope(Dispatchers.Main).launch { - val request = Request.Builder() - .url("https://api.github.com/repos/$path/releases") - .build() + val request = + Request.Builder().url("https://api.github.com/repos/$path/releases").build() withContext(Dispatchers.IO) { var releases: ArrayList @@ -165,28 +174,25 @@ class DriverFetcherFragment : Fragment() { } val body = response.body?.string() ?: return@withContext - releases = Release.fromJsonArray(body, useTagName) + releases = Release.fromJsonArray(body, useTagName, sortMode) } } catch (e: Exception) { withContext(Dispatchers.Main) { - MaterialAlertDialogBuilder(requireActivity().applicationContext) - .setTitle(getString(R.string.error_during_fetch)) + MaterialAlertDialogBuilder(requireActivity()).setTitle(getString(R.string.error_during_fetch)) .setMessage("${getString(R.string.failed_to_fetch)} ${name}:\n${e.message}") .setPositiveButton(getString(R.string.ok)) { dialog, _ -> dialog.cancel() } .show() - releases = ArrayList() + releases = ArrayList() } } - val driver = DriverGroup( - name, - releases, - sort + val group = DriverGroup( + name, releases, sort ) synchronized(driverGroups) { - driverGroups.add(driver) + driverGroups.add(group) driverGroups.sortBy { it.sort } @@ -204,39 +210,41 @@ class DriverFetcherFragment : Fragment() { } } - private fun setInsets() = - ViewCompat.setOnApplyWindowInsetsListener( - binding.root - ) { _: View, windowInsets: WindowInsetsCompat -> - val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) - val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) + private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener( + binding.root + ) { _: View, windowInsets: WindowInsetsCompat -> + val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) + val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) - val leftInsets = barInsets.left + cutoutInsets.left - val rightInsets = barInsets.right + cutoutInsets.right + val leftInsets = barInsets.left + cutoutInsets.left + val rightInsets = barInsets.right + cutoutInsets.right - binding.toolbarDrivers.updateMargins(left = leftInsets, right = rightInsets) - binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets) + binding.toolbarDrivers.updateMargins(left = leftInsets, right = rightInsets) + binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets) - binding.listDrivers.updatePadding( - bottom = barInsets.bottom + - resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab) - ) + binding.listDrivers.updatePadding( + bottom = barInsets.bottom + resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab) + ) - windowInsets - } + windowInsets + } data class Artifact(val url: URL, val name: String) data class Release( var tagName: String = "", + var titleName: String = "", var title: String = "", var body: String = "", - var artifacts: List = ArrayList(), + var artifacts: List = ArrayList(), var prerelease: Boolean = false, - var latest: Boolean = false + var latest: Boolean = false, + var publishTime: LocalDateTime = LocalDateTime.now(), ) { companion object { - fun fromJsonArray(jsonString: String, useTagName: Boolean): ArrayList { + fun fromJsonArray( + jsonString: String, useTagName: Boolean, sortMode: SortMode + ): ArrayList { val mapper = jacksonObjectMapper() try { @@ -256,39 +264,55 @@ class DriverFetcherFragment : Fragment() { } releases.add(release) + + println(release.publishTime) } } + when (sortMode) { + SortMode.PublishTime -> releases.sortByDescending { + it.publishTime + } + + else -> {} + } + return releases } catch (e: Exception) { e.printStackTrace() - return ArrayList() + return ArrayList() } } - fun fromJson(node: JsonNode, useTagName: Boolean): Release { + private fun fromJson(node: JsonNode, useTagName: Boolean): Release { try { val tagName = node.get("tag_name").toString().removeSurrounding("\"") val body = node.get("body").toString().removeSurrounding("\"") val prerelease = node.get("prerelease").toString().toBoolean() - val title = if (useTagName) tagName else node.get("name").toString().removeSurrounding("\"") + val titleName = node.get("name").toString().removeSurrounding("\"") + + val published = node.get("published_at").toString().removeSurrounding("\"") + val instantTime: Instant? = Instant.parse(published) + val localTime = instantTime?.atZone(ZoneId.systemDefault())?.toLocalDateTime() ?: LocalDateTime.now() + + val title = if (useTagName) tagName else titleName val assets = node.get("assets") val artifacts = ArrayList() if (assets?.isArray == true) { - assets.forEach { node -> - val urlStr = - node.get("browser_download_url").toString().removeSurrounding("\"") + assets.forEach { subNode -> + val urlStr = subNode.get("browser_download_url").toString() + .removeSurrounding("\"") val url = URL(urlStr) - val name = node.get("name").toString().removeSurrounding("\"") + val name = subNode.get("name").toString().removeSurrounding("\"") val artifact = Artifact(url, name) artifacts.add(artifact) } } - return Release(tagName, title, body, artifacts, prerelease) + return Release(tagName, titleName, title, body, artifacts, prerelease, false, localTime) } catch (e: Exception) { // TODO: handle malformed input. e.printStackTrace() diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 3a9c5486a8..5177e78874 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -335,7 +335,13 @@ class MainActivity : AppCompatActivity(), ThemeProvider { Toast.LENGTH_SHORT ).show() homeViewModel.setCheckKeys(true) - homeViewModel.setCheckFirmware(true) + + val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext) + .getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true) + if (!firstTimeSetup) { + homeViewModel.setCheckFirmware(true) + } + gamesViewModel.reloadGames(true) return true } else { -- 2.39.5 From 39a46d755f103579a1ef19cd5fbda2916fd334c1 Mon Sep 17 00:00:00 2001 From: Aleksandr Popovich Date: Fri, 4 Jul 2025 21:37:15 +0000 Subject: [PATCH 08/20] [android] Update carousel view (#254) - Cherry picked the patches from xbzk PR. Signed-off-by: Aleksandr Popovich Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/254 Co-authored-by: Aleksandr Popovich Co-committed-by: Aleksandr Popovich --- src/android/app/build.gradle.kts | 2 +- .../org/yuzu/yuzu_emu/adapters/GameAdapter.kt | 26 +- .../MidScreenSwipeRefreshLayout.kt | 6 +- .../org/yuzu/yuzu_emu/model/GamesViewModel.kt | 10 + .../org/yuzu/yuzu_emu/ui/GamesFragment.kt | 88 ++-- .../yuzu/yuzu_emu/ui/JukeboxRecyclerView.kt | 287 ------------ .../yuzu_emu/views/CarouselRecyclerView.kt | 409 ++++++++++++++++++ .../res/layout-land/card_game_carousel.xml | 46 ++ .../main/res/layout-land/fragment_games.xml | 3 +- .../app/src/main/res/values/dimens.xml | 1 - .../app/src/main/res/values/fractions.xml | 8 +- .../app/src/main/res/values/integers.xml | 4 + 12 files changed, 544 insertions(+), 346 deletions(-) rename src/android/app/src/main/java/org/yuzu/yuzu_emu/{ui => layout}/MidScreenSwipeRefreshLayout.kt (75%) delete mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/JukeboxRecyclerView.kt create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/views/CarouselRecyclerView.kt create mode 100644 src/android/app/src/main/res/layout-land/card_game_carousel.xml diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index b235698b22..5a65a28baf 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -127,7 +127,7 @@ android { applicationIdSuffix = ".relWithDebInfo" isJniDebuggable = true } - + // Signed by debug key disallowing distribution on Play Store. // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. debug { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index c5fc6ff168..750e8f4729 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -32,6 +32,7 @@ import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.utils.GameIconUtils import org.yuzu.yuzu_emu.utils.ViewUtils.marquee import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder +import androidx.recyclerview.widget.RecyclerView class GameAdapter(private val activity: AppCompatActivity) : AbstractDiffAdapter(exact = false) { @@ -49,7 +50,7 @@ class GameAdapter(private val activity: AppCompatActivity) : notifyDataSetChanged() } - var cardSize: Int = 0 + public var cardSize: Int = 0 private set fun setCardSize(size: Int) { @@ -63,7 +64,6 @@ class GameAdapter(private val activity: AppCompatActivity) : override fun onBindViewHolder(holder: GameViewHolder, position: Int) { super.onBindViewHolder(holder, position) - // Always reset scale/alpha for recycled views when (getItemViewType(position)) { VIEW_TYPE_LIST -> { val listBinding = holder.binding as CardGameListBinding @@ -85,14 +85,9 @@ class GameAdapter(private val activity: AppCompatActivity) : } VIEW_TYPE_CAROUSEL -> { val carouselBinding = holder.binding as CardGameCarouselBinding - carouselBinding.cardGameCarousel.scaleX = 1f - carouselBinding.cardGameCarousel.scaleY = 1f + //soothens transient flickering + carouselBinding.cardGameCarousel.scaleY = 0f carouselBinding.cardGameCarousel.alpha = 0f - // Set square size for carousel - if (cardSize > 0) { - carouselBinding.root.layoutParams.width = cardSize - carouselBinding.root.layoutParams.height = cardSize - } } } } @@ -158,16 +153,6 @@ class GameAdapter(private val activity: AppCompatActivity) : private fun bindCarouselView(model: Game) { val carouselBinding = binding as CardGameCarouselBinding - // Remove padding from the root LinearLayout - (carouselBinding.root.getChildAt(0) as? LinearLayout)?.setPadding(0, 0, 0, 0) - - // Always set square size and remove margins for carousel - val params = carouselBinding.root.layoutParams - params.width = cardSize - params.height = cardSize - if (params is ViewGroup.MarginLayoutParams) params.setMargins(0, 0, 0, 0) - carouselBinding.root.layoutParams = params - carouselBinding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP GameIconUtils.loadGameIcon(model, carouselBinding.imageGameScreen) @@ -178,6 +163,9 @@ class GameAdapter(private val activity: AppCompatActivity) : carouselBinding.imageGameScreen.contentDescription = binding.root.context.getString(R.string.game_image_desc, model.title) + + // Ensure zero-heighted-full-width cards for carousel + carouselBinding.root.layoutParams.width = cardSize } fun onClick(game: Game) { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/MidScreenSwipeRefreshLayout.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/MidScreenSwipeRefreshLayout.kt similarity index 75% rename from src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/MidScreenSwipeRefreshLayout.kt rename to src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/MidScreenSwipeRefreshLayout.kt index 74de15205f..649bea9d54 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/MidScreenSwipeRefreshLayout.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/MidScreenSwipeRefreshLayout.kt @@ -3,6 +3,7 @@ package org.yuzu.yuzu_emu.ui +import org.yuzu.yuzu_emu.R import android.content.Context import android.util.AttributeSet import android.view.MotionEvent @@ -21,8 +22,9 @@ class MidScreenSwipeRefreshLayout @JvmOverloads constructor( MotionEvent.ACTION_DOWN -> { startX = ev.x val width = width - val leftBound = width / 3 - val rightBound = width * 2 / 3 + val center_fraction = resources.getFraction(R.fraction.carousel_midscreenswipe_width_fraction, 1, 1).coerceIn(0f, 1f) + val leftBound = ((1 - center_fraction) / 2) * width + val rightBound = leftBound + (width * center_fraction) allowRefresh = startX >= leftBound && startX <= rightBound } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt index 8e4b566766..66f012d1af 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt @@ -42,11 +42,16 @@ class GamesViewModel : ViewModel() { val searchFocused: StateFlow get() = _searchFocused private val _searchFocused = MutableStateFlow(false) + val shouldScrollAfterReload: StateFlow get() = _shouldScrollAfterReload + private val _shouldScrollAfterReload = MutableStateFlow(false) + private val _folders = MutableStateFlow(mutableListOf()) val folders = _folders.asStateFlow() private val _filteredGames = MutableStateFlow>(emptyList()) + var lastScrollPosition: Int = 0 + init { // Ensure keys are loaded so that ROM metadata can be decrypted. NativeLibrary.reloadKeys() @@ -74,6 +79,10 @@ class GamesViewModel : ViewModel() { _shouldScrollToTop.value = shouldScroll } + fun setShouldScrollAfterReload(shouldScroll: Boolean) { + _shouldScrollAfterReload.value = shouldScroll + } + fun setSearchFocused(searchFocused: Boolean) { _searchFocused.value = searchFocused } @@ -123,6 +132,7 @@ class GamesViewModel : ViewModel() { setGames(GameHelper.getGames()) reloading.set(false) _isReloading.value = false + _shouldScrollAfterReload.value = true if (directoriesChanged) { setShouldSwapData(true) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt index 38d6ebc7d3..1a74057569 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt @@ -11,6 +11,7 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.ViewTreeObserver import android.view.inputmethod.InputMethodManager import android.widget.ImageButton import android.widget.PopupMenu @@ -48,6 +49,8 @@ import java.util.Locale import androidx.core.content.edit import androidx.core.view.updateLayoutParams import org.yuzu.yuzu_emu.features.settings.model.Settings +import android.view.ViewParent +import androidx.core.view.doOnNextLayout class GamesFragment : Fragment() { private var _binding: FragmentGamesBinding? = null @@ -62,8 +65,6 @@ class GamesFragment : Fragment() { companion object { private const val SEARCH_TEXT = "SearchText" - private const val PREF_VIEW_TYPE_PORTRAIT = "GamesViewTypePortrait" - private const val PREF_VIEW_TYPE_LANDSCAPE = "GamesViewTypeLandscape" private const val PREF_SORT_TYPE = "GamesSortType" } @@ -84,14 +85,14 @@ class GamesFragment : Fragment() { private fun getCurrentViewType(): Int { val isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE - val key = if (isLandscape) PREF_VIEW_TYPE_LANDSCAPE else PREF_VIEW_TYPE_PORTRAIT + val key = if (isLandscape) CarouselRecyclerView.CAROUSEL_VIEW_TYPE_LANDSCAPE else CarouselRecyclerView.CAROUSEL_VIEW_TYPE_PORTRAIT val fallback = if (isLandscape) GameAdapter.VIEW_TYPE_CAROUSEL else GameAdapter.VIEW_TYPE_GRID return preferences.getInt(key, fallback) } private fun setCurrentViewType(type: Int) { val isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE - val key = if (isLandscape) PREF_VIEW_TYPE_LANDSCAPE else PREF_VIEW_TYPE_PORTRAIT + val key = if (isLandscape) CarouselRecyclerView.CAROUSEL_VIEW_TYPE_LANDSCAPE else CarouselRecyclerView.CAROUSEL_VIEW_TYPE_PORTRAIT preferences.edit { putInt(key, type) } } override fun onCreateView( @@ -150,7 +151,9 @@ class GamesFragment : Fragment() { ) } gamesViewModel.games.collect(viewLifecycleOwner) { - setAdapter(it) + if (it.size > 0) { + setAdapter(it) + } } gamesViewModel.shouldSwapData.collect( viewLifecycleOwner, @@ -165,6 +168,16 @@ class GamesFragment : Fragment() { resetState = { gamesViewModel.setShouldScrollToTop(false) } ) { if (it) scrollToTop() } + gamesViewModel.shouldScrollAfterReload.collect(viewLifecycleOwner) { shouldScroll -> + if (shouldScroll) { + binding.gridGames.post { + (binding.gridGames as? CarouselRecyclerView)?.pendingScrollAfterReload = true + gameAdapter.notifyDataSetChanged() + } + gamesViewModel.setShouldScrollAfterReload(false) + } + } + setupTopView() binding.addDirectory.setOnClickListener { @@ -176,17 +189,12 @@ class GamesFragment : Fragment() { val applyGridGamesBinding = { (binding.gridGames as? RecyclerView)?.apply { - val savedViewType = getCurrentViewType() val isLandscape = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE - val effectiveViewType = if (!isLandscape && savedViewType == GameAdapter.VIEW_TYPE_CAROUSEL) { - GameAdapter.VIEW_TYPE_GRID - } else { - savedViewType - } - gameAdapter.setViewType(effectiveViewType) + val currentViewType = getCurrentViewType() + val savedViewType = if (isLandscape || currentViewType != GameAdapter.VIEW_TYPE_CAROUSEL) currentViewType else GameAdapter.VIEW_TYPE_GRID + gameAdapter.setViewType(savedViewType) currentFilter = preferences.getInt(PREF_SORT_TYPE, View.NO_ID) - val overlapPx = resources.getDimensionPixelSize(R.dimen.carousel_overlap) // Set the correct layout manager layoutManager = when (savedViewType) { @@ -203,23 +211,14 @@ class GamesFragment : Fragment() { } else -> throw IllegalArgumentException("Invalid view type: $savedViewType") } - - // Carousel mode: wait for layout, then set card size and enable carousel features if (savedViewType == GameAdapter.VIEW_TYPE_CAROUSEL) { - post { - val insets = ViewCompat.getRootWindowInsets(this) - val bottomInset = insets?.getInsets(WindowInsetsCompat.Type.systemBars())?.bottom ?: 0 - val size = (resources.getFraction(R.fraction.carousel_card_size_multiplier, 1, 1) * (height - bottomInset)).toInt() - if (size > 0) { - gameAdapter.setCardSize(size) - (this as? JukeboxRecyclerView)?.setCarouselMode(true, overlapPx, size) - } + doOnNextLayout { + (this as? CarouselRecyclerView)?.setCarouselMode(true, gameAdapter) + adapter = gameAdapter } } else { - // Disable carousel features in other modes - (this as? JukeboxRecyclerView)?.setCarouselMode(false, overlapPx, 0) + (this as? CarouselRecyclerView)?.setCarouselMode(false) } - adapter = gameAdapter lastViewType = savedViewType } @@ -232,12 +231,34 @@ class GamesFragment : Fragment() { } } + override fun onPause() { + super.onPause() + if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) { + gamesViewModel.lastScrollPosition = (binding.gridGames as? CarouselRecyclerView)?.getClosestChildPosition() ?: 0 + } + } + + override fun onResume() { + super.onResume() + if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) { + (binding.gridGames as? CarouselRecyclerView)?.restoreScrollState(gamesViewModel.lastScrollPosition) + } + } + + private var lastSearchText: String = "" + private var lastFilter: Int = preferences.getInt(PREF_SORT_TYPE, View.NO_ID) + private fun setAdapter(games: List) { val currentSearchText = binding.searchText.text.toString() val currentFilter = binding.filterButton.id - if (currentSearchText.isNotEmpty() || currentFilter != View.NO_ID) { + val searchChanged = currentSearchText != lastSearchText + val filterChanged = currentFilter != lastFilter + + if (searchChanged || filterChanged) { filterAndSearch(games) + lastSearchText = currentSearchText + lastFilter = currentFilter } else { ((binding.gridGames as? RecyclerView)?.adapter as? GameAdapter)?.submitList(games) gamesViewModel.setFilteredGames(games) @@ -292,6 +313,7 @@ class GamesFragment : Fragment() { popup.setOnMenuItemClickListener { item -> when (item.itemId) { R.id.view_grid -> { + if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) onPause() setCurrentViewType(GameAdapter.VIEW_TYPE_GRID) applyGridGamesBinding() item.isChecked = true @@ -299,6 +321,7 @@ class GamesFragment : Fragment() { } R.id.view_list -> { + if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) onPause() setCurrentViewType(GameAdapter.VIEW_TYPE_LIST) applyGridGamesBinding() item.isChecked = true @@ -306,9 +329,12 @@ class GamesFragment : Fragment() { } R.id.view_carousel -> { - setCurrentViewType(GameAdapter.VIEW_TYPE_CAROUSEL) - applyGridGamesBinding() - item.isChecked = true + if (!item.isChecked || getCurrentViewType() != GameAdapter.VIEW_TYPE_CAROUSEL) { + setCurrentViewType(GameAdapter.VIEW_TYPE_CAROUSEL) + applyGridGamesBinding() + item.isChecked = true + onResume() + } true } @@ -402,7 +428,7 @@ class GamesFragment : Fragment() { private fun scrollToTop() { if (_binding != null) { - (binding.gridGames as? JukeboxRecyclerView)?.smoothScrollToPosition(0) + (binding.gridGames as? CarouselRecyclerView)?.smoothScrollToPosition(0) } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/JukeboxRecyclerView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/JukeboxRecyclerView.kt deleted file mode 100644 index 130e10dacf..0000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/JukeboxRecyclerView.kt +++ /dev/null @@ -1,287 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -package org.yuzu.yuzu_emu.ui - -import android.content.Context -import android.graphics.Rect -import android.util.AttributeSet -import android.view.View -import android.view.KeyEvent -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.PagerSnapHelper -import androidx.recyclerview.widget.RecyclerView -import kotlin.math.abs -import org.yuzu.yuzu_emu.R - -/** - * JukeboxRecyclerView encapsulates all carousel/grid/list logic for the games UI. - * It manages overlapping cards, center snapping, custom drawing order, and mid-screen swipe-to-refresh. - * Use setCarouselMode(enabled, overlapPx) to toggle carousel features. - */ -class JukeboxRecyclerView @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyle: Int = 0 -) : RecyclerView(context, attrs, defStyle) { - - // Carousel/overlap/snap state - private var overlapPx: Int = 0 - private var overlapDecoration: OverlappingDecoration? = null - private var pagerSnapHelper: PagerSnapHelper? = null - - var flingMultiplier: Float = resources.getFraction(R.fraction.carousel_fling_multiplier, 1, 1) - - var useCustomDrawingOrder: Boolean = false - set(value) { - field = value - setChildrenDrawingOrderEnabled(value) - invalidate() - } - - init { - setChildrenDrawingOrderEnabled(true) - } - - /** - * Returns the horizontal center given width and paddings. - */ - private fun calculateCenter(width: Int, paddingStart: Int, paddingEnd: Int): Int { - return paddingStart + (width - paddingStart - paddingEnd) / 2 - } - - /** - * Returns the horizontal center of this RecyclerView, accounting for padding. - */ - private fun getRecyclerViewCenter(): Float { - return calculateCenter(width, paddingLeft, paddingRight).toFloat() - } - - /** - * Returns the horizontal center of a LayoutManager, accounting for padding. - */ - private fun getLayoutManagerCenter(layoutManager: RecyclerView.LayoutManager): Int { - return if (layoutManager is LinearLayoutManager) { - calculateCenter(layoutManager.width, layoutManager.paddingStart, layoutManager.paddingEnd) - } else { - width / 2 - } - } - - private fun updateChildScalesAndAlpha() { - val center = getRecyclerViewCenter() - - for (i in 0 until childCount) { - val child = getChildAt(i) - val childCenter = (child.left + child.right) / 2f - val distance = abs(center - childCenter) - val minScale = resources.getFraction(R.fraction.carousel_min_scale, 1, 1) - val scale = minScale + (1f - minScale) * (1f - distance / center).coerceAtMost(1f) - child.scaleX = scale - child.scaleY = scale - - val maxDistance = width / 2f - val norm = (distance / maxDistance).coerceIn(0f, 1f) - val minAlpha = resources.getFraction(R.fraction.carousel_min_alpha, 1, 1) - val alpha = minAlpha + (1f - minAlpha) * kotlin.math.cos(norm * Math.PI).toFloat() - child.alpha = alpha - } - } - - /** - * Enable or disable carousel mode. - * When enabled, applies overlap, snap, and custom drawing order. - */ - fun setCarouselMode(enabled: Boolean, overlapPx: Int = 0, cardSize: Int = 0) { - this.overlapPx = overlapPx - if (enabled) { - // Add overlap decoration if not present - if (overlapDecoration == null) { - overlapDecoration = OverlappingDecoration(overlapPx) - addItemDecoration(overlapDecoration!!) - } - // Attach PagerSnapHelper - if (pagerSnapHelper == null) { - pagerSnapHelper = CenterPagerSnapHelper() - pagerSnapHelper!!.attachToRecyclerView(this) - } - useCustomDrawingOrder = true - flingMultiplier = resources.getFraction(R.fraction.carousel_fling_multiplier, 1, 1) - - // Center first/last card - post { - if (cardSize > 0) { - val sidePadding = (width - cardSize) / 2 - setPadding(sidePadding, 0, sidePadding, 0) - clipToPadding = false - } - } - // Handle bottom insets for keyboard/navigation bar only - androidx.core.view.ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets -> - val imeInset = insets.getInsets(androidx.core.view.WindowInsetsCompat.Type.ime()).bottom - val navInset = insets.getInsets(androidx.core.view.WindowInsetsCompat.Type.navigationBars()).bottom - // Only adjust bottom padding, keep top at 0 - view.setPadding(view.paddingLeft, 0, view.paddingRight, maxOf(imeInset, navInset)) - insets - } - } else { - // Remove overlap decoration - overlapDecoration?.let { removeItemDecoration(it) } - overlapDecoration = null - // Detach PagerSnapHelper - pagerSnapHelper?.attachToRecyclerView(null) - pagerSnapHelper = null - useCustomDrawingOrder = false - // Reset padding and fling - setPadding(0, 0, 0, 0) - clipToPadding = true - flingMultiplier = 1.0f - // Reset scaling - for (i in 0 until childCount) { - val child = getChildAt(i) - child?.scaleX = 1f - child?.scaleY = 1f - } - } - } - - // trap past boundaries navigation - override fun focusSearch(focused: View, direction: Int): View? { - val lm = layoutManager as? LinearLayoutManager ?: return super.focusSearch(focused, direction) - val vh = findContainingViewHolder(focused) ?: return super.focusSearch(focused, direction) - val position = vh.bindingAdapterPosition - val itemCount = adapter?.itemCount ?: return super.focusSearch(focused, direction) - - return when (direction) { - View.FOCUS_LEFT -> { - if (position > 0) { - findViewHolderForAdapterPosition(position - 1)?.itemView ?: super.focusSearch(focused, direction) - } else { - focused - } - } - View.FOCUS_RIGHT -> { - if (position < itemCount - 1) { - findViewHolderForAdapterPosition(position + 1)?.itemView ?: super.focusSearch(focused, direction) - } else { - focused - } - } - else -> super.focusSearch(focused, direction) - } - } - - // Custom fling multiplier for carousel - override fun fling(velocityX: Int, velocityY: Int): Boolean { - val newVelocityX = (velocityX * flingMultiplier).toInt() - val newVelocityY = (velocityY * flingMultiplier).toInt() - return super.fling(newVelocityX, newVelocityY) - } - - private var scaleUpdatePosted = false - // Custom drawing order for carousel (for alpha fade) - override fun getChildDrawingOrder(childCount: Int, i: Int): Int { - if (!useCustomDrawingOrder || childCount == 0) return i - val center = getRecyclerViewCenter() - val children = (0 until childCount).map { idx -> - val child = getChildAt(idx) - val childCenter = (child.left + child.right) / 2f - val distance = abs(childCenter - center) - Pair(idx, distance) - } - val sorted = children.sortedWith( - compareByDescending> { it.second } - .thenBy { it.first } - ) - // Post scale update once per frame - if (!scaleUpdatePosted && i == childCount - 1) { - scaleUpdatePosted = true - post { - updateChildScalesAndAlpha() - scaleUpdatePosted = false - } - } - //Log.d("JukeboxRecyclerView", "Child $i got order ${sorted[i].first} at distance ${sorted[i].second} from center $center") - return sorted[i].first - } - - // --- OverlappingDecoration (inner class) --- - inner class OverlappingDecoration(private val overlapPx: Int) : ItemDecoration() { - override fun getItemOffsets( - outRect: Rect, view: View, parent: RecyclerView, state: State - ) { - val position = parent.getChildAdapterPosition(view) - if (position > 0) { - outRect.left = -overlapPx - } - } - } - - // Enable proper center snapping - inner class CenterPagerSnapHelper : PagerSnapHelper() { - - // NEEDED: fixes center snapping, but introduces ghost movement - override fun findSnapView(layoutManager: RecyclerView.LayoutManager): View? { - if (layoutManager !is LinearLayoutManager) return null - val center = (this@JukeboxRecyclerView).getLayoutManagerCenter(layoutManager) - var minDistance = Int.MAX_VALUE - var closestChild: View? = null - for (i in 0 until layoutManager.childCount) { - val child = layoutManager.getChildAt(i) ?: continue - val childCenter = (child.left + child.right) / 2 - val distance = kotlin.math.abs(childCenter - center) - if (distance < minDistance) { - minDistance = distance - closestChild = child - } - } - return closestChild - } - - //NEEDED: fixes ghost movement when snapping, but breaks inertial scrolling - override fun calculateDistanceToFinalSnap( - layoutManager: RecyclerView.LayoutManager, - targetView: View - ): IntArray? { - if (layoutManager !is LinearLayoutManager) return super.calculateDistanceToFinalSnap(layoutManager, targetView) - val out = IntArray(2) - val center = (this@JukeboxRecyclerView).getLayoutManagerCenter(layoutManager) - val childCenter = (targetView.left + targetView.right) / 2 - out[0] = childCenter - center - out[1] = 0 - return out - } - - // NEEDED: fixes inertial scrolling (broken by calculateDistanceToFinalSnap) - override fun findTargetSnapPosition( - layoutManager: RecyclerView.LayoutManager, - velocityX: Int, - velocityY: Int - ): Int { - if (layoutManager !is LinearLayoutManager) return RecyclerView.NO_POSITION - val firstVisible = layoutManager.findFirstVisibleItemPosition() - val lastVisible = layoutManager.findLastVisibleItemPosition() - val center = (this@JukeboxRecyclerView).getLayoutManagerCenter(layoutManager) - - var closestChild: View? = null - var minDistance = Int.MAX_VALUE - var closestPosition = RecyclerView.NO_POSITION - for (i in firstVisible..lastVisible) { - val child = layoutManager.findViewByPosition(i) ?: continue - val childCenter = (child.left + child.right) / 2 - val distance = kotlin.math.abs(childCenter - center) - if (distance < minDistance) { - minDistance = distance - closestChild = child - closestPosition = i - } - } - - val flingCount = if (velocityX == 0) 0 else velocityX / 2000 - var targetPos = closestPosition + flingCount - val itemCount = layoutManager.itemCount - targetPos = targetPos.coerceIn(0, itemCount - 1) - return targetPos - } - } -} \ No newline at end of file diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/CarouselRecyclerView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/CarouselRecyclerView.kt new file mode 100644 index 0000000000..ae40fcb498 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/CarouselRecyclerView.kt @@ -0,0 +1,409 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +package org.yuzu.yuzu_emu.ui + +import android.content.Context +import android.graphics.Rect +import android.util.AttributeSet +import android.view.View +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.PagerSnapHelper +import androidx.recyclerview.widget.RecyclerView +import kotlin.math.abs +import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.adapters.GameAdapter +import androidx.core.view.doOnNextLayout +import org.yuzu.yuzu_emu.YuzuApplication +import androidx.preference.PreferenceManager + +/** + * CarouselRecyclerView encapsulates all carousel logic for the games UI. + * It manages overlapping cards, center snapping, custom drawing order, + * joypad & fling navigation and mid-screen swipe-to-refresh. + */ +class CarouselRecyclerView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyle: Int = 0 +) : RecyclerView(context, attrs, defStyle) { + + private var overlapFactor: Float = 0f + private var overlapPx: Int = 0 + private var overlapDecoration: OverlappingDecoration? = null + private var pagerSnapHelper: PagerSnapHelper? = null + private var scalingScrollListener: OnScrollListener? = null + + companion object { + private const val CAROUSEL_CARD_SIZE_FACTOR = "CarouselCardSizeMultiplier" + private const val CAROUSEL_BORDERCARDS_SCALE = "CarouselBorderCardsScale" + private const val CAROUSEL_BORDERCARDS_ALPHA = "CarouselBorderCardsAlpha" + private const val CAROUSEL_OVERLAP_FACTOR = "CarouselOverlapFactor" + private const val CAROUSEL_MAX_FLING_COUNT = "CarouselMaxFlingCount" + private const val CAROUSEL_FLING_MULTIPLIER = "CarouselFlingMultiplier" + private const val CAROUSEL_CARDS_SCALING_SHAPE = "CarouselCardsScalingShape" + private const val CAROUSEL_CARDS_ALPHA_SHAPE = "CarouselCardsAlphaShape" + const val CAROUSEL_LAST_SCROLL_POSITION = "CarouselLastScrollPosition" + const val CAROUSEL_VIEW_TYPE_PORTRAIT = "GamesViewTypePortrait" + const val CAROUSEL_VIEW_TYPE_LANDSCAPE = "GamesViewTypeLandscape" + } + + private val preferences = + PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) + + var flingMultiplier: Float = 1f + + public var pendingScrollAfterReload: Boolean = false + + var useCustomDrawingOrder: Boolean = false + set(value) { + field = value + setChildrenDrawingOrderEnabled(value) + invalidate() + } + + init { + setChildrenDrawingOrderEnabled(true) + } + + private fun calculateCenter(width: Int, paddingStart: Int, paddingEnd: Int): Int { + return paddingStart + (width - paddingStart - paddingEnd) / 2 + } + + private fun getRecyclerViewCenter(): Float { + return calculateCenter(width, paddingLeft, paddingRight).toFloat() + } + + private fun getLayoutManagerCenter(layoutManager: RecyclerView.LayoutManager): Int { + return if (layoutManager is LinearLayoutManager) { + calculateCenter(layoutManager.width, layoutManager.paddingStart, layoutManager.paddingEnd) + } else { + width / 2 + } + } + + private fun getChildDistanceToCenter(view: View): Float { + return 0.5f * (view.left + view.right) - getRecyclerViewCenter() + } + + fun restoreScrollState(position: Int = 0, attempts: Int = 0) { + val lm = layoutManager as? LinearLayoutManager ?: return + if (lm.findLastVisibleItemPosition() == RecyclerView.NO_POSITION && attempts < 10) { + post { restoreScrollState(position, attempts + 1) } + return + } + scrollToPosition(position) + } + + fun getClosestChildPosition(fullRange: Boolean = false): Int { + val lm = layoutManager as? LinearLayoutManager ?: return RecyclerView.NO_POSITION + var minDistance = Int.MAX_VALUE + var closestPosition = RecyclerView.NO_POSITION + val start = if (fullRange) 0 else lm.findFirstVisibleItemPosition() + val end = if (fullRange) lm.childCount - 1 else lm.findLastVisibleItemPosition() + for (i in start..end) { + val child = lm.findViewByPosition(i) ?: continue + val distance = kotlin.math.abs(getChildDistanceToCenter(child).toInt()) + if (distance < minDistance) { + minDistance = distance + closestPosition = i + } + } + return closestPosition + } + + fun updateChildScalesAndAlpha() { + for (i in 0 until childCount) { + val child = getChildAt(i) ?: continue + updateChildScaleAndAlphaForPosition(child) + } + } + + fun shapingFunction(x: Float, option: Int = 0): Float { + return when (option) { + 0 -> 1f //Off + 1 -> 1f - x //linear descending + 2 -> (1f - x) * (1f - x) //Ease out + 3 -> if (x < 0.05f) 1f else (1f-x) * 0.8f + 4 -> kotlin.math.cos(x * Math.PI).toFloat() //Cosine + 5 -> kotlin.math.cos( (1.5f * x).coerceIn(0f, 1f) * Math.PI).toFloat() //Cosine 1.5x trimmed + else -> 1f //Default to Off + } + } + + fun updateChildScaleAndAlphaForPosition(child: View) { + val cardSize = (adapter as? GameAdapter ?: return).cardSize + val position = getChildViewHolder(child).bindingAdapterPosition + if (position == RecyclerView.NO_POSITION || cardSize <= 0) { + return // No valid position or card size + } + child.layoutParams.width = cardSize + child.layoutParams.height = cardSize + + val center = getRecyclerViewCenter() + val distance = abs(getChildDistanceToCenter(child)) + val internalBorderScale = resources.getFraction(R.fraction.carousel_bordercards_scale, 1, 1) + val borderScale = preferences.getFloat(CAROUSEL_BORDERCARDS_SCALE, internalBorderScale).coerceIn(0f, 1f) + + val shapeInput = (distance / center).coerceIn(0f, 1f) + val internalShapeSetting = resources.getInteger(R.integer.carousel_cards_scaling_shape) + val scalingShapeSetting = preferences.getInt(CAROUSEL_CARDS_SCALING_SHAPE, internalShapeSetting) + val shapedScaling = shapingFunction(shapeInput, scalingShapeSetting) + val scale = (borderScale + (1f - borderScale) * shapedScaling).coerceIn(0f, 1f) + + val maxDistance = width / 2f + val alphaInput = (distance / maxDistance).coerceIn(0f, 1f) + val internalBordersAlpha = resources.getFraction(R.fraction.carousel_bordercards_alpha, 1, 1) + val borderAlpha = preferences.getFloat(CAROUSEL_BORDERCARDS_ALPHA, internalBordersAlpha).coerceIn(0f, 1f) + val internalAlphaShapeSetting = resources.getInteger(R.integer.carousel_cards_alpha_shape) + val alphaShapeSetting = preferences.getInt(CAROUSEL_CARDS_ALPHA_SHAPE, internalAlphaShapeSetting) + val shapedAlpha = shapingFunction(alphaInput, alphaShapeSetting) + val alpha = (borderAlpha + (1f - borderAlpha) * shapedAlpha).coerceIn(0f, 1f) + + child.animate().cancel() + child.alpha = alpha + child.scaleX = scale + child.scaleY = scale + } + + fun focusCenteredCard() { + val centeredPos = getClosestChildPosition() + if (centeredPos != RecyclerView.NO_POSITION) { + val vh = findViewHolderForAdapterPosition(centeredPos) + vh?.itemView?.let { child -> + child.isFocusable = true + child.isFocusableInTouchMode = true + child.requestFocus() + } + } + } + + fun setCarouselMode(enabled: Boolean, gameAdapter: GameAdapter? = null) { + if (enabled) { + useCustomDrawingOrder = true + + val insets = rootWindowInsets + val bottomInset = insets?.getInsets(android.view.WindowInsets.Type.systemBars())?.bottom ?: 0 + val internalFactor = resources.getFraction(R.fraction.carousel_card_size_factor, 1, 1) + val userFactor = preferences.getFloat(CAROUSEL_CARD_SIZE_FACTOR, internalFactor).coerceIn(0f, 1f) + val cardSize = (userFactor * (height - bottomInset)).toInt() + gameAdapter?.setCardSize(cardSize) + + val internalOverlapFactor = resources.getFraction(R.fraction.carousel_overlap_factor, 1, 1) + overlapFactor = preferences.getFloat(CAROUSEL_OVERLAP_FACTOR, internalOverlapFactor).coerceIn(0f, 1f) + overlapPx = (cardSize * overlapFactor).toInt() + + val internalFlingMultiplier = resources.getFraction(R.fraction.carousel_fling_multiplier, 1, 1) + flingMultiplier = preferences.getFloat(CAROUSEL_FLING_MULTIPLIER, internalFlingMultiplier).coerceIn(1f, 5f) + + gameAdapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { + override fun onChanged() { + if (pendingScrollAfterReload) { + post { + jigglyScroll() + pendingScrollAfterReload = false + } + } + } + }) + + // Detach SnapHelper during setup + pagerSnapHelper?.attachToRecyclerView(null) + + // Add overlap decoration if not present + if (overlapDecoration == null) { + overlapDecoration = OverlappingDecoration(overlapPx) + addItemDecoration(overlapDecoration!!) + } + + // Gradual scalingAdd commentMore actions + if (scalingScrollListener == null) { + scalingScrollListener = object : OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + updateChildScalesAndAlpha() + } + } + addOnScrollListener(scalingScrollListener!!) + } + + if (cardSize > 0) { + val topPadding = ((height - bottomInset - cardSize) / 2).coerceAtLeast(0) // Center vertically + val sidePadding = (width - cardSize) / 2 // Center first/last card + setPadding(sidePadding, topPadding, sidePadding, 0) + clipToPadding = false + } + + if (pagerSnapHelper == null) { + pagerSnapHelper = CenterPagerSnapHelper() + pagerSnapHelper!!.attachToRecyclerView(this) + } + } else { + // Remove overlap decoration + overlapDecoration?.let { removeItemDecoration(it) } + overlapDecoration = null + // Remove scaling scroll listener + scalingScrollListener?.let { removeOnScrollListener(it) } + scalingScrollListener = null + // Detach PagerSnapHelper + pagerSnapHelper?.attachToRecyclerView(null) + pagerSnapHelper = null + useCustomDrawingOrder = false + // Reset padding and fling + setPadding(0, 0, 0, 0) + clipToPadding = true + flingMultiplier = 1f + // Reset scaling + for (i in 0 until childCount) { + val child = getChildAt(i) + child?.scaleX = 1f + child?.scaleY = 1f + child?.alpha = 1f + } + } + } + + override fun onScrollStateChanged(state: Int) { + super.onScrollStateChanged(state) + if (state == RecyclerView.SCROLL_STATE_IDLE) { + focusCenteredCard() + } + } + + override fun scrollToPosition(position: Int) { + super.scrollToPosition(position) + (layoutManager as? LinearLayoutManager)?.scrollToPositionWithOffset(position, overlapPx) + doOnNextLayout { + updateChildScalesAndAlpha() + focusCenteredCard() + } + } + + private var lastFocusSearchTime: Long = 0 + override fun focusSearch(focused: View, direction: Int): View? { + if (layoutManager !is LinearLayoutManager) return super.focusSearch(focused, direction) + val vh = findContainingViewHolder(focused) ?: return super.focusSearch(focused, direction) + val itemCount = adapter?.itemCount ?: return super.focusSearch(focused, direction) + val position = vh.bindingAdapterPosition + + return when (direction) { + View.FOCUS_LEFT -> { + if (position > 0) { + val now = System.currentTimeMillis() + val repeatDetected = (now - lastFocusSearchTime) < resources.getInteger(R.integer.carousel_focus_search_repeat_threshold_ms) + lastFocusSearchTime = now + if (!repeatDetected) { //ensures the first run + val offset = focused.width - overlapPx + smoothScrollBy(-offset, 0) + } + findViewHolderForAdapterPosition(position - 1)?.itemView ?: super.focusSearch(focused, direction) + } else { + focused + } + } + View.FOCUS_RIGHT -> { + if (position < itemCount - 1) { + findViewHolderForAdapterPosition(position + 1)?.itemView ?: super.focusSearch(focused, direction) + } else { + focused + } + } + else -> super.focusSearch(focused, direction) + } + } + + // Custom fling multiplier for carousel + override fun fling(velocityX: Int, velocityY: Int): Boolean { + val newVelocityX = (velocityX * flingMultiplier).toInt() + val newVelocityY = (velocityY * flingMultiplier).toInt() + return super.fling(newVelocityX, newVelocityY) + } + + // Custom drawing order for carousel (for alpha fade) + override fun getChildDrawingOrder(childCount: Int, i: Int): Int { + if (!useCustomDrawingOrder || childCount == 0) return i + val children = (0 until childCount).map { idx -> + val distance = abs(getChildDistanceToCenter(getChildAt(idx))) + Pair(idx, distance) + } + val sorted = children.sortedWith( + compareByDescending> { it.second } + .thenBy { it.first } + ) + return sorted[i].first + } + + fun jigglyScroll() { + scrollBy(-1, 0) + scrollBy(1, 0) + focusCenteredCard() + } + + inner class OverlappingDecoration(private val overlap: Int) : ItemDecoration() { + override fun getItemOffsets( + outRect: Rect, view: View, parent: RecyclerView, state: State + ) { + val position = parent.getChildAdapterPosition(view) + if (position > 0) { + outRect.left = -overlap + } + } + } + + inner class VerticalCenterDecoration : ItemDecoration() { + override fun getItemOffsets( + outRect: android.graphics.Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + val parentHeight = parent.height + val childHeight = view.layoutParams.height.takeIf { it > 0 } + ?: view.measuredHeight.takeIf { it > 0 } + ?: view.height + + if (parentHeight > 0 && childHeight > 0) { + val verticalPadding = ((parentHeight - childHeight) / 2).coerceAtLeast(0) + outRect.top = verticalPadding + outRect.bottom = verticalPadding + } + } + } + + inner class CenterPagerSnapHelper : PagerSnapHelper() { + + // NEEDED: fixes center snapping, but introduces ghost movement + override fun findSnapView(layoutManager: RecyclerView.LayoutManager): View? { + if (layoutManager !is LinearLayoutManager) return null + return layoutManager.findViewByPosition(getClosestChildPosition()) + } + + //NEEDED: fixes ghost movement when snapping, but breaks inertial scrolling + override fun calculateDistanceToFinalSnap( + layoutManager: RecyclerView.LayoutManager, + targetView: View + ): IntArray? { + if (layoutManager !is LinearLayoutManager) return super.calculateDistanceToFinalSnap(layoutManager, targetView) + val out = IntArray(2) + out[0] = getChildDistanceToCenter(targetView).toInt() + out[1] = 0 + return out + } + + // NEEDED: fixes inertial scrolling (broken by calculateDistanceToFinalSnap) + override fun findTargetSnapPosition( + layoutManager: RecyclerView.LayoutManager, + velocityX: Int, + velocityY: Int + ): Int { + if (layoutManager !is LinearLayoutManager) return RecyclerView.NO_POSITION + val closestPosition = this@CarouselRecyclerView.getClosestChildPosition() + val internalMaxFling = resources.getInteger(R.integer.carousel_max_fling_count) + val maxFling = preferences.getInt(CAROUSEL_MAX_FLING_COUNT, internalMaxFling).coerceIn(1, 10) + val rawFlingCount = if (velocityX == 0) 0 else velocityX / 2000 + val flingCount = rawFlingCount.coerceIn(-maxFling, maxFling) + var targetPos = (closestPosition + flingCount).coerceIn(0, layoutManager.itemCount - 1) + return targetPos + } + } +} \ No newline at end of file diff --git a/src/android/app/src/main/res/layout-land/card_game_carousel.xml b/src/android/app/src/main/res/layout-land/card_game_carousel.xml new file mode 100644 index 0000000000..fcc9397a13 --- /dev/null +++ b/src/android/app/src/main/res/layout-land/card_game_carousel.xml @@ -0,0 +1,46 @@ + + + + + + + + + + diff --git a/src/android/app/src/main/res/layout-land/fragment_games.xml b/src/android/app/src/main/res/layout-land/fragment_games.xml index 087a943497..14e9d5358c 100644 --- a/src/android/app/src/main/res/layout-land/fragment_games.xml +++ b/src/android/app/src/main/res/layout-land/fragment_games.xml @@ -185,7 +185,7 @@ android:visibility="gone" /> - - diff --git a/src/android/app/src/main/res/values/dimens.xml b/src/android/app/src/main/res/values/dimens.xml index 1533dd2831..555f8c1e97 100644 --- a/src/android/app/src/main/res/values/dimens.xml +++ b/src/android/app/src/main/res/values/dimens.xml @@ -15,7 +15,6 @@ 24dp 96dp 24dp - 150dp 20dp 3dp diff --git a/src/android/app/src/main/res/values/fractions.xml b/src/android/app/src/main/res/values/fractions.xml index 5c5b0b289c..deb8ac3bea 100644 --- a/src/android/app/src/main/res/values/fractions.xml +++ b/src/android/app/src/main/res/values/fractions.xml @@ -1,6 +1,8 @@ - 60% - 60% + 60% + 60% + 60% + 95% 200% - 100% + 20% diff --git a/src/android/app/src/main/res/values/integers.xml b/src/android/app/src/main/res/values/integers.xml index 5ddc913c41..cc05478c21 100644 --- a/src/android/app/src/main/res/values/integers.xml +++ b/src/android/app/src/main/res/values/integers.xml @@ -3,6 +3,10 @@ 1 1 2 + 4 + 100 + 1 + 4 760 -- 2.39.5 From d8bfc691d145cef736b7f12e23fdc6c454e8f926 Mon Sep 17 00:00:00 2001 From: Bix Date: Fri, 4 Jul 2025 21:47:42 +0000 Subject: [PATCH 09/20] [Android] Add proper Bluetooth permissions check to avoid crashes Authored-by: edendev Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/261 Co-authored-by: Bix Co-committed-by: Bix --- src/android/app/src/main/AndroidManifest.xml | 4 ++ .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 37 ++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index e4885e5126..353c2f722d 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml @@ -25,6 +25,10 @@ SPDX-License-Identifier: GPL-3.0-or-later + + + + + val granted = permissions.entries.all { it.value } + if (granted) { + // Permissions were granted. + android.widget.Toast.makeText(this, "Bluetooth permissions granted.", android.widget.Toast.LENGTH_SHORT).show() + } else { + // Permissions were denied. + android.widget.Toast.makeText(this, "Bluetooth permissions denied. Controller support may be limited.", android.widget.Toast.LENGTH_LONG).show() + } + } + + private fun checkAndRequestBluetoothPermissions() { + // This check is only necessary for Android 12 (API level 31) and above. + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { + val permissionsToRequest = arrayOf( + android.Manifest.permission.BLUETOOTH_SCAN, + android.Manifest.permission.BLUETOOTH_CONNECT + ) + + val permissionsNotGranted = permissionsToRequest.filter { + checkSelfPermission(it) != android.content.pm.PackageManager.PERMISSION_GRANTED + } + + if (permissionsNotGranted.isNotEmpty()) { + requestBluetoothPermissionsLauncher.launch(permissionsNotGranted.toTypedArray()) + } + } + } + override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen() splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } @@ -75,8 +105,13 @@ class MainActivity : AppCompatActivity(), ThemeProvider { NativeLibrary.initMultiplayer() binding = ActivityMainBinding.inflate(layoutInflater) - setContentView(binding.root) + + setContentView(binding.root) + + + checkAndRequestBluetoothPermissions() + if (savedInstanceState != null) { checkedDecryption = savedInstanceState.getBoolean(CHECKED_DECRYPTION) checkedFirmware = savedInstanceState.getBoolean(CHECKED_FIRMWARE) -- 2.39.5 From 0ce2ec3b36513c6911917857edf11bf0f2ba17e1 Mon Sep 17 00:00:00 2001 From: Bix <114880614+Bixbr@users.noreply.github.com> Date: Sat, 5 Jul 2025 23:59:23 +0100 Subject: [PATCH 10/20] [cmake] Update URL to new repo --- CMakeLists.txt | 4 ++-- CMakeModules/DownloadExternals.cmake | 2 +- README.md | 4 ++-- src/yuzu/discord_impl.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c3541aa78..4836ef811e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,7 +149,7 @@ if (YUZU_USE_BUNDLED_VCPKG) set(VCPKG_DOWNLOADS_PATH ${PROJECT_SOURCE_DIR}/externals/vcpkg/downloads) set(NASM_VERSION "2.16.01") set(NASM_DESTINATION_PATH ${VCPKG_DOWNLOADS_PATH}/nasm-${NASM_VERSION}-win64.zip) - set(NASM_DOWNLOAD_URL "https://git.eden-emu.dev/eden-emu/ext-windows-bin/raw/master/nasm/nasm-${NASM_VERSION}-win64.zip") + set(NASM_DOWNLOAD_URL "https://github.com/eden-emulator/ext-windows-bin/raw/master/nasm/nasm-${NASM_VERSION}-win64.zip") if (NOT EXISTS ${NASM_DESTINATION_PATH}) file(DOWNLOAD ${NASM_DOWNLOAD_URL} ${NASM_DESTINATION_PATH} SHOW_PROGRESS STATUS NASM_STATUS) @@ -548,7 +548,7 @@ if (NOT CLANG_FORMAT) message(STATUS "Clang format not found! Downloading...") set(CLANG_FORMAT "${PROJECT_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe") file(DOWNLOAD - https://git.eden-emu.dev/eden-emu/ext-windows-bin/raw/master/clang-format${CLANG_FORMAT_POSTFIX}.exe + https://github.com/eden-emulator/ext-windows-bin/raw/master/clang-format${CLANG_FORMAT_POSTFIX}.exe "${CLANG_FORMAT}" SHOW_PROGRESS STATUS DOWNLOAD_SUCCESS) if (NOT DOWNLOAD_SUCCESS EQUAL 0) diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake index 244e21ca31..232908e172 100644 --- a/CMakeModules/DownloadExternals.cmake +++ b/CMakeModules/DownloadExternals.cmake @@ -8,7 +8,7 @@ set(CURRENT_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR}) function(download_bundled_external remote_path lib_name prefix_var) -set(package_base_url "https://git.eden-emu.dev/eden-emu/") +set(package_base_url "https://github.com/eden-emulator") set(package_repo "no_platform") set(package_extension "no_platform") if (WIN32) diff --git a/README.md b/README.md index 8d766a9c98..d0db6bd038 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@


- Eden + Eden
Eden
@@ -46,7 +46,7 @@ Check out our [website](https://eden-emulator.github.io) for the latest news on ## Development -Most of the development happens on our Git server. It is also where [our central repository](https://git.eden-emu.dev/eden-emu/eden) is hosted. For development discussions, please join us on [Discord](https://discord.gg/ynGGJAN4Rx). +Most of the development happens on our Git server. It is also where [our central repository](https://github.com/pflyly/eden-mirror) is hosted. For development discussions, please join us on [Discord](https://discord.gg/edenemu). If you would like to contribute, we are open to new developers and pull requests. Please ensure that your work is of a high standard and properly documented. You can also contact any of the developers on Discord to learn more about the current state of the emulator. diff --git a/src/yuzu/discord_impl.cpp b/src/yuzu/discord_impl.cpp index 7ed400c955..6b1bff9ef0 100644 --- a/src/yuzu/discord_impl.cpp +++ b/src/yuzu/discord_impl.cpp @@ -62,7 +62,7 @@ std::string DiscordImpl::GetGameString(const std::string& title) { void DiscordImpl::UpdateGameStatus(bool use_default) { const std::string default_text = "eden is an emulator for the Nintendo Switch"; - const std::string default_image = "https://git.eden-emu.dev/eden-emu/eden/raw/branch/master/" + const std::string default_image = "https://github.com/pflyly/eden-mirror/raw/branch/master/" "dist/qt_themes/default/icons/256x256/eden_named.png"; const std::string url = use_default ? default_image : game_url; s64 start_time = std::chrono::duration_cast( -- 2.39.5 From 444109c2511ab835823c98b947ea82e371244445 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 6 Jul 2025 18:20:21 +0000 Subject: [PATCH 11/20] [android] Snapdragon 865 patches (#23) Co-authored-by: Aleksandr Popovich Reviewed-on: https://git.bixed.xyz/Bix/eden/pulls/23 --- src/common/microprofile.h | 20 +++++++++++++++++-- src/core/arm/nce/arm_nce.cpp | 2 +- src/core/hle/service/sockets/sfdnsres.cpp | 15 +++++++++++--- .../maxwell/translate/impl/warp_shuffle.cpp | 17 +++++++++++++++- src/video_core/buffer_cache/buffer_cache.h | 10 ++++++++-- .../buffer_cache/buffer_cache_base.h | 18 ++++++++++++++++- src/video_core/host1x/host1x.cpp | 5 +++++ src/video_core/host1x/host1x.h | 5 +++++ .../texture_cache/texture_cache_base.h | 11 ++++++++++ .../vulkan_common/vulkan_memory_allocator.cpp | 5 ++++- 10 files changed, 97 insertions(+), 11 deletions(-) diff --git a/src/common/microprofile.h b/src/common/microprofile.h index 56ef0a2dcf..25bf362500 100644 --- a/src/common/microprofile.h +++ b/src/common/microprofile.h @@ -1,11 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -// Uncomment this to disable microprofile. This will get you cleaner profiles when using +// Use this to disable microprofile. This will get you cleaner profiles when using // external sampling profilers like "Very Sleepy", and will improve performance somewhat. -// #define MICROPROFILE_ENABLED 0 +#ifdef ANDROID +#define MICROPROFILE_ENABLED 0 +#define MICROPROFILEUI_ENABLED 0 +#define MicroProfileOnThreadExit() do{}while(0) +#define MICROPROFILE_TOKEN(x) 0 +#define MicroProfileEnter(x) 0 +#define MicroProfileLeave(x, y) ignore_all(x, y) +#endif // Customized Citra settings. // This file wraps the MicroProfile header so that these are consistent everywhere. @@ -19,6 +29,12 @@ typedef void* HANDLE; #endif +#include +template +void ignore_all(Args&&... args) { + (static_cast(std::ignore = args), ...); +} + #include #define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0) diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index 877e8ac3c7..0e0d72fc8a 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp @@ -227,7 +227,7 @@ HaltReason ArmNce::RunThread(Kernel::KThread* thread) { if (auto it = post_handlers.find(m_guest_ctx.pc); it != post_handlers.end()) { hr = ReturnToRunCodeByTrampoline(thread_params, &m_guest_ctx, it->second); } else { - hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); + hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); // Android: Use "process handle SIGUSR2 -n true -p true -s false" (and SIGURG) in LLDB when debugging } // Critical section for thread cleanup diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index b07bd3e58e..d9f01a65b8 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -53,6 +53,16 @@ enum class NetDbError : s32 { NoData = 4, }; +const std::vector blockedDomains = {"srv.nintendo.net", "battle.net", + "microsoft.com", "mojang.com", + "xboxlive.com", "minecraftservices.com"}; + +static bool IsBlockedHost(const std::string& host) { + return std::any_of( + blockedDomains.begin(), blockedDomains.end(), + [&host](const std::string& domain) { return host.find(domain) != std::string::npos; }); +} + static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) { // These combinations have been verified on console (but are not // exhaustive). @@ -154,7 +164,7 @@ static std::pair GetHostByNameRequestImpl(HLERequestConte // For now, ignore options, which are in input buffer 1 for GetHostByNameRequestWithOptions. // Prevent resolution of Nintendo servers - if (host.find("srv.nintendo.net") != std::string::npos) { + if (IsBlockedHost(host)) { LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host); return {0, GetAddrInfoError::AGAIN}; } @@ -271,7 +281,7 @@ static std::pair GetAddrInfoRequestImpl(HLERequestContext const std::string host = Common::StringFromBuffer(host_buffer); // Prevent resolution of Nintendo servers - if (host.find("srv.nintendo.net") != std::string::npos) { + if (IsBlockedHost(host)) { LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host); return {0, GetAddrInfoError::AGAIN}; } @@ -359,5 +369,4 @@ void SFDNSRES::ResolverSetOptionRequest(HLERequestContext& ctx) { rb.Push(ResultSuccess); rb.Push(0); // bsd errno } - } // namespace Service::Sockets diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp index 972eec8276..b904821619 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/warp_shuffle.cpp @@ -7,6 +7,7 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" +#include namespace Shader::Maxwell { namespace { @@ -36,6 +37,17 @@ enum class ShuffleMode : u64 { } } +bool IsKONA() { + std::ifstream machineFile("/sys/devices/soc0/machine"); + if (machineFile.is_open()) { + std::string line; + std::getline(machineFile, line); + if (line == "KONA") + return true; + } + return false; +} + void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32& mask) { union { u64 insn; @@ -47,7 +59,10 @@ void Shuffle(TranslatorVisitor& v, u64 insn, const IR::U32& index, const IR::U32 const IR::U32 result{ShuffleOperation(v.ir, v.X(shfl.src_reg), index, mask, shfl.mode)}; v.ir.SetPred(shfl.pred, v.ir.GetInBoundsFromOp(result)); - v.X(shfl.dest_reg, result); + if (IsKONA()) + v.X(shfl.dest_reg, v.ir.Imm32(0xffffffff)); // This fixes the freeze for Retroid / Snapdragon SD865 + else + v.X(shfl.dest_reg, result); } } // Anonymous namespace diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 0ce2abc627..e134e26e66 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -26,7 +26,9 @@ BufferCache

::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, R void(slot_buffers.insert(runtime, NullBufferParams{})); gpu_modified_ranges.Clear(); inline_buffer_id = NULL_BUFFER_ID; - +#ifdef ANDROID + immediately_free = (Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Aggressive); +#endif if (!runtime.CanReportMemoryUsage()) { minimum_memory = DEFAULT_EXPECTED_MEMORY; critical_memory = DEFAULT_CRITICAL_MEMORY; @@ -1383,6 +1385,8 @@ void BufferCache

::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, }); new_buffer.MarkUsage(copies[0].dst_offset, copies[0].size); runtime.CopyBuffer(new_buffer, overlap, copies, true); + if (immediately_free) + runtime.Finish(); DeleteBuffer(overlap_id, true); } @@ -1674,7 +1678,9 @@ void BufferCache

::DeleteBuffer(BufferId buffer_id, bool do_not_mark) { } Unregister(buffer_id); - delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id])); + + if (!do_not_mark || !immediately_free) + delayed_destruction_ring.Push(std::move(slot_buffers[buffer_id])); slot_buffers.erase(buffer_id); if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) { diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index d45f595ea8..dbe44c875f 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -159,7 +159,11 @@ template class BufferCache : public VideoCommon::ChannelSetupCaches { // Page size for caching purposes. // This is unrelated to the CPU page size and it can be changed as it seems optimal. +#ifdef ANDROID + static constexpr u32 CACHING_PAGEBITS = 12; +#else static constexpr u32 CACHING_PAGEBITS = 16; +#endif static constexpr u64 CACHING_PAGESIZE = u64{1} << CACHING_PAGEBITS; static constexpr bool IS_OPENGL = P::IS_OPENGL; @@ -173,9 +177,15 @@ class BufferCache : public VideoCommon::ChannelSetupCaches slot_buffers; - DelayedDestructionRing delayed_destruction_ring; +#ifdef ANDROID + static constexpr size_t TICKS_TO_DESTROY = 6; +#else + static constexpr size_t TICKS_TO_DESTROY = 8; +#endif + DelayedDestructionRing delayed_destruction_ring; const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{}; @@ -483,6 +498,7 @@ private: u64 minimum_memory = 0; u64 critical_memory = 0; BufferId inline_buffer_id; + bool immediately_free = false; std::array> CACHING_PAGEBITS)> page_table; Common::ScratchBuffer tmp_buffer; diff --git a/src/video_core/host1x/host1x.cpp b/src/video_core/host1x/host1x.cpp index 293bca6d79..652d387031 100644 --- a/src/video_core/host1x/host1x.cpp +++ b/src/video_core/host1x/host1x.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -18,9 +21,11 @@ Host1x::~Host1x() = default; void Host1x::StartDevice(s32 fd, ChannelType type, u32 syncpt) { switch (type) { case ChannelType::NvDec: + std::call_once(nvdec_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer devices[fd] = std::make_unique(*this, fd, syncpt, frame_queue); break; case ChannelType::VIC: + std::call_once(vic_first_init, []() {std::this_thread::sleep_for(std::chrono::milliseconds{500});}); // HACK: For Astroneer devices[fd] = std::make_unique(*this, fd, syncpt, frame_queue); break; default: diff --git a/src/video_core/host1x/host1x.h b/src/video_core/host1x/host1x.h index 8debac93dd..5ecffa442c 100644 --- a/src/video_core/host1x/host1x.h +++ b/src/video_core/host1x/host1x.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -201,6 +204,8 @@ private: std::unique_ptr> allocator; FrameQueue frame_queue; std::unordered_map> devices; + std::once_flag nvdec_first_init; + std::once_flag vic_first_init; }; } // namespace Tegra::Host1x diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index cbc27344b0..3f67828b86 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -110,10 +110,17 @@ class TextureCache : public VideoCommon::ChannelSetupCaches::max()}; + #ifdef ANDROID + static constexpr s64 TARGET_THRESHOLD = 3_GiB; + static constexpr s64 DEFAULT_EXPECTED_MEMORY = 1_GiB + 125_MiB; + static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB + 625_MiB; + static constexpr size_t GC_EMERGENCY_COUNTS = 2; + #else static constexpr s64 TARGET_THRESHOLD = 4_GiB; static constexpr s64 DEFAULT_EXPECTED_MEMORY = 1_GiB + 125_MiB; static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB + 625_MiB; static constexpr size_t GC_EMERGENCY_COUNTS = 2; + #endif using Runtime = typename P::Runtime; using Image = typename P::Image; @@ -479,7 +486,11 @@ private: }; Common::LeastRecentlyUsedCache lru_cache; + #ifdef ANDROID + static constexpr size_t TICKS_TO_DESTROY = 6; + #else static constexpr size_t TICKS_TO_DESTROY = 8; +#endif DelayedDestructionRing sentenced_images; DelayedDestructionRing sentenced_image_view; DelayedDestructionRing sentenced_framebuffers; diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index e80808621b..04b362f9b0 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -271,7 +271,10 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsa VmaAllocation allocation{}; VkMemoryPropertyFlags property_flags{}; - vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info)); + VkResult result = vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info); + if (result == VK_ERROR_OUT_OF_DEVICE_MEMORY) { + LOG_ERROR(Render_Vulkan, "Out of memory creating buffer (size: {})", ci.size); + } vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags); u8* data = reinterpret_cast(alloc_info.pMappedData); -- 2.39.5 From 05f536694ab49cae61f86c844712b9db10bb2468 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 6 Jul 2025 18:20:30 +0000 Subject: [PATCH 12/20] [android] Fix 1.5x and warn at resolutions >= 2x (#21) Co-authored-by: Aleksandr Popovich Reviewed-on: https://git.bixed.xyz/Bix/eden/pulls/21 --- .../settings/model/view/SettingsItem.kt | 4 +++- .../settings/model/view/SingleChoiceSetting.kt | 4 +++- .../settings/ui/SettingsDialogFragment.kt | 12 +++++++++++- .../app/src/main/res/values-ar/strings.xml | 1 + .../app/src/main/res/values-ckb/strings.xml | 1 + .../app/src/main/res/values-cs/strings.xml | 1 + .../app/src/main/res/values-de/strings.xml | 1 + .../app/src/main/res/values-es/strings.xml | 1 + .../app/src/main/res/values-fa/strings.xml | 1 + .../app/src/main/res/values-fr/strings.xml | 1 + .../app/src/main/res/values-he/strings.xml | 1 + .../app/src/main/res/values-hu/strings.xml | 1 + .../app/src/main/res/values-id/strings.xml | 1 + .../app/src/main/res/values-it/strings.xml | 1 + .../app/src/main/res/values-ja/strings.xml | 1 + .../app/src/main/res/values-ko/strings.xml | 1 + .../app/src/main/res/values-nb/strings.xml | 1 + .../app/src/main/res/values-pl/strings.xml | 1 + .../app/src/main/res/values-pt-rBR/strings.xml | 1 + .../app/src/main/res/values-pt-rPT/strings.xml | 1 + .../app/src/main/res/values-ru/strings.xml | 1 + .../app/src/main/res/values-sr/strings.xml | 18 +++++++++++------- .../app/src/main/res/values-uk/strings.xml | 1 + .../app/src/main/res/values-vi/strings.xml | 1 + .../app/src/main/res/values-zh-rCN/strings.xml | 1 + .../app/src/main/res/values-zh-rTW/strings.xml | 1 + src/android/app/src/main/res/values/arrays.xml | 2 ++ .../app/src/main/res/values/strings.xml | 4 ++++ 28 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 6ec678717b..f225d8d8b7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -378,7 +378,9 @@ abstract class SettingsItem( IntSetting.RENDERER_RESOLUTION, titleId = R.string.renderer_resolution, choicesId = R.array.rendererResolutionNames, - valuesId = R.array.rendererResolutionValues + valuesId = R.array.rendererResolutionValues, + warnChoices = (5..7).toList(), + warningMessage = R.string.warning_resolution ) ) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt index ea5e099ede..624bc2445c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt @@ -15,7 +15,9 @@ class SingleChoiceSetting( @StringRes descriptionId: Int = 0, descriptionString: String = "", @ArrayRes val choicesId: Int, - @ArrayRes val valuesId: Int + @ArrayRes val valuesId: Int, + val warnChoices: List = ArrayList(), + @StringRes val warningMessage: Int = 0, ) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) { override val type = TYPE_SINGLE_CHOICE diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt index 1485d9a6cc..b54958c110 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt @@ -14,7 +14,6 @@ import android.text.TextWatcher import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.EditText import androidx.core.view.isVisible import androidx.fragment.app.DialogFragment import androidx.fragment.app.activityViewModels @@ -113,6 +112,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener SettingsItem.TYPE_SINGLE_CHOICE -> { val item = settingsViewModel.clickedItem as SingleChoiceSetting val value = getSelectionForSingleChoiceValue(item) + MaterialAlertDialogBuilder(requireContext()) .setTitle(item.title) .setSingleChoiceItems(item.choicesId, value, this) @@ -125,6 +125,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener settingsViewModel.setSliderTextValue(item.getSelectedValue().toFloat(), item.units) sliderBinding.slider.apply { + stepSize = 1.0f valueFrom = item.min.toFloat() valueTo = item.max.toFloat() value = settingsViewModel.sliderProgress.value.toFloat() @@ -244,6 +245,15 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener is SingleChoiceSetting -> { val scSetting = settingsViewModel.clickedItem as SingleChoiceSetting val value = getValueForSingleChoiceSelection(scSetting, which) + + if (value in scSetting.warnChoices) { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.warning) + .setMessage(scSetting.warningMessage) + .setPositiveButton(R.string.ok, null) + .create() + .show() + } scSetting.setSelectedValue(value) } diff --git a/src/android/app/src/main/res/values-ar/strings.xml b/src/android/app/src/main/res/values-ar/strings.xml index fba704d516..a71ef92fe8 100644 --- a/src/android/app/src/main/res/values-ar/strings.xml +++ b/src/android/app/src/main/res/values-ar/strings.xml @@ -678,6 +678,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (بطيء) 3X (2160p/3240p) (بطيء) 4X (2880p/4320p) (بطيء) diff --git a/src/android/app/src/main/res/values-ckb/strings.xml b/src/android/app/src/main/res/values-ckb/strings.xml index 014e6f724a..c9a1c57f3f 100644 --- a/src/android/app/src/main/res/values-ckb/strings.xml +++ b/src/android/app/src/main/res/values-ckb/strings.xml @@ -636,6 +636,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (خاو) 3X (2160p/3240p) (خاو) 4X (2880p/4320p) (خاو) diff --git a/src/android/app/src/main/res/values-cs/strings.xml b/src/android/app/src/main/res/values-cs/strings.xml index 27e2bd5c6b..d18c56755b 100644 --- a/src/android/app/src/main/res/values-cs/strings.xml +++ b/src/android/app/src/main/res/values-cs/strings.xml @@ -577,6 +577,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Pomalé) 3X (2160p/3240p) (Pomalé) 4X (2880p/4320p) (Pomalé) diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index 2349c70c89..e030369d8f 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml @@ -721,6 +721,7 @@ Wirklich fortfahren? 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Langsam) 3X (2160p/3240p) (Langsam) 4X (2880p/4320p) (Langsam) diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 27bbb35cae..6a1ccbff26 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -786,6 +786,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) x1 (720p/1080p) + x1 (1080p/1620p) 2X (1440p/2160p) (Lento) 3X (2160p/3240p) (Lento) 4X (2880p/4320p) (Lento) diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml index da78876baf..f445d28356 100644 --- a/src/android/app/src/main/res/values-fa/strings.xml +++ b/src/android/app/src/main/res/values-fa/strings.xml @@ -785,6 +785,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (کند) 3X (2160p/3240p) (کند) 4X (2880p/4320p) (کند) diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index 452f43bd6d..d3bec19dd9 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -834,6 +834,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Lent) 3X (2160p/3240p) (Lent) 4X (2880p/4320p) (Lent) diff --git a/src/android/app/src/main/res/values-he/strings.xml b/src/android/app/src/main/res/values-he/strings.xml index 09952ae0b1..3be619cac8 100644 --- a/src/android/app/src/main/res/values-he/strings.xml +++ b/src/android/app/src/main/res/values-he/strings.xml @@ -698,6 +698,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (איטי) 3X (2160p/3240p) (איטי) 4X (2880p/4320p) (איטי) diff --git a/src/android/app/src/main/res/values-hu/strings.xml b/src/android/app/src/main/res/values-hu/strings.xml index 121edfdced..65ed9248c8 100644 --- a/src/android/app/src/main/res/values-hu/strings.xml +++ b/src/android/app/src/main/res/values-hu/strings.xml @@ -822,6 +822,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Lassú) 3X (2160p/3240p) (Lassú) 4X (2880p/4320p) (Lassú) diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index 83ae800e94..71f974a767 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -778,6 +778,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Lambat) 3X (2160p/3240p) (Lambat) 4X (2880p/4320p) (Lambat) diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index bc0f7996b1..a81e41adf0 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml @@ -736,6 +736,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Slow) 3X (2160p/3240p) (Slow) 4X (2880p/4320p) (Slow) diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index 1fc162a600..b5d28599a8 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml @@ -686,6 +686,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (低速) 3X (2160p/3240p) (低速) 4X (2880p/4320p) (低速) diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index d99bc5e92f..7843a9200b 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml @@ -777,6 +777,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (느림) 3X (2160p/3240p) (느림) 4X (2880p/4320p) (느림) diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index b66d7e3a9f..93ebb5013b 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml @@ -645,6 +645,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Slow) 3X (2160p/3240p) (Slow) 4X (2880p/4320p) (Slow) diff --git a/src/android/app/src/main/res/values-pl/strings.xml b/src/android/app/src/main/res/values-pl/strings.xml index da5f3c6874..f87d1a411e 100644 --- a/src/android/app/src/main/res/values-pl/strings.xml +++ b/src/android/app/src/main/res/values-pl/strings.xml @@ -643,6 +643,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Wolno) 3X (2160p/3240p) (Wolno) 4X (2880p/4320p) (Wolno) diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index 99fd14463a..d602afb92a 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml @@ -835,6 +835,7 @@ uma tentativa de mapeamento automático 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Lento) 3X (2160p/3240p) (Lento) 4X (2880p/4320p) (Lento) diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index 11f331ac15..dc46c1b68e 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml @@ -835,6 +835,7 @@ uma tentativa de mapeamento automático 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Lento) 3X (2160p/3240p) (Lento) 4X (2880p/4320p) (Lento) diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index e8ddf96d17..02ceb48943 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -836,6 +836,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Медленно) 3X (2160p/3240p) (Медленно) 4X (2880p/4320p) (Медленно) diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index 5065b7d171..814466a707 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -279,6 +279,7 @@ О томе Изградите верзију, кредите и још много тога Помоћи + упозорење Прескочити Отказати Инсталирајте Амиибо Кеис @@ -465,6 +466,8 @@ Анисотропни филтрирање Побољшава квалитет текстура када се посматра у косим угловима + Познато је да скалирање резолуције изнад 2x изазива проблеме и може довести до значајног успоравања вашег уређаја. + ЦПУ ЦПУ уклањање погрешака @@ -852,13 +855,14 @@ Агресиван - 0,25к (180п / 270п) - 0,5к (360п / 540п) - 0,75к (540п / 810п) - 1к (720п / 1080п) - 2к (1440п / 2160п) (споро) - 3к (2160п / 3240п) (споро) - 4к (2880п / 4320п) (споро) + 0.25X (180p/270p) + 0.5X (360p/540p) + 0.75X (540p/810p) + 1X (720p/1080p) + 1.5X (1080p/1620p) + 2X (1440p/2160p) (споро) + 3X (2160p/3240p) (споро) + 4X (2880p/4320p) (споро) Непосредан (искључен) diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index 55d767b384..3a1366e975 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -625,6 +625,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Повільно) 3X (2160p/3240p) (Повільно) 4X (2880p/4320p) (Повільно) diff --git a/src/android/app/src/main/res/values-vi/strings.xml b/src/android/app/src/main/res/values-vi/strings.xml index dbe74f18f4..8f6ea3ffa5 100644 --- a/src/android/app/src/main/res/values-vi/strings.xml +++ b/src/android/app/src/main/res/values-vi/strings.xml @@ -648,6 +648,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Chậm) 3X (2160p/3240p) (Chậm) 4X (2880p/4320p) (Chậm) diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index 2105a95e1e..8f25344789 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -829,6 +829,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (慢速) 3X (2160p/3240p) (慢速) 4X (2880p/4320p) (慢速) diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index 0226ae0804..5e4ed21c35 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -835,6 +835,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (慢) 3X (2160p/3240p) (慢) 4X (2880p/4320p) (慢) diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 8a8b89d44f..23514a0a23 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -180,6 +180,7 @@ @string/resolution_half @string/resolution_three_quarter @string/resolution_one + @string/resolution_three_half @string/resolution_two @string/resolution_three @string/resolution_four @@ -200,6 +201,7 @@ 4 5 6 + 7 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 01d4d83e27..454e633cc3 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -290,6 +290,7 @@ About Build version, credits, and more Help + Warning Skip Cancel Install Amiibo keys @@ -491,6 +492,8 @@ Anisotropic filtering Improves the quality of textures when viewed at oblique angles + Resolution scaling above 2x is known to cause issues, and may result in significant slowdowns of your device. + CPU CPU Debugging @@ -884,6 +887,7 @@ 0.5X (360p/540p) 0.75X (540p/810p) 1X (720p/1080p) + 1.5X (1080p/1620p) 2X (1440p/2160p) (Slow) 3X (2160p/3240p) (Slow) 4X (2880p/4320p) (Slow) -- 2.39.5 From 38561cd7e30e9ef96fc67e2191015d9674d752fd Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 6 Jul 2025 15:46:49 -0400 Subject: [PATCH 13/20] update discord link Signed-off-by: crueter --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0db6bd038..5d8104fc55 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Any donations received will go towards things such as: * Additional hardware (e.g. GPUs as needed to improve rendering support, other peripherals to add support for, etc.) * CI Infrastructure -If you would prefer to support us in a different way, please join our [Discord](https://discord.gg/ynGGJAN4Rx), once public, and talk to Camille or any of our other developers. +If you would prefer to support us in a different way, please join our [Discord](https://discord.gg/edenemu), once public, and talk to Camille or any of our other developers. ## License -- 2.39.5 From 35f6afb03152d5a1ed547bff03ca9dd3da2b4b03 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 6 Jul 2025 15:49:04 -0400 Subject: [PATCH 14/20] Test push Signed-off-by: crueter --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5d8104fc55..af9f146499 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -- 2.39.5 From 789dacedca57d0e8d8be11a4b103013cc97340cd Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 6 Jul 2025 16:07:23 -0400 Subject: [PATCH 15/20] fix Signed-off-by: crueter --- CMakeModules/DownloadExternals.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake index 232908e172..a82d1d72a3 100644 --- a/CMakeModules/DownloadExternals.cmake +++ b/CMakeModules/DownloadExternals.cmake @@ -8,7 +8,7 @@ set(CURRENT_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR}) function(download_bundled_external remote_path lib_name prefix_var) -set(package_base_url "https://github.com/eden-emulator") +set(package_base_url "https://github.com/eden-emulator/") set(package_repo "no_platform") set(package_extension "no_platform") if (WIN32) -- 2.39.5 From 9d60900ecffe05c601176913aab1f16efc27f159 Mon Sep 17 00:00:00 2001 From: Esther1024 Date: Tue, 8 Jul 2025 21:00:45 +0000 Subject: [PATCH 16/20] .gitignore cache things (#25) annoying Reviewed-on: https://git.bixed.xyz/Bix/eden/pulls/25 Co-authored-by: Esther1024 Co-committed-by: Esther1024 --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 970127309f..7484a368e6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,14 @@ dist/english_plurals/generated_en.ts .idea/ .vs/ .vscode/ +.cache/ +profile.json.gz CMakeLists.txt.user* +# kdevelop +.kdev4/ +*.kdev4 + # *nix related # Common convention for backup or temporary files *~ -- 2.39.5 From 347d54bc26073f47690f03a26d58df82c08dff29 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 8 Jul 2025 21:12:02 +0000 Subject: [PATCH 17/20] [android] add power consumption and battery status overlay (#22) - adds the option to show power draw in amperes - shows if the battery is charging Signed-off-by: Aleksandr Popovich Co-authored-by: Aleksandr Popovich Reviewed-on: https://git.bixed.xyz/Bix/eden/pulls/22 --- .../features/settings/model/BooleanSetting.kt | 2 + .../features/settings/model/IntSetting.kt | 2 +- .../settings/model/view/SettingsItem.kt | 45 ++++++++++----- .../settings/ui/SettingsFragmentPresenter.kt | 2 + .../yuzu_emu/fragments/EmulationFragment.kt | 42 ++++++++++---- .../app/src/main/jni/android_settings.h | 52 +++++++++++------ .../app/src/main/res/values-sr/strings.xml | 57 +++++++++++-------- .../app/src/main/res/values/arrays.xml | 10 ++++ .../app/src/main/res/values/strings.xml | 11 +++- src/common/settings_enums.h | 2 + 10 files changed, 156 insertions(+), 69 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 21dc51513d..79cfed1cd0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -58,7 +58,9 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { SHOW_APP_RAM_USAGE("show_app_ram_usage"), SHOW_SYSTEM_RAM_USAGE("show_system_ram_usage"), SHOW_BAT_TEMPERATURE("show_bat_temperature"), + SHOW_POWER_INFO("show_power_info"), SHOW_SHADERS_BUILDING("show_shaders_building"), + DEBUG_FLUSH_BY_LINE("flush_lines"), USE_LRU_CACHE("use_lru_cache"),; diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index 63206e0bee..a674857bc1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -42,7 +42,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { FAST_CPU_TIME("fast_cpu_time"), CPU_TICKS("cpu_ticks"), FAST_GPU_TIME("fast_gpu_time"), - + BAT_TEMPERATURE_UNIT("bat_temperature_unit"), CABINET_APPLET("cabinet_applet_mode"), CONTROLLER_APPLET("controller_applet_mode"), DATA_ERASE_APPLET("data_erase_applet_mode"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index f225d8d8b7..4e206ab541 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -78,7 +78,7 @@ abstract class SettingsItem( val needsRuntimeGlobal: Boolean get() = NativeLibrary.isRunning() && !setting.global && - !NativeConfig.isPerGameConfigLoaded() + !NativeConfig.isPerGameConfigLoaded() val clearable: Boolean get() = !setting.global && NativeConfig.isPerGameConfigLoaded() @@ -260,12 +260,12 @@ abstract class SettingsItem( ) ) put( - SwitchSetting( - BooleanSetting.CORE_SYNC_CORE_SPEED, - titleId = R.string.use_sync_core, - descriptionId = R.string.use_sync_core_description - ) - ) + SwitchSetting( + BooleanSetting.CORE_SYNC_CORE_SPEED, + titleId = R.string.use_sync_core, + descriptionId = R.string.use_sync_core_description + ) + ) put( SingleChoiceSetting( @@ -443,6 +443,21 @@ abstract class SettingsItem( descriptionId = R.string.show_bat_temperature_description ) ) + put( + SingleChoiceSetting( + IntSetting.BAT_TEMPERATURE_UNIT, + R.string.bat_temperature_unit, + choicesId = R.array.temperatureUnitEntries, + valuesId = R.array.temperatureUnitValues + ) + ) + put( + SwitchSetting( + BooleanSetting.SHOW_POWER_INFO, + R.string.show_power_info, + descriptionId = R.string.show_power_info_description + ) + ) put( SwitchSetting( BooleanSetting.SHOW_SHADERS_BUILDING, @@ -688,12 +703,12 @@ abstract class SettingsItem( ) ) put( - SwitchSetting( - BooleanSetting.USE_AUTO_STUB, - titleId = R.string.use_auto_stub, - descriptionId = R.string.use_auto_stub_description - ) - ) + SwitchSetting( + BooleanSetting.USE_AUTO_STUB, + titleId = R.string.use_auto_stub, + descriptionId = R.string.use_auto_stub_description + ) + ) put( SwitchSetting( BooleanSetting.CPU_DEBUG_MODE, @@ -705,7 +720,7 @@ abstract class SettingsItem( val fastmem = object : AbstractBooleanSetting { override fun getBoolean(needsGlobal: Boolean): Boolean = BooleanSetting.FASTMEM.getBoolean() && - BooleanSetting.FASTMEM_EXCLUSIVES.getBoolean() + BooleanSetting.FASTMEM_EXCLUSIVES.getBoolean() override fun setBoolean(value: Boolean) { BooleanSetting.FASTMEM.setBoolean(value) @@ -720,7 +735,7 @@ abstract class SettingsItem( override var global: Boolean get() { return BooleanSetting.FASTMEM.global && - BooleanSetting.FASTMEM_EXCLUSIVES.global + BooleanSetting.FASTMEM_EXCLUSIVES.global } set(value) { BooleanSetting.FASTMEM.global = value diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 0cf7be74d3..430e2f3426 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -260,6 +260,8 @@ class SettingsFragmentPresenter( add(BooleanSetting.SHOW_APP_RAM_USAGE.key) add(BooleanSetting.SHOW_SYSTEM_RAM_USAGE.key) add(BooleanSetting.SHOW_BAT_TEMPERATURE.key) + add(IntSetting.BAT_TEMPERATURE_UNIT.key) + add(BooleanSetting.SHOW_POWER_INFO.key) add(BooleanSetting.SHOW_SHADERS_BUILDING.key) } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 9ba2d9e625..05c14e278d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -17,6 +17,7 @@ import android.content.pm.ActivityInfo import android.content.res.Configuration import android.net.Uri import android.os.BatteryManager +import android.os.BatteryManager.* import android.os.Build import android.os.Bundle import android.os.Handler @@ -574,12 +575,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { if (emulationViewModel.emulationStarted.value && !emulationViewModel.isEmulationStopping.value ) { + val needsGlobal = NativeConfig.isPerGameConfigLoaded() sb.setLength(0) val perfStats = NativeLibrary.getPerfStats() val actualFps = perfStats[FPS] - if (BooleanSetting.SHOW_FPS.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.SHOW_FPS.getBoolean(needsGlobal)) { val enableFrameInterpolation = BooleanSetting.FRAME_INTERPOLATION.getBoolean() // val enableFrameSkipping = BooleanSetting.FRAME_SKIPPING.getBoolean() @@ -597,7 +599,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { sb.append(fpsText) } - if (BooleanSetting.SHOW_FRAMETIME.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.SHOW_FRAMETIME.getBoolean(needsGlobal)) { if (sb.isNotEmpty()) sb.append(" | ") sb.append( String.format( @@ -607,13 +609,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { ) } - if (BooleanSetting.SHOW_APP_RAM_USAGE.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.SHOW_APP_RAM_USAGE.getBoolean(needsGlobal)) { if (sb.isNotEmpty()) sb.append(" | ") - val appRamUsage = File("/proc/self/statm").readLines()[0].split(' ')[1].toLong() * 4096 / 1000000 + val appRamUsage = + File("/proc/self/statm").readLines()[0].split(' ')[1].toLong() * 4096 / 1000000 sb.append(getString(R.string.process_ram, appRamUsage)) } - if (BooleanSetting.SHOW_SYSTEM_RAM_USAGE.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.SHOW_SYSTEM_RAM_USAGE.getBoolean(needsGlobal)) { if (sb.isNotEmpty()) sb.append(" | ") context?.let { ctx -> val activityManager = @@ -625,16 +628,35 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } } - if (BooleanSetting.SHOW_BAT_TEMPERATURE.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.SHOW_BAT_TEMPERATURE.getBoolean(needsGlobal)) { if (sb.isNotEmpty()) sb.append(" | ") + val batteryTemp = getBatteryTemperature() - val tempF = celsiusToFahrenheit(batteryTemp) - sb.append(String.format("%.1f°C/%.1f°F", batteryTemp, tempF)) + when (IntSetting.BAT_TEMPERATURE_UNIT.getInt(needsGlobal)) { + 0 -> sb.append(String.format("%.1f°C", batteryTemp)) + 1 -> sb.append(String.format("%.1f°F", celsiusToFahrenheit(batteryTemp))) + } + } + + if (BooleanSetting.SHOW_POWER_INFO.getBoolean(needsGlobal)) { + if (sb.isNotEmpty()) sb.append(" | ") + + val battery: BatteryManager = + requireContext().getSystemService(Context.BATTERY_SERVICE) as BatteryManager + + val capacity = battery.getIntProperty(BATTERY_PROPERTY_CAPACITY) + val nowUAmps = battery.getIntProperty(BATTERY_PROPERTY_CURRENT_NOW) + + sb.append(String.format("%.1fA (%d%%)", nowUAmps / 1000000.0, capacity)) + + if (battery.isCharging || nowUAmps > 0.0) { + sb.append(" ${getString(R.string.charging)}") + } } val shadersBuilding = NativeLibrary.getShadersBuilding() - if (BooleanSetting.SHOW_SHADERS_BUILDING.getBoolean(NativeConfig.isPerGameConfigLoaded()) && shadersBuilding != 0) { + if (BooleanSetting.SHOW_SHADERS_BUILDING.getBoolean(needsGlobal) && shadersBuilding != 0) { if (sb.isNotEmpty()) sb.append(" | ") val prefix = getString(R.string.shaders_prefix) @@ -642,7 +664,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { sb.append(String.format("$prefix %d $suffix", shadersBuilding)) } - if (BooleanSetting.PERF_OVERLAY_BACKGROUND.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.PERF_OVERLAY_BACKGROUND.getBoolean(needsGlobal)) { binding.showStatsOverlayText.setBackgroundResource(R.color.yuzu_transparent_black) } else { binding.showStatsOverlayText.setBackgroundResource(0) diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h index e7401a8947..cd18f1e5b3 100644 --- a/src/android/app/src/main/jni/android_settings.h +++ b/src/android/app/src/main/jni/android_settings.h @@ -9,6 +9,7 @@ #include #include "common/common_types.h" #include "common/settings_setting.h" +#include "common/settings_enums.h" namespace AndroidSettings { @@ -79,9 +80,10 @@ namespace AndroidSettings { Settings::Specialization::Paired, true, true}; Settings::Setting perf_overlay_background{linkage, false, "perf_overlay_background", - Settings::Category::Overlay, - Settings::Specialization::Default, true, true, - &show_performance_overlay}; + Settings::Category::Overlay, + Settings::Specialization::Default, true, + true, + &show_performance_overlay}; Settings::Setting perf_overlay_position{linkage, 0, "perf_overlay_position", Settings::Category::Overlay, Settings::Specialization::Default, true, true, @@ -107,10 +109,23 @@ namespace AndroidSettings { Settings::Category::Overlay, Settings::Specialization::Default, true, true, &show_performance_overlay}; + Settings::Setting bat_temperature_unit{linkage, + Settings::TemperatureUnits::Celsius, + "bat_temperature_unit", + Settings::Category::Overlay, + Settings::Specialization::Default, + true, true, + &show_bat_temperature}; + Settings::Setting show_power_info{linkage, false, "show_power_info", + Settings::Category::Overlay, + Settings::Specialization::Default, true, true, + &show_performance_overlay}; Settings::Setting show_shaders_building{linkage, true, "show_shaders_building", Settings::Category::Overlay, Settings::Specialization::Default, true, true, &show_performance_overlay}; + + Settings::Setting show_input_overlay{linkage, true, "show_input_overlay", Settings::Category::Overlay}; Settings::Setting touchscreen{linkage, true, "touchscreen", @@ -125,14 +140,14 @@ namespace AndroidSettings { Settings::Specialization::Paired, true, true}; Settings::Setting show_device_model{linkage, true, "show_device_model", - Settings::Category::Overlay, - Settings::Specialization::Default, true, true, - &show_soc_overlay}; + Settings::Category::Overlay, + Settings::Specialization::Default, true, true, + &show_performance_overlay}; Settings::Setting show_gpu_model{linkage, true, "show_gpu_model", - Settings::Category::Overlay, - Settings::Specialization::Default, true, true, - &show_soc_overlay}; + Settings::Category::Overlay, + Settings::Specialization::Default, true, true, + &show_performance_overlay}; Settings::Setting show_soc_model{linkage, true, "show_soc_model", Settings::Category::Overlay, @@ -140,18 +155,19 @@ namespace AndroidSettings { &show_soc_overlay}; Settings::Setting show_fw_version{linkage, true, "show_firmware_version", - Settings::Category::Overlay, - Settings::Specialization::Default, true, true, - &show_soc_overlay}; + Settings::Category::Overlay, + Settings::Specialization::Default, true, true, + &show_performance_overlay}; Settings::Setting soc_overlay_background{linkage, false, "soc_overlay_background", - Settings::Category::Overlay, - Settings::Specialization::Default, true, true, - &show_soc_overlay}; + Settings::Category::Overlay, + Settings::Specialization::Default, true, + true, + &show_soc_overlay}; Settings::Setting soc_overlay_position{linkage, 2, "soc_overlay_position", - Settings::Category::Overlay, - Settings::Specialization::Default, true, true, - &show_soc_overlay}; + Settings::Category::Overlay, + Settings::Specialization::Default, true, true, + &show_soc_overlay}; Settings::Setting dont_show_eden_veil_warning{linkage, false, "dont_show_eden_veil_warning", diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index 814466a707..d0cb8d5d14 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -14,6 +14,8 @@ Зграда Схадер (с) Систем: + (Пуњење) + Покажи Статистика перформанси Статистика Прилагођавање Видљивост @@ -31,7 +33,10 @@ Прикажи употребу система меморије Прикажите износ РАМ-а који користи систем Прикажи температуру батерије - Прикажи тренутну температуру батерије у Целзијусу и Фахренхеиту + Прикажи тренутну температуру батерије + Јединице за температуру батерије + Прикажи информације о батерији + Приказ тренутне потрошње енергије и преостали капацитет батерије Прикажи Схадерс Буилдинг Прикажи тренутни број саграђених Схадера Положај прекривања @@ -98,11 +103,11 @@ Изглед меморије (Експериментално) Промените изглед емулираног меморије. Ово постављање неће повећати перформансе, али може помоћи у играма које користе високе резолуције путем модова. Не користите на телефонима са 8 ГБ РАМ-а или мање. Ради само на динамичком (ЈИТ) бацкенд-у. - Семпловање сенчења - Омогућава фрагмент шејдеру да се извршава по узорку у вишеузорачном фрагменту уместо једном по фрагменту. Побољшава квалитет графике на рачун перформанси. Само Vulkan 1.1+ уређаји подржавају ову екстензију. - Прилагођени CPU тактови - Поставите прилагођену вредност CPU тактова. Веће вредности могу повећати перформансе, али могу изазвати залеђивање игре. Препоручује се опсег 77–21000. - Тактови + Семпловање сенчења + Омогућава фрагмент шејдеру да се извршава по узорку у вишеузорачном фрагменту уместо једном по фрагменту. Побољшава квалитет графике на рачун перформанси. Само Vulkan 1.1+ уређаји подржавају ову екстензију. + Прилагођени CPU тактови + Поставите прилагођену вредност CPU тактова. Веће вредности могу повећати перформансе, али могу изазвати залеђивање игре. Препоручује се опсег 77–21000. + Тактови Схадер Бацкенд @@ -205,23 +210,23 @@ Није пронађена није пронађена игара Морате одабрати преферирану игру да бисте угостили собу. Мора бити дугачко 48 знакова и садржати само мала слова a-z - Тип лобија - Јавно - Неприказано - Име је прекратко - Неисправна адреса - Мора бити између 4–20 знакова + Тип лобија + Јавно + Неприказано + Име је прекратко + Неисправна адреса + Мора бити између 4–20 знакова Отказати У реду Освежити Листа соба Придружујем се… - Креирам… - Обавезно - Потребан је веб токен, идите на Напредне поставке -> Систем -> Мрежа - Неисправан ИП формат - Мора бити између 1 и 65535 - Мора бити између 3 и 20 знакова + Креирам… + Обавезно + Потребан је веб токен, идите на Напредне поставке -> Систем -> Мрежа + Неисправан ИП формат + Мора бити између 1 и 65535 + Мора бити између 3 и 20 знакова Добродошли! @@ -428,16 +433,16 @@ Генериши - Веб корисничко име - Корисничко име које ће бити приказано у мултиплејер лобијима. Мора бити дугачко 4–20 знакова. + Веб корисничко име + Корисничко име које ће бити приказано у мултиплејер лобијима. Мора бити дугачко 4–20 знакова. Веб токен Веб токен који се користи за стварање јавних лобија. То је низ од 48 знакова који садржи само мала слова А-З. Мрежа Бекенд - Приказ - Постпроцесирање + Приказ + Постпроцесирање ВИП: Фрамескип Пребацивање оквира прескакање да бисте побољшали перформансе смањењем броја пружених оквира. Ова функција се и даље ради и биће омогућена у будућим издањима. Ниво тачности @@ -791,6 +796,10 @@ Средња (256) Висок (512) + + Целзијус + Фаренхајт + 日本語 English @@ -979,8 +988,8 @@ Софтверска тастатура - Авионски режим - Прослеђује авионски режим на Switch OS + Авионски режим + Прослеђује авионски режим на Switch OS Лиценце diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 23514a0a23..42dcfbc68b 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -471,4 +471,14 @@ 1 2 + + + @string/temperature_celsius + @string/temperature_fahrenheit + + + + 0 + 1 + diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 454e633cc3..658dfedc6b 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -14,6 +14,8 @@ Process RAM: %1$d MB Building Shader(s) + (Charging) + System: Show Performance Stats Overlay Customization @@ -32,7 +34,10 @@ Show System Memory Usage Display the amount of RAM used by the system Show Battery Temperature - Display current Battery temperature in Celsius and Fahrenheit + Display current battery temperature + Battery Temperature Units + Show Battery Info + Display current power draw and remaining capacity on battery Show Shaders Building Display current number of shaders being built Overlay Position @@ -818,6 +823,10 @@ Medium (256) High (512) + + Celsius + Fahrenheit + 日本語 English diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index f0c5c96cc4..c2347f74d0 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -178,6 +178,8 @@ ENUM(SpirvOptimizeMode, Never, OnLoad, Always); ENUM(GpuOverclock, Low, Medium, High) +ENUM(TemperatureUnits, Celsius, Fahrenheit) + template inline std::string CanonicalizeEnum(Type id) { const auto group = EnumMetadata::Canonicalizations(); -- 2.39.5 From 693404bf3755e6e9b09b83bdaccff7423542a081 Mon Sep 17 00:00:00 2001 From: Esther1024 Date: Wed, 9 Jul 2025 01:31:18 +0000 Subject: [PATCH 18/20] fix LLVM not using current top level src dir (#30) Reviewed-on: https://git.bixed.xyz/Bix/eden/pulls/30 Co-authored-by: Esther1024 Co-committed-by: Esther1024 --- CMakeModules/FindLLVM.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeModules/FindLLVM.cmake b/CMakeModules/FindLLVM.cmake index efbd0ca460..8dc064d5d1 100644 --- a/CMakeModules/FindLLVM.cmake +++ b/CMakeModules/FindLLVM.cmake @@ -19,7 +19,7 @@ if (LLVM_FOUND AND LLVM_Demangle_FOUND AND NOT TARGET LLVM::Demangle) target_include_directories(LLVM::Demangle INTERFACE ${LLVM_INCLUDE_DIRS}) # prefer shared LLVM: https://github.com/llvm/llvm-project/issues/34593 # but use ugly hack because llvm_config doesn't support interface library - add_library(_dummy_lib SHARED EXCLUDE_FROM_ALL src/yuzu/main.cpp) + add_library(_dummy_lib SHARED EXCLUDE_FROM_ALL ${CMAKE_SOURCE_DIR}/src/yuzu/main.cpp) llvm_config(_dummy_lib USE_SHARED demangle) get_target_property(LLVM_LIBRARIES _dummy_lib LINK_LIBRARIES) target_link_libraries(LLVM::Demangle INTERFACE ${LLVM_LIBRARIES}) -- 2.39.5 From 3e44389bfcde32ce70be2bf17e374c0e50bcc138 Mon Sep 17 00:00:00 2001 From: Gamer64 <76565986+Gamer64ytb@users.noreply.github.com> Date: Wed, 9 Jul 2025 04:23:07 +0200 Subject: [PATCH 19/20] [Rasterizer]: Implement "Skip CPU Inner Invalidation" hack --- .../yuzu_emu/features/settings/model/BooleanSetting.kt | 1 + .../yuzu_emu/features/settings/model/view/SettingsItem.kt | 7 +++++++ .../features/settings/ui/SettingsFragmentPresenter.kt | 1 + src/android/app/src/main/res/values/strings.xml | 2 ++ src/common/settings.h | 7 +++++++ src/video_core/rasterizer_interface.h | 7 +++++-- src/yuzu/configuration/shared_translation.cpp | 5 +++++ 7 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 79cfed1cd0..a558afab47 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -17,6 +17,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_USE_SPEED_LIMIT("use_speed_limit"), USE_FAST_CPU_TIME("use_fast_cpu_time"), USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"), + SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"), USE_DOCKED_MODE("use_docked_mode"), USE_AUTO_STUB("use_auto_stub"), RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 4e206ab541..ec56362f77 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -655,6 +655,13 @@ abstract class SettingsItem( max = 65535 ) ) + put( + SwitchSetting( + BooleanSetting.SKIP_CPU_INNER_INVALIDATION, + titleId = R.string.skip_cpu_inner_invalidation, + descriptionId = R.string.skip_cpu_inner_invalidation_description + ) + ) put( SwitchSetting( BooleanSetting.RENDERER_REACTIVE_FLUSHING, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 430e2f3426..31e2873b58 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -463,6 +463,7 @@ class SettingsFragmentPresenter( add(IntSetting.FAST_CPU_TIME.key) add(BooleanSetting.USE_CUSTOM_CPU_TICKS.key) add(IntSetting.CPU_TICKS.key) + add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key) add(BooleanSetting.USE_LRU_CACHE.key) add(BooleanSetting.CORE_SYNC_CORE_SPEED.key) add(IntSetting.MEMORY_LAYOUT.key) diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 658dfedc6b..6f446758b5 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -104,6 +104,8 @@ Custom CPU Ticks Set a custom value of CPU ticks. Higher values can increase performance, but may also cause the game to freeze. A range of 77–21000 is recommended. Ticks + Skip CPU Inner Invalidation + 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. CPU Clock Use Boost (1700MHz) to run at the Switch\'s highest native clock, or Fast (2000MHz) to run at 2x clock. Memory Layout diff --git a/src/common/settings.h b/src/common/settings.h index 2d5a1c4736..941a4513e6 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -450,6 +450,13 @@ struct Values { VramUsageMode::Aggressive, "vram_usage_mode", Category::RendererAdvanced}; + SwitchableSetting skip_cpu_inner_invalidation{linkage, + true, + "skip_cpu_inner_invalidation", + Category::RendererAdvanced, + Specialization::Default, + true, + true}; SwitchableSetting async_presentation{linkage, #ifdef ANDROID true, diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 6e2eccfbf0..481efbf53b 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -9,6 +9,7 @@ #include #include "common/common_types.h" #include "common/polyfill_thread.h" +#include "common/settings.h" #include "video_core/cache_types.h" #include "video_core/engines/fermi_2d.h" #include "video_core/gpu.h" @@ -100,8 +101,10 @@ public: VideoCommon::CacheType which = VideoCommon::CacheType::All) = 0; virtual void InnerInvalidation(std::span> sequences) { - for (const auto& [cpu_addr, size] : sequences) { - InvalidateRegion(cpu_addr, size); + if (!Settings::values.skip_cpu_inner_invalidation.GetValue()) { + for (const auto& [cpu_addr, size] : sequences) { + InvalidateRegion(cpu_addr, size); + } } } diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 2ff2626b6c..c743e65ae3 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -250,6 +250,11 @@ std::unique_ptr InitializeTranslations(QWidget* parent) "of available video memory for performance. Has no effect on integrated graphics. " "Aggressive mode may severely impact the performance of other applications such as " "recording software.")); + INSERT(Settings, + skip_cpu_inner_invalidation, + tr("Skip CPU Inner Invalidation"), + tr("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.")); INSERT( Settings, vsync_mode, -- 2.39.5 From 312b3d4743ad734ac3234385f1edaa94d5b69440 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 9 Jul 2025 17:19:26 +0000 Subject: [PATCH 20/20] [android] update icon background (#31) credit: AntaBaka Signed-off-by: crueter Reviewed-on: https://git.bixed.xyz/Bix/eden/pulls/31 --- .../app/src/main/res/drawable/ic_icon_bg.xml | 1701 +++++++++-------- 1 file changed, 951 insertions(+), 750 deletions(-) diff --git a/src/android/app/src/main/res/drawable/ic_icon_bg.xml b/src/android/app/src/main/res/drawable/ic_icon_bg.xml index df62dde92e..b409a61ea2 100644 --- a/src/android/app/src/main/res/drawable/ic_icon_bg.xml +++ b/src/android/app/src/main/res/drawable/ic_icon_bg.xml @@ -1,751 +1,952 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- 2.39.5