mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-18 06:10:35 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 99d285b43b |
Vendored
+327
-386
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+329
-388
File diff suppressed because it is too large
Load Diff
Vendored
+327
-384
File diff suppressed because it is too large
Load Diff
Vendored
+328
-387
File diff suppressed because it is too large
Load Diff
Vendored
+324
-381
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+464
-523
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
Vendored
+329
-388
File diff suppressed because it is too large
Load Diff
Vendored
+326
-383
File diff suppressed because it is too large
Load Diff
-1
@@ -31,7 +31,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
||||
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
|
||||
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
|
||||
ENABLE_GPU_BUFFER_READBACK("enable_gpu_buffer_readback"),
|
||||
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
|
||||
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
|
||||
RENDERER_DEBUG("debug"),
|
||||
|
||||
-7
@@ -806,13 +806,6 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.enable_buffer_history_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.ENABLE_GPU_BUFFER_READBACK,
|
||||
titleId = R.string.enable_gpu_buffer_readback,
|
||||
descriptionId = R.string.enable_gpu_buffer_readback_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS,
|
||||
|
||||
-1
@@ -292,7 +292,6 @@ class SettingsFragmentPresenter(
|
||||
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
|
||||
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
|
||||
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
|
||||
add(BooleanSetting.ENABLE_GPU_BUFFER_READBACK.key)
|
||||
add(BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS.key)
|
||||
|
||||
add(HeaderSetting(R.string.hacks))
|
||||
|
||||
@@ -573,6 +573,8 @@
|
||||
<string name="gpu_log_level_description">مستوى التفاصيل لسجلات وحدة معالجة الرسومات (كلما زاد المستوى، زادت التفاصيل وزادت التكاليف الإضافية)</string>
|
||||
<string name="gpu_log_vulkan_calls">تسجيل استدعاءات واجهة برمجة تطبيقات Vulkan</string>
|
||||
<string name="gpu_log_vulkan_calls_description">تتبع جميع استدعاءات واجهة برمجة تطبيقات Vulkan في المخزن المؤقت الحلقي</string>
|
||||
<string name="gpu_log_shader_dumps">تفريغ التظليل</string>
|
||||
<string name="gpu_log_shader_dumps_description">حفظ تظليل SPIR-V المجمع في ملفات</string>
|
||||
<string name="gpu_log_memory_tracking">تتبع ذاكرة وحدة معالجة الرسومات</string>
|
||||
<string name="gpu_log_memory_tracking_description">مراقبة تخصيصات ذاكرة وحدة معالجة الرسومات وإلغاء تخصيصها</string>
|
||||
<string name="gpu_log_driver_debug">معلومات تصحيح أخطاء برنامج التشغيل</string>
|
||||
|
||||
@@ -491,8 +491,6 @@
|
||||
<string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string>
|
||||
<string name="enable_buffer_history">Activar el historial del búfer</string>
|
||||
<string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string>
|
||||
<string name="enable_gpu_buffer_readback">Activar la lectura del buffer de la GPU</string>
|
||||
<string name="enable_gpu_buffer_readback_description">Conserva los datos del búfer modificados por la GPU leyéndolos antes de subirlos.\nAlgunos juegos requieren esto para renderizar correctamente ciertos efectos.\nPuede causar problemas si el hardware no puede soportar la carga de trabajo adicional.</string>
|
||||
<string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Fallará con controladores Turnip más antiguos (versión 25.3 o inferior).</string>
|
||||
|
||||
@@ -569,12 +567,8 @@
|
||||
<string name="gpu_log_level_description">Nivel de detalle de los registros de la GPU (más alto = más detalles, más sobrecarga)</string>
|
||||
<string name="gpu_log_vulkan_calls">Registros de llamadas del API de Vulkan</string>
|
||||
<string name="gpu_log_vulkan_calls_description">Rastrear todas las llamadas del API de Vulkan en el búfer circular</string>
|
||||
<string name="gpu_log_shader_dumps">Volcar sombreadores SPIR-V</string>
|
||||
<string name="gpu_log_shader_dumps_description">Guardar binarios recompilados SPIR-V (.spv) a la carpeta de volcado. Inspeccionar con spirv-dis/spirv-cross/spirv-val.</string>
|
||||
<string name="dump_guest_shaders">Volcar sombreadores huesped (Maxwell)</string>
|
||||
<string name="dump_guest_shaders_description">Guardar archivos bytecode del sombreador huesped Maxwell (*.ash) a la carpeta de volcado. Inspeccionar con nvdisasm.</string>
|
||||
<string name="dump_macros">Volcar macros Maxwell</string>
|
||||
<string name="dump_macros_description">Guardar archivos de programa macro Maxwell (*.macro) a la carpeta de volcado. Inspeccionar con envydis.</string>
|
||||
<string name="gpu_log_shader_dumps">Volcar sombreadores</string>
|
||||
<string name="gpu_log_shader_dumps_description">Guardar sombreadores compilados de SPIR-V en archivos</string>
|
||||
<string name="gpu_log_memory_tracking">Rastrear memoria de la GPU</string>
|
||||
<string name="gpu_log_memory_tracking_description">Monitorizar las asignaciones y desasignaciones de memoria de la GPU</string>
|
||||
<string name="gpu_log_driver_debug">Información de depuración del controlador</string>
|
||||
|
||||
@@ -527,6 +527,8 @@
|
||||
<string name="gpu_logging_header">Journalisation GPU</string>
|
||||
<string name="gpu_log_level">Niveau de journalisation</string>
|
||||
<string name="gpu_log_vulkan_calls">Journaliser les appels API Vulkan</string>
|
||||
<string name="gpu_log_shader_dumps">Extraire les shaders</string>
|
||||
<string name="gpu_log_shader_dumps_description">Sauvegarder le shader SPIR-V complié dans les fichiers</string>
|
||||
<string name="gpu_log_memory_tracking">Monitorer la mémoire GPU</string>
|
||||
<string name="gpu_log_memory_tracking_description">Monitorer les allocations et désallocations de la mémoire GPU</string>
|
||||
<string name="gpu_log_driver_debug">Informations de débogage du pilote</string>
|
||||
|
||||
@@ -566,6 +566,8 @@
|
||||
<string name="gpu_log_level_description">Уровень детализации логов ГПУ (больше значение = больше деталей, выше нагрузка)</string>
|
||||
<string name="gpu_log_vulkan_calls">Записывать вызовы Vulkan API</string>
|
||||
<string name="gpu_log_vulkan_calls_description">Отслеживать все вызовы Vulkan API в кольцевом буфере</string>
|
||||
<string name="gpu_log_shader_dumps">Выгрузить шейдеры</string>
|
||||
<string name="gpu_log_shader_dumps_description">Сохранять скомпилированные SPIR-V шейдеры в файлы</string>
|
||||
<string name="gpu_log_memory_tracking">Отслеживать память ГПУ</string>
|
||||
<string name="gpu_log_memory_tracking_description">Мониторить выделение и освобождение памяти ГПУ</string>
|
||||
<string name="gpu_log_driver_debug">Отладочная информация драйвера</string>
|
||||
|
||||
@@ -569,6 +569,8 @@
|
||||
<string name="gpu_log_level_description">Рівень подробиць у журналі ГП (вищий = більше подробиць, більший вплив на швидкодію)</string>
|
||||
<string name="gpu_log_vulkan_calls">Записувати виклики API Vulkan</string>
|
||||
<string name="gpu_log_vulkan_calls_description">Відстежувати всі виклики API Vulkan у кільцевому буфері</string>
|
||||
<string name="gpu_log_shader_dumps">Зберігати шейдери</string>
|
||||
<string name="gpu_log_shader_dumps_description">Зберігати до файлів скомпільовані шейдери SPIR-V</string>
|
||||
<string name="gpu_log_memory_tracking">Відстежувати пам’ять ГП</string>
|
||||
<string name="gpu_log_memory_tracking_description">Відстежувати використання і звільнення пам’яті ГП</string>
|
||||
<string name="gpu_log_driver_debug">Зневаджувальна інформація драйверів</string>
|
||||
|
||||
@@ -487,8 +487,6 @@
|
||||
<string name="renderer_reactive_flushing_description">通过牺牲性能来提升某些游戏的渲染精度。</string>
|
||||
<string name="enable_buffer_history">启用缓冲区历史</string>
|
||||
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
|
||||
<string name="enable_gpu_buffer_readback">启用 GPU 缓冲区回读</string>
|
||||
<string name="enable_gpu_buffer_readback_description">在上传前回读经由 GPU 修改过的缓冲区数据,以将其保留。一些游戏需要这样做才能正确渲染某些效果。如果硬件无法处理额外的工作负载,则可能会导致问题。</string>
|
||||
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
|
||||
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
|
||||
|
||||
@@ -565,12 +563,8 @@
|
||||
<string name="gpu_log_level_description">GPU 日志的详细级别(数值越高 = 细节越多,开销越大)</string>
|
||||
<string name="gpu_log_vulkan_calls">记录 Vulkan API 调用</string>
|
||||
<string name="gpu_log_vulkan_calls_description">在环形缓冲区中跟踪所有 Vulkan API 调用</string>
|
||||
<string name="gpu_log_shader_dumps">转储 SPIR-V 着色器</string>
|
||||
<string name="gpu_log_shader_dumps_description">将经过重编译的 SPIR-V 二进制文件(.spv)保存到 dump 文件夹中。使用 spirv-dis/spirv-cross/spirv-val 进行检查。</string>
|
||||
<string name="dump_guest_shaders">转储 Guest (Maxwell) 着色器</string>
|
||||
<string name="dump_guest_shaders_description">将 Maxwell guest 着色器字节码文件(*.ash)保存到 dump 文件夹。使用 nvdisasm 进行检查。</string>
|
||||
<string name="dump_macros">转储 Maxwell 宏</string>
|
||||
<string name="dump_macros_description">将 Maxwell 宏程序文件(*.macro)保存到 dump 文件夹。使用 envydis 进行检查。</string>
|
||||
<string name="gpu_log_shader_dumps">转储着色器</string>
|
||||
<string name="gpu_log_shader_dumps_description">保存已编译的着色器 SPIR-V 到文件中</string>
|
||||
<string name="gpu_log_memory_tracking">追踪 GPU 内存</string>
|
||||
<string name="gpu_log_memory_tracking_description">监控 GPU 内存的分配和释放</string>
|
||||
<string name="gpu_log_driver_debug">驱动调试信息</string>
|
||||
|
||||
@@ -503,8 +503,6 @@
|
||||
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
|
||||
<string name="enable_buffer_history">Enable buffer history</string>
|
||||
<string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string>
|
||||
<string name="enable_gpu_buffer_readback">Enable GPU Buffer Readback</string>
|
||||
<string name="enable_gpu_buffer_readback_description">Preserves GPU-modified buffer data by reading it back before uploads. Some games require this to render certain effects properly. May cause issues if the hardware cannot handle the additional workload.</string>
|
||||
<string name="use_optimized_vertex_buffers">Optimized Vertex Buffers</string>
|
||||
<string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers (25.3 and below).</string>
|
||||
|
||||
|
||||
+1
-1
@@ -350,7 +350,7 @@ struct System::Impl {
|
||||
|
||||
// Register with applet manager
|
||||
// All threads are started, begin main process execution, now that we're in the clear
|
||||
applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params);
|
||||
applet_manager.CreateAndInsertByFrontendAppletParameters(std::make_unique<Service::Process>(*std::move(process)), params);
|
||||
|
||||
if (Settings::values.gamecard_inserted) {
|
||||
if (Settings::values.gamecard_current_game) {
|
||||
|
||||
@@ -729,7 +729,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface(ctx, ensure_token_id);
|
||||
rb.PushIpcInterface(ensure_token_id);
|
||||
}
|
||||
|
||||
void LoadIdTokenCacheDeprecated(HLERequestContext& ctx) {
|
||||
@@ -921,7 +921,7 @@ void Module::Interface::GetProfile(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IProfile>(ctx, system, user_id, *profile_manager);
|
||||
rb.PushIpcInterface<IProfile>(system, user_id, *profile_manager);
|
||||
}
|
||||
|
||||
void Module::Interface::IsUserRegistrationRequestPermitted(HLERequestContext& ctx) {
|
||||
@@ -993,7 +993,7 @@ void Module::Interface::GetBaasAccountManagerForApplication(HLERequestContext& c
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IManagerForApplication>(ctx, system, profile_manager);
|
||||
rb.PushIpcInterface<IManagerForApplication>(system, profile_manager);
|
||||
}
|
||||
|
||||
void Module::Interface::IsUserAccountSwitchLocked(HLERequestContext& ctx) {
|
||||
@@ -1089,7 +1089,7 @@ void Module::Interface::GetProfileEditor(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IProfileEditor>(ctx, system, user_id, *profile_manager);
|
||||
rb.PushIpcInterface<IProfileEditor>(system, user_id, *profile_manager);
|
||||
}
|
||||
|
||||
void Module::Interface::GetBaasAccountAdministrator(HLERequestContext &ctx) {
|
||||
@@ -1100,7 +1100,7 @@ void Module::Interface::GetBaasAccountAdministrator(HLERequestContext &ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAdministrator>(ctx, system, uuid);
|
||||
rb.PushIpcInterface<IAdministrator>(system, uuid);
|
||||
}
|
||||
|
||||
void Module::Interface::ListQualifiedUsers(HLERequestContext& ctx) {
|
||||
@@ -1143,7 +1143,7 @@ void Module::Interface::GetBaasAccountManagerForSystemService(HLERequestContext&
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IManagerForSystemService>(ctx, system, uuid);
|
||||
rb.PushIpcInterface<IManagerForSystemService>(system, uuid);
|
||||
}
|
||||
|
||||
void Module::Interface::StoreSaveDataThumbnailSystem(HLERequestContext& ctx) {
|
||||
|
||||
@@ -35,7 +35,7 @@ void IAsyncContext::GetSystemEvent(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, completion_event->GetReadableEvent());
|
||||
rb.PushCopyObjects(completion_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IAsyncContext::Cancel(HLERequestContext& ctx) {
|
||||
|
||||
@@ -109,10 +109,6 @@ struct Applet {
|
||||
std::list<std::shared_ptr<Applet>> child_applets{};
|
||||
bool is_completed{};
|
||||
|
||||
std::shared_ptr<Applet> reserved_applet{};
|
||||
bool unwind_after_reserved{};
|
||||
bool is_winding{};
|
||||
|
||||
// Self state
|
||||
bool exit_locked{};
|
||||
s32 fatal_section_count{};
|
||||
|
||||
@@ -25,13 +25,6 @@ void AppletStorageChannel::Push(Kernel::KernelCore& kernel, std::shared_ptr<ISto
|
||||
m_event.Signal(kernel);
|
||||
}
|
||||
|
||||
void AppletStorageChannel::Unpop(Kernel::KernelCore& kernel, std::shared_ptr<IStorage> storage) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
m_data.emplace_front(std::move(storage));
|
||||
m_event.Signal(kernel);
|
||||
}
|
||||
|
||||
Result AppletStorageChannel::Pop(Kernel::KernelCore& kernel, std::shared_ptr<IStorage>* out_storage) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ public:
|
||||
~AppletStorageChannel();
|
||||
|
||||
void Push(Kernel::KernelCore& kernel, std::shared_ptr<IStorage> storage);
|
||||
void Unpop(Kernel::KernelCore& kernel, std::shared_ptr<IStorage> storage);
|
||||
Result Pop(Kernel::KernelCore& kernel, std::shared_ptr<IStorage>* out_storage);
|
||||
Kernel::KReadableEvent* GetEvent();
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) {
|
||||
|
||||
if (Settings::values.enable_overlay && m_window_system->GetOverlayDisplayApplet() == nullptr) {
|
||||
if (auto overlay_process = CreateProcess(m_system, static_cast<u64>(AppletProgramId::OverlayDisplay), 0, 0)) {
|
||||
auto overlay_applet = std::make_shared<Applet>(m_system, std::move(overlay_process), false);
|
||||
auto overlay_applet = std::make_shared<Applet>(m_system, std::make_unique<Service::Process>(*std::move(overlay_process)), false);
|
||||
overlay_applet->program_id = static_cast<u64>(AppletProgramId::OverlayDisplay);
|
||||
overlay_applet->applet_id = AppletId::OverlayDisplay;
|
||||
overlay_applet->type = AppletType::OverlayApplet;
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -15,10 +12,7 @@ namespace Service::AM {
|
||||
|
||||
HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) {
|
||||
m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid", true);
|
||||
this->RegisterCurrentProcess();
|
||||
}
|
||||
|
||||
void HidRegistration::RegisterCurrentProcess() {
|
||||
if (m_process.IsInitialized()) {
|
||||
m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(),
|
||||
true);
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -27,7 +24,6 @@ public:
|
||||
explicit HidRegistration(Core::System& system, Process& process);
|
||||
~HidRegistration();
|
||||
|
||||
void RegisterCurrentProcess();
|
||||
void EnableAppletToGetInput(bool enable);
|
||||
|
||||
private:
|
||||
|
||||
@@ -171,18 +171,6 @@ void LifecycleManager::SignalSystemEventIfNeeded(Kernel::KernelCore& kernel) {
|
||||
}
|
||||
}
|
||||
|
||||
void LifecycleManager::ResetForRelaunch() {
|
||||
m_unordered_messages.clear();
|
||||
|
||||
m_activity_state = ActivityState::BackgroundVisible;
|
||||
m_requested_focus_state = FocusState{};
|
||||
m_acknowledged_focus_state = FocusState{};
|
||||
m_has_focus_state_changed = true;
|
||||
|
||||
m_suspend_mode = SuspendMode::NoOverride;
|
||||
m_forced_suspend = false;
|
||||
}
|
||||
|
||||
bool LifecycleManager::PopMessage(Kernel::KernelCore& kernel, AppletMessage* out_message) {
|
||||
const auto message = this->PopMessageInOrderOfPriority();
|
||||
this->SignalSystemEventIfNeeded(kernel);
|
||||
|
||||
@@ -138,8 +138,6 @@ public:
|
||||
void PushUnorderedMessage(Kernel::KernelCore& kernel, AppletMessage message);
|
||||
bool PopMessage(Kernel::KernelCore& kernel, AppletMessage* out_message);
|
||||
|
||||
void ResetForRelaunch();
|
||||
|
||||
private:
|
||||
FocusState GetFocusStateWhileForegroundObscured() const;
|
||||
FocusState GetFocusStateWhileBackground(bool is_obscured) const;
|
||||
|
||||
@@ -40,23 +40,23 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::unique_ptr<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
|
||||
[[nodiscard]] inline std::optional<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
|
||||
// Get the appropriate loader to parse this NCA.
|
||||
out_loader = Loader::GetLoader(system, file, program_id, program_index);
|
||||
// Ensure we have a loader which can parse the NCA.
|
||||
if (out_loader) {
|
||||
// Try to load the process.
|
||||
auto process = std::make_unique<Process>(system);
|
||||
auto process = std::make_optional<Process>(system);
|
||||
if (process->Initialize(*out_loader, out_load_result)) {
|
||||
return process;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation) {
|
||||
std::optional<Process> CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation) {
|
||||
// Attempt to load program NCA.
|
||||
FileSys::VirtualFile nca_raw{};
|
||||
|
||||
@@ -66,7 +66,7 @@ std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id, u8
|
||||
|
||||
// Ensure we retrieved a program NCA.
|
||||
if (!nca_raw) {
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Ensure we have a suitable version.
|
||||
@@ -76,7 +76,7 @@ std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id, u8
|
||||
(nca.GetKeyGeneration() < minimum_key_generation ||
|
||||
nca.GetKeyGeneration() > maximum_key_generation)) {
|
||||
LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id, nca.GetKeyGeneration());
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id, u8
|
||||
return CreateProcessImpl(loader, status, system, nca_raw, program_id, 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control, std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
|
||||
std::optional<Process> CreateApplicationProcess(std::vector<u8>& out_control, std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index) {
|
||||
if (auto process = CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index); process) {
|
||||
FileSys::NACP nacp;
|
||||
if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
|
||||
@@ -110,23 +110,7 @@ std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
|
||||
system.GetARPManager().Register(launch.title_id, launch, out_control);
|
||||
return process;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ReinitializeProcess(Core::System& system, Process& process, u64 program_id) {
|
||||
auto& storage = system.GetContentProviderUnion();
|
||||
const auto nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
|
||||
if (!nca_raw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto loader = Loader::GetLoader(system, nca_raw, program_id, 0);
|
||||
if (!loader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Loader::ResultStatus status{};
|
||||
return process.Initialize(*loader, status);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -27,9 +27,7 @@ class Process;
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation);
|
||||
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control, std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index);
|
||||
|
||||
bool ReinitializeProcess(Core::System& system, Process& process, u64 program_id);
|
||||
std::optional<Process> CreateProcess(Core::System& system, u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation);
|
||||
std::optional<Process> CreateApplicationProcess(std::vector<u8>& out_control, std::unique_ptr<Loader::AppLoader>& out_loader, Loader::ResultStatus& out_load_result, Core::System& system, FileSys::VirtualFile file, u64 program_id, u64 program_index);
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -35,9 +35,9 @@ Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_applicati
|
||||
std::unique_ptr<Loader::AppLoader> loader;
|
||||
Loader::ResultStatus result;
|
||||
auto process = CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
|
||||
R_UNLESS(process != nullptr, ResultUnknown);
|
||||
R_UNLESS(process != std::nullopt, ResultUnknown);
|
||||
|
||||
const auto applet = std::make_shared<Applet>(system, std::move(process), true);
|
||||
const auto applet = std::make_shared<Applet>(system, std::make_unique<Service::Process>(*std::move(process)), true);
|
||||
applet->program_id = program_id;
|
||||
applet->applet_id = AppletId::Application;
|
||||
applet->type = AppletType::Application;
|
||||
@@ -88,9 +88,9 @@ Result IApplicationCreator::CreateSystemApplication(
|
||||
std::vector<u8> control;
|
||||
std::unique_ptr<Loader::AppLoader> loader;
|
||||
auto process = CreateProcess(system, application_id, 1, 22);
|
||||
R_UNLESS(process != nullptr, ResultUnknown);
|
||||
R_UNLESS(process != std::nullopt, ResultUnknown);
|
||||
|
||||
const auto applet = std::make_shared<Applet>(system, std::move(process), true);
|
||||
const auto applet = std::make_shared<Applet>(system, std::make_unique<Service::Process>(*std::move(process)), true);
|
||||
applet->program_id = application_id;
|
||||
applet->applet_id = AppletId::Starter;
|
||||
applet->type = AppletType::LibraryApplet;
|
||||
|
||||
@@ -75,7 +75,7 @@ ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
|
||||
{105, D<&ILibraryAppletAccessor::GetPopOutDataEvent>, "GetPopOutDataEvent"},
|
||||
{106, D<&ILibraryAppletAccessor::GetPopInteractiveOutDataEvent>, "GetPopInteractiveOutDataEvent"},
|
||||
{110, nullptr, "NeedsToExitProcess"},
|
||||
{120, D<&ILibraryAppletAccessor::GetLibraryAppletInfo>, "GetLibraryAppletInfo"},
|
||||
{120, nullptr, "GetLibraryAppletInfo"},
|
||||
{150, nullptr, "RequestForAppletToGetForeground"},
|
||||
{160, D<&ILibraryAppletAccessor::GetIndirectLayerConsumerHandle>, "GetIndirectLayerConsumerHandle"}, //2.0.0+
|
||||
{170, D<&ILibraryAppletAccessor::Unknown170>, "Unknown170"}, //22.0.0+
|
||||
@@ -218,16 +218,6 @@ Result ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(Out<u64> out_handl
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletAccessor::GetLibraryAppletInfo(
|
||||
Out<LibraryAppletInfo> out_library_applet_info) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_library_applet_info = {
|
||||
.applet_id = m_applet->applet_id,
|
||||
.library_applet_mode = m_applet->library_applet_mode,
|
||||
};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletAccessor::Unknown170(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_event = m_applet->unknown_event.GetHandle();
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/am/service/library_applet_self_accessor.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
@@ -22,10 +21,6 @@ public:
|
||||
std::shared_ptr<Applet> applet);
|
||||
~ILibraryAppletAccessor();
|
||||
|
||||
std::shared_ptr<Applet> GetApplet() const {
|
||||
return m_applet;
|
||||
}
|
||||
|
||||
private:
|
||||
Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result IsCompleted(Out<bool> out_is_completed);
|
||||
@@ -42,7 +37,6 @@ private:
|
||||
Result GetPopOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetPopInteractiveOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetIndirectLayerConsumerHandle(Out<u64> out_handle);
|
||||
Result GetLibraryAppletInfo(Out<LibraryAppletInfo> out_library_applet_info);
|
||||
Result Unknown170(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
void FrontendExecute();
|
||||
|
||||
@@ -123,7 +123,7 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
|
||||
|
||||
auto process = CreateProcess(system, program_id, Firmware1400, Firmware2200);
|
||||
if (process) {
|
||||
const auto applet = std::make_shared<Applet>(system, std::move(process), false);
|
||||
const auto applet = std::make_shared<Applet>(system, std::make_unique<Service::Process>(*std::move(process)), false);
|
||||
applet->program_id = program_id;
|
||||
applet->applet_id = applet_id;
|
||||
applet->type = AppletType::LibraryApplet;
|
||||
|
||||
@@ -233,9 +233,8 @@ Result ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext(
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::UnpopInData(SharedPointer<IStorage> storage) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
m_broker->GetInData().Unpop(system.Kernel(), storage);
|
||||
Result ILibraryAppletSelfAccessor::UnpopInData() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ private:
|
||||
Result ReportVisibleError(ErrorCode error_code);
|
||||
Result ReportVisibleErrorWithErrorContext(
|
||||
ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context);
|
||||
Result UnpopInData(SharedPointer<IStorage> storage);
|
||||
Result UnpopInData();
|
||||
Result GetMainAppletApplicationDesiredLanguage(Out<u64> out_desired_language);
|
||||
Result GetCurrentApplicationId(Out<u64> out_application_id);
|
||||
Result GetMainAppletAvailableUsers(Out<bool> out_can_select_any_user, Out<s32> out_users_count,
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/service/library_applet_accessor.h"
|
||||
#include "core/hle/service/am/service/process_winding_controller.h"
|
||||
@@ -45,18 +43,6 @@ Result IProcessWindingController::OpenCallingLibraryApplet(
|
||||
Out<SharedPointer<ILibraryAppletAccessor>> out_calling_library_applet) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
std::shared_ptr<Applet> reserved_applet;
|
||||
{
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
reserved_applet = std::move(m_applet->reserved_applet);
|
||||
}
|
||||
|
||||
if (reserved_applet != nullptr) {
|
||||
*out_calling_library_applet = std::make_shared<ILibraryAppletAccessor>(
|
||||
system, reserved_applet->caller_applet_broker, reserved_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
const auto caller_applet = m_applet->caller_applet.lock();
|
||||
if (caller_applet == nullptr) {
|
||||
LOG_ERROR(Service_AM, "No caller applet available");
|
||||
@@ -88,82 +74,22 @@ Result IProcessWindingController::PopContext(Out<SharedPointer<IStorage>> out_co
|
||||
}
|
||||
|
||||
Result IProcessWindingController::CancelWindingReservation() {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->reserved_applet.reset();
|
||||
m_applet->unwind_after_reserved = false;
|
||||
|
||||
LOG_WARNING(Service_AM, "STUBBED");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IProcessWindingController::WindAndDoReserved() {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
std::shared_ptr<Applet> reserved_applet;
|
||||
{
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
|
||||
reserved_applet = m_applet->reserved_applet;
|
||||
m_applet->display_layer_manager.SetWindowVisibility(false);
|
||||
m_applet->exit_locked = false;
|
||||
system.SetExitLocked(false);
|
||||
}
|
||||
|
||||
if (reserved_applet) {
|
||||
{
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->is_winding = true;
|
||||
}
|
||||
|
||||
{
|
||||
std::scoped_lock lk{reserved_applet->lock};
|
||||
reserved_applet->window_visible = true;
|
||||
reserved_applet->process->Run();
|
||||
}
|
||||
|
||||
if (reserved_applet->frontend) {
|
||||
reserved_applet->frontend->Initialize();
|
||||
reserved_applet->frontend->Execute();
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING(Service_AM, "called without a reserved applet to start");
|
||||
}
|
||||
|
||||
m_applet->process->Terminate();
|
||||
|
||||
LOG_WARNING(Service_AM, "STUBBED");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IProcessWindingController::ReserveToStartAndWaitAndUnwindThis(
|
||||
SharedPointer<ILibraryAppletAccessor> reserved_applet_accessor) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
if (reserved_applet_accessor == nullptr) {
|
||||
LOG_ERROR(Service_AM, "No applet accessor provided");
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->reserved_applet = reserved_applet_accessor->GetApplet();
|
||||
m_applet->unwind_after_reserved = true;
|
||||
|
||||
Result IProcessWindingController::ReserveToStartAndWaitAndUnwindThis() {
|
||||
LOG_WARNING(Service_AM, "STUBBED");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IProcessWindingController::ReserveToStartAndWait(
|
||||
SharedPointer<ILibraryAppletAccessor> reserved_applet_accessor) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
if (reserved_applet_accessor == nullptr) {
|
||||
LOG_ERROR(Service_AM, "No applet accessor provided");
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->reserved_applet = reserved_applet_accessor->GetApplet();
|
||||
m_applet->unwind_after_reserved = false;
|
||||
|
||||
Result IProcessWindingController::ReserveToStartAndWait() {
|
||||
LOG_WARNING(Service_AM, "STUBBED");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
@@ -29,9 +29,8 @@ private:
|
||||
Result PopContext(Out<SharedPointer<IStorage>> out_context);
|
||||
Result CancelWindingReservation();
|
||||
Result WindAndDoReserved();
|
||||
Result ReserveToStartAndWaitAndUnwindThis(
|
||||
SharedPointer<ILibraryAppletAccessor> reserved_applet_accessor);
|
||||
Result ReserveToStartAndWait(SharedPointer<ILibraryAppletAccessor> reserved_applet_accessor);
|
||||
Result ReserveToStartAndWaitAndUnwindThis();
|
||||
Result ReserveToStartAndWait();
|
||||
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/event_observer.h"
|
||||
#include "core/hle/service/am/process_creation.h"
|
||||
#include "core/hle/service/am/window_system.h"
|
||||
|
||||
namespace Service::AM {
|
||||
@@ -241,37 +240,6 @@ void WindowSystem::PruneTerminatedAppletsLocked() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// A winding applet has had its own process killed but is kept alive as a transparent slot
|
||||
// while the reserved applet running in its place finishes (see WindAndDoReserved()).
|
||||
if (applet->is_winding) {
|
||||
if (!applet->child_applets.empty()) {
|
||||
it = std::next(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool unwind = applet->unwind_after_reserved;
|
||||
applet->is_winding = false;
|
||||
applet->unwind_after_reserved = false;
|
||||
|
||||
if (unwind && this->RestartAppletProcessLocked(applet.get())) {
|
||||
const u64 new_aruid = applet->aruid.pid;
|
||||
const auto next = std::next(it);
|
||||
|
||||
if (new_aruid != aruid) {
|
||||
auto node = m_applets.extract(it);
|
||||
node.key() = new_aruid;
|
||||
m_applets.insert(std::move(node));
|
||||
}
|
||||
|
||||
applet->process->Run();
|
||||
m_event_observer->RequestUpdate();
|
||||
it = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
applet->reserved_applet.reset();
|
||||
}
|
||||
|
||||
// Terminated, so ensure all child applets are terminated.
|
||||
if (!applet->child_applets.empty()) {
|
||||
this->TerminateChildAppletsLocked(applet.get());
|
||||
@@ -333,28 +301,6 @@ void WindowSystem::PruneTerminatedAppletsLocked() {
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowSystem::RestartAppletProcessLocked(Applet* applet) {
|
||||
if (!ReinitializeProcess(m_system, *applet->process, applet->program_id)) {
|
||||
LOG_ERROR(Service_AM, "Failed to restart winding applet_id={}",
|
||||
static_cast<u32>(applet->applet_id));
|
||||
return false;
|
||||
}
|
||||
|
||||
applet->aruid.pid = applet->process->GetProcessId();
|
||||
applet->is_process_running = false;
|
||||
applet->is_completed = false;
|
||||
|
||||
applet->hid_registration.RegisterCurrentProcess();
|
||||
|
||||
applet->lifecycle_manager.ResetForRelaunch();
|
||||
applet->is_activity_runnable = false;
|
||||
|
||||
applet->launch_reason.flag = 1;
|
||||
|
||||
m_event_observer->TrackAppletProcess(*applet);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowSystem::LockHomeMenuIntoForegroundLocked() {
|
||||
// If the home menu is not locked into foreground, then there's nothing to do.
|
||||
if (m_home_menu == nullptr || !m_home_menu_foreground_locked) {
|
||||
@@ -406,9 +352,6 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
|
||||
const bool has_obscuring_child_applets = [&] {
|
||||
for (const auto& child_applet : applet->child_applets) {
|
||||
std::scoped_lock lk2{child_applet->lock};
|
||||
if (child_applet->is_winding) {
|
||||
return true;
|
||||
}
|
||||
const auto mode = child_applet->library_applet_mode;
|
||||
if (child_applet->is_process_running && child_applet->window_visible &&
|
||||
(mode == LibraryAppletMode::AllForeground ||
|
||||
|
||||
@@ -61,7 +61,6 @@ public:
|
||||
|
||||
private:
|
||||
void PruneTerminatedAppletsLocked();
|
||||
bool RestartAppletProcessLocked(Applet* applet);
|
||||
bool LockHomeMenuIntoForegroundLocked();
|
||||
void TerminateChildAppletsLocked(Applet* applet);
|
||||
void UpdateAppletStateLocked(Applet* applet, bool is_foreground, bool overlay_blocking = false);
|
||||
|
||||
@@ -82,7 +82,7 @@ void APM::OpenSession(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISession>(ctx, system, controller);
|
||||
rb.PushIpcInterface<ISession>(system, controller);
|
||||
}
|
||||
|
||||
void APM::GetPerformanceMode(HLERequestContext& ctx) {
|
||||
@@ -125,7 +125,7 @@ void APM_Sys::GetPerformanceEvent(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISession>(ctx, system, controller);
|
||||
rb.PushIpcInterface<ISession>(system, controller);
|
||||
}
|
||||
|
||||
void APM_Sys::SetCpuBoostMode(HLERequestContext& ctx) {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -48,7 +45,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IRequest>(ctx, system);
|
||||
rb.PushIpcInterface<IRequest>(system);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(readable_event.Signal(system.Kernel()));
|
||||
rb.PushCopyObjects(ctx, readable_event);
|
||||
rb.PushCopyObjects(readable_event);
|
||||
}
|
||||
|
||||
void Cancel(HLERequestContext& ctx) {
|
||||
@@ -400,7 +400,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, notification_event->GetReadableEvent());
|
||||
rb.PushCopyObjects(notification_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void Clear(HLERequestContext& ctx) {
|
||||
@@ -476,7 +476,7 @@ private:
|
||||
void Module::Interface::CreateFriendService(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IFriendService>(ctx, system);
|
||||
rb.PushIpcInterface<IFriendService>(system);
|
||||
LOG_DEBUG(Service_Friend, "called");
|
||||
}
|
||||
|
||||
@@ -488,12 +488,12 @@ void Module::Interface::CreateNotificationService(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<INotificationService>(ctx, system, uuid);
|
||||
rb.PushIpcInterface<INotificationService>(system, uuid);
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, const char* name)
|
||||
: ServiceFramework{system_, name}, module{std::move(module_)}
|
||||
{}
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
|
||||
const char* name)
|
||||
: ServiceFramework{system_, name}, module{std::move(module_)} {}
|
||||
|
||||
Module::Interface::~Interface() = default;
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ void ARP_W::AcquireRegistrar(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface(ctx, registrar);
|
||||
rb.PushIpcInterface(registrar);
|
||||
}
|
||||
|
||||
void ARP_W::UnregisterApplicationInstance(HLERequestContext& ctx) {
|
||||
|
||||
@@ -28,7 +28,7 @@ void BGTC_T::OpenTaskService(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ITaskService>(ctx, system);
|
||||
rb.PushIpcInterface<ITaskService>(system);
|
||||
}
|
||||
|
||||
ITaskService::ITaskService(Core::System& system_) : ServiceFramework{system_, "ITaskService"} {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -59,7 +56,7 @@ ECTX_AW::~ECTX_AW() = default;
|
||||
void ECTX_AW::CreateContextRegistrar(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IContextRegistrar>(ctx, system);
|
||||
rb.PushIpcInterface<IContextRegistrar>(std::make_shared<IContextRegistrar>(system));
|
||||
}
|
||||
|
||||
} // namespace Service::Glue
|
||||
|
||||
@@ -726,7 +726,7 @@ void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& c
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, acquire_device_registered_event->GetReadableEvent());
|
||||
rb.PushCopyObjects(acquire_device_registered_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx) {
|
||||
@@ -734,7 +734,7 @@ void IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport(HLEReque
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, acquire_device_registered_event->GetReadableEvent());
|
||||
rb.PushCopyObjects(acquire_device_registered_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IHidSystemServer::GetRegisteredDevices(HLERequestContext& ctx) {
|
||||
@@ -759,7 +759,7 @@ void IHidSystemServer::AcquireUniquePadConnectionEventHandle(HLERequestContext&
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.PushCopyObjects(ctx, unique_pad_connection_event->GetReadableEvent());
|
||||
rb.PushCopyObjects(unique_pad_connection_event->GetReadableEvent());
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
@@ -776,7 +776,7 @@ void IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestConte
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, joy_detach_event->GetReadableEvent());
|
||||
rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void IHidSystemServer::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
|
||||
|
||||
@@ -31,7 +31,7 @@ class Memory;
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
struct ResponseBuilder;
|
||||
class ResponseBuilder;
|
||||
}
|
||||
|
||||
namespace Service {
|
||||
@@ -392,7 +392,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct IPC::ResponseBuilder;
|
||||
friend class IPC::ResponseBuilder;
|
||||
|
||||
void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
|
||||
|
||||
|
||||
@@ -24,7 +24,45 @@ namespace IPC {
|
||||
|
||||
constexpr Result ResultSessionClosed{ErrorModule::HIPC, 301};
|
||||
|
||||
struct ResponseBuilder {
|
||||
class RequestHelperBase {
|
||||
protected:
|
||||
Service::HLERequestContext* context = nullptr;
|
||||
u32* cmdbuf;
|
||||
u32 index = 0;
|
||||
|
||||
public:
|
||||
explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {}
|
||||
|
||||
explicit RequestHelperBase(Service::HLERequestContext& ctx)
|
||||
: context(&ctx), cmdbuf(ctx.CommandBuffer()) {}
|
||||
|
||||
void Skip(u32 size_in_words, bool set_to_null) {
|
||||
if (set_to_null) {
|
||||
memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
|
||||
}
|
||||
index += size_in_words;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aligns the current position forward to a 16-byte boundary, padding with zeros.
|
||||
*/
|
||||
void AlignWithPadding() {
|
||||
if (index & 3) {
|
||||
Skip(static_cast<u32>(4 - (index & 3)), true);
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetCurrentOffset() const {
|
||||
return index;
|
||||
}
|
||||
|
||||
void SetCurrentOffset(u32 offset) {
|
||||
index = offset;
|
||||
}
|
||||
};
|
||||
|
||||
class ResponseBuilder : public RequestHelperBase {
|
||||
public:
|
||||
/// Flags used for customizing the behavior of ResponseBuilder
|
||||
enum class Flags : u32 {
|
||||
None = 0,
|
||||
@@ -33,13 +71,14 @@ struct ResponseBuilder {
|
||||
AlwaysMoveHandles = 1,
|
||||
};
|
||||
|
||||
inline explicit ResponseBuilder(Service::HLERequestContext& ctx, u32 normal_params_size_, u32 num_handles_to_copy_ = 0, u32 num_objects_to_move_ = 0, Flags flags = Flags::None)
|
||||
: cmdbuf(ctx.CommandBuffer())
|
||||
, normal_params_size(normal_params_size_)
|
||||
, num_handles_to_copy(num_handles_to_copy_)
|
||||
, num_objects_to_move(num_objects_to_move_)
|
||||
{
|
||||
std::memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
|
||||
explicit ResponseBuilder(Service::HLERequestContext& ctx, u32 normal_params_size_,
|
||||
u32 num_handles_to_copy_ = 0, u32 num_objects_to_move_ = 0,
|
||||
Flags flags = Flags::None)
|
||||
: RequestHelperBase(ctx), normal_params_size(normal_params_size_),
|
||||
num_handles_to_copy(num_handles_to_copy_),
|
||||
num_objects_to_move(num_objects_to_move_), kernel{ctx.kernel} {
|
||||
|
||||
memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
|
||||
|
||||
IPC::CommandHeader header{};
|
||||
auto const mgr = ctx.GetManager().get();
|
||||
@@ -78,7 +117,9 @@ struct ResponseBuilder {
|
||||
handle_descriptor_header.num_handles_to_copy.Assign(num_handles_to_copy_);
|
||||
handle_descriptor_header.num_handles_to_move.Assign(num_handles_to_move);
|
||||
PushRaw(handle_descriptor_header);
|
||||
|
||||
ctx.handles_offset = index;
|
||||
|
||||
Skip(num_handles_to_copy + num_handles_to_move, true);
|
||||
}
|
||||
|
||||
@@ -90,6 +131,7 @@ struct ResponseBuilder {
|
||||
domain_header.num_objects = num_domain_objects;
|
||||
PushRaw(domain_header);
|
||||
}
|
||||
|
||||
IPC::DataPayloadHeader data_payload_header{};
|
||||
data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
|
||||
PushRaw(data_payload_header);
|
||||
@@ -99,39 +141,34 @@ struct ResponseBuilder {
|
||||
|
||||
ctx.data_payload_offset = index;
|
||||
ctx.write_size += index;
|
||||
ctx.domain_offset = u32(index + raw_data_size / sizeof(u32));
|
||||
ctx.domain_offset = static_cast<u32>(index + raw_data_size / sizeof(u32));
|
||||
}
|
||||
|
||||
inline void Skip(u32 size_in_words, bool set_to_null) {
|
||||
if (set_to_null) std::memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
|
||||
index += size_in_words;
|
||||
}
|
||||
/// @brief Aligns the current position forward to a 16-byte boundary, padding with zeros.
|
||||
inline void AlignWithPadding() { if (index & 3) Skip(u32(4 - (index & 3)), true); }
|
||||
inline u32 GetCurrentOffset() const { return index; }
|
||||
inline void SetCurrentOffset(u32 offset) { index = offset; }
|
||||
template <class T>
|
||||
void PushIpcInterface(std::shared_ptr<T> iface) {
|
||||
auto manager{context->GetManager()};
|
||||
|
||||
template <class T> inline void PushIpcInterface(Service::HLERequestContext& ctx, std::shared_ptr<T> iface) {
|
||||
auto manager = ctx.GetManager();
|
||||
if (manager->IsDomain()) {
|
||||
ctx.AddDomainObject(std::move(iface));
|
||||
context->AddDomainObject(std::move(iface));
|
||||
} else {
|
||||
ASSERT(Kernel::GetCurrentProcess(ctx.kernel).GetResourceLimit()->Reserve(ctx.kernel, Kernel::LimitableResource::SessionCountMax, 1));
|
||||
ASSERT(Kernel::GetCurrentProcess(kernel).GetResourceLimit()->Reserve(kernel, Kernel::LimitableResource::SessionCountMax, 1));
|
||||
|
||||
auto* session = Kernel::KSession::Create(ctx.kernel);
|
||||
session->Initialize(ctx.kernel, nullptr, 0);
|
||||
Kernel::KSession::Register(ctx.kernel, session);
|
||||
auto* session = Kernel::KSession::Create(kernel);
|
||||
session->Initialize(kernel, nullptr, 0);
|
||||
Kernel::KSession::Register(kernel, session);
|
||||
|
||||
auto next_manager = std::make_shared<Service::SessionRequestManager>(ctx.kernel, manager->GetServerManager());
|
||||
auto next_manager = std::make_shared<Service::SessionRequestManager>(
|
||||
kernel, manager->GetServerManager());
|
||||
next_manager->SetSessionHandler(iface);
|
||||
manager->GetServerManager().RegisterSession(&session->GetServerSession(), next_manager);
|
||||
|
||||
ctx.AddMoveObject(&session->GetClientSession());
|
||||
context->AddMoveObject(&session->GetClientSession());
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class... Args> inline void PushIpcInterface(Service::HLERequestContext& ctx, Args&&... args) {
|
||||
PushIpcInterface<T>(ctx, std::make_shared<T>(std::forward<Args>(args)...));
|
||||
template <class T, class... Args>
|
||||
void PushIpcInterface(Args&&... args) {
|
||||
PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
void PushImpl(s8 value);
|
||||
@@ -147,38 +184,59 @@ struct ResponseBuilder {
|
||||
void PushImpl(bool value);
|
||||
void PushImpl(Result value);
|
||||
|
||||
template <typename T> inline void Push(T value) {
|
||||
template <typename T>
|
||||
void Push(T value) {
|
||||
return PushImpl(value);
|
||||
}
|
||||
|
||||
template <typename First, typename... Other>
|
||||
void Push(const First& first_value, const Other&... other_values);
|
||||
|
||||
/// @brief Helper function for pushing strongly-typed enumeration values.
|
||||
/// @tparam Enum The enumeration type to be pushed
|
||||
/// @param value The value to push.
|
||||
/// @note The underlying size of the enumeration type is the size of the data that gets pushed.
|
||||
/// e.g. "enum class SomeEnum : u16" will push a u16-sized amount of data.
|
||||
template <typename Enum> inline void PushEnum(Enum value) {
|
||||
/**
|
||||
* Helper function for pushing strongly-typed enumeration values.
|
||||
*
|
||||
* @tparam Enum The enumeration type to be pushed
|
||||
*
|
||||
* @param value The value to push.
|
||||
*
|
||||
* @note The underlying size of the enumeration type is the size of the
|
||||
* data that gets pushed. e.g. "enum class SomeEnum : u16" will
|
||||
* push a u16-sized amount of data.
|
||||
*/
|
||||
template <typename Enum>
|
||||
void PushEnum(Enum value) {
|
||||
static_assert(std::is_enum_v<Enum>, "T must be an enum type within a PushEnum call.");
|
||||
static_assert(!std::is_convertible_v<Enum, int>, "enum type in PushEnum must be a strongly typed enum.");
|
||||
static_assert(!std::is_convertible_v<Enum, int>,
|
||||
"enum type in PushEnum must be a strongly typed enum.");
|
||||
Push(static_cast<std::underlying_type_t<Enum>>(value));
|
||||
}
|
||||
|
||||
/// @brief Copies the content of the given trivially copyable class to the buffer as a normal param
|
||||
/// @note: The input class must be correctly packed/padded to fit hardware layout.
|
||||
template <typename T> void PushRaw(const T& value);
|
||||
template <typename... O> void PushMoveObjects(Service::HLERequestContext& ctx, O*... pointers);
|
||||
template <typename... O> void PushMoveObjects(Service::HLERequestContext& ctx, O&... pointers);
|
||||
template <typename... O> void PushCopyObjects(Service::HLERequestContext& ctx, O*... pointers);
|
||||
template <typename... O> void PushCopyObjects(Service::HLERequestContext& ctx, O&... pointers);
|
||||
/**
|
||||
* @brief Copies the content of the given trivially copyable class to the buffer as a normal
|
||||
* param
|
||||
* @note: The input class must be correctly packed/padded to fit hardware layout.
|
||||
*/
|
||||
template <typename T>
|
||||
void PushRaw(const T& value);
|
||||
|
||||
u32* cmdbuf;
|
||||
u32 index = 0;
|
||||
template <typename... O>
|
||||
void PushMoveObjects(O*... pointers);
|
||||
|
||||
template <typename... O>
|
||||
void PushMoveObjects(O&... pointers);
|
||||
|
||||
template <typename... O>
|
||||
void PushCopyObjects(O*... pointers);
|
||||
|
||||
template <typename... O>
|
||||
void PushCopyObjects(O&... pointers);
|
||||
|
||||
private:
|
||||
u32 normal_params_size{};
|
||||
u32 num_handles_to_copy{};
|
||||
u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent
|
||||
u32 data_payload_index{};
|
||||
Kernel::KernelCore& kernel;
|
||||
};
|
||||
|
||||
/// Push ///
|
||||
@@ -193,7 +251,8 @@ inline void ResponseBuilder::PushImpl(u32 value) {
|
||||
|
||||
template <typename T>
|
||||
void ResponseBuilder::PushRaw(const T& value) {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
std::memcpy(cmdbuf + index, &value, sizeof(T));
|
||||
index += (sizeof(T) + 3) / 4; // round up to word length
|
||||
}
|
||||
@@ -213,8 +272,8 @@ inline void ResponseBuilder::PushImpl(s16 value) {
|
||||
}
|
||||
|
||||
inline void ResponseBuilder::PushImpl(s64 value) {
|
||||
PushImpl(u32(value));
|
||||
PushImpl(u32(value >> 32));
|
||||
PushImpl(static_cast<u32>(value));
|
||||
PushImpl(static_cast<u32>(value >> 32));
|
||||
}
|
||||
|
||||
inline void ResponseBuilder::PushImpl(u8 value) {
|
||||
@@ -226,8 +285,8 @@ inline void ResponseBuilder::PushImpl(u16 value) {
|
||||
}
|
||||
|
||||
inline void ResponseBuilder::PushImpl(u64 value) {
|
||||
PushImpl(u32(value));
|
||||
PushImpl(u32(value >> 32));
|
||||
PushImpl(static_cast<u32>(value));
|
||||
PushImpl(static_cast<u32>(value >> 32));
|
||||
}
|
||||
|
||||
inline void ResponseBuilder::PushImpl(float value) {
|
||||
@@ -253,88 +312,90 @@ void ResponseBuilder::Push(const First& first_value, const Other&... other_value
|
||||
}
|
||||
|
||||
template <typename... O>
|
||||
inline void ResponseBuilder::PushCopyObjects(Service::HLERequestContext& ctx, O*... pointers) {
|
||||
inline void ResponseBuilder::PushCopyObjects(O*... pointers) {
|
||||
auto objects = {pointers...};
|
||||
for (auto& object : objects) {
|
||||
ctx.AddCopyObject(object);
|
||||
context->AddCopyObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... O>
|
||||
inline void ResponseBuilder::PushCopyObjects(Service::HLERequestContext& ctx, O&... pointers) {
|
||||
inline void ResponseBuilder::PushCopyObjects(O&... pointers) {
|
||||
auto objects = {&pointers...};
|
||||
for (auto& object : objects) {
|
||||
ctx.AddCopyObject(object);
|
||||
context->AddCopyObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... O>
|
||||
inline void ResponseBuilder::PushMoveObjects(Service::HLERequestContext& ctx, O*... pointers) {
|
||||
inline void ResponseBuilder::PushMoveObjects(O*... pointers) {
|
||||
auto objects = {pointers...};
|
||||
for (auto& object : objects) {
|
||||
ctx.AddMoveObject(object);
|
||||
context->AddMoveObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... O>
|
||||
inline void ResponseBuilder::PushMoveObjects(Service::HLERequestContext& ctx, O&... pointers) {
|
||||
inline void ResponseBuilder::PushMoveObjects(O&... pointers) {
|
||||
auto objects = {&pointers...};
|
||||
for (auto& object : objects) {
|
||||
ctx.AddMoveObject(object);
|
||||
context->AddMoveObject(object);
|
||||
}
|
||||
}
|
||||
|
||||
struct RequestParser {
|
||||
inline explicit RequestParser(u32* command_buffer) : cmdbuf(command_buffer) {}
|
||||
inline explicit RequestParser(Service::HLERequestContext& ctx)
|
||||
: cmdbuf(ctx.CommandBuffer())
|
||||
{
|
||||
class RequestParser : public RequestHelperBase {
|
||||
public:
|
||||
explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {}
|
||||
|
||||
explicit RequestParser(Service::HLERequestContext& ctx) : RequestHelperBase(ctx) {
|
||||
// TIPC does not have data payload offset
|
||||
if (!ctx.IsTipc()) {
|
||||
ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete");
|
||||
Skip(ctx.GetDataPayloadOffset(), false);
|
||||
}
|
||||
|
||||
// Skip the u64 command id, it's already stored in the context
|
||||
static constexpr u32 CommandIdSize = 2;
|
||||
Skip(CommandIdSize, false);
|
||||
}
|
||||
|
||||
inline void Skip(u32 size_in_words, bool set_to_null) {
|
||||
if (set_to_null) std::memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
|
||||
index += size_in_words;
|
||||
}
|
||||
/// @brief Aligns the current position forward to a 16-byte boundary, padding with zeros.
|
||||
inline void AlignWithPadding() { if (index & 3) Skip(u32(4 - (index & 3)), true); }
|
||||
inline u32 GetCurrentOffset() const { return index; }
|
||||
inline void SetCurrentOffset(u32 offset) { index = offset; }
|
||||
template <typename T>
|
||||
T Pop();
|
||||
|
||||
template <typename T> T Pop();
|
||||
template <typename T> void Pop(T& value);
|
||||
template <typename First, typename... Other> void Pop(First& first_value, Other&... other_values);
|
||||
template <typename T>
|
||||
void Pop(T& value);
|
||||
|
||||
template <typename First, typename... Other>
|
||||
void Pop(First& first_value, Other&... other_values);
|
||||
|
||||
template <typename T>
|
||||
T PopEnum() {
|
||||
static_assert(std::is_enum_v<T>, "T must be an enum type within a PopEnum call.");
|
||||
static_assert(!std::is_convertible_v<T, int>, "enum type in PopEnum must be a strongly typed enum.");
|
||||
return T(Pop<std::underlying_type_t<T>>());
|
||||
static_assert(!std::is_convertible_v<T, int>,
|
||||
"enum type in PopEnum must be a strongly typed enum.");
|
||||
return static_cast<T>(Pop<std::underlying_type_t<T>>());
|
||||
}
|
||||
|
||||
/// @brief Reads the next normal parameters as a struct, by copying it
|
||||
/// @note: The output class must be correctly packed/padded to fit hardware layout.
|
||||
template <typename T> void PopRaw(T& value);
|
||||
/**
|
||||
* @brief Reads the next normal parameters as a struct, by copying it
|
||||
* @note: The output class must be correctly packed/padded to fit hardware layout.
|
||||
*/
|
||||
template <typename T>
|
||||
void PopRaw(T& value);
|
||||
|
||||
/// @brief Reads the next normal parameters as a struct, by copying it into a new value
|
||||
/// @note: The output class must be correctly packed/padded to fit hardware layout.
|
||||
template <typename T> T PopRaw();
|
||||
/**
|
||||
* @brief Reads the next normal parameters as a struct, by copying it into a new value
|
||||
* @note: The output class must be correctly packed/padded to fit hardware layout.
|
||||
*/
|
||||
template <typename T>
|
||||
T PopRaw();
|
||||
|
||||
template <class T> [[nodiscard]] std::weak_ptr<T> PopIpcInterface(Service::HLERequestContext& ctx) {
|
||||
ASSERT(ctx.GetManager()->IsDomain());
|
||||
ASSERT(ctx.GetDomainMessageHeader().input_object_count > 0);
|
||||
return ctx.GetDomainHandler<T>(Pop<u32>() - 1);
|
||||
template <class T>
|
||||
std::weak_ptr<T> PopIpcInterface() {
|
||||
ASSERT(context->GetManager()->IsDomain());
|
||||
ASSERT(context->GetDomainMessageHeader().input_object_count > 0);
|
||||
return context->GetDomainHandler<T>(Pop<u32>() - 1);
|
||||
}
|
||||
|
||||
u32* cmdbuf;
|
||||
u32 index = 0;
|
||||
};
|
||||
|
||||
/// Pop ///
|
||||
@@ -346,7 +407,7 @@ inline u32 RequestParser::Pop() {
|
||||
|
||||
template <>
|
||||
inline s32 RequestParser::Pop() {
|
||||
return s32(Pop<u32>());
|
||||
return static_cast<s32>(Pop<u32>());
|
||||
}
|
||||
|
||||
// Ignore the -Wclass-memaccess warning on memcpy for non-trivially default constructible objects.
|
||||
@@ -356,7 +417,8 @@ inline s32 RequestParser::Pop() {
|
||||
#endif
|
||||
template <typename T>
|
||||
void RequestParser::PopRaw(T& value) {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
std::memcpy(&value, cmdbuf + index, sizeof(T));
|
||||
index += (sizeof(T) + 3) / 4; // round up to word length
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ILogger>(ctx, system);
|
||||
rb.PushIpcInterface<ILogger>(system);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IAm>(ctx, system);
|
||||
rb.PushIpcInterface<IAm>(system);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -173,7 +173,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<MFIUser>(ctx, system);
|
||||
rb.PushIpcInterface<MFIUser>(system);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -195,7 +195,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IUser>(ctx, system);
|
||||
rb.PushIpcInterface<IUser>(system);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -217,7 +217,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISystem>(ctx, system);
|
||||
rb.PushIpcInterface<ISystem>(system);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ void NfcInterface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, GetManager()->AttachAvailabilityChangeEvent());
|
||||
rb.PushCopyObjects(GetManager()->AttachAvailabilityChangeEvent());
|
||||
}
|
||||
|
||||
void NfcInterface::StartDetection(HLERequestContext& ctx) {
|
||||
@@ -203,7 +203,7 @@ void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(result);
|
||||
rb.PushCopyObjects(ctx, out_event);
|
||||
rb.PushCopyObjects(out_event);
|
||||
}
|
||||
|
||||
void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
|
||||
@@ -217,7 +217,7 @@ void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(result);
|
||||
rb.PushCopyObjects(ctx, out_event);
|
||||
rb.PushCopyObjects(out_event);
|
||||
}
|
||||
|
||||
void NfcInterface::SetNfcEnabled(HLERequestContext& ctx) {
|
||||
|
||||
@@ -157,7 +157,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IUser>(ctx, system);
|
||||
rb.PushIpcInterface<IUser>(system);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -179,7 +179,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISystem>(ctx, system);
|
||||
rb.PushIpcInterface<ISystem>(system);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -201,7 +201,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDebug>(ctx, system);
|
||||
rb.PushIpcInterface<IDebug>(system);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@ private:
|
||||
void GetSystemEventReadableHandle(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, evt_scan_complete->GetReadableEvent(),
|
||||
rb.PushCopyObjects(evt_scan_complete->GetReadableEvent(),
|
||||
evt_processing->GetReadableEvent());
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, event1->GetReadableEvent(), event2->GetReadableEvent());
|
||||
rb.PushCopyObjects(event1->GetReadableEvent(), event2->GetReadableEvent());
|
||||
}
|
||||
|
||||
void Cancel(HLERequestContext& ctx) {
|
||||
@@ -528,7 +528,7 @@ void IGeneralService::CreateScanRequest(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IScanRequest>(ctx, system);
|
||||
rb.PushIpcInterface<IScanRequest>(system);
|
||||
}
|
||||
|
||||
void IGeneralService::CreateRequest(HLERequestContext& ctx) {
|
||||
@@ -537,7 +537,7 @@ void IGeneralService::CreateRequest(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IRequest>(ctx, system);
|
||||
rb.PushIpcInterface<IRequest>(system);
|
||||
}
|
||||
|
||||
void IGeneralService::GetCurrentNetworkProfile(HLERequestContext& ctx) {
|
||||
@@ -716,7 +716,7 @@ void IGeneralService::GetNetworkProfile(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<INetworkProfile>(ctx, system);
|
||||
rb.PushIpcInterface<INetworkProfile>(system);
|
||||
}
|
||||
|
||||
void IGeneralService::SetNetworkProfile(HLERequestContext& ctx) {
|
||||
@@ -869,7 +869,7 @@ void IGeneralService::CreateTemporaryNetworkProfile(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 6, 0, 1};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<INetworkProfile>(ctx, system);
|
||||
rb.PushIpcInterface<INetworkProfile>(system);
|
||||
rb.PushRaw<u128>(uuid);
|
||||
}
|
||||
|
||||
@@ -1124,7 +1124,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IGeneralService>(ctx, system);
|
||||
rb.PushIpcInterface<IGeneralService>(system);
|
||||
}
|
||||
|
||||
void CreateGeneralService(HLERequestContext& ctx) {
|
||||
@@ -1132,7 +1132,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IGeneralService>(ctx, system);
|
||||
rb.PushIpcInterface<IGeneralService>(system);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ private:
|
||||
LOG_WARNING(Service_NIM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IShopServiceAsync>(ctx, system);
|
||||
rb.PushIpcInterface<IShopServiceAsync>(system);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,7 +75,7 @@ private:
|
||||
LOG_WARNING(Service_NIM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IShopServiceAccessor>(ctx, system);
|
||||
rb.PushIpcInterface<IShopServiceAccessor>(system);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -336,7 +336,7 @@ private:
|
||||
LOG_DEBUG(Service_NIM, "(STUBBED) called");
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IShopServiceAccessServer>(ctx, system);
|
||||
rb.PushIpcInterface<IShopServiceAccessServer>(system);
|
||||
}
|
||||
|
||||
void IsLargeResourceAvailable(HLERequestContext& ctx) {
|
||||
@@ -356,7 +356,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IShopServiceAccessServer>(ctx, system);
|
||||
rb.PushIpcInterface<IShopServiceAccessServer>(system);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -439,7 +439,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, finished_event->GetReadableEvent());
|
||||
rb.PushCopyObjects(finished_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void GetResult(HLERequestContext& ctx) {
|
||||
@@ -500,7 +500,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(ctx, system);
|
||||
rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(system);
|
||||
}
|
||||
|
||||
// TODO(ogniK): Do we need these?
|
||||
|
||||
@@ -359,8 +359,8 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestCo
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, async_value->ReadableEvent());
|
||||
rb.PushIpcInterface(ctx, std::move(async_value));
|
||||
rb.PushCopyObjects(async_value->ReadableEvent());
|
||||
rb.PushIpcInterface(std::move(async_value));
|
||||
}
|
||||
|
||||
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData3(
|
||||
|
||||
@@ -199,7 +199,7 @@ void NVDRV::QueryEvent(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
auto& readable_event = event->GetReadableEvent();
|
||||
rb.PushCopyObjects(ctx, readable_event);
|
||||
rb.PushCopyObjects(readable_event);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
} else {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid event request!");
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -30,15 +28,6 @@ public:
|
||||
inline explicit Process(Core::System& system) noexcept : m_system(system) {}
|
||||
inline ~Process() { this->Finalize(); }
|
||||
|
||||
Process(const Process&) = delete;
|
||||
Process& operator=(const Process&) = delete;
|
||||
Process& operator=(Process&&) = delete;
|
||||
inline Process(Process&& other) noexcept
|
||||
: m_system(other.m_system), m_process(std::exchange(other.m_process, nullptr)),
|
||||
m_main_thread_stack_size(std::exchange(other.m_main_thread_stack_size, 0)),
|
||||
m_main_thread_priority(std::exchange(other.m_main_thread_priority, 0)),
|
||||
m_process_started(std::exchange(other.m_process_started, false)) {}
|
||||
|
||||
bool Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result);
|
||||
void Finalize();
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -127,7 +124,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IClkrstSession>(ctx, system, device_code);
|
||||
rb.PushIpcInterface<IClkrstSession>(system, device_code);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, *process);
|
||||
rb.PushCopyObjects(*process);
|
||||
rb.PushRaw(program_location);
|
||||
rb.PushRaw(override_status);
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ void IAlarmService::CreateWakeupAlarm(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISteadyClockAlarm>(ctx, system, m_alarms, AlarmType::WakeupAlarm);
|
||||
rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::WakeupAlarm);
|
||||
}
|
||||
|
||||
void IAlarmService::CreateBackgroundTaskAlarm(HLERequestContext& ctx) {
|
||||
@@ -155,7 +155,7 @@ void IAlarmService::CreateBackgroundTaskAlarm(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISteadyClockAlarm>(ctx, system, m_alarms, AlarmType::BackgroundTaskAlarm);
|
||||
rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::BackgroundTaskAlarm);
|
||||
}
|
||||
|
||||
ISteadyClockAlarm::ISteadyClockAlarm(Core::System& system_, Alarms& alarms, AlarmType type)
|
||||
@@ -179,7 +179,7 @@ void ISteadyClockAlarm::GetAlarmEvent(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, m_alarm.GetEventHandle());
|
||||
rb.PushCopyObjects(m_alarm.GetEventHandle());
|
||||
}
|
||||
|
||||
void ISteadyClockAlarm::Enable(HLERequestContext& ctx) {
|
||||
|
||||
@@ -67,7 +67,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(ctx, state_change_event->GetReadableEvent());
|
||||
rb.PushCopyObjects(state_change_event->GetReadableEvent());
|
||||
}
|
||||
|
||||
void UnbindStateChangeEvent(HLERequestContext& ctx) {
|
||||
@@ -186,7 +186,7 @@ void PSM::OpenSession(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IPsmSession>(ctx, system);
|
||||
rb.PushIpcInterface<IPsmSession>(system);
|
||||
}
|
||||
|
||||
void PSM::GetBatteryVoltageState(HLERequestContext& ctx) {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -85,7 +82,7 @@ void TS::OpenSession(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISession>(ctx, system);
|
||||
rb.PushIpcInterface<ISession>(system);
|
||||
}
|
||||
|
||||
} // namespace Service::PTM
|
||||
|
||||
@@ -140,7 +140,7 @@ void SM::GetServiceCmif(HLERequestContext& ctx) {
|
||||
if (result == ResultSuccess) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(result);
|
||||
rb.PushMoveObjects(ctx, client_session);
|
||||
rb.PushMoveObjects(client_session);
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
@@ -157,7 +157,7 @@ void SM::GetServiceTipc(HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(result);
|
||||
rb.PushMoveObjects(ctx, result == ResultSuccess ? client_session : nullptr);
|
||||
rb.PushMoveObjects(result == ResultSuccess ? client_session : nullptr);
|
||||
}
|
||||
|
||||
static std::string PopServiceName(IPC::RequestParser& rp) {
|
||||
@@ -230,7 +230,8 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s
|
||||
max_session_count, is_light);
|
||||
|
||||
Kernel::KServerPort* server_port{};
|
||||
if (const auto result = service_manager.RegisterService(std::addressof(server_port), name, max_session_count, nullptr);
|
||||
if (const auto result = service_manager.RegisterService(std::addressof(server_port), name,
|
||||
max_session_count, nullptr);
|
||||
result.IsError()) {
|
||||
LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
@@ -240,7 +241,7 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushMoveObjects(ctx, server_port);
|
||||
rb.PushMoveObjects(server_port);
|
||||
}
|
||||
|
||||
void SM::UnregisterService(HLERequestContext& ctx) {
|
||||
|
||||
@@ -60,7 +60,7 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) {
|
||||
// We succeeded.
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushMoveObjects(ctx, session->GetClientSession());
|
||||
rb.PushMoveObjects(session->GetClientSession());
|
||||
}
|
||||
|
||||
void Controller::CloneCurrentObjectEx(HLERequestContext& ctx) {
|
||||
|
||||
@@ -543,7 +543,8 @@ private:
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(res);
|
||||
if (res == ResultSuccess) {
|
||||
rb.PushIpcInterface<ISslConnection>(ctx, system, ssl_version, shared_data, std::move(backend));
|
||||
rb.PushIpcInterface<ISslConnection>(system, ssl_version, shared_data,
|
||||
std::move(backend));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,11 +624,12 @@ private:
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto parameters = rp.PopRaw<Parameters>();
|
||||
|
||||
LOG_WARNING(Service_SSL, "(STUBBED) called, api_version={}, pid_placeholder={}", parameters.ssl_version.api_version, parameters.pid_placeholder);
|
||||
LOG_WARNING(Service_SSL, "(STUBBED) called, api_version={}, pid_placeholder={}",
|
||||
parameters.ssl_version.api_version, parameters.pid_placeholder);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<ISslContext>(ctx, system, parameters.ssl_version);
|
||||
rb.PushIpcInterface<ISslContext>(system, parameters.ssl_version);
|
||||
}
|
||||
|
||||
void SetInterfaceVersion(HLERequestContext& ctx) {
|
||||
|
||||
@@ -155,7 +155,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IPdSession>(ctx, system);
|
||||
rb.PushIpcInterface<IPdSession>(system);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -199,7 +199,7 @@ private:
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IPdCradleSession>(ctx, system);
|
||||
rb.PushIpcInterface<IPdCradleSession>(system);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service
|
||||
auto& controller = controller_data[aruid_index][i];
|
||||
controller.device = hid_core.GetEmulatedControllerByIndex(i);
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this, i, kernel = &hid_core.kernel](Core::HID::ControllerTriggerType type) {
|
||||
ControllerUpdate(*kernel, type, i);
|
||||
.on_change = [this, i](Core::HID::ControllerTriggerType type) {
|
||||
ControllerUpdate(hid_core.kernel, type, i);
|
||||
},
|
||||
.is_npad_service = true,
|
||||
};
|
||||
|
||||
@@ -236,11 +236,8 @@ void LowerGeometryPassthrough(const IR::Program& program, const HostTranslateInf
|
||||
|
||||
IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
|
||||
Environment& env, Flow::CFG& cfg, const HostTranslateInfo& host_info) {
|
||||
HostTranslateInfo normalized_host_info{host_info};
|
||||
normalized_host_info.ApplyDescriptorLimitPolicy();
|
||||
|
||||
IR::Program program;
|
||||
program.syntax_list = BuildASL(inst_pool, block_pool, env, cfg, normalized_host_info);
|
||||
program.syntax_list = BuildASL(inst_pool, block_pool, env, cfg, host_info);
|
||||
program.blocks = GenerateBlocks(program.syntax_list);
|
||||
program.post_order_blocks = PostOrder(program.syntax_list.front());
|
||||
program.stage = env.ShaderStage();
|
||||
@@ -263,9 +260,9 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
||||
program.info.passthrough.mask[i] = ((mask[i / 32] >> (i % 32)) & 1) == 0;
|
||||
}
|
||||
|
||||
if (!normalized_host_info.support_geometry_shader_passthrough) {
|
||||
if (!host_info.support_geometry_shader_passthrough) {
|
||||
program.output_vertices = GetOutputTopologyVertices(program.output_topology);
|
||||
LowerGeometryPassthrough(program, normalized_host_info);
|
||||
LowerGeometryPassthrough(program, host_info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -280,16 +277,16 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
||||
RemoveUnreachableBlocks(program);
|
||||
|
||||
// Replace instructions before the SSA rewrite
|
||||
if (!normalized_host_info.support_float64) {
|
||||
if (!host_info.support_float64) {
|
||||
Optimization::LowerFp64ToFp32(program);
|
||||
}
|
||||
if (!normalized_host_info.support_float16) {
|
||||
if (!host_info.support_float16) {
|
||||
Optimization::LowerFp16ToFp32(program);
|
||||
}
|
||||
if (!normalized_host_info.support_int64) {
|
||||
if (!host_info.support_int64) {
|
||||
Optimization::LowerInt64ToInt32(program);
|
||||
}
|
||||
if (!normalized_host_info.support_conditional_barrier) {
|
||||
if (!host_info.support_conditional_barrier) {
|
||||
Optimization::ConditionalBarrierPass(program);
|
||||
}
|
||||
Optimization::SsaRewritePass(program);
|
||||
@@ -298,8 +295,8 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
||||
|
||||
Optimization::PositionPass(env, program);
|
||||
|
||||
Optimization::GlobalMemoryToStorageBufferPass(program, normalized_host_info);
|
||||
Optimization::TexturePass(env, program, normalized_host_info);
|
||||
Optimization::GlobalMemoryToStorageBufferPass(program, host_info);
|
||||
Optimization::TexturePass(env, program, host_info);
|
||||
|
||||
if (Settings::values.resolution_info.active || Settings::values.rescale_hack.GetValue()) {
|
||||
Optimization::RescalingPass(program);
|
||||
@@ -309,7 +306,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
||||
Optimization::VerificationPass(program);
|
||||
}
|
||||
Optimization::CollectShaderInfoPass(env, program);
|
||||
Optimization::LayerPass(program, normalized_host_info);
|
||||
Optimization::LayerPass(program, host_info);
|
||||
Optimization::VendorWorkaroundPass(program);
|
||||
|
||||
CollectInterpolationInfo(env, program);
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Shader {
|
||||
|
||||
// Try to keep entries here to a minimum
|
||||
@@ -15,52 +13,20 @@ namespace Shader {
|
||||
|
||||
/// Misc information about the host
|
||||
struct HostTranslateInfo {
|
||||
static constexpr u32 DEFAULT_DESCRIPTOR_LIMIT = 1024;
|
||||
|
||||
u64 min_ssbo_alignment{}; ///< Minimum alignment supported by the device for SSBOs
|
||||
u32 max_per_stage_descriptor_sampled_images{}; ///< maximum sampled descriptors per stage
|
||||
u32 max_per_stage_resources{}; ///< maximum resources per stage
|
||||
u32 max_descriptor_set_samplers{};
|
||||
u32 max_descriptor_set_uniform_buffers{};
|
||||
u32 max_descriptor_set_uniform_buffers_dynamic{};
|
||||
u32 max_descriptor_set_storage_buffers{};
|
||||
u32 max_descriptor_set_storage_buffers_dynamic{};
|
||||
u32 max_descriptor_set_sampled_images{};
|
||||
u32 max_descriptor_set_storage_images{};
|
||||
u32 max_descriptor_set_input_attachements{};
|
||||
bool support_float64{}; ///< True when the device supports 64-bit floats
|
||||
bool support_float16{}; ///< True when the device supports 16-bit floats
|
||||
bool support_int64{}; ///< True when the device supports 64-bit integers
|
||||
bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered
|
||||
bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers
|
||||
bool support_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 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
|
||||
///< passthrough shaders
|
||||
bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional
|
||||
///< control flow
|
||||
|
||||
void ApplyDescriptorLimitPolicy() noexcept {
|
||||
if (min_ssbo_alignment == 0) {
|
||||
min_ssbo_alignment = 1;
|
||||
}
|
||||
ApplyDescriptorLimitFallback(max_per_stage_descriptor_sampled_images);
|
||||
ApplyDescriptorLimitFallback(max_per_stage_resources);
|
||||
ApplyDescriptorLimitFallback(max_descriptor_set_samplers);
|
||||
ApplyDescriptorLimitFallback(max_descriptor_set_uniform_buffers);
|
||||
ApplyDescriptorLimitFallback(max_descriptor_set_uniform_buffers_dynamic);
|
||||
ApplyDescriptorLimitFallback(max_descriptor_set_storage_buffers);
|
||||
ApplyDescriptorLimitFallback(max_descriptor_set_storage_buffers_dynamic);
|
||||
ApplyDescriptorLimitFallback(max_descriptor_set_sampled_images);
|
||||
ApplyDescriptorLimitFallback(max_descriptor_set_storage_images);
|
||||
ApplyDescriptorLimitFallback(max_descriptor_set_input_attachements);
|
||||
}
|
||||
|
||||
private:
|
||||
static void ApplyDescriptorLimitFallback(u32& limit) noexcept {
|
||||
if (limit == 0) {
|
||||
limit = DEFAULT_DESCRIPTOR_LIMIT;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Shader
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -548,7 +545,7 @@ void GlobalMemoryToStorageBufferPass(IR::Program& program, const HostTranslateIn
|
||||
IR::Block* const block{storage_inst.block};
|
||||
IR::Inst* const inst{storage_inst.inst};
|
||||
const IR::U32 offset{
|
||||
StorageOffset(*block, *inst, storage_buffer, u32(host_info.min_ssbo_alignment))};
|
||||
StorageOffset(*block, *inst, storage_buffer, host_info.min_ssbo_alignment)};
|
||||
Replace(*block, *inst, index, offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,62 +32,71 @@ struct TextureInst {
|
||||
using TextureInstVector = boost::container::small_vector<TextureInst, 24>;
|
||||
|
||||
constexpr u32 DESCRIPTOR_SIZE = 8;
|
||||
constexpr u32 DESCRIPTOR_SIZE_SHIFT = u32(std::countr_zero(DESCRIPTOR_SIZE));
|
||||
constexpr u32 DESCRIPTOR_MAX_COUNT = 1024;
|
||||
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)
|
||||
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())
|
||||
}
|
||||
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;
|
||||
}
|
||||
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, u32 max_descriptors) {
|
||||
auto const descriptor_limit = (std::max)(1U, max_descriptors);
|
||||
auto const max_cbuf_bytes = 16 * descriptor_limit;
|
||||
if (size_shift >= 31 || base_offset >= max_cbuf_bytes)
|
||||
u32 DynamicDescriptorCount(u32 base_offset, u32 size_shift) {
|
||||
if (size_shift >= 31 || base_offset >= DYNAMIC_DESCRIPTOR_CBUF_BYTES) {
|
||||
return 1;
|
||||
auto const stride = 1U << size_shift;
|
||||
auto const available = max_cbuf_bytes - base_offset;
|
||||
if (available < DESCRIPTOR_SIZE)
|
||||
}
|
||||
const u32 stride{1U << size_shift};
|
||||
const u32 available{DYNAMIC_DESCRIPTOR_CBUF_BYTES - base_offset};
|
||||
if (available < DESCRIPTOR_SIZE) {
|
||||
return 1;
|
||||
auto const available_count = 1U + (available - DESCRIPTOR_SIZE) / stride;
|
||||
return std::min(descriptor_limit, available_count);
|
||||
}
|
||||
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 T>
|
||||
[[nodiscard]] u32 StaticDescriptorCount(T const& descriptors) noexcept {
|
||||
return std::accumulate(descriptors.cbegin(), descriptors.cend(), 0U, [](auto const& acc, auto const& e) {
|
||||
return acc + (e.count <= 1 ? e.count : 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) {
|
||||
auto const sampled_limit = (std::max)(1U, std::min(host_info.max_per_stage_descriptor_sampled_images,
|
||||
host_info.max_descriptor_set_sampled_images));
|
||||
auto const resource_limit = (std::max)(1U, host_info.max_per_stage_resources);
|
||||
if (dynamic_arrays > 0) {
|
||||
auto const sampled_static_count = StaticDescriptorCount(info.texture_buffer_descriptors) + StaticDescriptorCount(info.texture_descriptors);
|
||||
auto const 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);
|
||||
auto const sampled_budget = SaturatingSub(sampled_limit, sampled_static_count);
|
||||
auto const resource_budget = SaturatingSub(resource_limit, resource_static_count);
|
||||
auto const sampled_cap = sampled_budget / dynamic_arrays;
|
||||
auto const resource_cap = resource_budget / dynamic_arrays;
|
||||
return (std::max)(1U, (std::min)(sampled_cap, resource_cap));
|
||||
u32 DynamicSampledTextureCap(const Info& info, const HostTranslateInfo& host_info,
|
||||
u32 dynamic_arrays) {
|
||||
if (dynamic_arrays == 0) {
|
||||
return MAX_DYNAMIC_DESCRIPTOR_COUNT;
|
||||
}
|
||||
return (std::min)({DESCRIPTOR_MAX_COUNT, sampled_limit, resource_limit});
|
||||
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) {
|
||||
@@ -295,23 +304,21 @@ static inline bool IsTexturePixelFormatIntegerCached(Environment& env,
|
||||
}
|
||||
|
||||
|
||||
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info);
|
||||
static inline std::optional<ConstBufferAddr> TrackCached(const IR::Value& v, Environment& env, const HostTranslateInfo& host_info) {
|
||||
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env);
|
||||
static inline std::optional<ConstBufferAddr> TrackCached(const IR::Value& v, Environment& env) {
|
||||
if (const IR::Inst* key = v.InstRecursive()) {
|
||||
if (auto it = env.track_cache.find(key); it != env.track_cache.end()) return it->second;
|
||||
auto found = Track(v, env, host_info);
|
||||
auto found = Track(v, env);
|
||||
if (found) env.track_cache.emplace(key, *found);
|
||||
return found;
|
||||
}
|
||||
return Track(v, env, host_info);
|
||||
return Track(v, env);
|
||||
}
|
||||
|
||||
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info);
|
||||
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env);
|
||||
|
||||
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info) {
|
||||
return IR::BreadthFirstSearch(value, [&env, &host_info](const IR::Inst* inst) {
|
||||
return TryGetConstBuffer(inst, env, host_info);
|
||||
});
|
||||
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env) {
|
||||
return IR::BreadthFirstSearch(value, [&env](const IR::Inst* inst) { return TryGetConstBuffer(inst, env); });
|
||||
}
|
||||
|
||||
std::optional<u32> TryGetConstant(IR::Value& value, Environment& env) {
|
||||
@@ -335,13 +342,13 @@ std::optional<u32> TryGetConstant(IR::Value& value, Environment& env) {
|
||||
return ReadCbufCached(env, index_number, offset_number);
|
||||
}
|
||||
|
||||
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info) {
|
||||
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env) {
|
||||
switch (inst->GetOpcode()) {
|
||||
default:
|
||||
return std::nullopt;
|
||||
case IR::Opcode::BitwiseOr32: {
|
||||
std::optional lhs{TrackCached(inst->Arg(0), env, host_info)};
|
||||
std::optional rhs{TrackCached(inst->Arg(1), env, host_info)};
|
||||
std::optional lhs{TrackCached(inst->Arg(0), env)};
|
||||
std::optional rhs{TrackCached(inst->Arg(1), env)};
|
||||
if (!lhs || !rhs) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -371,11 +378,12 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
||||
if (!shift.IsImmediate()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional lhs{TrackCached(inst->Arg(0), env, host_info)};
|
||||
std::optional lhs{TrackCached(inst->Arg(0), env)};
|
||||
if (lhs) {
|
||||
lhs->shift_left = shift.U32();
|
||||
}
|
||||
return lhs;
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::BitwiseAnd32: {
|
||||
IR::Value op1{inst->Arg(0)};
|
||||
@@ -399,7 +407,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
||||
return std::nullopt;
|
||||
} while (false);
|
||||
}
|
||||
std::optional lhs{TrackCached(op1, env, host_info)};
|
||||
std::optional lhs{TrackCached(op1, env)};
|
||||
if (lhs) {
|
||||
lhs->shift_left = static_cast<u32>(std::countr_zero(op2.U32()));
|
||||
}
|
||||
@@ -445,10 +453,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto const size_shift = DynamicDescriptorSizeShift(dynamic_offset);
|
||||
auto const sampled_limit = (std::max)(1U, (std::min)(host_info.max_per_stage_descriptor_sampled_images,
|
||||
host_info.max_descriptor_set_sampled_images));
|
||||
auto const resource_limit = (std::max)(1U, host_info.max_per_stage_resources);
|
||||
const u32 size_shift{DynamicDescriptorSizeShift(dynamic_offset)};
|
||||
return ConstBufferAddr{
|
||||
.index = index.U32(),
|
||||
.offset = base_offset,
|
||||
@@ -457,15 +462,15 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
||||
.secondary_offset = 0,
|
||||
.secondary_shift_left = 0,
|
||||
.dynamic_offset = dynamic_offset,
|
||||
.count = DynamicDescriptorCount(base_offset, size_shift, (std::min)({DESCRIPTOR_MAX_COUNT, sampled_limit, resource_limit})),
|
||||
.count = DynamicDescriptorCount(base_offset, size_shift),
|
||||
.has_secondary = false,
|
||||
};
|
||||
}
|
||||
|
||||
TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst, const HostTranslateInfo& host_info) {
|
||||
TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
|
||||
ConstBufferAddr addr;
|
||||
if (IsBindless(inst)) {
|
||||
const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env, host_info)};
|
||||
const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env)};
|
||||
|
||||
if (!track_addr) {
|
||||
throw NotImplementedException("Failed to track bindless texture constant buffer");
|
||||
@@ -501,15 +506,15 @@ u32 GetTextureHandle(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
return lhs_raw | rhs_raw;
|
||||
}
|
||||
|
||||
[[maybe_unused]] TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
[[maybe_unused]]TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
return env.ReadTextureType(GetTextureHandle(env, cbuf));
|
||||
}
|
||||
|
||||
[[maybe_unused]] TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
[[maybe_unused]]TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
|
||||
}
|
||||
|
||||
[[maybe_unused]] bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
[[maybe_unused]]bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
|
||||
return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf));
|
||||
}
|
||||
|
||||
@@ -670,7 +675,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
||||
if (!IsTextureInstruction(inst)) {
|
||||
continue;
|
||||
}
|
||||
to_replace.push_back(MakeInst(env, block, inst, host_info));
|
||||
to_replace.push_back(MakeInst(env, block, inst));
|
||||
}
|
||||
}
|
||||
// Sort instructions to visit textures by constant buffer index, then by offset
|
||||
@@ -684,7 +689,8 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
||||
program.info.texture_descriptors,
|
||||
program.info.image_descriptors,
|
||||
};
|
||||
const u32 sampled_dynamic_cap = DynamicSampledTextureCap(program.info, host_info, DynamicSampledTextureArrayCount(to_replace));
|
||||
const u32 sampled_dynamic_cap{
|
||||
DynamicSampledTextureCap(program.info, host_info, DynamicSampledTextureArrayCount(to_replace))};
|
||||
for (TextureInst& texture_inst : to_replace) {
|
||||
// TODO: Handle arrays
|
||||
IR::Inst* const inst{texture_inst.inst};
|
||||
|
||||
@@ -92,6 +92,7 @@ struct Profile {
|
||||
bool has_broken_robust{};
|
||||
|
||||
u64 min_ssbo_alignment{};
|
||||
|
||||
u32 max_user_clip_distances{};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -18,19 +15,12 @@ static constexpr auto PERMS = Common::MemoryPermission::ReadWrite;
|
||||
static constexpr auto HEAP = false;
|
||||
|
||||
TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") {
|
||||
{
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
}
|
||||
{
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
}
|
||||
{ HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); }
|
||||
{ HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); }
|
||||
}
|
||||
|
||||
TEST_CASE("HostMemory: Simple map", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x5000, 0x8000, 0x1000, PERMS, HEAP);
|
||||
|
||||
volatile u8* const data = mem.VirtualBasePointer() + 0x5000;
|
||||
@@ -40,7 +30,6 @@ TEST_CASE("HostMemory: Simple map", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Simple mirror map", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP);
|
||||
mem.Map(0x8000, 0x4000, 0x1000, PERMS, HEAP);
|
||||
|
||||
@@ -52,7 +41,6 @@ TEST_CASE("HostMemory: Simple mirror map", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Simple unmap", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP);
|
||||
|
||||
volatile u8* const data = mem.VirtualBasePointer() + 0x5000;
|
||||
@@ -64,7 +52,6 @@ TEST_CASE("HostMemory: Simple unmap", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Simple unmap and remap", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP);
|
||||
|
||||
volatile u8* const data = mem.VirtualBasePointer() + 0x5000;
|
||||
@@ -82,7 +69,6 @@ TEST_CASE("HostMemory: Simple unmap and remap", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Nieche allocation", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x0000, 0, 0x20000, PERMS, HEAP);
|
||||
mem.Unmap(0x0000, 0x4000, HEAP);
|
||||
mem.Map(0x1000, 0, 0x2000, PERMS, HEAP);
|
||||
@@ -92,7 +78,6 @@ TEST_CASE("HostMemory: Nieche allocation", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Full unmap", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Unmap(0x8000, 0x4000, HEAP);
|
||||
mem.Map(0x6000, 0, 0x16000, PERMS, HEAP);
|
||||
@@ -100,7 +85,6 @@ TEST_CASE("HostMemory: Full unmap", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Unmap(0x2000, 0x4000, HEAP);
|
||||
mem.Map(0x2000, 0x80000, 0x4000, PERMS, HEAP);
|
||||
@@ -108,7 +92,6 @@ TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
|
||||
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Unmap(0x6000, 0x4000, HEAP);
|
||||
mem.Map(0x8000, 0, 0x2000, PERMS, HEAP);
|
||||
@@ -116,7 +99,6 @@ TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Map(0x4000, 0, 0x1b000, PERMS, HEAP);
|
||||
mem.Unmap(0x3000, 0x1c000, HEAP);
|
||||
@@ -125,7 +107,6 @@ TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Unmap between placeholders", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Unmap(0x2000, 0x4000, HEAP);
|
||||
@@ -134,7 +115,6 @@ TEST_CASE("HostMemory: Unmap between placeholders", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Unmap to origin", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Unmap(0x4000, 0x4000, HEAP);
|
||||
@@ -144,7 +124,6 @@ TEST_CASE("HostMemory: Unmap to origin", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Unmap to right", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||
mem.Unmap(0x8000, 0x4000, HEAP);
|
||||
@@ -153,7 +132,6 @@ TEST_CASE("HostMemory: Unmap to right", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x4000, 0x10000, 0x4000, PERMS, HEAP);
|
||||
|
||||
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
|
||||
@@ -166,7 +144,6 @@ TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x4000, 0x10000, 0x4000, PERMS, HEAP);
|
||||
|
||||
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
|
||||
@@ -181,7 +158,6 @@ TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x4000, 0x10000, 0x4000, PERMS, HEAP);
|
||||
|
||||
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
|
||||
@@ -196,7 +172,6 @@ TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") {
|
||||
|
||||
TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common]") {
|
||||
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||
mem.Map(0x4000, 0x10000, 0x2000, PERMS, HEAP);
|
||||
mem.Map(0x6000, 0x20000, 0x2000, PERMS, HEAP);
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||
#define END_PUSH_CONSTANTS };
|
||||
#define UNIFORM(n)
|
||||
#define BINDING_INPUT_BUFFER 0
|
||||
#define BINDING_OUTPUT_IMAGE 1
|
||||
#define BINDING_SWIZZLE_BUFFER 0
|
||||
#define BINDING_INPUT_BUFFER 1
|
||||
#define BINDING_OUTPUT_IMAGE 2
|
||||
|
||||
#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
|
||||
|
||||
@@ -25,7 +26,8 @@
|
||||
#define BEGIN_PUSH_CONSTANTS
|
||||
#define END_PUSH_CONSTANTS
|
||||
#define UNIFORM(n) layout (location = n) uniform
|
||||
#define BINDING_INPUT_BUFFER 0
|
||||
#define BINDING_SWIZZLE_BUFFER 0
|
||||
#define BINDING_INPUT_BUFFER 1
|
||||
#define BINDING_OUTPUT_IMAGE 0
|
||||
|
||||
#endif
|
||||
@@ -41,6 +43,10 @@ UNIFORM(6) uint block_height;
|
||||
UNIFORM(7) uint block_height_mask;
|
||||
END_PUSH_CONSTANTS
|
||||
|
||||
layout(binding = BINDING_SWIZZLE_BUFFER, std430) readonly buffer SwizzleTable {
|
||||
uint swizzle_table[];
|
||||
};
|
||||
|
||||
#if HAS_EXTENDED_TYPES
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU8 { uint8_t u8data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU16 { uint16_t u16data[]; };
|
||||
@@ -65,19 +71,9 @@ const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHI
|
||||
|
||||
const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1, GOB_SIZE_Y - 1);
|
||||
|
||||
uint SwizzleTable(uint pos) {
|
||||
const uint t[8] = uint[](
|
||||
0x12100200, 0x13110301, 0x16140604, 0x17150705,
|
||||
0x1a180a08, 0x1b190b09, 0x1e1c0e0c, 0x1f1d0f0d
|
||||
);
|
||||
const uint i = pos >> 4;
|
||||
const uint h = (t[i / 4] >> ((i % 4) * 8)) & 0xff;
|
||||
return (h << 4) | (pos & 0xf);
|
||||
}
|
||||
|
||||
uint SwizzleOffset(uvec2 pos) {
|
||||
pos = pos & SWIZZLE_MASK;
|
||||
return SwizzleTable(pos.y * 64 + pos.x);
|
||||
return swizzle_table[pos.y * 64 + pos.x];
|
||||
}
|
||||
|
||||
uvec4 ReadTexel(uint offset) {
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||
#define END_PUSH_CONSTANTS };
|
||||
#define UNIFORM(n)
|
||||
#define BINDING_INPUT_BUFFER 0
|
||||
#define BINDING_OUTPUT_IMAGE 1
|
||||
#define BINDING_SWIZZLE_BUFFER 0
|
||||
#define BINDING_INPUT_BUFFER 1
|
||||
#define BINDING_OUTPUT_IMAGE 2
|
||||
|
||||
#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
|
||||
|
||||
@@ -25,7 +26,8 @@
|
||||
#define BEGIN_PUSH_CONSTANTS
|
||||
#define END_PUSH_CONSTANTS
|
||||
#define UNIFORM(n) layout (location = n) uniform
|
||||
#define BINDING_INPUT_BUFFER 0
|
||||
#define BINDING_SWIZZLE_BUFFER 0
|
||||
#define BINDING_INPUT_BUFFER 1
|
||||
#define BINDING_OUTPUT_IMAGE 0
|
||||
|
||||
#endif
|
||||
@@ -43,6 +45,10 @@ UNIFORM(8) uint block_depth;
|
||||
UNIFORM(9) uint block_depth_mask;
|
||||
END_PUSH_CONSTANTS
|
||||
|
||||
layout(binding = BINDING_SWIZZLE_BUFFER, std430) readonly buffer SwizzleTable {
|
||||
uint swizzle_table[];
|
||||
};
|
||||
|
||||
#if HAS_EXTENDED_TYPES
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU8 { uint8_t u8data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU16 { uint16_t u16data[]; };
|
||||
@@ -67,19 +73,9 @@ const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHI
|
||||
|
||||
const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1, GOB_SIZE_Y - 1);
|
||||
|
||||
uint SwizzleTable(uint pos) {
|
||||
const uint t[8] = uint[](
|
||||
0x12100200, 0x13110301, 0x16140604, 0x17150705,
|
||||
0x1a180a08, 0x1b190b09, 0x1e1c0e0c, 0x1f1d0f0d
|
||||
);
|
||||
const uint i = pos >> 4;
|
||||
const uint h = (t[i / 4] >> ((i % 4) * 8)) & 0xff;
|
||||
return (h << 4) | (pos & 0xf);
|
||||
}
|
||||
|
||||
uint SwizzleOffset(uvec2 pos) {
|
||||
pos = pos & SWIZZLE_MASK;
|
||||
return SwizzleTable(pos.y * 64 + pos.x);
|
||||
return swizzle_table[pos.y * 64 + pos.x];
|
||||
}
|
||||
|
||||
uvec4 ReadTexel(uint offset) {
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||
#define END_PUSH_CONSTANTS };
|
||||
#define UNIFORM(n)
|
||||
#define BINDING_INPUT_BUFFER 0
|
||||
#define BINDING_OUTPUT_BUFFER 1
|
||||
#define BINDING_SWIZZLE_BUFFER 0
|
||||
#define BINDING_INPUT_BUFFER 1
|
||||
#define BINDING_OUTPUT_BUFFER 2
|
||||
#else
|
||||
#extension GL_NV_gpu_shader5 : enable
|
||||
#ifdef GL_NV_gpu_shader5
|
||||
@@ -22,6 +23,7 @@
|
||||
#define BEGIN_PUSH_CONSTANTS
|
||||
#define END_PUSH_CONSTANTS
|
||||
#define UNIFORM(n) layout(location = n) uniform
|
||||
#define BINDING_SWIZZLE_BUFFER 0
|
||||
#define BINDING_INPUT_BUFFER 1
|
||||
#define BINDING_OUTPUT_BUFFER 0
|
||||
#endif
|
||||
@@ -64,9 +66,13 @@ END_PUSH_CONSTANTS
|
||||
#endif
|
||||
|
||||
// --- Buffers ---
|
||||
layout(binding = BINDING_SWIZZLE_BUFFER, std430) readonly buffer SwizzleTable {
|
||||
uint swizzle_table[];
|
||||
};
|
||||
|
||||
#if HAS_EXTENDED_TYPES
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU8 { uint8_t u8data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU16 { uint16_t u16data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU8 { uint8_t u8data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU16 { uint16_t u16data[]; };
|
||||
#endif
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU32 { uint u32data[]; };
|
||||
layout(binding = BINDING_INPUT_BUFFER, std430) buffer InputBufferU64 { uvec2 u64data[]; };
|
||||
@@ -90,20 +96,10 @@ const uint GOB_SIZE_Z_SHIFT = 0;
|
||||
const uint GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHIFT;
|
||||
const uvec2 SWIZZLE_MASK = uvec2(GOB_SIZE_X - 1u, GOB_SIZE_Y - 1u);
|
||||
|
||||
uint SwizzleTable(uint pos) {
|
||||
const uint t[8] = uint[](
|
||||
0x12100200, 0x13110301, 0x16140604, 0x17150705,
|
||||
0x1a180a08, 0x1b190b09, 0x1e1c0e0c, 0x1f1d0f0d
|
||||
);
|
||||
const uint i = pos >> 4;
|
||||
const uint h = (t[i / 4] >> ((i % 4) * 8)) & 0xff;
|
||||
return (h << 4) | (pos & 0xf);
|
||||
}
|
||||
|
||||
// --- Helpers ---
|
||||
uint SwizzleOffset(uvec2 pos) {
|
||||
pos &= SWIZZLE_MASK;
|
||||
return SwizzleTable(pos.y * 64u + pos.x);
|
||||
return swizzle_table[pos.y * 64u + pos.x];
|
||||
}
|
||||
|
||||
uvec4 ReadTexel(uint offset) {
|
||||
|
||||
@@ -54,7 +54,7 @@ using VideoCommon::LoadPipelines;
|
||||
using VideoCommon::SerializePipeline;
|
||||
using Context = ShaderContext::Context;
|
||||
|
||||
constexpr u32 CACHE_VERSION = 15;
|
||||
constexpr u32 CACHE_VERSION = 16;
|
||||
|
||||
template <typename Container>
|
||||
auto MakeSpan(Container& container) {
|
||||
@@ -245,31 +245,16 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
std::min<u32>(device.GetMaxUserClipDistances(), Maxwell::Regs::NumClipDistances),
|
||||
},
|
||||
host_info{
|
||||
.min_ssbo_alignment = static_cast<u32>(device.GetShaderStorageBufferAlignment()),
|
||||
.max_per_stage_descriptor_sampled_images =
|
||||
Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.max_per_stage_resources = Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.max_descriptor_set_samplers = Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.max_descriptor_set_uniform_buffers = Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.max_descriptor_set_uniform_buffers_dynamic =
|
||||
Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.max_descriptor_set_storage_buffers = Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.max_descriptor_set_storage_buffers_dynamic =
|
||||
Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.max_descriptor_set_sampled_images = Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.max_descriptor_set_storage_images = Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.max_descriptor_set_input_attachements =
|
||||
Shader::HostTranslateInfo::DEFAULT_DESCRIPTOR_LIMIT,
|
||||
.support_float64 = true,
|
||||
.support_float16 = false,
|
||||
.support_int64 = device.HasShaderInt64(),
|
||||
.needs_demote_reorder = device.IsAmd(),
|
||||
.support_snorm_render_buffer = false,
|
||||
.support_viewport_index_layer = device.HasVertexViewportLayer(),
|
||||
.support_geometry_shader_passthrough = device.HasGeometryShaderPassthrough(),
|
||||
.support_conditional_barrier = device.SupportsConditionalBarriers(),
|
||||
.support_float64 = true,
|
||||
.support_float16 = false,
|
||||
.support_int64 = device.HasShaderInt64(),
|
||||
.needs_demote_reorder = device.IsAmd(),
|
||||
.support_snorm_render_buffer = false,
|
||||
.support_viewport_index_layer = device.HasVertexViewportLayer(),
|
||||
.min_ssbo_alignment = static_cast<u32>(device.GetShaderStorageBufferAlignment()),
|
||||
.support_geometry_shader_passthrough = device.HasGeometryShaderPassthrough(),
|
||||
.support_conditional_barrier = device.SupportsConditionalBarriers(),
|
||||
} {
|
||||
host_info.ApplyDescriptorLimitPolicy();
|
||||
if (use_asynchronous_shaders) {
|
||||
workers = CreateWorkers();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -59,8 +56,10 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
|
||||
copy_bc4_program(MakeProgram(OPENGL_COPY_BC4_COMP)),
|
||||
convert_s8d24_program(MakeProgram(OPENGL_CONVERT_S8D24_COMP)),
|
||||
convert_ms_to_nonms_program(MakeProgram(CONVERT_MSAA_TO_NON_MSAA_COMP)),
|
||||
convert_nonms_to_ms_program(MakeProgram(CONVERT_NON_MSAA_TO_MSAA_COMP))
|
||||
{
|
||||
convert_nonms_to_ms_program(MakeProgram(CONVERT_NON_MSAA_TO_MSAA_COMP)) {
|
||||
const auto swizzle_table = Tegra::Texture::MakeSwizzleTable();
|
||||
swizzle_table_buffer.Create();
|
||||
glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
|
||||
}
|
||||
|
||||
UtilShaders::~UtilShaders() = default;
|
||||
@@ -117,11 +116,13 @@ void UtilShaders::ASTCDecode(Image& image, const StagingBufferMap& map,
|
||||
void UtilShaders::BlockLinearUpload2D(Image& image, const StagingBufferMap& map,
|
||||
std::span<const SwizzleParameters> swizzles) {
|
||||
static constexpr Extent3D WORKGROUP_SIZE{32, 32, 1};
|
||||
static constexpr GLuint BINDING_INPUT_BUFFER = 0;
|
||||
static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0;
|
||||
static constexpr GLuint BINDING_INPUT_BUFFER = 1;
|
||||
static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
|
||||
|
||||
program_manager.BindComputeProgram(block_linear_unswizzle_2d_program.handle);
|
||||
glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
|
||||
|
||||
const GLenum store_format = StoreFormat(BytesPerBlock(image.info.format));
|
||||
for (const SwizzleParameters& swizzle : swizzles) {
|
||||
@@ -152,11 +153,14 @@ void UtilShaders::BlockLinearUpload2D(Image& image, const StagingBufferMap& map,
|
||||
void UtilShaders::BlockLinearUpload3D(Image& image, const StagingBufferMap& map,
|
||||
std::span<const SwizzleParameters> swizzles) {
|
||||
static constexpr Extent3D WORKGROUP_SIZE{16, 8, 8};
|
||||
static constexpr GLuint BINDING_INPUT_BUFFER = 0;
|
||||
|
||||
static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0;
|
||||
static constexpr GLuint BINDING_INPUT_BUFFER = 1;
|
||||
static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
|
||||
|
||||
glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
|
||||
program_manager.BindComputeProgram(block_linear_unswizzle_3d_program.handle);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
|
||||
|
||||
const GLenum store_format = StoreFormat(BytesPerBlock(image.info.format));
|
||||
for (const SwizzleParameters& swizzle : swizzles) {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -48,6 +45,9 @@ public:
|
||||
|
||||
private:
|
||||
ProgramManager& program_manager;
|
||||
|
||||
OGLBuffer swizzle_table_buffer;
|
||||
|
||||
OGLProgram astc_decoder_program;
|
||||
OGLProgram block_linear_unswizzle_2d_program;
|
||||
OGLProgram block_linear_unswizzle_3d_program;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user