From bb8dde848078280c627af16152885e25ad8674fc Mon Sep 17 00:00:00 2001 From: Steveice10 <1269164+Steveice10@users.noreply.github.com> Date: Thu, 16 Feb 2023 05:35:17 -0800 Subject: [PATCH 1/6] aes: Fix derivation of slot 0x25 key X from NATIVE_FIRM. (#6283) --- src/core/hw/aes/key.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hw/aes/key.cpp b/src/core/hw/aes/key.cpp index 8fdb7f514..0cf2a217d 100644 --- a/src/core/hw/aes/key.cpp +++ b/src/core/hw/aes/key.cpp @@ -233,7 +233,7 @@ void LoadNativeFirmKeysOld3DS() { firm->Read(0, firm_buffer.size(), firm_buffer.data()); firm->Close(); - constexpr std::size_t SLOT_0x25_KEY_X_SECRET_OFFSET = 933480; + constexpr std::size_t SLOT_0x25_KEY_X_SECRET_OFFSET = 934444; constexpr std::size_t SLOT_0x25_KEY_X_SECRET_SIZE = 64; std::vector secret_data(SLOT_0x25_KEY_X_SECRET_SIZE); std::memcpy(secret_data.data(), firm_buffer.data() + SLOT_0x25_KEY_X_SECRET_OFFSET, From 9eb1cd28752223e0ed4434dc3ed0cd81d70f8f0c Mon Sep 17 00:00:00 2001 From: komasanzura <29124334+komasanzura@users.noreply.github.com> Date: Fri, 17 Feb 2023 09:19:52 -0500 Subject: [PATCH 2/6] Added an option to set the proportion of the screens when using layout "Large Screen Small Screen", to allow the user to define how much bigger the large screen should be with respect to the smaller screen. Currently the value must be between 1 and 16, but I could set a different maximum value if that would be desired. Thank you very much! (#6252) --- src/citra/config.cpp | 2 + src/citra/default_ini.h | 4 ++ src/citra_qt/configuration/config.cpp | 2 + .../configuration/configure_enhancements.cpp | 2 + .../configuration/configure_enhancements.ui | 25 ++++++++ src/common/settings.cpp | 2 + src/common/settings.h | 2 + src/core/frontend/emu_window.cpp | 3 +- src/core/frontend/framebuffer_layout.cpp | 57 +++++++++++++------ src/core/frontend/framebuffer_layout.h | 4 +- 10 files changed, 83 insertions(+), 20 deletions(-) diff --git a/src/citra/config.cpp b/src/citra/config.cpp index cf8a1e01e..f8447713a 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -160,6 +160,8 @@ void Config::ReadValues() { static_cast(sdl2_config->GetInteger("Layout", "layout_option", 0)); Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false); Settings::values.upright_screen = sdl2_config->GetBoolean("Layout", "upright_screen", false); + Settings::values.large_screen_proportion = + sdl2_config->GetReal("Layout", "large_screen_proportion", 4.0); Settings::values.custom_layout = sdl2_config->GetBoolean("Layout", "custom_layout", false); Settings::values.custom_top_left = static_cast(sdl2_config->GetInteger("Layout", "custom_top_left", 0)); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 9cc72ba09..19f57afb8 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -216,6 +216,10 @@ swap_screen = # 0 (default): Off, 1: On upright_screen = +# The proportion between the large and small screens when playing in Large Screen Small Screen layout. +# Must be a real value between 1.0 and 16.0. Default is 4 +large_screen_proportion = + # Dumps textures as PNG to dump/textures/[Title ID]/. # 0 (default): Off, 1: On dump_textures = diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index bfccdbe18..d611d3306 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -485,6 +485,7 @@ void Config::ReadLayoutValues() { ReadGlobalSetting(Settings::values.layout_option); ReadGlobalSetting(Settings::values.swap_screen); ReadGlobalSetting(Settings::values.upright_screen); + ReadGlobalSetting(Settings::values.large_screen_proportion); if (global) { ReadBasicSetting(Settings::values.mono_render_option); @@ -996,6 +997,7 @@ void Config::SaveLayoutValues() { WriteGlobalSetting(Settings::values.layout_option); WriteGlobalSetting(Settings::values.swap_screen); WriteGlobalSetting(Settings::values.upright_screen); + WriteGlobalSetting(Settings::values.large_screen_proportion); if (global) { WriteBasicSetting(Settings::values.mono_render_option); diff --git a/src/citra_qt/configuration/configure_enhancements.cpp b/src/citra_qt/configuration/configure_enhancements.cpp index f48612d34..1c2d6b993 100644 --- a/src/citra_qt/configuration/configure_enhancements.cpp +++ b/src/citra_qt/configuration/configure_enhancements.cpp @@ -69,6 +69,7 @@ void ConfigureEnhancements::SetConfiguration() { static_cast(Settings::values.layout_option.GetValue())); ui->swap_screen->setChecked(Settings::values.swap_screen.GetValue()); ui->upright_screen->setChecked(Settings::values.upright_screen.GetValue()); + ui->large_screen_proportion->setValue(Settings::values.large_screen_proportion.GetValue()); ui->toggle_dump_textures->setChecked(Settings::values.dump_textures.GetValue()); ui->toggle_custom_textures->setChecked(Settings::values.custom_textures.GetValue()); ui->toggle_preload_textures->setChecked(Settings::values.preload_textures.GetValue()); @@ -122,6 +123,7 @@ void ConfigureEnhancements::ApplyConfiguration() { static_cast(ui->layout_combobox->currentIndex()); Settings::values.swap_screen = ui->swap_screen->isChecked(); Settings::values.upright_screen = ui->upright_screen->isChecked(); + Settings::values.large_screen_proportion = ui->large_screen_proportion->value(); Settings::values.dump_textures = ui->toggle_dump_textures->isChecked(); Settings::values.custom_textures = ui->toggle_custom_textures->isChecked(); Settings::values.preload_textures = ui->toggle_preload_textures->isChecked(); diff --git a/src/citra_qt/configuration/configure_enhancements.ui b/src/citra_qt/configuration/configure_enhancements.ui index 0d4ed0161..d8b31af86 100644 --- a/src/citra_qt/configuration/configure_enhancements.ui +++ b/src/citra_qt/configuration/configure_enhancements.ui @@ -295,6 +295,30 @@ + + + + + + Large Screen Proportion: + + + + + + + 1 + + + 16 + + + 4 + + + + + @@ -384,6 +408,7 @@ layout_combobox swap_screen upright_screen + large_screen_proportion bg_button toggle_custom_textures toggle_dump_textures diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 44627a6b7..8e3143dbe 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -113,6 +113,7 @@ void LogSettings() { log_setting("Layout_LayoutOption", values.layout_option.GetValue()); log_setting("Layout_SwapScreen", values.swap_screen.GetValue()); log_setting("Layout_UprightScreen", values.upright_screen.GetValue()); + log_setting("Layout_LargeScreenProportion", values.large_screen_proportion.GetValue()); log_setting("Utility_DumpTextures", values.dump_textures.GetValue()); log_setting("Utility_CustomTextures", values.custom_textures.GetValue()); log_setting("Utility_UseDiskShaderCache", values.use_disk_shader_cache.GetValue()); @@ -189,6 +190,7 @@ void RestoreGlobalState(bool is_powered_on) { values.layout_option.SetGlobal(true); values.swap_screen.SetGlobal(true); values.upright_screen.SetGlobal(true); + values.large_screen_proportion.SetGlobal(true); values.bg_red.SetGlobal(true); values.bg_green.SetGlobal(true); values.bg_blue.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index a29123af1..98579cff7 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -455,6 +455,8 @@ struct Values { SwitchableSetting layout_option{LayoutOption::Default, "layout_option"}; SwitchableSetting swap_screen{false, "swap_screen"}; SwitchableSetting upright_screen{false, "upright_screen"}; + SwitchableSetting large_screen_proportion{4.f, 1.f, 16.f, + "large_screen_proportion"}; Setting custom_layout{false, "custom_layout"}; Setting custom_top_left{0, "custom_top_left"}; Setting custom_top_top{0, "custom_top_top"}; diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index acb81fdaa..2b37a2494 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -197,7 +197,8 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height, case Settings::LayoutOption::LargeScreen: layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue()); + Settings::values.upright_screen.GetValue(), + Settings::values.large_screen_proportion.GetValue()); break; case Settings::LayoutOption::SideScreen: layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen.GetValue(), diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 75f330f18..092812053 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -231,7 +231,8 @@ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped, bool up return res; } -FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upright) { +FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upright, + float scale_factor) { ASSERT(width > 0); ASSERT(height > 0); @@ -244,25 +245,29 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr float small_screen_aspect_ratio; if (upright) { if (swapped) { - emulation_aspect_ratio = (Core::kScreenBottomWidth * 4.0f + Core::kScreenTopWidth) / - (Core::kScreenBottomHeight * 4); + emulation_aspect_ratio = + (Core::kScreenBottomWidth * scale_factor + Core::kScreenTopWidth) / + (Core::kScreenBottomHeight * scale_factor); large_screen_aspect_ratio = BOT_SCREEN_UPRIGHT_ASPECT_RATIO; small_screen_aspect_ratio = TOP_SCREEN_UPRIGHT_ASPECT_RATIO; } else { - emulation_aspect_ratio = (Core::kScreenTopWidth * 4.0f + Core::kScreenBottomWidth) / - (Core::kScreenTopHeight * 4); + emulation_aspect_ratio = + (Core::kScreenTopWidth * scale_factor + Core::kScreenBottomWidth) / + (Core::kScreenTopHeight * scale_factor); large_screen_aspect_ratio = TOP_SCREEN_UPRIGHT_ASPECT_RATIO; small_screen_aspect_ratio = BOT_SCREEN_UPRIGHT_ASPECT_RATIO; } } else { if (swapped) { - emulation_aspect_ratio = Core::kScreenBottomHeight * 4 / - (Core::kScreenBottomWidth * 4.0f + Core::kScreenTopWidth); + emulation_aspect_ratio = + Core::kScreenBottomHeight * scale_factor / + (Core::kScreenBottomWidth * scale_factor + Core::kScreenTopWidth); large_screen_aspect_ratio = BOT_SCREEN_ASPECT_RATIO; small_screen_aspect_ratio = TOP_SCREEN_ASPECT_RATIO; } else { - emulation_aspect_ratio = Core::kScreenTopHeight * 4 / - (Core::kScreenTopWidth * 4.0f + Core::kScreenBottomWidth); + emulation_aspect_ratio = + Core::kScreenTopHeight * scale_factor / + (Core::kScreenTopWidth * scale_factor + Core::kScreenBottomWidth); large_screen_aspect_ratio = TOP_SCREEN_ASPECT_RATIO; small_screen_aspect_ratio = BOT_SCREEN_ASPECT_RATIO; } @@ -271,7 +276,7 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr Common::Rectangle screen_window_area{0, 0, width, height}; Common::Rectangle total_rect = maxRectangle(screen_window_area, emulation_aspect_ratio); Common::Rectangle large_screen = maxRectangle(total_rect, large_screen_aspect_ratio); - Common::Rectangle fourth_size_rect = total_rect.Scale(.25f); + Common::Rectangle fourth_size_rect = total_rect.Scale(1.f / scale_factor); Common::Rectangle small_screen = maxRectangle(fourth_size_rect, small_screen_aspect_ratio); if (window_aspect_ratio < emulation_aspect_ratio) { @@ -416,22 +421,35 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondar if (Settings::values.upright_screen.GetValue()) { if (Settings::values.swap_screen.GetValue()) { width = Core::kScreenBottomHeight * res_scale; - height = (Core::kScreenBottomWidth + Core::kScreenTopWidth / 4) * res_scale; + height = (Core::kScreenBottomWidth + + Core::kScreenTopWidth / + Settings::values.large_screen_proportion.GetValue()) * + res_scale; } else { width = Core::kScreenTopHeight * res_scale; - height = (Core::kScreenTopWidth + Core::kScreenBottomWidth / 4) * res_scale; + height = (Core::kScreenTopWidth + + Core::kScreenBottomWidth / + Settings::values.large_screen_proportion.GetValue()) * + res_scale; } } else { if (Settings::values.swap_screen.GetValue()) { - width = (Core::kScreenBottomWidth + Core::kScreenTopWidth / 4) * res_scale; + width = (Core::kScreenBottomWidth + + Core::kScreenTopWidth / + Settings::values.large_screen_proportion.GetValue()) * + res_scale; height = Core::kScreenBottomHeight * res_scale; } else { - width = (Core::kScreenTopWidth + Core::kScreenBottomWidth / 4) * res_scale; + width = (Core::kScreenTopWidth + + Core::kScreenBottomWidth / + Settings::values.large_screen_proportion.GetValue()) * + res_scale; height = Core::kScreenTopHeight * res_scale; } } layout = LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue()); + Settings::values.upright_screen.GetValue(), + Settings::values.large_screen_proportion.GetValue()); break; case Settings::LayoutOption::SideScreen: if (Settings::values.upright_screen.GetValue()) { @@ -576,9 +594,12 @@ std::pair GetMinimumSizeFromLayout(Settings::LayoutOption la min_height = Core::kScreenBottomHeight; break; case Settings::LayoutOption::LargeScreen: - min_width = Settings::values.swap_screen - ? Core::kScreenTopWidth / 4 + Core::kScreenBottomWidth - : Core::kScreenTopWidth + Core::kScreenBottomWidth / 4; + min_width = + Settings::values.swap_screen + ? Core::kScreenTopWidth / Settings::values.large_screen_proportion.GetValue() + + Core::kScreenBottomWidth + : Core::kScreenTopWidth + Core::kScreenBottomWidth / + Settings::values.large_screen_proportion.GetValue(); min_height = Core::kScreenBottomHeight; break; case Settings::LayoutOption::SideScreen: diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 763262663..36a983ee3 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -83,9 +83,11 @@ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool is_swapped, bool * @param width Window framebuffer width in pixels * @param height Window framebuffer height in pixels * @param is_swapped if true, the bottom screen will be the large display + * @param scale_factor The ratio between the large screen with respect to the smaller screen * @return Newly created FramebufferLayout object with default screen regions initialized */ -FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool is_swapped, bool upright); +FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool is_swapped, bool upright, + float scale_factor); /** * Factory method for constructing a Frame with the Top screen and bottom From bf73cb57caec9d910231684bd225afe6bccd2929 Mon Sep 17 00:00:00 2001 From: Steveice10 <1269164+Steveice10@users.noreply.github.com> Date: Fri, 17 Feb 2023 06:20:56 -0800 Subject: [PATCH 3/6] am: Return installed titles in GetNumTickets and GetTicketList stubs. (#6292) --- src/core/hle/service/am/am.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 4578ffc23..af4532b75 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1087,7 +1087,11 @@ void Module::Interface::DeleteTicket(Kernel::HLERequestContext& ctx) { void Module::Interface::GetNumTickets(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0008, 0, 0); // 0x00080000 + u32 ticket_count = 0; + for (const auto& title_list : am->am_title_list) { + ticket_count += static_cast(title_list.size()); + } IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); @@ -1101,9 +1105,18 @@ void Module::Interface::GetTicketList(Kernel::HLERequestContext& ctx) { u32 ticket_index = rp.Pop(); auto& ticket_tids_out = rp.PopMappedBuffer(); + u32 tickets_written = 0; + for (const auto& title_list : am->am_title_list) { + const auto tickets_to_write = + std::min(static_cast(title_list.size()), ticket_list_count - tickets_written); + ticket_tids_out.Write(title_list.data(), tickets_written * sizeof(u64), + tickets_to_write * sizeof(u64)); + tickets_written += tickets_to_write; + } + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); rb.Push(RESULT_SUCCESS); - rb.Push(ticket_list_count); + rb.Push(tickets_written); rb.PushMappedBuffer(ticket_tids_out); LOG_WARNING(Service_AM, "(STUBBED) ticket_list_count=0x{:08x}, ticket_index=0x{:08x}", ticket_list_count, ticket_index); From cda358443fa632b5e27dbe6272882d33d68bb529 Mon Sep 17 00:00:00 2001 From: Steveice10 <1269164+Steveice10@users.noreply.github.com> Date: Fri, 17 Feb 2023 10:30:47 -0800 Subject: [PATCH 4/6] nim: Fully stub nim:u service. (#6290) --- src/core/hle/service/nim/nim_u.cpp | 733 ++++++++++++++++++++++++++++- src/core/hle/service/nim/nim_u.h | 508 +++++++++++++++++++- 2 files changed, 1215 insertions(+), 26 deletions(-) diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp index b44ef3539..7a677aa85 100644 --- a/src/core/hle/service/nim/nim_u.cpp +++ b/src/core/hle/service/nim/nim_u.cpp @@ -3,9 +3,9 @@ // Refer to the license.txt file included. #include "common/archives.h" +#include "common/string_util.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" #include "core/hle/service/nim/nim_u.h" SERVICE_CONSTRUCT_IMPL(Service::NIM::NIM_U) @@ -13,37 +13,736 @@ SERIALIZE_EXPORT_IMPL(Service::NIM::NIM_U) namespace Service::NIM { +enum class SystemUpdateState : u32 { + NotInitialized, + StartingSystemUpdate, + FetchingHashAndAccountStatus, + InstallingNewTickets, + InstallingTitles, + UpdateComplete, + SystemUpdatesDisabled, + Unknown7, + Unknown8, +}; + +struct SystemUpdateProgress { + SystemUpdateState state; + u32 last_operation_result; + u64 current_title_downloaded_bytes; + u64 current_title_total_bytes; + u64 titles_downloaded; + u64 titles_total; +}; + +static_assert(sizeof(SystemUpdateProgress) == 0x28, "SystemUpdateProgress structure size is wrong"); + +enum class TitleDownloadState : u32 { + NotInitialized, + StartingTitleDownload, + InstallingTmd, + CommittingTmd, + InstallingContents, + ContentsInstalled, + CommittingTitles, + Finished, + Unknown8, + Unknown9, + BackgroundDownloadFailed, +}; + +struct TitleDownloadProgress { + TitleDownloadState state; + u32 last_operation_result; + u64 downloaded_bytes; + u64 total_bytes; +}; + +static_assert(sizeof(TitleDownloadProgress) == 0x18, + "TitleDownloadProgress structure size is wrong"); + +struct TitleDownloadConfig { + u64 title_id; + u32 title_version; + u32 unknown_1; + u8 age_rating; + u8 media_type; + INSERT_PADDING_BYTES(2); + u32 unknown_2; +}; + +static_assert(sizeof(TitleDownloadConfig) == 0x18, "TitleDownloadConfig structure size is wrong"); + +#pragma pack(1) +struct BackgroundTitleDownloadConfig { + TitleDownloadConfig base_config; + u8 unknown_1; + u8 unknown_2; + INSERT_PADDING_BYTES(6); + u64 requester_title_id; + std::array title_name; + u16 title_name_terminator; + std::array developer_name; + u16 developer_name_terminator; +}; + +static_assert(sizeof(BackgroundTitleDownloadConfig) == 0x104, + "BackgroundTitleDownloadConfig structure size is wrong"); + +struct BackgroundTitleDownloadTaskInfo { + BackgroundTitleDownloadConfig config; + INSERT_PADDING_BYTES(4); + TitleDownloadProgress progress; +}; + +static_assert(sizeof(BackgroundTitleDownloadTaskInfo) == 0x120, + "BackgroundTitleDownloadTaskInfo structure size is wrong"); + +struct AutoTitleDownloadTaskInfo { + u64 task_id; + u64 title_id; + u32 title_version; + u8 unknown_4[0x14]; + u64 required_size; + u32 last_operation_result_code; + u32 last_operation_customer_support_code; + std::array title_name; + u16 title_name_terminator; + std::array developer_name; + u16 developer_name_terminator; + u8 unknown_5[0x24]; +}; + +static_assert(sizeof(AutoTitleDownloadTaskInfo) == 0x138, + "AutoTitleDownloadTaskInfo structure size is wrong"); + +struct AutoDbgDat { + u8 unknown_1[0x4]; + u32 num_auto_download_tasks; + u8 unknown_2[0x100]; +}; + +static_assert(sizeof(AutoDbgDat) == 0x108, "AutoDbgDat structure size is wrong"); + NIM_U::NIM_U(Core::System& system) : ServiceFramework("nim:u", 2) { const FunctionInfo functions[] = { - {0x00010000, nullptr, "StartSysUpdate"}, - {0x00020000, nullptr, "GetUpdateDownloadProgress"}, - {0x00040000, nullptr, "FinishTitlesInstall"}, - {0x00050000, &NIM_U::CheckForSysUpdateEvent, "CheckForSysUpdateEvent"}, - {0x00090000, &NIM_U::CheckSysUpdateAvailable, "CheckSysUpdateAvailable"}, - {0x000A0000, nullptr, "GetState"}, - {0x000B0000, nullptr, "GetSystemTitleHash"}, + {0x00010000, &NIM_U::StartNetworkUpdate, "StartNetworkUpdate"}, + {0x00020000, &NIM_U::GetProgress, "GetProgress"}, + {0x00030000, &NIM_U::Cancel, "Cancel"}, + {0x00040000, &NIM_U::CommitSystemTitles, "CommitSystemTitles"}, + {0x00050000, &NIM_U::GetBackgroundEventForMenu, "GetBackgroundEventForMenu"}, + {0x00060000, &NIM_U::GetBackgroundEventForNews, "GetBackgroundEventForNews"}, + {0x00070000, &NIM_U::FormatSaveData, "FormatSaveData"}, + {0x00080000, &NIM_U::GetCustomerSupportCode, "GetCustomerSupportCode"}, + {0x00090000, &NIM_U::IsCommittableAllSystemTitles, "IsCommittableAllSystemTitles"}, + {0x000A0000, &NIM_U::GetBackgroundProgress, "GetBackgroundProgress"}, + {0x000B0000, &NIM_U::GetSavedHash, "GetSavedHash"}, + {0x000C0082, &NIM_U::UnregisterTask, "UnregisterTask"}, + {0x000D0080, &NIM_U::IsRegistered, "IsRegistered"}, + {0x000E0080, &NIM_U::FindTaskInfo, "FindTaskInfo"}, + {0x000F0042, &NIM_U::GetTaskInfos, "GetTaskInfos"}, + {0x00100000, &NIM_U::DeleteUnmanagedContexts, "DeleteUnmanagedContexts"}, + {0x00110000, &NIM_U::UpdateAutoTitleDownloadTasksAsync, + "UpdateAutoTitleDownloadTasksAsync"}, + {0x00120000, &NIM_U::StartPendingAutoTitleDownloadTasksAsync, + "StartPendingAutoTitleDownloadTasksAsync"}, + {0x00130000, &NIM_U::GetAsyncResult, "GetAsyncResult"}, + {0x00140000, &NIM_U::CancelAsyncCall, "CancelAsyncCall"}, + {0x00150000, &NIM_U::IsPendingAutoTitleDownloadTasks, "IsPendingAutoTitleDownloadTasks"}, + {0x00160000, &NIM_U::GetNumAutoTitleDownloadTasks, "GetNumAutoTitleDownloadTasks"}, + {0x00170042, &NIM_U::GetAutoTitleDownloadTaskInfos, "GetAutoTitleDownloadTaskInfos"}, + {0x00180080, &NIM_U::CancelAutoTitleDownloadTask, "CancelAutoTitleDownloadTask"}, + {0x00190002, &NIM_U::SetAutoDbgDat, "SetAutoDbgDat"}, + {0x001A0002, &NIM_U::GetAutoDbgDat, "GetAutoDbgDat"}, + {0x001B0042, &NIM_U::SetDbgTasks, "SetDbgTasks"}, + {0x001C0042, &NIM_U::GetDbgTasks, "GetDbgTasks"}, + {0x001D0000, &NIM_U::DeleteDbgData, "DeleteDbgData"}, + {0x001E0042, &NIM_U::SetTslXml, "SetTslXml"}, + {0x001F0000, &NIM_U::GetTslXmlSize, "GetTslXmlSize"}, + {0x00200042, &NIM_U::GetTslXml, "GetTslXml"}, + {0x00210000, &NIM_U::DeleteTslXml, "DeleteTslXml"}, + {0x00220042, &NIM_U::SetDtlXml, "SetDtlXml"}, + {0x00230000, &NIM_U::GetDtlXmlSize, "GetDtlXmlSize"}, + {0x00240042, &NIM_U::GetDtlXml, "GetDtlXml"}, + {0x00250000, &NIM_U::UpdateAccountStatus, "UpdateAccountStatus"}, + {0x00260180, &NIM_U::StartTitleDownload, "StartTitleDownload"}, + {0x00270000, &NIM_U::StopTitleDownload, "StopTitleDownload"}, + {0x00280000, &NIM_U::GetTitleDownloadProgress, "GetTitleDownloadProgress"}, + {0x00290246, &NIM_U::RegisterTask, "RegisterTask"}, + {0x002A0000, &NIM_U::IsSystemUpdateAvailable, "IsSystemUpdateAvailable"}, + {0x002B0000, &NIM_U::Unknown2B, "Unknown2B"}, + {0x002C0000, &NIM_U::UpdateTickets, "UpdateTickets"}, + {0x002D00C0, &NIM_U::DownloadTitleSeedAsync, "DownloadTitleSeedAsync"}, + {0x002E0000, &NIM_U::DownloadMissingTitleSeedsAsync, "DownloadMissingTitleSeedsAsync"}, }; RegisterHandlers(functions); - nim_system_update_event = - system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "NIM System Update Event"); + nim_system_update_event_for_menu = + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "NIM System Update Event (Menu)"); + nim_system_update_event_for_news = + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "NIM System Update Event (News)"); + nim_async_completion_event = + system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "NIM Async Completion Event"); } NIM_U::~NIM_U() = default; -void NIM_U::CheckForSysUpdateEvent(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x5, 0, 0); // 0x50000 - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); +void NIM_U::StartNetworkUpdate(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1, 0, 0); // 0x10000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(nim_system_update_event); - LOG_TRACE(Service_NIM, "called"); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); } -void NIM_U::CheckSysUpdateAvailable(Kernel::HLERequestContext& ctx) { +void NIM_U::GetProgress(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x2, 0, 0); // 0x20000 + + SystemUpdateProgress progress{}; + std::memset(&progress, 0, sizeof(progress)); + + IPC::RequestBuilder rb = rp.MakeBuilder(13, 0); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(progress); + rb.Push(0); + rb.Push(0); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::Cancel(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x3, 0, 0); // 0x30000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::CommitSystemTitles(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x4, 0, 0); // 0x40000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetBackgroundEventForMenu(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x5, 0, 0); // 0x50000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(nim_system_update_event_for_menu); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetBackgroundEventForNews(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x6, 0, 0); // 0x60000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(nim_system_update_event_for_news); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::FormatSaveData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x7, 0, 0); // 0x70000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetCustomerSupportCode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x8, 0, 0); // 0x80000 + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(0); // Customer support code + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::IsCommittableAllSystemTitles(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x9, 0, 0); // 0x90000 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); - rb.Push(false); // No update available + rb.Push(false); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetBackgroundProgress(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0xA, 0, 0); // 0xA0000 + + SystemUpdateProgress progress{}; + std::memset(&progress, 0, sizeof(progress)); + + IPC::RequestBuilder rb = rp.MakeBuilder(13, 0); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(progress); + rb.Push(0); + rb.Push(0); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetSavedHash(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0xB, 0, 0); // 0xB0000 + + std::array hash{}; + std::memset(&hash, 0, sizeof(hash)); + + IPC::RequestBuilder rb = rp.MakeBuilder(10, 0); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(hash); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::UnregisterTask(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0xC, 2, 2); // 0xC0082 + + const u64 title_id = rp.Pop(); + const u32 process_id = rp.PopPID(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::NIM, ErrorSummary::NotFound, + ErrorLevel::Status)); + + LOG_WARNING(Service_NIM, "(STUBBED) called title_id={:016X}, process_id={:08X}", title_id, + process_id); +} + +void NIM_U::IsRegistered(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0xD, 2, 0); // 0xD0080 + + const u64 title_id = rp.Pop(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(false); + + LOG_WARNING(Service_NIM, "(STUBBED) called title_id={:016X}", title_id); +} + +void NIM_U::FindTaskInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0xE, 2, 0); // 0xE0080 + + const u64 title_id = rp.Pop(); + + std::vector buffer(0x120, 0); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::NIM, ErrorSummary::NotFound, + ErrorLevel::Status)); + rb.PushStaticBuffer(std::move(buffer), 0); + + LOG_WARNING(Service_NIM, "(STUBBED) called title_id={:016X}", title_id); +} + +void NIM_U::GetTaskInfos(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0xF, 1, 2); // 0xF0042 + + const u64 max_task_infos = rp.Pop(); + auto& task_infos_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + rb.PushMappedBuffer(task_infos_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called max_task_infos={:08X}, task_infos_buffer=0x{:08X}", + max_task_infos, task_infos_buffer.GetId()); +} + +void NIM_U::DeleteUnmanagedContexts(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x10, 0, 0); // 0x100000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::UpdateAutoTitleDownloadTasksAsync(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x11, 0, 0); // 0x110000 + + // Since this is a stub, signal the completion event so the caller won't get stuck waiting. + nim_async_completion_event->Signal(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(nim_async_completion_event); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::StartPendingAutoTitleDownloadTasksAsync(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x11, 0, 0); // 0x120000 + + // Since this is a stub, signal the completion event so the caller won't get stuck waiting. + nim_async_completion_event->Signal(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(nim_async_completion_event); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetAsyncResult(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x13, 0, 0); // 0x130000 + + IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::CancelAsyncCall(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x14, 0, 0); // 0x140000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::IsPendingAutoTitleDownloadTasks(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x15, 0, 0); // 0x150000 + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(false); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetNumAutoTitleDownloadTasks(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x16, 0, 0); // 0x160000 + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetAutoTitleDownloadTaskInfos(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x17, 1, 2); // 0x170042 + + const u64 max_task_infos = rp.Pop(); + auto& task_infos_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + rb.PushMappedBuffer(task_infos_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called max_task_infos={:08X}, task_infos_buffer=0x{:08X}", + max_task_infos, task_infos_buffer.GetId()); +} + +void NIM_U::CancelAutoTitleDownloadTask(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x18, 2, 0); // 0x180080 + + const u64 task_id = rp.Pop(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called task_id={:016X}", task_id); +} + +void NIM_U::SetAutoDbgDat(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x19, 0, 2); // 0x190002 + + auto& auto_dbg_dat_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(auto_dbg_dat_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called auto_dbg_dat_buffer=0x{:08X}", + auto_dbg_dat_buffer.GetId()); +} + +void NIM_U::GetAutoDbgDat(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1A, 0, 2); // 0x1A0002 + + auto& auto_dbg_dat_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(auto_dbg_dat_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called auto_dbg_dat_buffer=0x{:08X}", + auto_dbg_dat_buffer.GetId()); +} + +void NIM_U::SetDbgTasks(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1B, 1, 2); // 0x1B0042 + + const u64 max_task_infos = rp.Pop(); + auto& task_infos_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(task_infos_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called max_task_infos={:08X}, task_infos_buffer=0x{:08X}", + max_task_infos, task_infos_buffer.GetId()); +} + +void NIM_U::GetDbgTasks(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1C, 1, 2); // 0x1C0042 + + const u64 max_task_infos = rp.Pop(); + auto& task_infos_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + rb.PushMappedBuffer(task_infos_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called max_task_infos={:08X}, task_infos_buffer=0x{:08X}", + max_task_infos, task_infos_buffer.GetId()); +} + +void NIM_U::DeleteDbgData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1D, 0, 0); // 0x1D0000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::SetTslXml(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1E, 1, 2); // 0x1E0042 + + const u32 buffer_size = rp.Pop(); + auto& xml_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(xml_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called buffer_size={:08X}, xml_buffer=0x{:08X}", + buffer_size, xml_buffer.GetId()); +} + +void NIM_U::GetTslXmlSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1F, 0, 0); // 0x1F0000 + + IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetTslXml(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x20, 1, 2); // 0x200042 + + const u32 buffer_capacity = rp.Pop(); + auto& xml_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(xml_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called buffer_capacity={:08X}, xml_buffer=0x{:08X}", + buffer_capacity, xml_buffer.GetId()); +} + +void NIM_U::DeleteTslXml(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x21, 0, 0); // 0x210000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::SetDtlXml(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x22, 1, 2); // 0x220042 + + const u32 buffer_size = rp.Pop(); + auto& xml_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(xml_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called buffer_size={:08X}, xml_buffer=0x{:08X}", + buffer_size, xml_buffer.GetId()); +} + +void NIM_U::GetDtlXmlSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x23, 0, 0); // 0x230000 + + IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetDtlXml(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x24, 1, 2); // 0x240042 + + const u32 buffer_capacity = rp.Pop(); + auto& xml_buffer = rp.PopMappedBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushMappedBuffer(xml_buffer); + + LOG_WARNING(Service_NIM, "(STUBBED) called buffer_capacity={:08X}, xml_buffer=0x{:08X}", + buffer_capacity, xml_buffer.GetId()); +} + +void NIM_U::UpdateAccountStatus(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x25, 0, 0); // 0x250000 + + IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::StartTitleDownload(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x26, 6, 0); // 0x260180 + + const auto& download_config = rp.PopRaw(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called title_id={:016X}", download_config.title_id); +} + +void NIM_U::StopTitleDownload(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x27, 0, 0); // 0x270000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::GetTitleDownloadProgress(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x28, 0, 0); // 0x280000 + + TitleDownloadProgress progress{}; + std::memset(&progress, 0, sizeof(progress)); + + IPC::RequestBuilder rb = rp.MakeBuilder(9, 0); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(progress); + rb.Push(0); + rb.Push(0); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::RegisterTask(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x29, 9, 6); // 0x290246 + + const auto& download_config = rp.PopRaw(); + const u32 unknown_1 = rp.Pop(); + const u32 unknown_2 = rp.Pop(); + const u32 unknown_3 = rp.Pop(); + const u32 pid = rp.PopPID(); + const auto& title_name = rp.PopStaticBuffer(); + const auto& developer_name = rp.PopStaticBuffer(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + const auto title_name_end = std::find(title_name.begin(), title_name.end(), u'\0'); + const auto title_name_utf8 = + Common::UTF16ToUTF8(std::u16string{title_name.begin(), title_name_end}); + + const auto developer_name_end = std::find(developer_name.begin(), developer_name.end(), u'\0'); + const auto developer_name_utf8 = + Common::UTF16ToUTF8(std::u16string{developer_name.begin(), developer_name_end}); + + LOG_WARNING(Service_NIM, + "(STUBBED) called title_id={:016X}, unknown_1={:08X}, unknown_2={:08X}, " + "unknown_3={:08X}, pid={:08X}, title_name='{}', developer_name='{}'", + download_config.title_id, unknown_1, unknown_2, unknown_3, pid, title_name_utf8, + developer_name_utf8); +} + +void NIM_U::IsSystemUpdateAvailable(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x2A, 0, 0); // 0x2A0000 + + IPC::RequestBuilder rb = rp.MakeBuilder(4, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + rb.Push(false); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::Unknown2B(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x2B, 0, 0); // 0x2B0000 + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::UpdateTickets(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x2C, 0, 0); // 0x2C0000 + + IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(RESULT_SUCCESS); + rb.Push(0); + + LOG_WARNING(Service_NIM, "(STUBBED) called"); +} + +void NIM_U::DownloadTitleSeedAsync(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x2D, 3, 0); // 0x2D00C0 + + const u64 title_id = rp.Pop(); + const u16 country_code = rp.Pop(); + + // Since this is a stub, signal the completion event so the caller won't get stuck waiting. + nim_async_completion_event->Signal(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(nim_async_completion_event); + + LOG_WARNING(Service_NIM, "(STUBBED) called title_id={:016X}, country_code={:04X}", title_id, + country_code); +} + +void NIM_U::DownloadMissingTitleSeedsAsync(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x2E, 0, 0); // 0x2E0000 + + // Since this is a stub, signal the completion event so the caller won't get stuck waiting. + nim_async_completion_event->Signal(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(nim_async_completion_event); LOG_WARNING(Service_NIM, "(STUBBED) called"); } diff --git a/src/core/hle/service/nim/nim_u.h b/src/core/hle/service/nim/nim_u.h index 98fec69b2..c3042e985 100644 --- a/src/core/hle/service/nim/nim_u.h +++ b/src/core/hle/service/nim/nim_u.h @@ -20,32 +20,522 @@ public: private: /** - * NIM::CheckForSysUpdateEvent service function + * NIM::StartNetworkUpdate service function * Inputs: * 1 : None * Outputs: * 1 : Result of function, 0 on success, otherwise error code - * 2 : Copy handle descriptor - * 3 : System Update event handle */ - void CheckForSysUpdateEvent(Kernel::HLERequestContext& ctx); + void StartNetworkUpdate(Kernel::HLERequestContext& ctx); /** - * NIM::CheckSysUpdateAvailable service function + * NIM::GetProgress service function * Inputs: * 1 : None * Outputs: * 1 : Result of function, 0 on success, otherwise error code - * 2 : u8 flag, 0 = no system update available, 1 = system update available. + * 2-11 : SystemUpdateProgress structure for the foreground system update + * 12: ? + * 13: ? */ - void CheckSysUpdateAvailable(Kernel::HLERequestContext& ctx); + void GetProgress(Kernel::HLERequestContext& ctx); - std::shared_ptr nim_system_update_event; + /** + * NIM::Cancel service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void Cancel(Kernel::HLERequestContext& ctx); + + /** + * NIM::CommitSystemTitles service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void CommitSystemTitles(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetBackgroundEventForMenu service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Copy handle IPC header + * 3 : System update ready event handle for home menu + */ + void GetBackgroundEventForMenu(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetBackgroundEventForNews service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Copy handle IPC header + * 3 : System update ready event handle for news module + */ + void GetBackgroundEventForNews(Kernel::HLERequestContext& ctx); + + /** + * NIM::FormatSaveData service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void FormatSaveData(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetCustomerSupportCode service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Customer support code for the last system update error + */ + void GetCustomerSupportCode(Kernel::HLERequestContext& ctx); + + /** + * NIM::IsCommittableAllSystemTitles service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Boolean indicating whether system titles are ready to commit + */ + void IsCommittableAllSystemTitles(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetBackgroundProgress service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-11 : SystemUpdateProgress structure for the background system update + * 12: ? + * 13: ? + */ + void GetBackgroundProgress(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetSavedHash service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-10 : NUL-terminated saved system update hash + */ + void GetSavedHash(Kernel::HLERequestContext& ctx); + + /** + * NIM::UnregisterTask service function + * Inputs: + * 1-2 : Title ID + * 3 : Process ID IPC Header + * 4 : Process ID (Auto-filled by kernel) + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void UnregisterTask(Kernel::HLERequestContext& ctx); + + /** + * NIM::IsRegistered service function + * Inputs: + * 1-2 : Title ID + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Boolean indicating whether a download task is registered for the title ID + */ + void IsRegistered(Kernel::HLERequestContext& ctx); + + /** + * NIM::FindTaskInfo service function + * Inputs: + * 1-2 : Title ID + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Static Buffer IPC Header (ID = 0, Size = 0x120) + * 3 : BackgroundTitleDownloadTaskInfo structure pointer + */ + void FindTaskInfo(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetTaskInfos service function + * Inputs: + * 1 : Maximum Number of BackgroundTitleDownloadTaskInfos + * 2 : Mapped Output Buffer IPC Header + * 3 : BackgroundTitleDownloadTaskInfos Output Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Number of BackgroundTitleDownloadTaskInfos Read + * 3 : Mapped Output Buffer IPC Header + * 4 : BackgroundTitleDownloadTaskInfos Output Buffer Pointer + */ + void GetTaskInfos(Kernel::HLERequestContext& ctx); + + /** + * NIM::DeleteUnmanagedContexts service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void DeleteUnmanagedContexts(Kernel::HLERequestContext& ctx); + + /** + * NIM::UpdateAutoTitleDownloadTasksAsync service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Copy Handle IPC Header + * 3 : Event handle signaled when the operation completes + */ + void UpdateAutoTitleDownloadTasksAsync(Kernel::HLERequestContext& ctx); + + /** + * NIM::StartPendingAutoTitleDownloadTasksAsync service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Copy Handle IPC Header + * 3 : Event handle signaled when the operation completes + */ + void StartPendingAutoTitleDownloadTasksAsync(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetAsyncResult service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Async operation result code + * 3 : Async operation customer support code + */ + void GetAsyncResult(Kernel::HLERequestContext& ctx); + + /** + * NIM::CancelAsyncCall service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void CancelAsyncCall(Kernel::HLERequestContext& ctx); + + /** + * NIM::IsPendingAutoTitleDownloadTasks service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Boolean indicating whether there are auto title downloads ready to start + */ + void IsPendingAutoTitleDownloadTasks(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetNumAutoTitleDownloadTasks service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Number of auto title download tasks + */ + void GetNumAutoTitleDownloadTasks(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetAutoTitleDownloadTasks service function + * Inputs: + * 1 : Maximum number of AutoTitleDownloadTaskInfos + * 2 : Mapped Output Buffer IPC Header + * 3 : AutoTitleDownloadTaskInfos Output Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Number of AutoTitleDownloadTaskInfos Read + * 3 : Mapped Output Buffer IPC Header + * 4 : AutoTitleDownloadTaskInfos Output Buffer Pointer + */ + void GetAutoTitleDownloadTaskInfos(Kernel::HLERequestContext& ctx); + + /** + * NIM::CancelAutoTitleDownloadTask service function + * Inputs: + * 1-2 : Auto Title Download Task ID + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void CancelAutoTitleDownloadTask(Kernel::HLERequestContext& ctx); + + /** + * NIM::SetAutoDbgDat service function + * Inputs: + * 1 : Mapped Input Buffer IPC Header + * 2 : AutoDbgDat Input Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Mapped Input Buffer IPC Header + * 3 : AutoDbgDat Input Buffer Pointer + */ + void SetAutoDbgDat(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetAutoDbgDat service function + * Inputs: + * 1 : Mapped Output Buffer IPC Header + * 2 : AutoDbgDat Output Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Mapped Output Buffer IPC Header + * 3 : AutoDbgDat Output Buffer Pointer + */ + void GetAutoDbgDat(Kernel::HLERequestContext& ctx); + + /** + * NIM::SetDbgTasks service function + * Inputs: + * 1 : Number of AutoTitleDownloadTaskInfos + * 2 : Mapped Input Buffer IPC Header + * 3 : AutoTitleDownloadTaskInfos Input Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 3 : Mapped Input Buffer IPC Header + * 4 : AutoTitleDownloadTaskInfos Input Buffer Pointer + */ + void SetDbgTasks(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetDbgTasks service function + * Inputs: + * 1 : Maximum number of AutoTitleDownloadTaskInfos + * 2 : Mapped Output Buffer IPC Header + * 3 : AutoTitleDownloadTaskInfos Output Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Number of AutoTitleDownloadTaskInfos Read + * 3 : Mapped Output Buffer IPC Header + * 4 : AutoTitleDownloadTaskInfos Output Buffer Pointer + */ + void GetDbgTasks(Kernel::HLERequestContext& ctx); + + /** + * NIM::DeleteDbgData service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void DeleteDbgData(Kernel::HLERequestContext& ctx); + + /** + * NIM::SetTslXml service function + * Inputs: + * 1 : Buffer Size + * 2 : Mapped Input Buffer IPC Header + * 3 : XML Input Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Mapped Input Buffer IPC Header + * 3 : XML Input Buffer Pointer + */ + void SetTslXml(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetTslXmlSize service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-3 : XML Size + */ + void GetTslXmlSize(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetTslXml service function + * Inputs: + * 1 : Buffer Capacity + * 2 : Mapped Output Buffer IPC Header + * 3 : XML Output Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Mapped Output Buffer IPC Header + * 3 : XML Output Buffer Pointer + */ + void GetTslXml(Kernel::HLERequestContext& ctx); + + /** + * NIM::DeleteTslXml service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void DeleteTslXml(Kernel::HLERequestContext& ctx); + + /** + * NIM::SetDtlXml service function + * Inputs: + * 1 : Buffer Size + * 2 : Mapped Input Buffer IPC Header + * 3 : XML Input Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Mapped Input Buffer IPC Header + * 3 : XML Input Buffer Pointer + */ + void SetDtlXml(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetDtlXmlSize service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-3 : XML Size + */ + void GetDtlXmlSize(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetDtlXml service function + * Inputs: + * 1 : Buffer Capacity + * 2 : Mapped Output Buffer IPC Header + * 3 : XML Output Buffer Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Mapped Output Buffer IPC Header + * 3 : XML Output Buffer Pointer + */ + void GetDtlXml(Kernel::HLERequestContext& ctx); + + /** + * NIM::UpdateAccountStatus service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Result of the actual operation + * 3 : Customer support code of the actual operation + */ + void UpdateAccountStatus(Kernel::HLERequestContext& ctx); + + /** + * NIM::StartTitleDownload service function + * Inputs: + * 1-6 : TitleDownloadConfig structure + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void StartTitleDownload(Kernel::HLERequestContext& ctx); + + /** + * NIM::StopDownload service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void StopTitleDownload(Kernel::HLERequestContext& ctx); + + /** + * NIM::GetTitleDownloadProgress service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-7 : TitleDownloadProgress structure + * 8: ? + * 9: ? + */ + void GetTitleDownloadProgress(Kernel::HLERequestContext& ctx); + + /** + * NIM::RegisterTask service function + * Inputs: + * 1-6 : TitleDownloadConfig structure + * 7: ? + * 8: ? + * 9: ? + * 10: Process ID IPC Header + * 11: Process ID (Auto-filled by Kernel) + * 12: Static Buffer IPC Header (ID = 0, Size = 0x90) + * 13: Title Name UTF-16 String Pointer + * 14: Static Buffer IPC Header (ID = 1, Size = 0x48) + * 15: Developer Name UTF-16 String Pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void RegisterTask(Kernel::HLERequestContext& ctx); + + /** + * NIM::IsSystemUpdateAvailable service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Result code from the actual operation + * 3 : Customer support code from the actual operation + * 4 : Boolean indicating whether a system update is available + */ + void IsSystemUpdateAvailable(Kernel::HLERequestContext& ctx); + + /** + * NIM::Unknown2B service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void Unknown2B(Kernel::HLERequestContext& ctx); + + /** + * NIM::UpdateTickets service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Result code from the actual operation + * 3 : Customer support code from the actual operation + */ + void UpdateTickets(Kernel::HLERequestContext& ctx); + + /** + * NIM::DownloadTitleSeedAsync service function + * Inputs: + * 1-2 : Title ID + * 3: u16 Country Code + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Copy Handle IPC Header + * 3 : Event handle signaled when the operation completes + */ + void DownloadTitleSeedAsync(Kernel::HLERequestContext& ctx); + + /** + * NIM::DownloadMissingTitleSeedsAsync service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Copy Handle IPC Header + * 3 : Event handle signaled when the operation completes + */ + void DownloadMissingTitleSeedsAsync(Kernel::HLERequestContext& ctx); + + std::shared_ptr nim_system_update_event_for_menu; + std::shared_ptr nim_system_update_event_for_news; + std::shared_ptr nim_async_completion_event; template void serialize(Archive& ar, const unsigned int) { ar& boost::serialization::base_object(*this); - ar& nim_system_update_event; + ar& nim_system_update_event_for_menu; + ar& nim_system_update_event_for_news; + ar& nim_async_completion_event; } friend class boost::serialization::access; }; From d8c9335ef0801927b7d3ab8e0d809ffa7dcf3189 Mon Sep 17 00:00:00 2001 From: SomeDudeOnDiscord <122324510+SomeDudeOnDiscord@users.noreply.github.com> Date: Sat, 18 Feb 2023 11:54:12 -0500 Subject: [PATCH 5/6] Resolve Black Screen on Intel GPU Regression (#6306) * Get value for swap screen setting and check mono_render_option again * resolve clang-format issue * do not disable opengl blending since it is enabled by default * reset blending state to default values after drawing second screen * prevent resetting state blending when custom opacity is not used --- .../renderer_opengl/renderer_opengl.cpp | 25 ++++++++++++++----- .../renderer_opengl/renderer_opengl.h | 1 + 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 89e58a9dc..0b7c8dd12 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -1002,7 +1002,7 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f } glUniform1i(uniform_layer, 0); - if (!Settings::values.swap_screen) { + if (!Settings::values.swap_screen.GetValue()) { DrawTopScreen(layout, top_screen, stereo_single_screen); glUniform1i(uniform_layer, 0); ApplySecondLayerOpacity(); @@ -1013,13 +1013,12 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f ApplySecondLayerOpacity(); DrawTopScreen(layout, top_screen, stereo_single_screen); } - state.blend.enabled = false; + ResetSecondLayerOpacity(); } void RendererOpenGL::ApplySecondLayerOpacity() { if (Settings::values.custom_layout && Settings::values.custom_second_layer_opacity.GetValue() < 100) { - state.blend.enabled = true; state.blend.src_rgb_func = GL_CONSTANT_ALPHA; state.blend.src_a_func = GL_CONSTANT_ALPHA; state.blend.dst_a_func = GL_ONE_MINUS_CONSTANT_ALPHA; @@ -1028,6 +1027,17 @@ void RendererOpenGL::ApplySecondLayerOpacity() { } } +void RendererOpenGL::ResetSecondLayerOpacity() { + if (Settings::values.custom_layout && + Settings::values.custom_second_layer_opacity.GetValue() < 100) { + state.blend.src_rgb_func = GL_ONE; + state.blend.dst_rgb_func = GL_ZERO; + state.blend.src_a_func = GL_ONE; + state.blend.dst_a_func = GL_ZERO; + state.blend.color.alpha = 0.0f; + } +} + void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, const Common::Rectangle& top_screen, const bool stereo_single_screen) { @@ -1037,8 +1047,10 @@ void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, if (layout.is_rotated) { if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Off) { - DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left, (float)top_screen.top, - (float)top_screen.GetWidth(), (float)top_screen.GetHeight()); + int eye = static_cast(Settings::values.mono_render_option.GetValue()); + DrawSingleScreenRotated(screen_infos[eye], (float)top_screen.left, + (float)top_screen.top, (float)top_screen.GetWidth(), + (float)top_screen.GetHeight()); } else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) { DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left / 2, @@ -1064,7 +1076,8 @@ void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout, } } else { if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::Off) { - DrawSingleScreen(screen_infos[0], (float)top_screen.left, (float)top_screen.top, + int eye = static_cast(Settings::values.mono_render_option.GetValue()); + DrawSingleScreen(screen_infos[eye], (float)top_screen.left, (float)top_screen.top, (float)top_screen.GetWidth(), (float)top_screen.GetHeight()); } else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) { diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index a168b055e..c823730e9 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -90,6 +90,7 @@ private: const GPU::Regs::FramebufferConfig& framebuffer); void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped); void ApplySecondLayerOpacity(); + void ResetSecondLayerOpacity(); void DrawBottomScreen(const Layout::FramebufferLayout& layout, const Common::Rectangle& bottom_screen, const bool stereo_single_screen); From 286f750c6c6b70b48e3fb2fb579e5bfafbf51a69 Mon Sep 17 00:00:00 2001 From: Tobias Date: Sat, 18 Feb 2023 23:24:15 +0100 Subject: [PATCH 6/6] citra_qt: Move CPU speed slider to debug tab and Report Comptaibility to help menu (#6250) --- .../configuration/configure_debug.cpp | 63 +++++++++ src/citra_qt/configuration/configure_debug.h | 1 + src/citra_qt/configuration/configure_debug.ui | 89 ++++++++++++- .../configuration/configure_per_game.cpp | 4 + .../configuration/configure_per_game.h | 2 + .../configuration/configure_system.cpp | 48 ------- .../configuration/configure_system.ui | 126 +++--------------- src/citra_qt/main.ui | 4 +- 8 files changed, 173 insertions(+), 164 deletions(-) diff --git a/src/citra_qt/configuration/configure_debug.cpp b/src/citra_qt/configuration/configure_debug.cpp index accc61b65..d08491f04 100644 --- a/src/citra_qt/configuration/configure_debug.cpp +++ b/src/citra_qt/configuration/configure_debug.cpp @@ -4,6 +4,7 @@ #include #include +#include "citra_qt/configuration/configuration_shared.h" #include "citra_qt/configuration/configure_debug.h" #include "citra_qt/debugger/console.h" #include "citra_qt/uisettings.h" @@ -13,6 +14,17 @@ #include "core/core.h" #include "ui_configure_debug.h" +// The QSlider doesn't have an easy way to set a custom step amount, +// so we can just convert from the sliders range (0 - 79) to the expected +// settings range (5 - 400) with simple math. +static constexpr int SliderToSettings(int value) { + return 5 * value + 5; +} + +static constexpr int SettingsToSlider(int value) { + return (value - 5) / 5; +} + ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(std::make_unique()) { ui->setupUi(this); @@ -25,6 +37,19 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) const bool is_powered_on = Core::System::GetInstance().IsPoweredOn(); ui->toggle_cpu_jit->setEnabled(!is_powered_on); + + // Set a minimum width for the label to prevent the slider from changing size. + // This scales across DPIs. (This value should be enough for "xxx%") + ui->clock_display_label->setMinimumWidth(40); + + connect(ui->slider_clock_speed, &QSlider::valueChanged, this, [&](int value) { + ui->clock_display_label->setText(QStringLiteral("%1%").arg(SliderToSettings(value))); + }); + + ui->clock_speed_label->setVisible(Settings::IsConfiguringGlobal()); + ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal()); + + SetupPerGameUI(); } ConfigureDebug::~ConfigureDebug() = default; @@ -37,6 +62,23 @@ void ConfigureDebug::SetConfiguration() { ui->toggle_console->setChecked(UISettings::values.show_console.GetValue()); ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue())); ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit.GetValue()); + + if (!Settings::IsConfiguringGlobal()) { + if (Settings::values.cpu_clock_percentage.UsingGlobal()) { + ui->clock_speed_combo->setCurrentIndex(0); + ui->slider_clock_speed->setEnabled(false); + } else { + ui->clock_speed_combo->setCurrentIndex(1); + ui->slider_clock_speed->setEnabled(true); + } + ConfigurationShared::SetHighlight(ui->clock_speed_widget, + !Settings::values.cpu_clock_percentage.UsingGlobal()); + } + + ui->slider_clock_speed->setValue( + SettingsToSlider(Settings::values.cpu_clock_percentage.GetValue())); + ui->clock_display_label->setText( + QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage.GetValue())); } void ConfigureDebug::ApplyConfiguration() { @@ -49,6 +91,27 @@ void ConfigureDebug::ApplyConfiguration() { filter.ParseFilterString(Settings::values.log_filter.GetValue()); Log::SetGlobalFilter(filter); Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked(); + + ConfigurationShared::ApplyPerGameSetting( + &Settings::values.cpu_clock_percentage, ui->clock_speed_combo, + [this](s32) { return SliderToSettings(ui->slider_clock_speed->value()); }); +} + +void ConfigureDebug::SetupPerGameUI() { + // Block the global settings if a game is currently running that overrides them + if (Settings::IsConfiguringGlobal()) { + ui->slider_clock_speed->setEnabled(Settings::values.cpu_clock_percentage.UsingGlobal()); + return; + } + + connect(ui->clock_speed_combo, qOverload(&QComboBox::activated), this, [this](int index) { + ui->slider_clock_speed->setEnabled(index == 1); + ConfigurationShared::SetHighlight(ui->clock_speed_widget, index == 1); + }); + + ui->groupBox->setVisible(false); + ui->groupBox_2->setVisible(false); + ui->toggle_cpu_jit->setVisible(false); } void ConfigureDebug::RetranslateUI() { diff --git a/src/citra_qt/configuration/configure_debug.h b/src/citra_qt/configuration/configure_debug.h index c0bae4c3e..59d05f41f 100644 --- a/src/citra_qt/configuration/configure_debug.h +++ b/src/citra_qt/configuration/configure_debug.h @@ -21,6 +21,7 @@ public: void ApplyConfiguration(); void RetranslateUI(); void SetConfiguration(); + void SetupPerGameUI(); std::unique_ptr ui; }; diff --git a/src/citra_qt/configuration/configure_debug.ui b/src/citra_qt/configuration/configure_debug.ui index 2bf1a5f88..6bfb7cb67 100644 --- a/src/citra_qt/configuration/configure_debug.ui +++ b/src/citra_qt/configuration/configure_debug.ui @@ -7,7 +7,7 @@ 0 0 443 - 300 + 358 @@ -107,12 +107,80 @@ - + - Miscellaneous + CPU - - + + + + + + 7 + + + + + + Use global clock speed + + + + + Set clock speed: + + + + + + + + CPU Clock Speed + + + + + + + <html><body>Changes the emulated CPU clock frequency.<br>Underclocking can increase performance but may cause the game to freeze.<br>Overclocking may reduce in game lag but also might cause freezes</body></html> + + + 0 + + + 79 + + + 5 + + + 15 + + + 25 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <html><head/><body><p>Enables the use of the ARM JIT compiler for emulating the 3DS CPUs. Don't disable unless for debugging purposes</p></body></html> @@ -125,6 +193,16 @@ + + + + <html><head/><body><p>CPU Clock Speed Information<br/>Underclocking can increase performance but may cause the game to freeze.<br/>Overclocking may reduce in game lag but also might cause freezes</p></body></html> + + + Qt::RichText + + + @@ -146,7 +224,6 @@ log_filter_edit toggle_console open_log_button - toggle_cpu_jit diff --git a/src/citra_qt/configuration/configure_per_game.cpp b/src/citra_qt/configuration/configure_per_game.cpp index fc74e9e4c..506b597ec 100644 --- a/src/citra_qt/configuration/configure_per_game.cpp +++ b/src/citra_qt/configuration/configure_per_game.cpp @@ -9,6 +9,7 @@ #include #include "citra_qt/configuration/config.h" #include "citra_qt/configuration/configure_audio.h" +#include "citra_qt/configuration/configure_debug.h" #include "citra_qt/configuration/configure_general.h" #include "citra_qt/configuration/configure_graphics.h" #include "citra_qt/configuration/configure_per_game.h" @@ -31,6 +32,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString general_tab = std::make_unique(this); graphics_tab = std::make_unique(this); system_tab = std::make_unique(this); + debug_tab = std::make_unique(this); ui->setupUi(this); @@ -38,6 +40,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString ui->tabWidget->addTab(system_tab.get(), tr("System")); ui->tabWidget->addTab(graphics_tab.get(), tr("Graphics")); ui->tabWidget->addTab(audio_tab.get(), tr("Audio")); + ui->tabWidget->addTab(debug_tab.get(), tr("Debug")); setFocusPolicy(Qt::ClickFocus); setWindowTitle(tr("Properties")); @@ -80,6 +83,7 @@ void ConfigurePerGame::ApplyConfiguration() { system_tab->ApplyConfiguration(); graphics_tab->ApplyConfiguration(); audio_tab->ApplyConfiguration(); + debug_tab->ApplyConfiguration(); Settings::LogSettings(); diff --git a/src/citra_qt/configuration/configure_per_game.h b/src/citra_qt/configuration/configure_per_game.h index 3bc2564b4..87addd6e7 100644 --- a/src/citra_qt/configuration/configure_per_game.h +++ b/src/citra_qt/configuration/configure_per_game.h @@ -17,6 +17,7 @@ class ConfigureAudio; class ConfigureGeneral; class ConfigureGraphics; class ConfigureSystem; +class ConfigureDebug; class QGraphicsScene; class QStandardItem; @@ -66,4 +67,5 @@ private: std::unique_ptr general_tab; std::unique_ptr graphics_tab; std::unique_ptr system_tab; + std::unique_ptr debug_tab; }; diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp index 8c4fbe5c5..73afb482a 100644 --- a/src/citra_qt/configuration/configure_system.cpp +++ b/src/citra_qt/configuration/configure_system.cpp @@ -225,17 +225,6 @@ static const std::array country_names = { QT_TRANSLATE_NOOP("ConfigureSystem", "Bermuda"), // 180-186 }; -// The QSlider doesn't have an easy way to set a custom step amount, -// so we can just convert from the sliders range (0 - 79) to the expected -// settings range (5 - 400) with simple math. -static constexpr int SliderToSettings(int value) { - return 5 * value + 5; -} - -static constexpr int SettingsToSlider(int value) { - return (value - 5) / 5; -} - ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(std::make_unique()) { ui->setupUi(this); @@ -255,17 +244,6 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) } } - // Set a minimum width for the label to prevent the slider from changing size. - // This scales across DPIs. (This value should be enough for "xxx%") - ui->clock_display_label->setMinimumWidth(40); - - connect(ui->slider_clock_speed, &QSlider::valueChanged, this, [&](int value) { - ui->clock_display_label->setText(QStringLiteral("%1%").arg(SliderToSettings(value))); - }); - - ui->clock_speed_label->setVisible(Settings::IsConfiguringGlobal()); - ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal()); - SetupPerGameUI(); ui->combo_download_mode->setCurrentIndex(1); // set to Recommended @@ -325,22 +303,6 @@ void ConfigureSystem::SetConfiguration() { ui->label_disable_info->hide(); } - if (!Settings::IsConfiguringGlobal()) { - if (Settings::values.cpu_clock_percentage.UsingGlobal()) { - ui->clock_speed_combo->setCurrentIndex(0); - ui->slider_clock_speed->setEnabled(false); - } else { - ui->clock_speed_combo->setCurrentIndex(1); - ui->slider_clock_speed->setEnabled(true); - } - ConfigurationShared::SetHighlight(ui->clock_speed_widget, - !Settings::values.cpu_clock_percentage.UsingGlobal()); - } - - ui->slider_clock_speed->setValue( - SettingsToSlider(Settings::values.cpu_clock_percentage.GetValue())); - ui->clock_display_label->setText( - QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage.GetValue())); ui->toggle_new_3ds->setChecked(Settings::values.is_new_3ds.GetValue()); ui->plugin_loader->setChecked(Settings::values.plugin_loader_enabled.GetValue()); ui->allow_plugin_loader->setChecked(Settings::values.allow_plugin_loader.GetValue()); @@ -452,10 +414,6 @@ void ConfigureSystem::ApplyConfiguration() { Settings::values.plugin_loader_enabled.SetValue(ui->plugin_loader->isChecked()); Settings::values.allow_plugin_loader.SetValue(ui->allow_plugin_loader->isChecked()); } - - ConfigurationShared::ApplyPerGameSetting( - &Settings::values.cpu_clock_percentage, ui->clock_speed_combo, - [this](s32) { return SliderToSettings(ui->slider_clock_speed->value()); }); } void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) { @@ -534,7 +492,6 @@ void ConfigureSystem::SetupPerGameUI() { // Block the global settings if a game is currently running that overrides them if (Settings::IsConfiguringGlobal()) { ui->toggle_new_3ds->setEnabled(Settings::values.is_new_3ds.UsingGlobal()); - ui->slider_clock_speed->setEnabled(Settings::values.cpu_clock_percentage.UsingGlobal()); return; } @@ -568,11 +525,6 @@ void ConfigureSystem::SetupPerGameUI() { ui->plugin_loader->setVisible(false); ui->allow_plugin_loader->setVisible(false); - connect(ui->clock_speed_combo, qOverload(&QComboBox::activated), this, [this](int index) { - ui->slider_clock_speed->setEnabled(index == 1); - ConfigurationShared::SetHighlight(ui->clock_speed_widget, index == 1); - }); - ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.is_new_3ds, is_new_3ds); } diff --git a/src/citra_qt/configuration/configure_system.ui b/src/citra_qt/configuration/configure_system.ui index 02acf35c5..064ce3835 100644 --- a/src/citra_qt/configuration/configure_system.ui +++ b/src/citra_qt/configuration/configure_system.ui @@ -6,7 +6,7 @@ 0 0 - 525 + 535 619 @@ -274,7 +274,7 @@ - + days @@ -287,7 +287,7 @@ - + HH:mm:ss @@ -341,25 +341,25 @@ - - - 3GX Plugin Loader: - - + + + 3GX Plugin Loader: + + - - - Enable 3GX plugin loader - - + + + Enable 3GX plugin loader + + - - - Allow games to change plugin loader state - - + + + Allow games to change plugin loader state + + @@ -410,86 +410,6 @@ - - - - Advanced - - - - - - - 7 - - - - - - Use global clock speed - - - - - Set clock speed: - - - - - - - - CPU Clock Speed - - - - - - - <html><body>Changes the emulated CPU clock frequency.<br>Underclocking can increase performance but may cause the game to freeze.<br>Overclocking may reduce in game lag but also might cause freezes</body></html> - - - 0 - - - 79 - - - 5 - - - 15 - - - 25 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - @@ -500,16 +420,6 @@ - - - - <html><head/><body><p>CPU Clock Speed Information<br/>Underclocking can increase performance but may cause the game to freeze.<br/>Overclocking may reduce in game lag but also might cause freezes</p></body></html> - - - Qt::RichText - - - diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index b3e36a978..4c88252eb 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -100,8 +100,6 @@ - - @@ -189,6 +187,8 @@ + +