mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-18 06:10:35 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cbd739de3 | |||
| d546a04479 | |||
| 82ed947bb5 | |||
| 774ec0a942 | |||
| 073ecd36af | |||
| a55ffc9225 | |||
| 8f4e8c6d6a | |||
| 4f4c298a39 | |||
| fee603f0b9 | |||
| fc5fa7f1b2 | |||
| 17c341ff6c | |||
| 2deee80f29 | |||
| 27e5cb0f12 | |||
| a76c76d122 |
@@ -444,6 +444,11 @@ if (NOT YUZU_STATIC_ROOM)
|
|||||||
if (NOT TARGET Opus::opus)
|
if (NOT TARGET Opus::opus)
|
||||||
add_library(Opus::opus ALIAS opus)
|
add_library(Opus::opus ALIAS opus)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
# KosmicKrisp
|
||||||
|
AddJsonPackage(kosmickrisp)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT TARGET Boost::headers)
|
if(NOT TARGET Boost::headers)
|
||||||
|
|||||||
@@ -114,5 +114,14 @@
|
|||||||
"QUAZIP_INSTALL OFF",
|
"QUAZIP_INSTALL OFF",
|
||||||
"QUAZIP_ENABLE_QTEXTCODEC OFF"
|
"QUAZIP_ENABLE_QTEXTCODEC OFF"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"kosmickrisp": {
|
||||||
|
"package": "KosmicKrisp",
|
||||||
|
"repo": "crueter-ci/KosmicKrisp",
|
||||||
|
"hash": "4709fb3735ed40048cab9a64abed9a661517dada92b6e8928d578e947fdd6af21b3da4887822f4c3ad3055c6641f9a63243e10e2dd2bba00379618dcc0cda4be",
|
||||||
|
"git_version": "26.0.6",
|
||||||
|
"tag": "v%VERSION%",
|
||||||
|
"artifact": "KosmicKrisp-%VERSION%.tar.zst",
|
||||||
|
"bundled": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -3403,7 +3403,7 @@ Would you like to delete the old save data?</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../../src/yuzu/configuration/configure_graphics_extensions.ui" line="62"/>
|
<location filename="../../src/yuzu/configuration/configure_graphics_extensions.ui" line="62"/>
|
||||||
<source>Vulkan Extensions</source>
|
<source>Vulkan Extensions</source>
|
||||||
<translation>Расшиерния Vulcan</translation>
|
<translation>Расширения Vulcan</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/yuzu/configuration/configure_graphics_extensions.cpp" line="49"/>
|
<location filename="../../src/yuzu/configuration/configure_graphics_extensions.cpp" line="49"/>
|
||||||
|
|||||||
Vendored
-14
@@ -389,17 +389,3 @@ if (ANDROID)
|
|||||||
|
|
||||||
add_library(oboe::oboe ALIAS oboe)
|
add_library(oboe::oboe ALIAS oboe)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
# moltenvk
|
|
||||||
if (NOT YUZU_USE_BUNDLED_MOLTENVK)
|
|
||||||
find_library(MOLTENVK_LIBRARY MoltenVK)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# TODO: kosmickrisp?
|
|
||||||
if (NOT MOLTENVK_LIBRARY OR YUZU_USE_BUNDLED_MOLTENVK)
|
|
||||||
AddJsonPackage(moltenvk)
|
|
||||||
|
|
||||||
set(MOLTENVK_LIBRARY "${moltenvk_SOURCE_DIR}/MoltenVK/dylib/macOS/libMoltenVK.dylib" CACHE STRING "" FORCE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|||||||
Vendored
-8
@@ -174,14 +174,6 @@
|
|||||||
"bundled": true,
|
"bundled": true,
|
||||||
"skip_updates": "true"
|
"skip_updates": "true"
|
||||||
},
|
},
|
||||||
"moltenvk": {
|
|
||||||
"repo": "V380-Ori/Ryujinx.MoltenVK",
|
|
||||||
"tag": "v%VERSION%-ryujinx",
|
|
||||||
"git_version": "1.4.1",
|
|
||||||
"artifact": "MoltenVK-macOS.tar",
|
|
||||||
"hash": "5695b36ca5775819a71791557fcb40a4a5ee4495be6b8442e0b666d0c436bec02aae68cc6210183f7a5c986bdbec0e117aecfad5396e496e9c2fd5c89133a347",
|
|
||||||
"bundled": true
|
|
||||||
},
|
|
||||||
"gamemode": {
|
"gamemode": {
|
||||||
"repo": "FeralInteractive/gamemode",
|
"repo": "FeralInteractive/gamemode",
|
||||||
"sha": "ce6fe122f3",
|
"sha": "ce6fe122f3",
|
||||||
|
|||||||
@@ -192,12 +192,6 @@ android {
|
|||||||
manifestPlaceholders += mapOf("appNameBase" to "Eden")
|
manifestPlaceholders += mapOf("appNameBase" to "Eden")
|
||||||
resValue("string", "app_name_suffixed", "Eden")
|
resValue("string", "app_name_suffixed", "Eden")
|
||||||
|
|
||||||
externalNativeBuild {
|
|
||||||
cmake {
|
|
||||||
arguments.add("-DGENSHIN_SPOOF=ON")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters += listOf("arm64-v8a")
|
abiFilters += listOf("arm64-v8a")
|
||||||
}
|
}
|
||||||
@@ -209,6 +203,12 @@ android {
|
|||||||
resValue("string", "app_name_suffixed", "Eden Optimized")
|
resValue("string", "app_name_suffixed", "Eden Optimized")
|
||||||
applicationId = "com.miHoYo.Yuanshen"
|
applicationId = "com.miHoYo.Yuanshen"
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
arguments.add("-DGENSHIN_SPOOF=ON")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters += listOf("arm64-v8a")
|
abiFilters += listOf("arm64-v8a")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -413,7 +413,9 @@
|
|||||||
<string name="frame_limit_slider">Limiter le pourcentage de vitesse</string>
|
<string name="frame_limit_slider">Limiter le pourcentage de vitesse</string>
|
||||||
<string name="frame_limit_slider_description">Spécifier le pourcentage pour limiter la vitesse d\'émulation. 100% correspond à la vitesse normale. Des valeurs plus élevées ou plus basses augmenteront ou diminueront la limite de vitesse.</string>
|
<string name="frame_limit_slider_description">Spécifier le pourcentage pour limiter la vitesse d\'émulation. 100% correspond à la vitesse normale. Des valeurs plus élevées ou plus basses augmenteront ou diminueront la limite de vitesse.</string>
|
||||||
<string name="turbo_speed_limit">Vitesse turbo</string>
|
<string name="turbo_speed_limit">Vitesse turbo</string>
|
||||||
|
<string name="turbo_speed_limit_description">Lorsque le mode Turbo est activé, l\'émulation s\'exécute à cette vitesse.</string>
|
||||||
<string name="slow_speed_limit">Vitesse lente</string>
|
<string name="slow_speed_limit">Vitesse lente</string>
|
||||||
|
<string name="slow_speed_limit_description">Lorsque le mode Lent est activé, l\'émulation s\'exécute à cette vitesse.</string>
|
||||||
<string name="cpu_backend">Backend du CPU</string>
|
<string name="cpu_backend">Backend du CPU</string>
|
||||||
<string name="cpu_accuracy">Précision du CPU</string>
|
<string name="cpu_accuracy">Précision du CPU</string>
|
||||||
<string name="value_with_units">%1$s%2$s</string>
|
<string name="value_with_units">%1$s%2$s</string>
|
||||||
|
|||||||
@@ -489,6 +489,8 @@
|
|||||||
<string name="enable_buffer_history">Включить историю буфера</string>
|
<string name="enable_buffer_history">Включить историю буфера</string>
|
||||||
<string name="enable_buffer_history_description">Позволяет обращаться к предыдущим состояниям буфера. Эта опция может повысить качество рендеринга и стабильность производительности в некоторых играх.</string>
|
<string name="enable_buffer_history_description">Позволяет обращаться к предыдущим состояниям буфера. Эта опция может повысить качество рендеринга и стабильность производительности в некоторых играх.</string>
|
||||||
<string name="use_optimized_vertex_buffers">Оптимизированные вершинные буферы</string>
|
<string name="use_optimized_vertex_buffers">Оптимизированные вершинные буферы</string>
|
||||||
|
<string name="use_optimized_vertex_buffers_description">Включает оптимизированную привязку вершинного буфера для повышения производительности. Требует Mesa Turnip 26.0+ / QCOM драйверы. Приводит к вылету на старых версиях Turnip.</string>
|
||||||
|
|
||||||
<string name="hacks">Хаки</string>
|
<string name="hacks">Хаки</string>
|
||||||
|
|
||||||
<string name="fast_gpu_time">Быстрое время ГПУ</string>
|
<string name="fast_gpu_time">Быстрое время ГПУ</string>
|
||||||
@@ -496,6 +498,9 @@
|
|||||||
<string name="skip_cpu_inner_invalidation">Пропустить внутреннюю инвалидацию ЦП</string>
|
<string name="skip_cpu_inner_invalidation">Пропустить внутреннюю инвалидацию ЦП</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх.</string>
|
<string name="skip_cpu_inner_invalidation_description">Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх.</string>
|
||||||
<string name="fix_bloom_effects">Исправить эффекты размытия</string>
|
<string name="fix_bloom_effects">Исправить эффекты размытия</string>
|
||||||
|
<string name="fix_bloom_effects_description">Частично убирает размытие в LA/EOW (Adreno A6XX - A7XX/ Turnip), полностью отключает его в Burnout. Внимание: может вызывать графические артефакты в других играх.</string>
|
||||||
|
<string name="emulate_bgr565">Эмулировать BGR565</string>
|
||||||
|
<string name="emulate_bgr565_description">Исправляет проблемы с инвертированными цветами в играх, а также со странными артефактами или некорректными тенями.</string>
|
||||||
<string name="renderer_asynchronous_shaders">Использовать асинхронные шейдеры</string>
|
<string name="renderer_asynchronous_shaders">Использовать асинхронные шейдеры</string>
|
||||||
<string name="renderer_asynchronous_shaders_description">Компилирует шейдеры асинхронно. Это может уменьшить подтормаживания, но также может вызвать графические артефакты.</string>
|
<string name="renderer_asynchronous_shaders_description">Компилирует шейдеры асинхронно. Это может уменьшить подтормаживания, но также может вызвать графические артефакты.</string>
|
||||||
<string name="gpu_unswizzle_settings">Настройки распаковки текстур (Unswizzle)</string>
|
<string name="gpu_unswizzle_settings">Настройки распаковки текстур (Unswizzle)</string>
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
|||||||
// Set other basic fields.
|
// Set other basic fields.
|
||||||
m_enable_aslr = enable_aslr;
|
m_enable_aslr = enable_aslr;
|
||||||
m_enable_device_address_space_merge = enable_das_merge;
|
m_enable_device_address_space_merge = enable_das_merge;
|
||||||
|
m_allowed_exec_device_mapping = false;
|
||||||
m_address_space_start = start;
|
m_address_space_start = start;
|
||||||
m_address_space_end = end;
|
m_address_space_end = end;
|
||||||
m_is_kernel = false;
|
m_is_kernel = false;
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ private:
|
|||||||
bool m_is_kernel{};
|
bool m_is_kernel{};
|
||||||
bool m_enable_aslr{};
|
bool m_enable_aslr{};
|
||||||
bool m_enable_device_address_space_merge{};
|
bool m_enable_device_address_space_merge{};
|
||||||
|
bool m_allowed_exec_device_mapping{};
|
||||||
KMemoryBlockSlabManager* m_memory_block_slab_manager{};
|
KMemoryBlockSlabManager* m_memory_block_slab_manager{};
|
||||||
KBlockInfoManager* m_block_info_manager{};
|
KBlockInfoManager* m_block_info_manager{};
|
||||||
KResourceLimit* m_resource_limit{};
|
KResourceLimit* m_resource_limit{};
|
||||||
@@ -255,6 +256,10 @@ public:
|
|||||||
return m_enable_aslr;
|
return m_enable_aslr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AllowDeviceMappingOfExecPages() {
|
||||||
|
m_allowed_exec_device_mapping = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Contains(KProcessAddress addr) const {
|
bool Contains(KProcessAddress addr) const {
|
||||||
return m_address_space_start <= addr && addr <= m_address_space_end - 1;
|
return m_address_space_start <= addr && addr <= m_address_space_end - 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -341,6 +341,11 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
|
|||||||
// Initialize capabilities.
|
// Initialize capabilities.
|
||||||
R_TRY(m_capabilities.InitializeForKip(caps, std::addressof(m_page_table)));
|
R_TRY(m_capabilities.InitializeForKip(caps, std::addressof(m_page_table)));
|
||||||
|
|
||||||
|
// Enable mapping device pages as executable on legacy processes.
|
||||||
|
if (m_capabilities.GetIntendedKernelMajorVersion() < 26) {
|
||||||
|
m_page_table.AllowDeviceMappingOfExecPages();
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the process id.
|
// Initialize the process id.
|
||||||
m_process_id = m_kernel.CreateNewUserProcessID();
|
m_process_id = m_kernel.CreateNewUserProcessID();
|
||||||
ASSERT(InitialProcessIdMin <= m_process_id);
|
ASSERT(InitialProcessIdMin <= m_process_id);
|
||||||
@@ -437,6 +442,11 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
|
|||||||
// Initialize capabilities.
|
// Initialize capabilities.
|
||||||
R_TRY(m_capabilities.InitializeForUser(user_caps, std::addressof(m_page_table)));
|
R_TRY(m_capabilities.InitializeForUser(user_caps, std::addressof(m_page_table)));
|
||||||
|
|
||||||
|
// Enable mapping device pages as executable on legacy processes.
|
||||||
|
if (m_capabilities.GetIntendedKernelMajorVersion() < 26) {
|
||||||
|
m_page_table.AllowDeviceMappingOfExecPages();
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the process id.
|
// Initialize the process id.
|
||||||
m_process_id = m_kernel.CreateNewUserProcessID();
|
m_process_id = m_kernel.CreateNewUserProcessID();
|
||||||
ASSERT(ProcessIdMin <= m_process_id);
|
ASSERT(ProcessIdMin <= m_process_id);
|
||||||
@@ -989,6 +999,9 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
|
|||||||
main_thread->GetContext().r[0] = 0;
|
main_thread->GetContext().r[0] = 0;
|
||||||
main_thread->GetContext().r[1] = thread_handle;
|
main_thread->GetContext().r[1] = thread_handle;
|
||||||
|
|
||||||
|
// Pass the thread handle to the thread local region.
|
||||||
|
this->GetMemory().Write32(GetInteger(main_thread->GetTlsAddress()) + 0x110, thread_handle);
|
||||||
|
|
||||||
// Update our state.
|
// Update our state.
|
||||||
this->ChangeState((state == State::Created) ? State::Running : State::RunningAttached);
|
this->ChangeState((state == State::Created) ? State::Running : State::RunningAttached);
|
||||||
ON_RESULT_FAILURE_2 {
|
ON_RESULT_FAILURE_2 {
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ public:
|
|||||||
m_page_table.Finalize();
|
m_page_table.Finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AllowDeviceMappingOfExecPages() {
|
||||||
|
m_page_table.AllowDeviceMappingOfExecPages();
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] Core::Memory::Memory& GetMemory() noexcept { return m_page_table.GetMemory(); }
|
[[nodiscard]] Core::Memory::Memory& GetMemory() noexcept { return m_page_table.GetMemory(); }
|
||||||
[[nodiscard]] Core::Memory::Memory const& GetMemory() const noexcept { return m_page_table.GetMemory(); }
|
[[nodiscard]] Core::Memory::Memory const& GetMemory() const noexcept { return m_page_table.GetMemory(); }
|
||||||
[[nodiscard]] Common::PageTable& GetImpl() noexcept { return m_page_table.GetImpl(); }
|
[[nodiscard]] Common::PageTable& GetImpl() noexcept { return m_page_table.GetImpl(); }
|
||||||
|
|||||||
@@ -76,11 +76,13 @@ namespace Kernel {
|
|||||||
std::atomic_uint16_t interrupt_flag;
|
std::atomic_uint16_t interrupt_flag;
|
||||||
std::atomic_uint8_t cache_maintenance_flag;
|
std::atomic_uint8_t cache_maintenance_flag;
|
||||||
std::atomic_int64_t thread_cpu_time;
|
std::atomic_int64_t thread_cpu_time;
|
||||||
|
std::atomic_uint32_t current_thread_handle;
|
||||||
};
|
};
|
||||||
static_assert(offsetof(ThreadLocalRegion, disable_count) == 0x100);
|
static_assert(offsetof(ThreadLocalRegion, disable_count) == 0x100);
|
||||||
static_assert(offsetof(ThreadLocalRegion, interrupt_flag) == 0x102);
|
static_assert(offsetof(ThreadLocalRegion, interrupt_flag) == 0x102);
|
||||||
static_assert(offsetof(ThreadLocalRegion, cache_maintenance_flag) == 0x104);
|
static_assert(offsetof(ThreadLocalRegion, cache_maintenance_flag) == 0x104);
|
||||||
static_assert(offsetof(ThreadLocalRegion, thread_cpu_time) == 0x108);
|
static_assert(offsetof(ThreadLocalRegion, thread_cpu_time) == 0x108);
|
||||||
|
static_assert(offsetof(ThreadLocalRegion, current_thread_handle) == 0x110);
|
||||||
|
|
||||||
class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait {
|
class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait {
|
||||||
public:
|
public:
|
||||||
@@ -128,24 +130,24 @@ namespace Kernel {
|
|||||||
|
|
||||||
// Next, assert things based on the type.
|
// Next, assert things based on the type.
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ThreadType::Main:
|
case ThreadType::Main:
|
||||||
ASSERT(arg == 0);
|
ASSERT(arg == 0);
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case ThreadType::User:
|
case ThreadType::User:
|
||||||
ASSERT(((owner == nullptr) ||
|
ASSERT(((owner == nullptr) ||
|
||||||
(owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask()));
|
(owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask()));
|
||||||
ASSERT(((owner == nullptr) || (prio > Svc::LowestThreadPriority) ||
|
ASSERT(((owner == nullptr) || (prio > Svc::LowestThreadPriority) ||
|
||||||
(owner->GetPriorityMask() | (1ULL << prio)) == owner->GetPriorityMask()));
|
(owner->GetPriorityMask() | (1ULL << prio)) == owner->GetPriorityMask()));
|
||||||
break;
|
break;
|
||||||
case ThreadType::HighPriority:
|
case ThreadType::HighPriority:
|
||||||
case ThreadType::Dummy:
|
case ThreadType::Dummy:
|
||||||
break;
|
break;
|
||||||
case ThreadType::Kernel:
|
case ThreadType::Kernel:
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ASSERT_MSG(false, "KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type));
|
ASSERT_MSG(false, "KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_thread_type = type;
|
m_thread_type = type;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
@@ -75,7 +75,12 @@ Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u
|
|||||||
KThread::Register(kernel, thread);
|
KThread::Register(kernel, thread);
|
||||||
|
|
||||||
// Add the thread to the handle table.
|
// Add the thread to the handle table.
|
||||||
R_RETURN(process.GetHandleTable().Add(out_handle, thread));
|
R_TRY(process.GetHandleTable().Add(out_handle, thread));
|
||||||
|
|
||||||
|
// Pass the thread handle to the thread local region.
|
||||||
|
process.GetMemory().Write32(GetInteger(thread->GetTlsAddress()) + 0x110, *out_handle);
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts the thread for the provided handle
|
/// Starts the thread for the provided handle
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
@@ -53,8 +53,8 @@ constexpr inline u32 RequiredKernelVersion =
|
|||||||
|
|
||||||
// This is the highest SVC version supported, to be updated on new kernel releases.
|
// This is the highest SVC version supported, to be updated on new kernel releases.
|
||||||
// NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor.
|
// NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor.
|
||||||
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(20);
|
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(22);
|
||||||
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion(5);
|
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion(2);
|
||||||
constexpr inline u32 SupportedKernelVersion =
|
constexpr inline u32 SupportedKernelVersion =
|
||||||
EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
|
EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
|
||||||
|
|
||||||
|
|||||||
@@ -1155,6 +1155,14 @@ void Module::Interface::StoreSaveDataThumbnailSystem(HLERequestContext& ctx) {
|
|||||||
StoreSaveDataThumbnail(ctx, uuid, tid);
|
StoreSaveDataThumbnail(ctx, uuid, tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Module::Interface::GetPinCodeLength(HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push<u32>(0);
|
||||||
|
}
|
||||||
|
|
||||||
void Module::Interface::StoreSaveDataThumbnail(HLERequestContext& ctx, const Common::UUID& uuid,
|
void Module::Interface::StoreSaveDataThumbnail(HLERequestContext& ctx, const Common::UUID& uuid,
|
||||||
const u64 tid) {
|
const u64 tid) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -48,6 +48,7 @@ public:
|
|||||||
void StoreSaveDataThumbnailApplication(HLERequestContext& ctx);
|
void StoreSaveDataThumbnailApplication(HLERequestContext& ctx);
|
||||||
void GetBaasAccountManagerForSystemService(HLERequestContext& ctx);
|
void GetBaasAccountManagerForSystemService(HLERequestContext& ctx);
|
||||||
void StoreSaveDataThumbnailSystem(HLERequestContext& ctx);
|
void StoreSaveDataThumbnailSystem(HLERequestContext& ctx);
|
||||||
|
void GetPinCodeLength(HLERequestContext& ctx);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Result InitializeApplicationInfoBase();
|
Result InitializeApplicationInfoBase();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -60,7 +60,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
|
|||||||
{291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"},
|
{291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"},
|
||||||
{299, nullptr, "SuspendBackgroundDaemon"},
|
{299, nullptr, "SuspendBackgroundDaemon"},
|
||||||
{400, nullptr, "SetPinCode"}, // 18.0.0+
|
{400, nullptr, "SetPinCode"}, // 18.0.0+
|
||||||
{401, nullptr, "GetPinCodeLength"}, // 18.0.0+
|
{401, &ACC_SU::GetPinCodeLength, "GetPinCodeLength"}, // 18.0.0+
|
||||||
{402, nullptr, "GetPinCode"}, // 18.0.0+
|
{402, nullptr, "GetPinCode"}, // 18.0.0+
|
||||||
{410, nullptr, "GetPinCodeErrorCount"}, // 18.0.0+
|
{410, nullptr, "GetPinCodeErrorCount"}, // 18.0.0+
|
||||||
{411, nullptr, "ResetPinCodeErrorCount"}, // 18.0.0+
|
{411, nullptr, "ResetPinCodeErrorCount"}, // 18.0.0+
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -40,7 +43,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
|
|||||||
{152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
|
{152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
|
||||||
{190, nullptr, "GetUserLastOpenedApplication"},
|
{190, nullptr, "GetUserLastOpenedApplication"},
|
||||||
{191, nullptr, "ActivateOpenContextHolder"},
|
{191, nullptr, "ActivateOpenContextHolder"},
|
||||||
{401, nullptr, "GetPinCodeLength"}, // 18.0.0+
|
{401, &ACC_U1::GetPinCodeLength, "GetPinCodeLength"}, // 18.0.0+
|
||||||
{402, nullptr, "GetPinCode"}, // 18.0.0+
|
{402, nullptr, "GetPinCode"}, // 18.0.0+
|
||||||
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
||||||
{998, nullptr, "DebugSetUserStateClose"},
|
{998, nullptr, "DebugSetUserStateClose"},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -92,7 +92,7 @@ Result IApplicationCreator::CreateSystemApplication(
|
|||||||
std::unique_ptr<Loader::AppLoader> loader;
|
std::unique_ptr<Loader::AppLoader> loader;
|
||||||
|
|
||||||
auto process =
|
auto process =
|
||||||
CreateProcess(system, application_id, 1, 21);
|
CreateProcess(system, application_id, 1, 22);
|
||||||
R_UNLESS(process != nullptr, ResultUnknown);
|
R_UNLESS(process != nullptr, ResultUnknown);
|
||||||
|
|
||||||
const auto applet = std::make_shared<Applet>(system, std::move(process), true);
|
const auto applet = std::make_shared<Applet>(system, std::move(process), true);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -75,7 +75,8 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Ap
|
|||||||
{502, nullptr, "IsSleepEnabled"},
|
{502, nullptr, "IsSleepEnabled"},
|
||||||
{503, nullptr, "IsDisablingSleepSuppressed"},
|
{503, nullptr, "IsDisablingSleepSuppressed"},
|
||||||
{600, nullptr, "Unknown600"}, //20.0.0+
|
{600, nullptr, "Unknown600"}, //20.0.0+
|
||||||
{610, nullptr, "Unknown610"}, //21.0.0+
|
{610, D<&ICommonStateGetter::Unknown610>, "Unknown610"}, //21.0.0+
|
||||||
|
{611, D<&ICommonStateGetter::Unknown611>, "Unknown611"}, //22.0.0+
|
||||||
{900, D<&ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled>, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, //11.0.0+
|
{900, D<&ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled>, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, //11.0.0+
|
||||||
{910, nullptr, "GetLaunchRequiredTick"}, //17.0.0+
|
{910, nullptr, "GetLaunchRequiredTick"}, //17.0.0+
|
||||||
{1000, nullptr, "BeginVrMode3d"}, //19.0.0+
|
{1000, nullptr, "BeginVrMode3d"}, //19.0.0+
|
||||||
@@ -362,4 +363,14 @@ Result ICommonStateGetter::SetHandlingHomeButtonShortPressedEnabled(bool enabled
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ICommonStateGetter::Unknown610() {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ICommonStateGetter::Unknown611() {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Service::AM
|
} // namespace Service::AM
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -63,6 +63,8 @@ private:
|
|||||||
Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled();
|
Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled();
|
||||||
Result PushToGeneralChannel(SharedPointer<IStorage> storage); // cmd 20
|
Result PushToGeneralChannel(SharedPointer<IStorage> storage); // cmd 20
|
||||||
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
|
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
|
||||||
|
Result Unknown610();
|
||||||
|
Result Unknown611();
|
||||||
|
|
||||||
void SetCpuBoostMode(HLERequestContext& ctx);
|
void SetCpuBoostMode(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
|
|||||||
{120, nullptr, "GetLibraryAppletInfo"},
|
{120, nullptr, "GetLibraryAppletInfo"},
|
||||||
{150, nullptr, "RequestForAppletToGetForeground"},
|
{150, nullptr, "RequestForAppletToGetForeground"},
|
||||||
{160, D<&ILibraryAppletAccessor::GetIndirectLayerConsumerHandle>, "GetIndirectLayerConsumerHandle"}, //2.0.0+
|
{160, D<&ILibraryAppletAccessor::GetIndirectLayerConsumerHandle>, "GetIndirectLayerConsumerHandle"}, //2.0.0+
|
||||||
|
{170, D<&ILibraryAppletAccessor::Unknown170>, "Unknown170"}, //22.0.0+
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@@ -217,6 +218,12 @@ Result ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(Out<u64> out_handl
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ILibraryAppletAccessor::Unknown170(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
*out_event = m_applet->unknown_event.GetHandle();
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
void ILibraryAppletAccessor::FrontendExecute() {
|
void ILibraryAppletAccessor::FrontendExecute() {
|
||||||
if (m_applet->frontend) {
|
if (m_applet->frontend) {
|
||||||
m_applet->frontend->Initialize();
|
m_applet->frontend->Initialize();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -37,6 +37,7 @@ private:
|
|||||||
Result GetPopOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
Result GetPopOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||||
Result GetPopInteractiveOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
Result GetPopInteractiveOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||||
Result GetIndirectLayerConsumerHandle(Out<u64> out_handle);
|
Result GetIndirectLayerConsumerHandle(Out<u64> out_handle);
|
||||||
|
Result Unknown170(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||||
|
|
||||||
void FrontendExecute();
|
void FrontendExecute();
|
||||||
void FrontendExecuteInteractive();
|
void FrontendExecuteInteractive();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
@@ -118,9 +118,10 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
|
|||||||
Firmware1900 = 19,
|
Firmware1900 = 19,
|
||||||
Firmware2000 = 20,
|
Firmware2000 = 20,
|
||||||
Firmware2100 = 21,
|
Firmware2100 = 21,
|
||||||
|
Firmware2200 = 22,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto process = CreateProcess(system, program_id, Firmware1400, Firmware2100);
|
auto process = CreateProcess(system, program_id, Firmware1400, Firmware2200);
|
||||||
if (!process) {
|
if (!process) {
|
||||||
// Couldn't initialize the guest process
|
// Couldn't initialize the guest process
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -199,25 +199,28 @@ NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) {
|
|||||||
return NvResult::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
|
bool nvhost_as_gpu::FreeMappingLocked(u64 offset) noexcept {
|
||||||
auto const it = mapping_map.find(offset);
|
if (auto const it = mapping_map.find(offset); it != mapping_map.end()) {
|
||||||
auto const mapping = it->second;
|
auto const mapping = it->second;
|
||||||
if (!mapping.fixed) {
|
if (!mapping.fixed) {
|
||||||
auto& allocator{mapping.big_page ? *vm.big_page_allocator : *vm.small_page_allocator};
|
auto& allocator{mapping.big_page ? *vm.big_page_allocator : *vm.small_page_allocator};
|
||||||
u32 page_size_bits{mapping.big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS};
|
u32 page_size_bits{mapping.big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS};
|
||||||
u32 page_size{mapping.big_page ? vm.big_page_size : VM::YUZU_PAGESIZE};
|
u32 page_size{mapping.big_page ? vm.big_page_size : VM::YUZU_PAGESIZE};
|
||||||
u64 aligned_size{Common::AlignUp(mapping.size, page_size)};
|
u64 aligned_size{Common::AlignUp(mapping.size, page_size)};
|
||||||
allocator.Free(u32(mapping.offset >> page_size_bits), u32(aligned_size >> page_size_bits));
|
allocator.Free(u32(mapping.offset >> page_size_bits), u32(aligned_size >> page_size_bits));
|
||||||
|
}
|
||||||
|
nvmap.UnpinHandle(mapping.handle);
|
||||||
|
// Sparse mappings shouldn't be fully unmapped, just returned to their sparse state
|
||||||
|
// Only FreeSpace can unmap them fully
|
||||||
|
if (mapping.sparse_alloc) {
|
||||||
|
gmmu->MapSparse(offset, mapping.size, mapping.big_page);
|
||||||
|
} else {
|
||||||
|
gmmu->Unmap(offset, mapping.size);
|
||||||
|
}
|
||||||
|
mapping_map.erase(offset);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
nvmap.UnpinHandle(mapping.handle);
|
return false;
|
||||||
// Sparse mappings shouldn't be fully unmapped, just returned to their sparse state
|
|
||||||
// Only FreeSpace can unmap them fully
|
|
||||||
if (mapping.sparse_alloc) {
|
|
||||||
gmmu->MapSparse(offset, mapping.size, mapping.big_page);
|
|
||||||
} else {
|
|
||||||
gmmu->Unmap(offset, mapping.size);
|
|
||||||
}
|
|
||||||
mapping_map.erase(it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) {
|
NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) {
|
||||||
@@ -232,7 +235,8 @@ NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) {
|
|||||||
return NvResult::BadValue;
|
return NvResult::BadValue;
|
||||||
|
|
||||||
for (const auto mapping_offset : allocation.mappings)
|
for (const auto mapping_offset : allocation.mappings)
|
||||||
FreeMappingLocked(mapping_offset);
|
if (!FreeMappingLocked(mapping_offset))
|
||||||
|
return NvResult::BadValue;
|
||||||
|
|
||||||
// Unset sparse flag if required
|
// Unset sparse flag if required
|
||||||
if (allocation.sparse)
|
if (allocation.sparse)
|
||||||
@@ -402,8 +406,8 @@ NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nvmap.UnpinHandle(mapping.handle);
|
nvmap.UnpinHandle(mapping.handle);
|
||||||
mapping_map.erase(it);
|
mapping_map.erase(params.offset);
|
||||||
map_buffer_offsets.erase(offset_it);
|
map_buffer_offsets.erase(params.offset);
|
||||||
}
|
}
|
||||||
return NvResult::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ private:
|
|||||||
NvResult GetVARegions1(IoctlGetVaRegions& params);
|
NvResult GetVARegions1(IoctlGetVaRegions& params);
|
||||||
NvResult GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions);
|
NvResult GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions);
|
||||||
|
|
||||||
void FreeMappingLocked(u64 offset);
|
[[nodiscard]] bool FreeMappingLocked(u64 offset) noexcept;
|
||||||
|
|
||||||
Module& module;
|
Module& module;
|
||||||
|
|
||||||
|
|||||||
@@ -409,6 +409,13 @@ struct AccountNotificationSettings {
|
|||||||
static_assert(sizeof(AccountNotificationSettings) == 0x18,
|
static_assert(sizeof(AccountNotificationSettings) == 0x18,
|
||||||
"AccountNotificationSettings is an invalid size");
|
"AccountNotificationSettings is an invalid size");
|
||||||
|
|
||||||
|
/// This is nn::settings::system::AccountUserSettings (stubbed)
|
||||||
|
struct AccountUserSettings {
|
||||||
|
std::array<u8, 0x40> data;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(AccountUserSettings) == 0x40,
|
||||||
|
"AccountUserSettings is an invalid size");
|
||||||
|
|
||||||
/// This is nn::settings::factory::BatteryLot
|
/// This is nn::settings::factory::BatteryLot
|
||||||
struct BatteryLot {
|
struct BatteryLot {
|
||||||
std::array<char, 0x18> lot_number;
|
std::array<char, 0x18> lot_number;
|
||||||
|
|||||||
@@ -340,9 +340,9 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
|
|||||||
{306, nullptr, "GetPinCodeReregistrationGuideAccounts"}, //20.0.0+
|
{306, nullptr, "GetPinCodeReregistrationGuideAccounts"}, //20.0.0+
|
||||||
{307, nullptr, "SetPinCodeReregistrationGuideAccounts"}, //20.0.0+
|
{307, nullptr, "SetPinCodeReregistrationGuideAccounts"}, //20.0.0+
|
||||||
{315, C<&ISystemSettingsServer::GetHttpAuthConfigs>, "GetHttpAuthConfigs"}, //21.0.0+
|
{315, C<&ISystemSettingsServer::GetHttpAuthConfigs>, "GetHttpAuthConfigs"}, //21.0.0+
|
||||||
{319, nullptr, "GetAccountUserSettings"}, //21.0.0+
|
{319, C<&ISystemSettingsServer::GetAccountUserSettings>, "GetAccountUserSettings"}, //21.0.0+
|
||||||
{320, nullptr, "SetAccountUserSettings"}, //21.0.0+
|
{320, nullptr, "SetAccountUserSettings"}, //21.0.0+
|
||||||
{321, nullptr, "GetDefaultAccountUserSettings"}, //21.0.0+
|
{321, C<&ISystemSettingsServer::GetDefaultAccountUserSettings>, "GetDefaultAccountUserSettings"}, //21.0.0+
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@@ -1428,6 +1428,23 @@ Result ISystemSettingsServer::GetHttpAuthConfigs(Out<s32> out_count, OutBuffer<B
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ISystemSettingsServer::GetAccountUserSettings(
|
||||||
|
Out<u32> out_count,
|
||||||
|
OutLargeData<AccountUserSettings, BufferAttr_HipcMapAlias> out_settings) {
|
||||||
|
LOG_WARNING(Service_SET, "(STUBBED) called");
|
||||||
|
|
||||||
|
*out_count = 0;
|
||||||
|
*out_settings = {};
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ISystemSettingsServer::GetDefaultAccountUserSettings(Out<AccountUserSettings> out_settings) {
|
||||||
|
LOG_WARNING(Service_SET, "(STUBBED) called");
|
||||||
|
|
||||||
|
*out_settings = {};
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
void ISystemSettingsServer::SetupSettings() {
|
void ISystemSettingsServer::SetupSettings() {
|
||||||
auto system_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000050";
|
auto system_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000050";
|
||||||
if (!LoadSettingsFile(system_dir, []() { return DefaultSystemSettings(); })) {
|
if (!LoadSettingsFile(system_dir, []() { return DefaultSystemSettings(); })) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -161,6 +161,10 @@ public:
|
|||||||
Result GetPanelCrcMode(Out<s32> out_panel_crc_mode);
|
Result GetPanelCrcMode(Out<s32> out_panel_crc_mode);
|
||||||
Result SetPanelCrcMode(s32 panel_crc_mode);
|
Result SetPanelCrcMode(s32 panel_crc_mode);
|
||||||
Result GetHttpAuthConfigs(Out<s32> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_configs);
|
Result GetHttpAuthConfigs(Out<s32> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_configs);
|
||||||
|
Result GetAccountUserSettings(
|
||||||
|
Out<u32> out_count,
|
||||||
|
OutLargeData<AccountUserSettings, BufferAttr_HipcMapAlias> out_settings);
|
||||||
|
Result GetDefaultAccountUserSettings(Out<AccountUserSettings> out_settings);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool LoadSettingsFile(std::filesystem::path& path, auto&& default_func);
|
bool LoadSettingsFile(std::filesystem::path& path, auto&& default_func);
|
||||||
|
|||||||
@@ -67,22 +67,24 @@ public:
|
|||||||
Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name);
|
Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name);
|
||||||
|
|
||||||
template <std::derived_from<SessionRequestHandler> T>
|
template <std::derived_from<SessionRequestHandler> T>
|
||||||
std::shared_ptr<T> GetService(const std::string& service_name, bool block = false) const {
|
std::shared_ptr<T> GetService(const std::string& name, bool block = false) const {
|
||||||
auto service = registered_services.find(service_name);
|
std::unique_lock l{lock};
|
||||||
if (service == registered_services.end() && !block) {
|
auto it = registered_services.find(name);
|
||||||
LOG_DEBUG(Service, "Can't find service: {}", service_name);
|
if (it == registered_services.end() && !block) {
|
||||||
|
LOG_DEBUG(Service, "Can't find service: {}", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (block) {
|
} else if (block) {
|
||||||
using namespace std::literals::chrono_literals;
|
using namespace std::literals::chrono_literals;
|
||||||
while (service == registered_services.end()) {
|
while (it == registered_services.end()) {
|
||||||
|
l.unlock();
|
||||||
Kernel::Svc::SleepThread(
|
Kernel::Svc::SleepThread(
|
||||||
kernel.System(),
|
kernel.System(),
|
||||||
std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count());
|
std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count());
|
||||||
service = registered_services.find(service_name);
|
l.lock();
|
||||||
|
it = registered_services.find(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return std::static_pointer_cast<T>(it->second());
|
||||||
return std::static_pointer_cast<T>(service->second());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvokeControlRequest(HLERequestContext& context);
|
void InvokeControlRequest(HLERequestContext& context);
|
||||||
@@ -96,7 +98,7 @@ private:
|
|||||||
std::unique_ptr<Controller> controller_interface;
|
std::unique_ptr<Controller> controller_interface;
|
||||||
|
|
||||||
/// Map of registered services, retrieved using GetServicePort.
|
/// Map of registered services, retrieved using GetServicePort.
|
||||||
std::mutex lock;
|
mutable std::mutex lock;
|
||||||
ankerl::unordered_dense::map<std::string, SessionRequestHandlerFactory> registered_services;
|
ankerl::unordered_dense::map<std::string, SessionRequestHandlerFactory> registered_services;
|
||||||
ankerl::unordered_dense::map<std::string, Kernel::KClientPort*> service_ports;
|
ankerl::unordered_dense::map<std::string, Kernel::KClientPort*> service_ports;
|
||||||
|
|
||||||
|
|||||||
@@ -866,10 +866,17 @@ void EmitIR<IR::Opcode::VectorMaxS32>(oaknut::CodeGenerator& code, EmitContext&
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::VectorMaxS64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::VectorMaxS64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
#ifdef __APPLE__
|
||||||
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
||||||
code.CMGT(Qresult->D2(), Qa->D2(), Qb->D2());
|
code.CMGT(Qresult->D2(), Qa->D2(), Qb->D2());
|
||||||
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
||||||
});
|
});
|
||||||
|
#else
|
||||||
|
(void)code;
|
||||||
|
(void)ctx;
|
||||||
|
(void)inst;
|
||||||
|
UNREACHABLE();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@@ -889,10 +896,17 @@ void EmitIR<IR::Opcode::VectorMaxU32>(oaknut::CodeGenerator& code, EmitContext&
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::VectorMaxU64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::VectorMaxU64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
#ifdef __APPLE__
|
||||||
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
||||||
code.CMHI(Qresult->D2(), Qa->D2(), Qb->D2());
|
code.CMHI(Qresult->D2(), Qa->D2(), Qb->D2());
|
||||||
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
||||||
});
|
});
|
||||||
|
#else
|
||||||
|
(void)code;
|
||||||
|
(void)ctx;
|
||||||
|
(void)inst;
|
||||||
|
UNREACHABLE();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@@ -912,10 +926,17 @@ void EmitIR<IR::Opcode::VectorMinS32>(oaknut::CodeGenerator& code, EmitContext&
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::VectorMinS64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::VectorMinS64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
#ifdef __APPLE__
|
||||||
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
||||||
code.CMGT(Qresult->D2(), Qb->D2(), Qa->D2());
|
code.CMGT(Qresult->D2(), Qb->D2(), Qa->D2());
|
||||||
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
||||||
});
|
});
|
||||||
|
#else
|
||||||
|
(void)code;
|
||||||
|
(void)ctx;
|
||||||
|
(void)inst;
|
||||||
|
UNREACHABLE();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@@ -935,10 +956,17 @@ void EmitIR<IR::Opcode::VectorMinU32>(oaknut::CodeGenerator& code, EmitContext&
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
void EmitIR<IR::Opcode::VectorMinU64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
void EmitIR<IR::Opcode::VectorMinU64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
#ifdef __APPLE__
|
||||||
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
EmitThreeOp(code, ctx, inst, [&](auto& Qresult, auto& Qa, auto& Qb) {
|
||||||
code.CMHI(Qresult->D2(), Qb->D2(), Qa->D2());
|
code.CMHI(Qresult->D2(), Qb->D2(), Qa->D2());
|
||||||
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
code.BSL(Qresult->B16(), Qa->B16(), Qb->B16());
|
||||||
});
|
});
|
||||||
|
#else
|
||||||
|
(void)code;
|
||||||
|
(void)ctx;
|
||||||
|
(void)inst;
|
||||||
|
UNREACHABLE();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|||||||
@@ -14,6 +14,38 @@
|
|||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
namespace {
|
namespace {
|
||||||
|
class DescriptorIndex {
|
||||||
|
public:
|
||||||
|
explicit DescriptorIndex(EmitContext& ctx, const IR::Value& index)
|
||||||
|
: id{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)},
|
||||||
|
is_non_uniform{ctx.profile.support_sampled_image_array_nonuniform_indexing &&
|
||||||
|
!index.IsImmediate()} {
|
||||||
|
if (!is_non_uniform) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ctx.profile.supported_spirv < 0x00010400) {
|
||||||
|
ctx.AddExtension("SPV_EXT_descriptor_indexing");
|
||||||
|
}
|
||||||
|
ctx.AddCapability(spv::Capability::ShaderNonUniform);
|
||||||
|
ctx.AddCapability(spv::Capability::SampledImageArrayNonUniformIndexing);
|
||||||
|
Decorate(ctx, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Id Value() const {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Decorate(EmitContext& ctx, Id object) const {
|
||||||
|
if (is_non_uniform) {
|
||||||
|
ctx.Decorate(object, spv::Decoration::NonUniform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Id id;
|
||||||
|
bool is_non_uniform;
|
||||||
|
};
|
||||||
|
|
||||||
class ImageOperands {
|
class ImageOperands {
|
||||||
public:
|
public:
|
||||||
[[maybe_unused]] static constexpr bool ImageSampleOffsetAllowed = false;
|
[[maybe_unused]] static constexpr bool ImageSampleOffsetAllowed = false;
|
||||||
@@ -189,8 +221,12 @@ private:
|
|||||||
Id Texture(EmitContext& ctx, IR::TextureInstInfo info, [[maybe_unused]] const IR::Value& index) {
|
Id Texture(EmitContext& ctx, IR::TextureInstInfo info, [[maybe_unused]] const IR::Value& index) {
|
||||||
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
|
||||||
if (def.count > 1) {
|
if (def.count > 1) {
|
||||||
const Id pointer{ctx.OpAccessChain(def.pointer_type, def.id, ctx.Def(index))};
|
const DescriptorIndex idx{ctx, index};
|
||||||
return ctx.OpLoad(def.sampled_type, pointer);
|
const Id pointer{ctx.OpAccessChain(def.pointer_type, def.id, idx.Value())};
|
||||||
|
idx.Decorate(ctx, pointer);
|
||||||
|
const Id object{ctx.OpLoad(def.sampled_type, pointer)};
|
||||||
|
idx.Decorate(ctx, object);
|
||||||
|
return object;
|
||||||
} else {
|
} else {
|
||||||
return ctx.OpLoad(def.sampled_type, def.id);
|
return ctx.OpLoad(def.sampled_type, def.id);
|
||||||
}
|
}
|
||||||
@@ -208,9 +244,14 @@ Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& ind
|
|||||||
} else {
|
} else {
|
||||||
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
|
||||||
if (def.count > 1) {
|
if (def.count > 1) {
|
||||||
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
|
const DescriptorIndex idx{ctx, index};
|
||||||
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
|
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx.Value())};
|
||||||
return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, ptr));
|
idx.Decorate(ctx, ptr);
|
||||||
|
const Id object{ctx.OpLoad(def.sampled_type, ptr)};
|
||||||
|
idx.Decorate(ctx, object);
|
||||||
|
const Id image{ctx.OpImage(def.image_type, object)};
|
||||||
|
idx.Decorate(ctx, image);
|
||||||
|
return image;
|
||||||
}
|
}
|
||||||
return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id));
|
return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -17,6 +20,9 @@ struct HostTranslateInfo {
|
|||||||
bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers
|
bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers
|
||||||
bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS
|
bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS
|
||||||
u32 min_ssbo_alignment{}; ///< Minimum alignment supported by the device for SSBOs
|
u32 min_ssbo_alignment{}; ///< Minimum alignment supported by the device for SSBOs
|
||||||
|
u32 max_per_stage_descriptor_sampled_images{1024}; ///< maximum sampled descriptors per stage
|
||||||
|
u32 max_per_stage_resources{4096}; ///< maximum resources per stage
|
||||||
|
u32 max_descriptor_set_sampled_images{1024}; ///< maximum sampled descriptors per set
|
||||||
bool support_geometry_shader_passthrough{}; ///< True when the device supports geometry
|
bool support_geometry_shader_passthrough{}; ///< True when the device supports geometry
|
||||||
///< passthrough shaders
|
///< passthrough shaders
|
||||||
bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional
|
bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional
|
||||||
|
|||||||
@@ -32,6 +32,71 @@ using TextureInstVector = boost::container::small_vector<TextureInst, 24>;
|
|||||||
|
|
||||||
constexpr u32 DESCRIPTOR_SIZE = 8;
|
constexpr u32 DESCRIPTOR_SIZE = 8;
|
||||||
constexpr u32 DESCRIPTOR_SIZE_SHIFT = static_cast<u32>(std::countr_zero(DESCRIPTOR_SIZE));
|
constexpr u32 DESCRIPTOR_SIZE_SHIFT = static_cast<u32>(std::countr_zero(DESCRIPTOR_SIZE));
|
||||||
|
constexpr u32 DYNAMIC_DESCRIPTOR_CBUF_BYTES = 16 * 1024;
|
||||||
|
constexpr u32 MAX_DYNAMIC_DESCRIPTOR_COUNT = 1024;
|
||||||
|
|
||||||
|
u32 DynamicDescriptorSizeShift(const IR::U32& dynamic_offset) {
|
||||||
|
const IR::Inst* const inst{dynamic_offset.InstRecursive()};
|
||||||
|
if (!inst || inst->GetOpcode() != IR::Opcode::ShiftLeftLogical32) {
|
||||||
|
return DESCRIPTOR_SIZE_SHIFT;
|
||||||
|
}
|
||||||
|
const IR::Value shift{inst->Arg(1)};
|
||||||
|
if (!shift.IsImmediate()) {
|
||||||
|
return DESCRIPTOR_SIZE_SHIFT;
|
||||||
|
}
|
||||||
|
const u32 size_shift{shift.U32()};
|
||||||
|
return size_shift >= DESCRIPTOR_SIZE_SHIFT && size_shift < 31 ? size_shift
|
||||||
|
: DESCRIPTOR_SIZE_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DynamicDescriptorCount(u32 base_offset, u32 size_shift) {
|
||||||
|
if (size_shift >= 31 || base_offset >= DYNAMIC_DESCRIPTOR_CBUF_BYTES) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const u32 stride{1U << size_shift};
|
||||||
|
const u32 available{DYNAMIC_DESCRIPTOR_CBUF_BYTES - base_offset};
|
||||||
|
if (available < DESCRIPTOR_SIZE) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const u32 available_count{1U + (available - DESCRIPTOR_SIZE) / stride};
|
||||||
|
return std::min(MAX_DYNAMIC_DESCRIPTOR_COUNT, available_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 SaturatingSub(u32 lhs, u32 rhs) {
|
||||||
|
return lhs > rhs ? lhs - rhs : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Descriptors>
|
||||||
|
u32 StaticDescriptorCount(const Descriptors& descriptors) {
|
||||||
|
u32 count{};
|
||||||
|
for (const auto& desc : descriptors) {
|
||||||
|
if (desc.count <= 1) {
|
||||||
|
count += desc.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DynamicSampledTextureCap(const Info& info, const HostTranslateInfo& host_info,
|
||||||
|
u32 dynamic_arrays) {
|
||||||
|
if (dynamic_arrays == 0) {
|
||||||
|
return MAX_DYNAMIC_DESCRIPTOR_COUNT;
|
||||||
|
}
|
||||||
|
const u32 sampled_static_count{StaticDescriptorCount(info.texture_buffer_descriptors) +
|
||||||
|
StaticDescriptorCount(info.texture_descriptors)};
|
||||||
|
const u32 resource_static_count{
|
||||||
|
NumDescriptors(info.constant_buffer_descriptors) +
|
||||||
|
NumDescriptors(info.storage_buffers_descriptors) + sampled_static_count +
|
||||||
|
NumDescriptors(info.image_buffer_descriptors) + NumDescriptors(info.image_descriptors)};
|
||||||
|
const u32 sampled_limit{std::min(host_info.max_per_stage_descriptor_sampled_images,
|
||||||
|
host_info.max_descriptor_set_sampled_images)};
|
||||||
|
const u32 sampled_budget{SaturatingSub(sampled_limit, sampled_static_count)};
|
||||||
|
const u32 resource_budget{SaturatingSub(host_info.max_per_stage_resources,
|
||||||
|
resource_static_count)};
|
||||||
|
const u32 sampled_cap{sampled_budget / dynamic_arrays};
|
||||||
|
const u32 resource_cap{resource_budget / dynamic_arrays};
|
||||||
|
return std::max(1U, std::min({MAX_DYNAMIC_DESCRIPTOR_COUNT, sampled_cap, resource_cap}));
|
||||||
|
}
|
||||||
|
|
||||||
IR::Opcode IndexedInstruction(const IR::Inst& inst) {
|
IR::Opcode IndexedInstruction(const IR::Inst& inst) {
|
||||||
switch (inst.GetOpcode()) {
|
switch (inst.GetOpcode()) {
|
||||||
@@ -109,6 +174,39 @@ IR::Opcode IndexedInstruction(const IR::Inst& inst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsStorageImageOpcode(IR::Opcode opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case IR::Opcode::ImageRead:
|
||||||
|
case IR::Opcode::ImageAtomicIAdd32:
|
||||||
|
case IR::Opcode::ImageAtomicSMin32:
|
||||||
|
case IR::Opcode::ImageAtomicUMin32:
|
||||||
|
case IR::Opcode::ImageAtomicSMax32:
|
||||||
|
case IR::Opcode::ImageAtomicUMax32:
|
||||||
|
case IR::Opcode::ImageAtomicInc32:
|
||||||
|
case IR::Opcode::ImageAtomicDec32:
|
||||||
|
case IR::Opcode::ImageAtomicAnd32:
|
||||||
|
case IR::Opcode::ImageAtomicOr32:
|
||||||
|
case IR::Opcode::ImageAtomicXor32:
|
||||||
|
case IR::Opcode::ImageAtomicExchange32:
|
||||||
|
case IR::Opcode::ImageWrite:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DynamicSampledTextureArrayCount(const TextureInstVector& to_replace) {
|
||||||
|
u32 count{};
|
||||||
|
for (const TextureInst& inst : to_replace) {
|
||||||
|
const auto flags{inst.inst->Flags<IR::TextureInstInfo>()};
|
||||||
|
if (inst.cbuf.count > 1 && !IsStorageImageOpcode(IndexedInstruction(*inst.inst)) &&
|
||||||
|
flags.type != TextureType::Buffer) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsBindless(const IR::Inst& inst) {
|
bool IsBindless(const IR::Inst& inst) {
|
||||||
switch (inst.GetOpcode()) {
|
switch (inst.GetOpcode()) {
|
||||||
case IR::Opcode::BindlessImageSampleImplicitLod:
|
case IR::Opcode::BindlessImageSampleImplicitLod:
|
||||||
@@ -354,6 +452,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
|||||||
} else {
|
} else {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
const u32 size_shift{DynamicDescriptorSizeShift(dynamic_offset)};
|
||||||
return ConstBufferAddr{
|
return ConstBufferAddr{
|
||||||
.index = index.U32(),
|
.index = index.U32(),
|
||||||
.offset = base_offset,
|
.offset = base_offset,
|
||||||
@@ -362,7 +461,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
|||||||
.secondary_offset = 0,
|
.secondary_offset = 0,
|
||||||
.secondary_shift_left = 0,
|
.secondary_shift_left = 0,
|
||||||
.dynamic_offset = dynamic_offset,
|
.dynamic_offset = dynamic_offset,
|
||||||
.count = 8,
|
.count = DynamicDescriptorCount(base_offset, size_shift),
|
||||||
.has_secondary = false,
|
.has_secondary = false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -589,6 +688,8 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||||||
program.info.texture_descriptors,
|
program.info.texture_descriptors,
|
||||||
program.info.image_descriptors,
|
program.info.image_descriptors,
|
||||||
};
|
};
|
||||||
|
const u32 sampled_dynamic_cap{
|
||||||
|
DynamicSampledTextureCap(program.info, host_info, DynamicSampledTextureArrayCount(to_replace))};
|
||||||
for (TextureInst& texture_inst : to_replace) {
|
for (TextureInst& texture_inst : to_replace) {
|
||||||
// TODO: Handle arrays
|
// TODO: Handle arrays
|
||||||
IR::Inst* const inst{texture_inst.inst};
|
IR::Inst* const inst{texture_inst.inst};
|
||||||
@@ -632,6 +733,9 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
u32 index;
|
u32 index;
|
||||||
|
const u32 size_shift{cbuf.count > 1 ? DynamicDescriptorSizeShift(cbuf.dynamic_offset)
|
||||||
|
: DESCRIPTOR_SIZE_SHIFT};
|
||||||
|
u32 count{cbuf.count};
|
||||||
switch (inst->GetOpcode()) {
|
switch (inst->GetOpcode()) {
|
||||||
case IR::Opcode::ImageRead:
|
case IR::Opcode::ImageRead:
|
||||||
case IR::Opcode::ImageAtomicIAdd32:
|
case IR::Opcode::ImageAtomicIAdd32:
|
||||||
@@ -660,8 +764,8 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||||||
.is_integer = is_integer,
|
.is_integer = is_integer,
|
||||||
.cbuf_index = cbuf.index,
|
.cbuf_index = cbuf.index,
|
||||||
.cbuf_offset = cbuf.offset,
|
.cbuf_offset = cbuf.offset,
|
||||||
.count = cbuf.count,
|
.count = count,
|
||||||
.size_shift = DESCRIPTOR_SIZE_SHIFT,
|
.size_shift = size_shift,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
index = descriptors.Add(ImageDescriptor{
|
index = descriptors.Add(ImageDescriptor{
|
||||||
@@ -672,8 +776,8 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||||||
.is_integer = is_integer,
|
.is_integer = is_integer,
|
||||||
.cbuf_index = cbuf.index,
|
.cbuf_index = cbuf.index,
|
||||||
.cbuf_offset = cbuf.offset,
|
.cbuf_offset = cbuf.offset,
|
||||||
.count = cbuf.count,
|
.count = count,
|
||||||
.size_shift = DESCRIPTOR_SIZE_SHIFT,
|
.size_shift = size_shift,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -688,10 +792,11 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||||||
.secondary_cbuf_index = cbuf.secondary_index,
|
.secondary_cbuf_index = cbuf.secondary_index,
|
||||||
.secondary_cbuf_offset = cbuf.secondary_offset,
|
.secondary_cbuf_offset = cbuf.secondary_offset,
|
||||||
.secondary_shift_left = cbuf.secondary_shift_left,
|
.secondary_shift_left = cbuf.secondary_shift_left,
|
||||||
.count = cbuf.count,
|
.count = count,
|
||||||
.size_shift = DESCRIPTOR_SIZE_SHIFT,
|
.size_shift = size_shift,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
count = std::min(count, sampled_dynamic_cap);
|
||||||
index = descriptors.Add(TextureDescriptor{
|
index = descriptors.Add(TextureDescriptor{
|
||||||
.type = flags.type,
|
.type = flags.type,
|
||||||
.is_depth = flags.is_depth != 0,
|
.is_depth = flags.is_depth != 0,
|
||||||
@@ -703,8 +808,8 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||||||
.secondary_cbuf_index = cbuf.secondary_index,
|
.secondary_cbuf_index = cbuf.secondary_index,
|
||||||
.secondary_cbuf_offset = cbuf.secondary_offset,
|
.secondary_cbuf_offset = cbuf.secondary_offset,
|
||||||
.secondary_shift_left = cbuf.secondary_shift_left,
|
.secondary_shift_left = cbuf.secondary_shift_left,
|
||||||
.count = cbuf.count,
|
.count = count,
|
||||||
.size_shift = DESCRIPTOR_SIZE_SHIFT,
|
.size_shift = size_shift,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -712,12 +817,12 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||||||
flags.descriptor_index.Assign(index);
|
flags.descriptor_index.Assign(index);
|
||||||
inst->SetFlags(flags);
|
inst->SetFlags(flags);
|
||||||
|
|
||||||
if (cbuf.count > 1) {
|
if (count > 1) {
|
||||||
const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)};
|
const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)};
|
||||||
IR::IREmitter ir{*texture_inst.block, insert_point};
|
IR::IREmitter ir{*texture_inst.block, insert_point};
|
||||||
const IR::U32 shift{ir.Imm32(DESCRIPTOR_SIZE_SHIFT)};
|
const IR::U32 shift{ir.Imm32(size_shift)};
|
||||||
inst->SetArg(0, ir.UMin(ir.ShiftRightLogical(cbuf.dynamic_offset, shift),
|
inst->SetArg(0, ir.UMin(ir.ShiftRightLogical(cbuf.dynamic_offset, shift),
|
||||||
ir.Imm32(DESCRIPTOR_SIZE - 1)));
|
ir.Imm32(count - 1)));
|
||||||
} else {
|
} else {
|
||||||
inst->SetArg(0, IR::Value{});
|
inst->SetArg(0, IR::Value{});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -45,6 +48,7 @@ struct Profile {
|
|||||||
bool support_scaled_attributes{};
|
bool support_scaled_attributes{};
|
||||||
bool support_multi_viewport{};
|
bool support_multi_viewport{};
|
||||||
bool support_geometry_streams{};
|
bool support_geometry_streams{};
|
||||||
|
bool support_sampled_image_array_nonuniform_indexing{};
|
||||||
|
|
||||||
bool warp_size_potentially_larger_than_guest{};
|
bool warp_size_potentially_larger_than_guest{};
|
||||||
|
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
|
|||||||
views += num_texture_buffers;
|
views += num_texture_buffers;
|
||||||
views += num_image_buffers;
|
views += num_image_buffers;
|
||||||
for (const auto& desc : info.texture_descriptors) {
|
for (const auto& desc : info.texture_descriptors) {
|
||||||
|
bool is_rescaled{};
|
||||||
for (u32 index = 0; index < desc.count; ++index) {
|
for (u32 index = 0; index < desc.count; ++index) {
|
||||||
const VideoCommon::ImageViewId image_view_id{(views++)->id};
|
const VideoCommon::ImageViewId image_view_id{(views++)->id};
|
||||||
const VideoCommon::SamplerId sampler_id{*(samplers++)};
|
const VideoCommon::SamplerId sampler_id{*(samplers++)};
|
||||||
@@ -200,10 +201,13 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
|
|||||||
const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy()
|
const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy()
|
||||||
: sampler.Handle()};
|
: sampler.Handle()};
|
||||||
guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler);
|
guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler);
|
||||||
rescaling.PushTexture(texture_cache.IsRescaling(image_view));
|
const bool element_rescaled{texture_cache.IsRescaling(image_view)};
|
||||||
|
is_rescaled |= element_rescaled;
|
||||||
}
|
}
|
||||||
|
rescaling.PushTexture(is_rescaled);
|
||||||
}
|
}
|
||||||
for (const auto& desc : info.image_descriptors) {
|
for (const auto& desc : info.image_descriptors) {
|
||||||
|
bool is_rescaled{};
|
||||||
for (u32 index = 0; index < desc.count; ++index) {
|
for (u32 index = 0; index < desc.count; ++index) {
|
||||||
ImageView& image_view{texture_cache.GetImageView((views++)->id)};
|
ImageView& image_view{texture_cache.GetImageView((views++)->id)};
|
||||||
if (desc.is_written) {
|
if (desc.is_written) {
|
||||||
@@ -211,8 +215,10 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
|
|||||||
}
|
}
|
||||||
const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)};
|
const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)};
|
||||||
guest_descriptor_queue.AddImage(vk_image_view);
|
guest_descriptor_queue.AddImage(vk_image_view);
|
||||||
rescaling.PushImage(texture_cache.IsRescaling(image_view));
|
const bool element_rescaled{texture_cache.IsRescaling(image_view)};
|
||||||
|
is_rescaled |= element_rescaled;
|
||||||
}
|
}
|
||||||
|
rescaling.PushImage(is_rescaled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,9 +127,8 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
|
|||||||
|
|
||||||
texture_cache.SynchronizeComputeDescriptors();
|
texture_cache.SynchronizeComputeDescriptors();
|
||||||
|
|
||||||
static constexpr size_t max_elements = 64;
|
boost::container::small_vector<VideoCommon::ImageViewInOut, 64> views;
|
||||||
boost::container::static_vector<VideoCommon::ImageViewInOut, max_elements> views;
|
boost::container::small_vector<VideoCommon::SamplerId, 64> samplers;
|
||||||
boost::container::static_vector<VideoCommon::SamplerId, max_elements> samplers;
|
|
||||||
|
|
||||||
const auto& qmd{kepler_compute.launch_description};
|
const auto& qmd{kepler_compute.launch_description};
|
||||||
const auto& cbufs{qmd.const_buffer_config};
|
const auto& cbufs{qmd.const_buffer_config};
|
||||||
|
|||||||
@@ -412,6 +412,8 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
|||||||
.support_scaled_attributes = !device.MustEmulateScaledFormats(),
|
.support_scaled_attributes = !device.MustEmulateScaledFormats(),
|
||||||
.support_multi_viewport = device.SupportsMultiViewport(),
|
.support_multi_viewport = device.SupportsMultiViewport(),
|
||||||
.support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
|
.support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
|
||||||
|
.support_sampled_image_array_nonuniform_indexing =
|
||||||
|
device.IsSampledImageArrayNonUniformIndexingSupported(),
|
||||||
|
|
||||||
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
|
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
|
||||||
|
|
||||||
@@ -447,6 +449,9 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
|||||||
.support_snorm_render_buffer = true,
|
.support_snorm_render_buffer = true,
|
||||||
.support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(),
|
.support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(),
|
||||||
.min_ssbo_alignment = static_cast<u32>(device.GetStorageBufferAlignment()),
|
.min_ssbo_alignment = static_cast<u32>(device.GetStorageBufferAlignment()),
|
||||||
|
.max_per_stage_descriptor_sampled_images = device.GetMaxPerStageDescriptorSampledImages(),
|
||||||
|
.max_per_stage_resources = device.GetMaxPerStageResources(),
|
||||||
|
.max_descriptor_set_sampled_images = device.GetMaxDescriptorSetSampledImages(),
|
||||||
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
|
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
|
||||||
.support_conditional_barrier = device.SupportsConditionalBarriers(),
|
.support_conditional_barrier = device.SupportsConditionalBarriers(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -70,14 +70,10 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
|
|||||||
(std::max)((std::min)(device_local_memory - min_vacancy_critical, min_spacing_critical),
|
(std::max)((std::min)(device_local_memory - min_vacancy_critical, min_spacing_critical),
|
||||||
DEFAULT_CRITICAL_MEMORY));
|
DEFAULT_CRITICAL_MEMORY));
|
||||||
minimum_memory = static_cast<u64>((device_local_memory - mem_threshold) / 2);
|
minimum_memory = static_cast<u64>((device_local_memory - mem_threshold) / 2);
|
||||||
|
|
||||||
lowmemorydevice = false;
|
|
||||||
} else {
|
} else {
|
||||||
expected_memory = DEFAULT_EXPECTED_MEMORY + 512_MiB;
|
expected_memory = DEFAULT_EXPECTED_MEMORY + 512_MiB;
|
||||||
critical_memory = DEFAULT_CRITICAL_MEMORY + 1_GiB;
|
critical_memory = DEFAULT_CRITICAL_MEMORY + 1_GiB;
|
||||||
minimum_memory = 0;
|
minimum_memory = 0;
|
||||||
|
|
||||||
lowmemorydevice = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool gpu_unswizzle_enabled = Settings::values.gpu_unswizzle_enabled.GetValue();
|
const bool gpu_unswizzle_enabled = Settings::values.gpu_unswizzle_enabled.GetValue();
|
||||||
@@ -122,102 +118,48 @@ void TextureCache<P>::RunGarbageCollector() {
|
|||||||
bool aggressive_mode = false;
|
bool aggressive_mode = false;
|
||||||
u64 ticks_to_destroy = 0;
|
u64 ticks_to_destroy = 0;
|
||||||
size_t num_iterations = 0;
|
size_t num_iterations = 0;
|
||||||
|
|
||||||
const auto Configure = [&](bool allow_aggressive) {
|
const auto Configure = [&](bool allow_aggressive) {
|
||||||
high_priority_mode = total_used_memory >= expected_memory;
|
high_priority_mode = total_used_memory >= expected_memory;
|
||||||
aggressive_mode = allow_aggressive && total_used_memory >= critical_memory;
|
aggressive_mode = allow_aggressive && total_used_memory >= critical_memory;
|
||||||
ticks_to_destroy = aggressive_mode ? 10ULL : high_priority_mode ? 25ULL : 50ULL;
|
ticks_to_destroy = aggressive_mode ? 10ULL : high_priority_mode ? 25ULL : 50ULL;
|
||||||
num_iterations = aggressive_mode ? 40 : (high_priority_mode ? 20 : 10);
|
num_iterations = aggressive_mode ? 40 : (high_priority_mode ? 20 : 10);
|
||||||
};
|
};
|
||||||
|
const auto Cleanup = [this, &num_iterations, &high_priority_mode, &aggressive_mode](ImageId image_id) {
|
||||||
const auto Cleanup = [this, &num_iterations, &high_priority_mode,
|
|
||||||
&aggressive_mode](ImageId image_id) {
|
|
||||||
if (num_iterations == 0) {
|
if (num_iterations == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
--num_iterations;
|
|
||||||
auto& image = slot_images[image_id];
|
auto& image = slot_images[image_id];
|
||||||
|
|
||||||
// Never delete recently allocated sparse textures (within 3 frames)
|
|
||||||
const bool is_recently_allocated = image.allocation_tick >= frame_tick - 3;
|
|
||||||
if (is_recently_allocated && image.info.is_sparse) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (True(image.flags & ImageFlagBits::IsDecoding)) {
|
if (True(image.flags & ImageFlagBits::IsDecoding)) {
|
||||||
// This image is still being decoded, deleting it will invalidate the slot
|
|
||||||
// used by the async decoder thread.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const bool must_download = image.IsSafeDownload() && False(image.flags & ImageFlagBits::BadOverlap);
|
||||||
// Prioritize large sparse textures for cleanup
|
if ((!aggressive_mode && True(image.flags & ImageFlagBits::CostlyLoad)) || (!high_priority_mode && must_download)) {
|
||||||
const bool is_large_sparse = lowmemorydevice &&
|
|
||||||
image.info.is_sparse &&
|
|
||||||
image.guest_size_bytes >= 256_MiB;
|
|
||||||
|
|
||||||
if (!aggressive_mode && !is_large_sparse &&
|
|
||||||
True(image.flags & ImageFlagBits::CostlyLoad)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
--num_iterations;
|
||||||
const bool must_download =
|
if (must_download) {
|
||||||
image.IsSafeDownload() && False(image.flags & ImageFlagBits::BadOverlap);
|
|
||||||
if (!high_priority_mode && !is_large_sparse && must_download) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (must_download && !is_large_sparse) {
|
|
||||||
auto map = runtime.DownloadStagingBuffer(image.unswizzled_size_bytes);
|
auto map = runtime.DownloadStagingBuffer(image.unswizzled_size_bytes);
|
||||||
const auto copies = FixSmallVectorADL(FullDownloadCopies(image.info));
|
const auto copies = FixSmallVectorADL(FullDownloadCopies(image.info));
|
||||||
image.DownloadMemory(map, copies);
|
image.DownloadMemory(map, copies);
|
||||||
runtime.Finish();
|
runtime.Finish();
|
||||||
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span,
|
SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span, swizzle_data_buffer);
|
||||||
swizzle_data_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (True(image.flags & ImageFlagBits::Tracked)) {
|
if (True(image.flags & ImageFlagBits::Tracked)) {
|
||||||
UntrackImage(image, image_id);
|
UntrackImage(image, image_id);
|
||||||
}
|
}
|
||||||
UnregisterImage(image_id);
|
UnregisterImage(image_id);
|
||||||
DeleteImage(image_id, image.scale_tick > frame_tick + 5);
|
DeleteImage(image_id, image.scale_tick > frame_tick + 5);
|
||||||
|
if (aggressive_mode && total_used_memory < critical_memory) {
|
||||||
if (total_used_memory < critical_memory) {
|
num_iterations >>= 2;
|
||||||
if (aggressive_mode) {
|
aggressive_mode = false;
|
||||||
// Sink the aggresiveness.
|
} else if (high_priority_mode && total_used_memory < expected_memory) {
|
||||||
num_iterations >>= 2;
|
num_iterations >>= 1;
|
||||||
aggressive_mode = false;
|
high_priority_mode = false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (high_priority_mode && total_used_memory < expected_memory) {
|
|
||||||
num_iterations >>= 1;
|
|
||||||
high_priority_mode = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Aggressively clear massive sparse textures
|
|
||||||
if (total_used_memory >= expected_memory) {
|
|
||||||
lru_cache.ForEachItemBelow(frame_tick, [&](ImageId image_id) {
|
|
||||||
auto& image = slot_images[image_id];
|
|
||||||
// Only target sparse textures that are old enough
|
|
||||||
if (lowmemorydevice &&
|
|
||||||
image.info.is_sparse &&
|
|
||||||
image.guest_size_bytes >= 256_MiB &&
|
|
||||||
image.allocation_tick < frame_tick - 3) {
|
|
||||||
LOG_DEBUG(HW_GPU, "GC targeting old sparse texture at 0x{:X} ({} MiB, age: {} frames)",
|
|
||||||
image.gpu_addr, image.guest_size_bytes / (1024 * 1024),
|
|
||||||
frame_tick - image.allocation_tick);
|
|
||||||
return Cleanup(image_id);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Configure(false);
|
Configure(false);
|
||||||
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, Cleanup);
|
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, Cleanup);
|
||||||
|
|
||||||
// If pressure is still too high, prune aggressively.
|
|
||||||
if (total_used_memory >= critical_memory) {
|
if (total_used_memory >= critical_memory) {
|
||||||
Configure(true);
|
Configure(true);
|
||||||
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, Cleanup);
|
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, Cleanup);
|
||||||
@@ -1196,9 +1138,6 @@ void TextureCache<P>::RefreshContents(Image& image, ImageId image_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
image.flags &= ~ImageFlagBits::CpuModified;
|
image.flags &= ~ImageFlagBits::CpuModified;
|
||||||
if( lowmemorydevice && image.info.format == PixelFormat::BC1_RGBA_UNORM && MapSizeBytes(image) >= 256_MiB ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TrackImage(image, image_id);
|
TrackImage(image, image_id);
|
||||||
|
|
||||||
@@ -1619,39 +1558,6 @@ ImageId TextureCache<P>::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ASSERT_MSG(cpu_addr, "Tried to insert an image to an invalid gpu_addr=0x{:x}", gpu_addr);
|
ASSERT_MSG(cpu_addr, "Tried to insert an image to an invalid gpu_addr=0x{:x}", gpu_addr);
|
||||||
|
|
||||||
// For large sparse textures, aggressively clean up old allocations at same address
|
|
||||||
if (lowmemorydevice && info.is_sparse && CalculateGuestSizeInBytes(info) >= 256_MiB) {
|
|
||||||
const auto alloc_it = image_allocs_table.find(gpu_addr);
|
|
||||||
if (alloc_it != image_allocs_table.end()) {
|
|
||||||
const ImageAllocId alloc_id = alloc_it->second;
|
|
||||||
auto& alloc_images = slot_image_allocs[alloc_id].images;
|
|
||||||
|
|
||||||
// Collect old images at this address that were created more than 2 frames ago
|
|
||||||
boost::container::small_vector<ImageId, 4> to_delete;
|
|
||||||
for (ImageId old_image_id : alloc_images) {
|
|
||||||
Image& old_image = slot_images[old_image_id];
|
|
||||||
if (old_image.info.is_sparse &&
|
|
||||||
old_image.gpu_addr == gpu_addr &&
|
|
||||||
old_image.allocation_tick < frame_tick - 2) { // Try not to delete fresh textures
|
|
||||||
to_delete.push_back(old_image_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete old images immediately
|
|
||||||
for (ImageId old_id : to_delete) {
|
|
||||||
Image& old_image = slot_images[old_id];
|
|
||||||
LOG_DEBUG(HW_GPU, "Immediately deleting old sparse texture at 0x{:X} ({} MiB)",
|
|
||||||
gpu_addr, old_image.guest_size_bytes / (1024 * 1024));
|
|
||||||
if (True(old_image.flags & ImageFlagBits::Tracked)) {
|
|
||||||
UntrackImage(old_image, old_id);
|
|
||||||
}
|
|
||||||
UnregisterImage(old_id);
|
|
||||||
DeleteImage(old_id, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ImageId image_id = JoinImages(info, gpu_addr, *cpu_addr);
|
const ImageId image_id = JoinImages(info, gpu_addr, *cpu_addr);
|
||||||
const Image& image = slot_images[image_id];
|
const Image& image = slot_images[image_id];
|
||||||
// Using "image.gpu_addr" instead of "gpu_addr" is important because it might be different
|
// Using "image.gpu_addr" instead of "gpu_addr" is important because it might be different
|
||||||
@@ -1667,27 +1573,6 @@ template <class P>
|
|||||||
ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DAddr cpu_addr) {
|
ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DAddr cpu_addr) {
|
||||||
ImageInfo new_info = info;
|
ImageInfo new_info = info;
|
||||||
const size_t size_bytes = CalculateGuestSizeInBytes(new_info);
|
const size_t size_bytes = CalculateGuestSizeInBytes(new_info);
|
||||||
|
|
||||||
// Proactive cleanup for large sparse texture allocations
|
|
||||||
if (lowmemorydevice && new_info.is_sparse && size_bytes >= 256_MiB) {
|
|
||||||
const u64 estimated_alloc_size = size_bytes;
|
|
||||||
|
|
||||||
if (total_used_memory + estimated_alloc_size >= critical_memory) {
|
|
||||||
LOG_DEBUG(HW_GPU, "Large sparse texture allocation ({} MiB) - running aggressive GC. "
|
|
||||||
"Current memory: {} MiB, Critical: {} MiB",
|
|
||||||
size_bytes / (1024 * 1024),
|
|
||||||
total_used_memory / (1024 * 1024),
|
|
||||||
critical_memory / (1024 * 1024));
|
|
||||||
RunGarbageCollector();
|
|
||||||
|
|
||||||
// If still over threshold after GC, try one more aggressive pass
|
|
||||||
if (total_used_memory + estimated_alloc_size >= critical_memory) {
|
|
||||||
LOG_DEBUG(HW_GPU, "Still critically low on memory, running second GC pass");
|
|
||||||
RunGarbageCollector();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool broken_views = runtime.HasBrokenTextureViewFormats();
|
const bool broken_views = runtime.HasBrokenTextureViewFormats();
|
||||||
const bool native_bgr = runtime.HasNativeBgr();
|
const bool native_bgr = runtime.HasNativeBgr();
|
||||||
join_overlap_ids.clear();
|
join_overlap_ids.clear();
|
||||||
|
|||||||
@@ -478,7 +478,6 @@ private:
|
|||||||
u64 minimum_memory;
|
u64 minimum_memory;
|
||||||
u64 expected_memory;
|
u64 expected_memory;
|
||||||
u64 critical_memory;
|
u64 critical_memory;
|
||||||
bool lowmemorydevice = false;
|
|
||||||
size_t gpu_unswizzle_maxsize = 0;
|
size_t gpu_unswizzle_maxsize = 0;
|
||||||
size_t swizzle_chunk_size = 0;
|
size_t swizzle_chunk_size = 0;
|
||||||
u32 swizzle_slices_per_batch = 0;
|
u32 swizzle_slices_per_batch = 0;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
FEATURE(KHR, VariablePointer, VARIABLE_POINTERS, variable_pointer)
|
FEATURE(KHR, VariablePointer, VARIABLE_POINTERS, variable_pointer)
|
||||||
|
|
||||||
#define FOR_EACH_VK_FEATURE_1_2(FEATURE) \
|
#define FOR_EACH_VK_FEATURE_1_2(FEATURE) \
|
||||||
|
FEATURE(EXT, DescriptorIndexing, DESCRIPTOR_INDEXING, descriptor_indexing) \
|
||||||
FEATURE(EXT, HostQueryReset, HOST_QUERY_RESET, host_query_reset) \
|
FEATURE(EXT, HostQueryReset, HOST_QUERY_RESET, host_query_reset) \
|
||||||
FEATURE(KHR, 8BitStorage, 8BIT_STORAGE, bit8_storage) \
|
FEATURE(KHR, 8BitStorage, 8BIT_STORAGE, bit8_storage) \
|
||||||
FEATURE(KHR, TimelineSemaphore, TIMELINE_SEMAPHORE, timeline_semaphore)
|
FEATURE(KHR, TimelineSemaphore, TIMELINE_SEMAPHORE, timeline_semaphore)
|
||||||
@@ -335,6 +336,18 @@ public:
|
|||||||
return properties.properties.limits.maxDescriptorSetUniformBuffersDynamic;
|
return properties.properties.limits.maxDescriptorSetUniformBuffersDynamic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 GetMaxPerStageDescriptorSampledImages() const {
|
||||||
|
return properties.properties.limits.maxPerStageDescriptorSampledImages;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetMaxPerStageResources() const {
|
||||||
|
return properties.properties.limits.maxPerStageResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetMaxDescriptorSetSampledImages() const {
|
||||||
|
return properties.properties.limits.maxDescriptorSetSampledImages;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns float control properties of the device.
|
/// Returns float control properties of the device.
|
||||||
const VkPhysicalDeviceFloatControlsPropertiesKHR& FloatControlProperties() const {
|
const VkPhysicalDeviceFloatControlsPropertiesKHR& FloatControlProperties() const {
|
||||||
return properties.float_controls;
|
return properties.float_controls;
|
||||||
@@ -355,6 +368,10 @@ public:
|
|||||||
return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsSampledImageArrayNonUniformIndexingSupported() const {
|
||||||
|
return features.descriptor_indexing.shaderSampledImageArrayNonUniformIndexing;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports float64 natively.
|
/// Returns true if the device supports float64 natively.
|
||||||
bool IsFloat64Supported() const {
|
bool IsFloat64Supported() const {
|
||||||
return features.features.shaderFloat64;
|
return features.features.shaderFloat64;
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ std::shared_ptr<Common::DynamicLibrary> OpenLibrary(
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
const auto libvulkan_filename =
|
const auto libvulkan_filename =
|
||||||
Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.1.dylib";
|
Common::FS::GetBundleDirectory() / "Contents/Frameworks/libvulkan.1.dylib";
|
||||||
const auto libmoltenvk_filename =
|
const char* library_paths[] = {std::getenv("LIBVULKAN_PATH"), libvulkan_filename.c_str()};
|
||||||
Common::FS::GetBundleDirectory() / "Contents/Frameworks/libMoltenVK.dylib";
|
|
||||||
const char* library_paths[] = {std::getenv("LIBVULKAN_PATH"), libvulkan_filename.c_str(),
|
|
||||||
libmoltenvk_filename.c_str()};
|
|
||||||
// Check if a path to a specific Vulkan library has been specified.
|
// Check if a path to a specific Vulkan library has been specified.
|
||||||
for (const auto& library_path : library_paths) {
|
for (const auto& library_path : library_paths) {
|
||||||
if (library_path && library->Open(library_path)) {
|
if (library_path && library->Open(library_path)) {
|
||||||
|
|||||||
+13
-5
@@ -389,14 +389,22 @@ if (APPLE)
|
|||||||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
|
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
|
||||||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
||||||
|
|
||||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib")
|
set(KK_LIBS
|
||||||
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
|
"${KosmicKrisp_SOURCE_DIR}/lib/libMoltenVK.dylib"
|
||||||
message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
|
"${KosmicKrisp_SOURCE_DIR}/lib/libvulkan.1.dylib"
|
||||||
|
"${KosmicKrisp_SOURCE_DIR}/lib/libvulkan_kosmickrisp.dylib")
|
||||||
|
|
||||||
set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES
|
set_source_files_properties(${KK_LIBS} PROPERTIES
|
||||||
MACOSX_PACKAGE_LOCATION Frameworks
|
MACOSX_PACKAGE_LOCATION Frameworks
|
||||||
XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
|
XCODE_FILE_ATTRIBUTES "CodeSignOnCopy")
|
||||||
target_sources(yuzu PRIVATE ${MOLTENVK_LIBRARY})
|
|
||||||
|
target_sources(yuzu PRIVATE ${KK_LIBS})
|
||||||
|
|
||||||
|
add_custom_command(TARGET yuzu POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
"${KosmicKrisp_SOURCE_DIR}/vulkan"
|
||||||
|
"$<TARGET_FILE_DIR:yuzu>/../Resources/vulkan"
|
||||||
|
COMMENT "Copying Vulkan ICDs")
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
# compile as a win32 gui application instead of a console application
|
# compile as a win32 gui application instead of a console application
|
||||||
target_link_libraries(yuzu PRIVATE Qt6::EntryPointPrivate)
|
target_link_libraries(yuzu PRIVATE Qt6::EntryPointPrivate)
|
||||||
|
|||||||
Reference in New Issue
Block a user