summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt9
-rw-r--r--src/core/core.cpp11
-rw-r--r--src/core/core.h6
-rw-r--r--src/core/crypto/key_manager.cpp8
-rw-r--r--src/core/file_sys/ips_layer.cpp4
-rw-r--r--src/core/file_sys/patch_manager.cpp4
-rw-r--r--src/core/file_sys/patch_manager.h2
-rw-r--r--src/core/hid/hid_core.cpp8
-rw-r--r--src/core/hid/hid_core.h7
-rw-r--r--src/core/hle/kernel/k_process.cpp5
-rw-r--r--src/core/hle/kernel/k_process.h8
-rw-r--r--src/core/hle/kernel/svc/svc_debug_string.cpp2
-rw-r--r--src/core/hle/kernel/svc/svc_exception.cpp6
-rw-r--r--src/core/hle/service/am/am.cpp14
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp41
-rw-r--r--src/core/hle/service/hid/controllers/npad.h20
-rw-r--r--src/core/hle/service/hid/hid.cpp2
-rw-r--r--src/core/hle/service/nfc/common/device.cpp14
-rw-r--r--src/core/hle/service/ngc/ngc.cpp150
-rw-r--r--src/core/hle/service/ngc/ngc.h (renamed from src/core/hle/service/ngct/ngct.h)4
-rw-r--r--src/core/hle/service/ngct/ngct.cpp62
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/hle/service/sockets/bsd.cpp2
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp8
-rw-r--r--src/core/loader/deconstructed_rom_directory.h4
-rw-r--r--src/core/loader/kip.cpp3
-rw-r--r--src/core/loader/nro.cpp3
-rw-r--r--src/core/loader/nso.cpp5
-rw-r--r--src/core/loader/nsp.cpp3
-rw-r--r--src/core/memory/cheat_engine.cpp2
-rw-r--r--src/core/tools/renderdoc.cpp55
-rw-r--r--src/core/tools/renderdoc.h22
33 files changed, 362 insertions, 137 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c33910ade..30d2f7df6 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -627,8 +627,8 @@ add_library(core STATIC
hle/service/nfp/nfp_interface.h
hle/service/nfp/nfp_result.h
hle/service/nfp/nfp_types.h
- hle/service/ngct/ngct.cpp
- hle/service/ngct/ngct.h
+ hle/service/ngc/ngc.cpp
+ hle/service/ngc/ngc.h
hle/service/nifm/nifm.cpp
hle/service/nifm/nifm.h
hle/service/nim/nim.cpp
@@ -864,6 +864,8 @@ add_library(core STATIC
telemetry_session.h
tools/freezer.cpp
tools/freezer.h
+ tools/renderdoc.cpp
+ tools/renderdoc.h
)
if (MSVC)
@@ -879,6 +881,7 @@ else()
-Werror=conversion
-Wno-sign-conversion
+ -Wno-cast-function-type
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
)
@@ -887,7 +890,7 @@ endif()
create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core nx_tzdb)
-target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::opus)
+target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::opus renderdoc)
if (MINGW)
target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
endif()
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 2d6e61398..e8300cd05 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -51,6 +51,7 @@
#include "core/reporter.h"
#include "core/telemetry_session.h"
#include "core/tools/freezer.h"
+#include "core/tools/renderdoc.h"
#include "network/network.h"
#include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h"
@@ -281,6 +282,10 @@ struct System::Impl {
microprofile_cpu[2] = MICROPROFILE_TOKEN(ARM_CPU2);
microprofile_cpu[3] = MICROPROFILE_TOKEN(ARM_CPU3);
+ if (Settings::values.enable_renderdoc_hotkey) {
+ renderdoc_api = std::make_unique<Tools::RenderdocAPI>();
+ }
+
LOG_DEBUG(Core, "Initialized OK");
return SystemResultStatus::Success;
@@ -521,6 +526,8 @@ struct System::Impl {
std::unique_ptr<Tools::Freezer> memory_freezer;
std::array<u8, 0x20> build_id{};
+ std::unique_ptr<Tools::RenderdocAPI> renderdoc_api;
+
/// Frontend applets
Service::AM::Applets::AppletManager applet_manager;
@@ -1024,6 +1031,10 @@ const Network::RoomNetwork& System::GetRoomNetwork() const {
return impl->room_network;
}
+Tools::RenderdocAPI& System::GetRenderdocAPI() {
+ return *impl->renderdoc_api;
+}
+
void System::RunServer(std::unique_ptr<Service::ServerManager>&& server_manager) {
return impl->kernel.RunServer(std::move(server_manager));
}
diff --git a/src/core/core.h b/src/core/core.h
index fba312125..df20f26f3 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -102,6 +102,10 @@ namespace Network {
class RoomNetwork;
}
+namespace Tools {
+class RenderdocAPI;
+}
+
namespace Core {
class ARM_Interface;
@@ -413,6 +417,8 @@ public:
/// Gets an immutable reference to the Room Network.
[[nodiscard]] const Network::RoomNetwork& GetRoomNetwork() const;
+ [[nodiscard]] Tools::RenderdocAPI& GetRenderdocAPI();
+
void SetExitLocked(bool locked);
bool GetExitLocked() const;
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index e13c5cdc7..43a3c5ffd 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -724,14 +724,14 @@ void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_ti
continue;
}
- const auto index = std::stoul(out[0].substr(8, 2), nullptr, 16);
+ const auto index = std::strtoul(out[0].substr(8, 2).c_str(), nullptr, 16);
keyblobs[index] = Common::HexStringToArray<0x90>(out[1]);
} else if (out[0].compare(0, 18, "encrypted_keyblob_") == 0) {
if (!ValidCryptoRevisionString(out[0], 18, 2)) {
continue;
}
- const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16);
+ const auto index = std::strtoul(out[0].substr(18, 2).c_str(), nullptr, 16);
encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]);
} else if (out[0].compare(0, 20, "eticket_extended_kek") == 0) {
eticket_extended_kek = Common::HexStringToArray<576>(out[1]);
@@ -750,7 +750,7 @@ void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_ti
}
if (out[0].compare(0, kv.second.size(), kv.second) == 0) {
const auto index =
- std::stoul(out[0].substr(kv.second.size(), 2), nullptr, 16);
+ std::strtoul(out[0].substr(kv.second.size(), 2).c_str(), nullptr, 16);
const auto sub = kv.first.second;
if (sub == 0) {
s128_keys[{kv.first.first, index, 0}] =
@@ -770,7 +770,7 @@ void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_ti
const auto& match = kak_names[j];
if (out[0].compare(0, std::strlen(match), match) == 0) {
const auto index =
- std::stoul(out[0].substr(std::strlen(match), 2), nullptr, 16);
+ std::strtoul(out[0].substr(std::strlen(match), 2).c_str(), nullptr, 16);
s128_keys[{S128KeyType::KeyArea, index, j}] =
Common::HexStringToArray<16>(out[1]);
}
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index efdf18cee..7be1322cc 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -165,7 +165,7 @@ static std::string EscapeStringSequences(std::string in) {
void IPSwitchCompiler::ParseFlag(const std::string& line) {
if (StartsWith(line, "@flag offset_shift ")) {
// Offset Shift Flag
- offset_shift = std::stoll(line.substr(19), nullptr, 0);
+ offset_shift = std::strtoll(line.substr(19).c_str(), nullptr, 0);
} else if (StartsWith(line, "@little-endian")) {
// Set values to read as little endian
is_little_endian = true;
@@ -263,7 +263,7 @@ void IPSwitchCompiler::Parse() {
// 11 - 8 hex digit offset + space + minimum two digit overwrite val
if (patch_line.length() < 11)
break;
- auto offset = std::stoul(patch_line.substr(0, 8), nullptr, 16);
+ auto offset = std::strtoul(patch_line.substr(0, 8).c_str(), nullptr, 16);
offset += static_cast<unsigned long>(offset_shift);
std::vector<u8> replace;
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index a4baddb15..8e475f25a 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -294,11 +294,11 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
return out;
}
-bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {
+bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name) const {
const auto build_id_raw = Common::HexToString(build_id_);
const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
- LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
+ LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index adcde7b7d..03e9c7301 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -52,7 +52,7 @@ public:
// Checks to see if PatchNSO() will have any effect given the NSO's build ID.
// Used to prevent expensive copies in NSO loader.
- [[nodiscard]] bool HasNSOPatch(const BuildID& build_id) const;
+ [[nodiscard]] bool HasNSOPatch(const BuildID& build_id, std::string_view name) const;
// Creates a CheatList object with all
[[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList(
diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp
index 7d6373414..cf53c04d9 100644
--- a/src/core/hid/hid_core.cpp
+++ b/src/core/hid/hid_core.cpp
@@ -154,6 +154,14 @@ NpadIdType HIDCore::GetFirstDisconnectedNpadId() const {
return NpadIdType::Player1;
}
+void HIDCore::SetLastActiveController(NpadIdType npad_id) {
+ last_active_controller = npad_id;
+}
+
+NpadIdType HIDCore::GetLastActiveController() const {
+ return last_active_controller;
+}
+
void HIDCore::EnableAllControllerConfiguration() {
player_1->EnableConfiguration();
player_2->EnableConfiguration();
diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h
index 5fe36551e..80abab18b 100644
--- a/src/core/hid/hid_core.h
+++ b/src/core/hid/hid_core.h
@@ -48,6 +48,12 @@ public:
/// Returns the first disconnected npad id
NpadIdType GetFirstDisconnectedNpadId() const;
+ /// Sets the npad id of the last active controller
+ void SetLastActiveController(NpadIdType npad_id);
+
+ /// Returns the npad id of the last controller that pushed a button
+ NpadIdType GetLastActiveController() const;
+
/// Sets all emulated controllers into configuring mode.
void EnableAllControllerConfiguration();
@@ -77,6 +83,7 @@ private:
std::unique_ptr<EmulatedConsole> console;
std::unique_ptr<EmulatedDevices> devices;
NpadStyleTag supported_style_tag{NpadStyleSet::All};
+ NpadIdType last_active_controller{NpadIdType::Handheld};
};
} // namespace Core::HID
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 703049ede..4a099286b 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -96,6 +96,7 @@ Result KProcess::Initialize(KProcess* process, Core::System& system, std::string
process->m_is_suspended = false;
process->m_schedule_count = 0;
process->m_is_handle_table_initialized = false;
+ process->m_is_hbl = false;
// Open a reference to the resource limit.
process->m_resource_limit->Open();
@@ -351,12 +352,14 @@ Result KProcess::SetActivity(ProcessActivity activity) {
R_SUCCEED();
}
-Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size) {
+Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
+ bool is_hbl) {
m_program_id = metadata.GetTitleID();
m_ideal_core = metadata.GetMainThreadCore();
m_is_64bit_process = metadata.Is64BitProgram();
m_system_resource_size = metadata.GetSystemResourceSize();
m_image_size = code_size;
+ m_is_hbl = is_hbl;
if (metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit) {
// For 39-bit processes, the ASLR region starts at 0x800'0000 and is ~512GiB large.
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 4fdeaf11a..146e07a57 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -338,7 +338,8 @@ public:
* @returns ResultSuccess if all relevant metadata was able to be
* loaded and parsed. Otherwise, an error code is returned.
*/
- Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size);
+ Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
+ bool is_hbl);
/**
* Starts the main application thread for this process.
@@ -368,6 +369,10 @@ public:
return GetProcessId();
}
+ bool IsHbl() const {
+ return m_is_hbl;
+ }
+
bool IsSignaled() const override;
void DoWorkerTaskImpl();
@@ -525,6 +530,7 @@ private:
bool m_is_immortal{};
bool m_is_handle_table_initialized{};
bool m_is_initialized{};
+ bool m_is_hbl{};
std::atomic<u16> m_num_running_threads{};
diff --git a/src/core/hle/kernel/svc/svc_debug_string.cpp b/src/core/hle/kernel/svc/svc_debug_string.cpp
index 4c14ce668..00b65429b 100644
--- a/src/core/hle/kernel/svc/svc_debug_string.cpp
+++ b/src/core/hle/kernel/svc/svc_debug_string.cpp
@@ -14,7 +14,7 @@ Result OutputDebugString(Core::System& system, u64 address, u64 len) {
std::string str(len, '\0');
GetCurrentMemory(system.Kernel()).ReadBlock(address, str.data(), str.size());
- LOG_DEBUG(Debug_Emulated, "{}", str);
+ LOG_INFO(Debug_Emulated, "{}", str);
R_SUCCEED();
}
diff --git a/src/core/hle/kernel/svc/svc_exception.cpp b/src/core/hle/kernel/svc/svc_exception.cpp
index 580cf2f75..c581c086b 100644
--- a/src/core/hle/kernel/svc/svc_exception.cpp
+++ b/src/core/hle/kernel/svc/svc_exception.cpp
@@ -3,6 +3,7 @@
#include "core/core.h"
#include "core/debugger/debugger.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_types.h"
@@ -107,7 +108,10 @@ void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) {
system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
}
- if (system.DebuggerEnabled()) {
+ const bool is_hbl = GetCurrentProcess(system.Kernel()).IsHbl();
+ const bool should_break = is_hbl || !notification_only;
+
+ if (system.DebuggerEnabled() && should_break) {
auto* thread = system.Kernel().GetCurrentEmuThread();
system.GetDebugger().NotifyThreadStopped(thread);
thread->RequestSuspend(Kernel::SuspendType::Debug);
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index f9c4f9678..8ffdd19e7 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1386,7 +1386,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
{27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
- {28, nullptr, "GetSaveDataSizeMax"},
+ {28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"},
{29, nullptr, "GetCacheStorageMax"},
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
@@ -1821,6 +1821,18 @@ void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
rb.PushRaw(resp);
}
+void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ constexpr u64 size_max_normal = 0xFFFFFFF;
+ constexpr u64 size_max_journal = 0xFFFFFFF;
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(ResultSuccess);
+ rb.Push(size_max_normal);
+ rb.Push(size_max_journal);
+}
+
void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index f75a665b2..f86841c60 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -316,6 +316,7 @@ private:
void ExtendSaveData(HLERequestContext& ctx);
void GetSaveDataSize(HLERequestContext& ctx);
void CreateCacheStorage(HLERequestContext& ctx);
+ void GetSaveDataSizeMax(HLERequestContext& ctx);
void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
void BeginBlockingHomeButton(HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index c744b0f87..146bb486d 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -193,7 +193,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
shared_memory->system_properties.use_minus.Assign(1);
shared_memory->system_properties.is_charging_joy_dual.Assign(
battery_level.dual.is_charging);
- shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
+ shared_memory->applet_footer_type = AppletFooterUiType::SwitchProController;
shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
break;
case Core::HID::NpadStyleIndex::Handheld:
@@ -216,8 +216,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
shared_memory->system_properties.is_charging_joy_right.Assign(
battery_level.right.is_charging);
shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
- shared_memory->applet_nfc_xcd.applet_footer.type =
- AppletFooterUiType::HandheldJoyConLeftJoyConRight;
+ shared_memory->applet_footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight;
shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1);
break;
case Core::HID::NpadStyleIndex::JoyconDual:
@@ -247,19 +246,19 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
- shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual;
+ shared_memory->applet_footer_type = AppletFooterUiType::JoyDual;
shared_memory->fullkey_color.fullkey = body_colors.left;
shared_memory->battery_level_dual = battery_level.left.battery_level;
shared_memory->system_properties.is_charging_joy_dual.Assign(
battery_level.left.is_charging);
} else if (controller.is_dual_left_connected) {
- shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
+ shared_memory->applet_footer_type = AppletFooterUiType::JoyDualLeftOnly;
shared_memory->fullkey_color.fullkey = body_colors.left;
shared_memory->battery_level_dual = battery_level.left.battery_level;
shared_memory->system_properties.is_charging_joy_dual.Assign(
battery_level.left.is_charging);
} else {
- shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
+ shared_memory->applet_footer_type = AppletFooterUiType::JoyDualRightOnly;
shared_memory->fullkey_color.fullkey = body_colors.right;
shared_memory->battery_level_dual = battery_level.right.battery_level;
shared_memory->system_properties.is_charging_joy_dual.Assign(
@@ -278,7 +277,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
shared_memory->system_properties.use_minus.Assign(1);
shared_memory->system_properties.is_charging_joy_left.Assign(
battery_level.left.is_charging);
- shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
+ shared_memory->applet_footer_type = AppletFooterUiType::JoyLeftHorizontal;
shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1);
break;
case Core::HID::NpadStyleIndex::JoyconRight:
@@ -293,7 +292,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
shared_memory->system_properties.use_plus.Assign(1);
shared_memory->system_properties.is_charging_joy_right.Assign(
battery_level.right.is_charging);
- shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
+ shared_memory->applet_footer_type = AppletFooterUiType::JoyRightHorizontal;
shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1);
break;
case Core::HID::NpadStyleIndex::GameCube:
@@ -314,12 +313,12 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
case Core::HID::NpadStyleIndex::SNES:
shared_memory->style_tag.lucia.Assign(1);
shared_memory->device_type.fullkey.Assign(1);
- shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lucia;
+ shared_memory->applet_footer_type = AppletFooterUiType::Lucia;
break;
case Core::HID::NpadStyleIndex::N64:
shared_memory->style_tag.lagoon.Assign(1);
shared_memory->device_type.fullkey.Assign(1);
- shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lagon;
+ shared_memory->applet_footer_type = AppletFooterUiType::Lagon;
break;
case Core::HID::NpadStyleIndex::SegaGenesis:
shared_memory->style_tag.lager.Assign(1);
@@ -419,9 +418,17 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
std::scoped_lock lock{mutex};
auto& controller = GetControllerFromNpadIdType(npad_id);
const auto controller_type = controller.device->GetNpadStyleIndex();
+
+ if (!controller.device->IsConnected() && controller.is_connected) {
+ DisconnectNpad(npad_id);
+ return;
+ }
if (!controller.device->IsConnected()) {
return;
}
+ if (controller.device->IsConnected() && !controller.is_connected) {
+ InitNewlyAddedController(npad_id);
+ }
// This function is unique to yuzu for the turbo buttons and motion to work properly
controller.device->StatusUpdate();
@@ -468,6 +475,10 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
pad_entry.npad_buttons.l.Assign(button_state.zl);
pad_entry.npad_buttons.r.Assign(button_state.zr);
}
+
+ if (pad_entry.npad_buttons.raw != Core::HID::NpadButton::None) {
+ hid_core.SetLastActiveController(npad_id);
+ }
}
void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
@@ -736,14 +747,6 @@ void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) {
// Once SetSupportedStyleSet is called controllers are fully initialized
is_controller_initialized = true;
-
- // Connect all active controllers
- for (auto& controller : controller_data) {
- const auto& device = controller.device;
- if (device->IsConnected()) {
- AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType());
- }
- }
}
Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
@@ -1116,7 +1119,7 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
.left = {},
.right = {},
};
- shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::None;
+ shared_memory->applet_footer_type = AppletFooterUiType::None;
controller.is_dual_left_connected = true;
controller.is_dual_right_connected = true;
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 0e9f899a4..949e58a4c 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -362,7 +362,7 @@ private:
enum class AppletFooterUiType : u8 {
None = 0,
HandheldNone = 1,
- HandheldJoyConLeftOnly = 1,
+ HandheldJoyConLeftOnly = 2,
HandheldJoyConRightOnly = 3,
HandheldJoyConLeftJoyConRight = 4,
JoyDual = 5,
@@ -384,13 +384,6 @@ private:
Lagon = 21,
};
- struct AppletFooterUi {
- AppletFooterUiAttributes attributes{};
- AppletFooterUiType type{AppletFooterUiType::None};
- INSERT_PADDING_BYTES(0x5B); // Reserved
- };
- static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size");
-
// This is nn::hid::NpadLarkType
enum class NpadLarkType : u32 {
Invalid,
@@ -421,13 +414,6 @@ private:
U,
};
- struct AppletNfcXcd {
- union {
- AppletFooterUi applet_footer{};
- Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo;
- };
- };
-
// This is nn::hid::detail::NpadInternalState
struct NpadInternalState {
Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
@@ -454,7 +440,9 @@ private:
Core::HID::NpadBatteryLevel battery_level_dual{};
Core::HID::NpadBatteryLevel battery_level_left{};
Core::HID::NpadBatteryLevel battery_level_right{};
- AppletNfcXcd applet_nfc_xcd{};
+ AppletFooterUiAttributes applet_footer_attributes{};
+ AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
+ INSERT_PADDING_BYTES(0x5B); // Reserved
INSERT_PADDING_BYTES(0x20); // Unknown
Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{};
NpadLarkType lark_type_l_and_main{};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 6f711c0da..4d70006c1 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2774,7 +2774,7 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.PushEnum(Core::HID::NpadIdType::Handheld);
+ rb.PushEnum(system.HIDCore().GetLastActiveController());
}
void GetUniquePadsFromNpad(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 5dda12343..674d2e4b2 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -874,17 +874,19 @@ Result NfcDevice::RestoreAmiibo() {
}
Result NfcDevice::Format() {
- auto result1 = DeleteApplicationArea();
- auto result2 = DeleteRegisterInfo();
+ Result result = ResultSuccess;
- if (result1.IsError()) {
- return result1;
+ if (device_state == DeviceState::TagFound) {
+ result = Mount(NFP::ModelType::Amiibo, NFP::MountTarget::All);
}
- if (result2.IsError()) {
- return result2;
+ if (result.IsError()) {
+ return result;
}
+ DeleteApplicationArea();
+ DeleteRegisterInfo();
+
return Flush();
}
diff --git a/src/core/hle/service/ngc/ngc.cpp b/src/core/hle/service/ngc/ngc.cpp
new file mode 100644
index 000000000..c26019ec0
--- /dev/null
+++ b/src/core/hle/service/ngc/ngc.cpp
@@ -0,0 +1,150 @@
+// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/ngc/ngc.h"
+#include "core/hle/service/server_manager.h"
+#include "core/hle/service/service.h"
+
+namespace Service::NGC {
+
+class NgctServiceImpl final : public ServiceFramework<NgctServiceImpl> {
+public:
+ explicit NgctServiceImpl(Core::System& system_) : ServiceFramework{system_, "ngct:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &NgctServiceImpl::Match, "Match"},
+ {1, &NgctServiceImpl::Filter, "Filter"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void Match(HLERequestContext& ctx) {
+ const auto buffer = ctx.ReadBuffer();
+ const auto text = Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(buffer.data()), buffer.size());
+
+ LOG_WARNING(Service_NGC, "(STUBBED) called, text={}", text);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ // Return false since we don't censor anything
+ rb.Push(false);
+ }
+
+ void Filter(HLERequestContext& ctx) {
+ const auto buffer = ctx.ReadBuffer();
+ const auto text = Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(buffer.data()), buffer.size());
+
+ LOG_WARNING(Service_NGC, "(STUBBED) called, text={}", text);
+
+ // Return the same string since we don't censor anything
+ ctx.WriteBuffer(buffer);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+};
+
+class NgcServiceImpl final : public ServiceFramework<NgcServiceImpl> {
+public:
+ explicit NgcServiceImpl(Core::System& system_) : ServiceFramework(system_, "ngc:u") {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &NgcServiceImpl::GetContentVersion, "GetContentVersion"},
+ {1, &NgcServiceImpl::Check, "Check"},
+ {2, &NgcServiceImpl::Mask, "Mask"},
+ {3, &NgcServiceImpl::Reload, "Reload"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ static constexpr u32 NgcContentVersion = 1;
+
+ // This is nn::ngc::detail::ProfanityFilterOption
+ struct ProfanityFilterOption {
+ INSERT_PADDING_BYTES_NOINIT(0x20);
+ };
+ static_assert(sizeof(ProfanityFilterOption) == 0x20,
+ "ProfanityFilterOption has incorrect size");
+
+ void GetContentVersion(HLERequestContext& ctx) {
+ LOG_INFO(Service_NGC, "(STUBBED) called");
+
+ // This calls nn::ngc::ProfanityFilter::GetContentVersion
+ const u32 version = NgcContentVersion;
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(version);
+ }
+
+ void Check(HLERequestContext& ctx) {
+ LOG_INFO(Service_NGC, "(STUBBED) called");
+
+ struct InputParameters {
+ u32 flags;
+ ProfanityFilterOption option;
+ };
+
+ IPC::RequestParser rp{ctx};
+ [[maybe_unused]] const auto params = rp.PopRaw<InputParameters>();
+ [[maybe_unused]] const auto input = ctx.ReadBuffer(0);
+
+ // This calls nn::ngc::ProfanityFilter::CheckProfanityWords
+ const u32 out_flags = 0;
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(out_flags);
+ }
+
+ void Mask(HLERequestContext& ctx) {
+ LOG_INFO(Service_NGC, "(STUBBED) called");
+
+ struct InputParameters {
+ u32 flags;
+ ProfanityFilterOption option;
+ };
+
+ IPC::RequestParser rp{ctx};
+ [[maybe_unused]] const auto params = rp.PopRaw<InputParameters>();
+ const auto input = ctx.ReadBuffer(0);
+
+ // This calls nn::ngc::ProfanityFilter::MaskProfanityWordsInText
+ const u32 out_flags = 0;
+ ctx.WriteBuffer(input);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(out_flags);
+ }
+
+ void Reload(HLERequestContext& ctx) {
+ LOG_INFO(Service_NGC, "(STUBBED) called");
+
+ // This reloads the database.
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+};
+
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("ngct:u", std::make_shared<NgctServiceImpl>(system));
+ server_manager->RegisterNamedService("ngc:u", std::make_shared<NgcServiceImpl>(system));
+ ServerManager::RunServer(std::move(server_manager));
+}
+
+} // namespace Service::NGC
diff --git a/src/core/hle/service/ngct/ngct.h b/src/core/hle/service/ngc/ngc.h
index 27c34dad4..823b1aa81 100644
--- a/src/core/hle/service/ngct/ngct.h
+++ b/src/core/hle/service/ngc/ngc.h
@@ -7,8 +7,8 @@ namespace Core {
class System;
}
-namespace Service::NGCT {
+namespace Service::NGC {
void LoopProcess(Core::System& system);
-} // namespace Service::NGCT
+} // namespace Service::NGC
diff --git a/src/core/hle/service/ngct/ngct.cpp b/src/core/hle/service/ngct/ngct.cpp
deleted file mode 100644
index 493c80ed2..000000000
--- a/src/core/hle/service/ngct/ngct.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "common/string_util.h"
-#include "core/core.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/ngct/ngct.h"
-#include "core/hle/service/server_manager.h"
-#include "core/hle/service/service.h"
-
-namespace Service::NGCT {
-
-class IService final : public ServiceFramework<IService> {
-public:
- explicit IService(Core::System& system_) : ServiceFramework{system_, "ngct:u"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IService::Match, "Match"},
- {1, &IService::Filter, "Filter"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void Match(HLERequestContext& ctx) {
- const auto buffer = ctx.ReadBuffer();
- const auto text = Common::StringFromFixedZeroTerminatedBuffer(
- reinterpret_cast<const char*>(buffer.data()), buffer.size());
-
- LOG_WARNING(Service_NGCT, "(STUBBED) called, text={}", text);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- // Return false since we don't censor anything
- rb.Push(false);
- }
-
- void Filter(HLERequestContext& ctx) {
- const auto buffer = ctx.ReadBuffer();
- const auto text = Common::StringFromFixedZeroTerminatedBuffer(
- reinterpret_cast<const char*>(buffer.data()), buffer.size());
-
- LOG_WARNING(Service_NGCT, "(STUBBED) called, text={}", text);
-
- // Return the same string since we don't censor anything
- ctx.WriteBuffer(buffer);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-};
-
-void LoopProcess(Core::System& system) {
- auto server_manager = std::make_unique<ServerManager>(system);
-
- server_manager->RegisterNamedService("ngct:u", std::make_shared<IService>(system));
- ServerManager::RunServer(std::move(server_manager));
-}
-
-} // namespace Service::NGCT
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 69cdb5918..0ad607391 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -43,7 +43,7 @@
#include "core/hle/service/ncm/ncm.h"
#include "core/hle/service/nfc/nfc.h"
#include "core/hle/service/nfp/nfp.h"
-#include "core/hle/service/ngct/ngct.h"
+#include "core/hle/service/ngc/ngc.h"
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/nim/nim.h"
#include "core/hle/service/npns/npns.h"
@@ -257,7 +257,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
kernel.RunOnGuestCoreProcess("NCM", [&] { NCM::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("nfc", [&] { NFC::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("nfp", [&] { NFP::LoopProcess(system); });
- kernel.RunOnGuestCoreProcess("ngct", [&] { NGCT::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("ngc", [&] { NGC::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("nifm", [&] { NIFM::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("nim", [&] { NIM::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("npns", [&] { NPNS::LoopProcess(system); });
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index d8509c1dd..85849d5f3 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -170,7 +170,7 @@ void BSD::Socket(HLERequestContext& ctx) {
}
void BSD::Select(HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called");
+ LOG_DEBUG(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index f4eaf3331..5a42dea48 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -18,7 +18,7 @@ namespace Loader {
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
bool override_update_)
- : AppLoader(std::move(file_)), override_update(override_update_) {
+ : AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) {
const auto file_dir = file->GetContainingDirectory();
// Title ID
@@ -69,9 +69,9 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
}
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
- FileSys::VirtualDir directory, bool override_update_)
+ FileSys::VirtualDir directory, bool override_update_, bool is_hbl_)
: AppLoader(directory->GetFile("main")), dir(std::move(directory)),
- override_update(override_update_) {}
+ override_update(override_update_), is_hbl(is_hbl_) {}
FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) {
if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) {
@@ -147,7 +147,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
}
// Setup the process code layout
- if (process.LoadFromMetadata(metadata, code_size).IsError()) {
+ if (process.LoadFromMetadata(metadata, code_size, is_hbl).IsError()) {
return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
}
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index f7702225e..1e9f765c9 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -27,7 +27,8 @@ public:
// Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory,
- bool override_update_ = false);
+ bool override_update_ = false,
+ bool is_hbl_ = false);
/**
* Identifies whether or not the given file is a deconstructed ROM directory.
@@ -62,6 +63,7 @@ private:
std::string name;
u64 title_id{};
bool override_update;
+ bool is_hbl;
Modules modules;
};
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index d722459c6..bf56a08b4 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -90,7 +90,8 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
codeset.DataSegment().size += kip->GetBSSSize();
// Setup the process code layout
- if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size())
+ if (process
+ .LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), false)
.IsError()) {
return {ResultStatus::ErrorNotInitialized, {}};
}
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index d7562b4bc..69f1a54ed 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -196,7 +196,8 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
// Setup the process code layout
- if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size())
+ if (process
+ .LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), false)
.IsError()) {
return false;
}
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 549822506..1350da8dc 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -127,13 +127,14 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
}
// Apply patches if necessary
- if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
+ const auto name = nso_file.GetName();
+ if (pm && (pm->HasNSOPatch(nso_header.build_id, name) || Settings::values.dump_nso)) {
std::vector<u8> pi_header(sizeof(NSOHeader) + program_image.size());
std::memcpy(pi_header.data(), &nso_header, sizeof(NSOHeader));
std::memcpy(pi_header.data() + sizeof(NSOHeader), program_image.data(),
program_image.size());
- pi_header = pm->PatchNSO(pi_header, nso_file.GetName());
+ pi_header = pm->PatchNSO(pi_header, name);
std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data());
}
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index fe2af1ae6..f4ab75b77 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -30,7 +30,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
}
if (nsp->IsExtractedType()) {
- secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS());
+ secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(
+ nsp->GetExeFS(), false, file->GetName() == "hbl.nsp");
} else {
const auto control_nca =
nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 7b52f61a7..a06e99166 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -154,7 +154,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
return {};
}
- const auto value = static_cast<u32>(std::stoul(hex, nullptr, 0x10));
+ const auto value = static_cast<u32>(std::strtoul(hex.c_str(), nullptr, 0x10));
out[*current_entry].definition.opcodes[out[*current_entry].definition.num_opcodes++] =
value;
diff --git a/src/core/tools/renderdoc.cpp b/src/core/tools/renderdoc.cpp
new file mode 100644
index 000000000..44d24822a
--- /dev/null
+++ b/src/core/tools/renderdoc.cpp
@@ -0,0 +1,55 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <renderdoc_app.h>
+
+#include "common/assert.h"
+#include "common/dynamic_library.h"
+#include "core/tools/renderdoc.h"
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+namespace Tools {
+
+RenderdocAPI::RenderdocAPI() {
+#ifdef WIN32
+ if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) {
+ const auto RENDERDOC_GetAPI =
+ reinterpret_cast<pRENDERDOC_GetAPI>(GetProcAddress(mod, "RENDERDOC_GetAPI"));
+ const s32 ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_6_0, (void**)&rdoc_api);
+ ASSERT(ret == 1);
+ }
+#else
+#ifdef ANDROID
+ static constexpr const char RENDERDOC_LIB[] = "libVkLayer_GLES_RenderDoc.so";
+#else
+ static constexpr const char RENDERDOC_LIB[] = "librenderdoc.so";
+#endif
+ if (void* mod = dlopen(RENDERDOC_LIB, RTLD_NOW | RTLD_NOLOAD)) {
+ const auto RENDERDOC_GetAPI =
+ reinterpret_cast<pRENDERDOC_GetAPI>(dlsym(mod, "RENDERDOC_GetAPI"));
+ const s32 ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_6_0, (void**)&rdoc_api);
+ ASSERT(ret == 1);
+ }
+#endif
+}
+
+RenderdocAPI::~RenderdocAPI() = default;
+
+void RenderdocAPI::ToggleCapture() {
+ if (!rdoc_api) [[unlikely]] {
+ return;
+ }
+ if (!is_capturing) {
+ rdoc_api->StartFrameCapture(NULL, NULL);
+ } else {
+ rdoc_api->EndFrameCapture(NULL, NULL);
+ }
+ is_capturing = !is_capturing;
+}
+
+} // namespace Tools
diff --git a/src/core/tools/renderdoc.h b/src/core/tools/renderdoc.h
new file mode 100644
index 000000000..0e5e43da5
--- /dev/null
+++ b/src/core/tools/renderdoc.h
@@ -0,0 +1,22 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+struct RENDERDOC_API_1_6_0;
+
+namespace Tools {
+
+class RenderdocAPI {
+public:
+ explicit RenderdocAPI();
+ ~RenderdocAPI();
+
+ void ToggleCapture();
+
+private:
+ RENDERDOC_API_1_6_0* rdoc_api{};
+ bool is_capturing{false};
+};
+
+} // namespace Tools