summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/core.cpp6
-rw-r--r--src/core/core_timing.cpp16
-rw-r--r--src/core/core_timing.h7
-rw-r--r--src/core/cpu_manager.cpp6
-rw-r--r--src/core/device_memory.cpp5
-rw-r--r--src/core/device_memory.h8
-rw-r--r--src/core/file_sys/registered_cache.cpp101
-rw-r--r--src/core/file_sys/registered_cache.h6
-rw-r--r--src/core/file_sys/xts_archive.cpp14
-rw-r--r--src/core/hardware_interrupt_manager.cpp4
-rw-r--r--src/core/hle/kernel/kernel.cpp2
-rw-r--r--src/core/hle/kernel/server_session.cpp6
-rw-r--r--src/core/hle/kernel/time_manager.cpp10
-rw-r--r--src/core/hle/service/am/am.cpp1
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp61
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h1
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp53
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp17
-rw-r--r--src/core/hle/service/hid/hid.cpp8
-rw-r--r--src/core/hle/service/hid/hid.h2
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp4
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h30
-rw-r--r--src/core/hle/service/vi/vi.cpp4
-rw-r--r--src/core/memory/cheat_engine.cpp12
-rw-r--r--src/core/memory/cheat_engine.h2
-rw-r--r--src/core/network/network.cpp654
-rw-r--r--src/core/network/network.h87
-rw-r--r--src/core/network/sockets.h94
-rw-r--r--src/core/settings.cpp1
-rw-r--r--src/core/settings.h1
-rw-r--r--src/core/tools/freezer.cpp11
-rw-r--r--src/core/tools/freezer.h2
33 files changed, 1061 insertions, 178 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c42f95705..c85c9485f 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -586,6 +586,9 @@ add_library(core STATIC
memory/dmnt_cheat_vm.h
memory.cpp
memory.h
+ network/network.cpp
+ network/network.h
+ network/sockets.h
perf_stats.cpp
perf_stats.h
reporter.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 69a1aa0a5..42277e2cd 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -43,6 +43,7 @@
#include "core/loader/loader.h"
#include "core/memory.h"
#include "core/memory/cheat_engine.h"
+#include "core/network/network.h"
#include "core/perf_stats.h"
#include "core/reporter.h"
#include "core/settings.h"
@@ -145,7 +146,7 @@ struct System::Impl {
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(HW_Memory, "initialized OK");
- device_memory = std::make_unique<Core::DeviceMemory>(system);
+ device_memory = std::make_unique<Core::DeviceMemory>();
is_multicore = Settings::values.use_multi_core.GetValue();
is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation.GetValue();
@@ -394,6 +395,9 @@ struct System::Impl {
/// Telemetry session for this emulation session
std::unique_ptr<Core::TelemetrySession> telemetry_session;
+ /// Network instance
+ Network::NetworkInstance network_instance;
+
ResultStatus status = ResultStatus::Success;
std::string status_details = "";
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index b5feb3f24..71af26ec5 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -23,7 +23,7 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
struct CoreTiming::Event {
u64 time;
u64 fifo_order;
- u64 userdata;
+ std::uintptr_t user_data;
std::weak_ptr<EventType> type;
// Sort by time, unless the times are the same, in which case sort by
@@ -58,7 +58,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
event_fifo_id = 0;
shutting_down = false;
ticks = 0;
- const auto empty_timed_callback = [](u64, std::chrono::nanoseconds) {};
+ const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {};
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
if (is_multicore) {
timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this));
@@ -107,22 +107,24 @@ bool CoreTiming::HasPendingEvents() const {
}
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
- const std::shared_ptr<EventType>& event_type, u64 userdata) {
+ const std::shared_ptr<EventType>& event_type,
+ std::uintptr_t user_data) {
{
std::scoped_lock scope{basic_lock};
const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count());
- event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
+ event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type});
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
event.Set();
}
-void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata) {
+void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
+ std::uintptr_t user_data) {
std::scoped_lock scope{basic_lock};
const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
- return e.type.lock().get() == event_type.get() && e.userdata == userdata;
+ return e.type.lock().get() == event_type.get() && e.user_data == user_data;
});
// Removing random items breaks the invariant so we have to re-establish it.
@@ -197,7 +199,7 @@ std::optional<s64> CoreTiming::Advance() {
if (const auto event_type{evt.type.lock()}) {
event_type->callback(
- evt.userdata, std::chrono::nanoseconds{static_cast<s64>(global_timer - evt.time)});
+ evt.user_data, std::chrono::nanoseconds{static_cast<s64>(global_timer - evt.time)});
}
basic_lock.lock();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 120c74e46..b0b6036e4 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -22,7 +22,8 @@
namespace Core::Timing {
/// A callback that may be scheduled for a particular core timing event.
-using TimedCallback = std::function<void(u64 userdata, std::chrono::nanoseconds ns_late)>;
+using TimedCallback =
+ std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>;
/// Contains the characteristics of a particular event.
struct EventType {
@@ -94,9 +95,9 @@ public:
/// Schedules an event in core timing
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
- const std::shared_ptr<EventType>& event_type, u64 userdata = 0);
+ const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0);
- void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata);
+ void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
/// We only permit one event of each type in the queue at a time.
void RemoveEvent(const std::shared_ptr<EventType>& event_type);
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 32afcf3ae..358943429 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -52,15 +52,15 @@ void CpuManager::Shutdown() {
}
std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
- return std::function<void(void*)>(GuestThreadFunction);
+ return GuestThreadFunction;
}
std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
- return std::function<void(void*)>(IdleThreadFunction);
+ return IdleThreadFunction;
}
std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
- return std::function<void(void*)>(SuspendThreadFunction);
+ return SuspendThreadFunction;
}
void CpuManager::GuestThreadFunction(void* cpu_manager_) {
diff --git a/src/core/device_memory.cpp b/src/core/device_memory.cpp
index 51097ced3..0c4b440ed 100644
--- a/src/core/device_memory.cpp
+++ b/src/core/device_memory.cpp
@@ -2,14 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "core/core.h"
#include "core/device_memory.h"
-#include "core/memory.h"
namespace Core {
-DeviceMemory::DeviceMemory(System& system) : buffer{DramMemoryMap::Size}, system{system} {}
-
+DeviceMemory::DeviceMemory() : buffer{DramMemoryMap::Size} {}
DeviceMemory::~DeviceMemory() = default;
} // namespace Core
diff --git a/src/core/device_memory.h b/src/core/device_memory.h
index 9efa088d0..5b1ae28f3 100644
--- a/src/core/device_memory.h
+++ b/src/core/device_memory.h
@@ -4,14 +4,11 @@
#pragma once
-#include "common/assert.h"
-#include "common/common_funcs.h"
+#include "common/common_types.h"
#include "common/virtual_buffer.h"
namespace Core {
-class System;
-
namespace DramMemoryMap {
enum : u64 {
Base = 0x80000000ULL,
@@ -26,7 +23,7 @@ enum : u64 {
class DeviceMemory : NonCopyable {
public:
- explicit DeviceMemory(Core::System& system);
+ explicit DeviceMemory();
~DeviceMemory();
template <typename T>
@@ -45,7 +42,6 @@ public:
private:
Common::VirtualBuffer<u8> buffer;
- Core::System& system;
};
} // namespace Core
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 37351c561..e94eed3b6 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -547,56 +547,6 @@ InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_ex
return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
}
-bool RegisteredCache::RemoveExistingEntry(u64 title_id) {
- const auto delete_nca = [this](const NcaID& id) {
- const auto path = GetRelativePathFromNcaID(id, false, true, false);
-
- if (dir->GetFileRelative(path) == nullptr) {
- return false;
- }
-
- Core::Crypto::SHA256Hash hash{};
- mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
- const auto dirname = fmt::format("000000{:02X}", hash[0]);
-
- const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
-
- const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false)));
-
- return res;
- };
-
- // If an entry exists in the registered cache, remove it
- if (HasEntry(title_id, ContentRecordType::Meta)) {
- LOG_INFO(Loader,
- "Previously installed entry (v{}) for title_id={:016X} detected! "
- "Attempting to remove...",
- GetEntryVersion(title_id).value_or(0), title_id);
- // Get all the ncas associated with the current CNMT and delete them
- const auto meta_old_id =
- GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
- const auto program_id =
- GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
- const auto data_id =
- GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
- const auto control_id =
- GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
- const auto html_id =
- GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
- const auto legal_id =
- GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
-
- delete_nca(meta_old_id);
- delete_nca(program_id);
- delete_nca(data_id);
- delete_nca(control_id);
- delete_nca(html_id);
- delete_nca(legal_id);
- return true;
- }
- return false;
-}
-
InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
const VfsCopyFunction& copy) {
const auto ncas = nsp.GetNCAsCollapsed();
@@ -692,6 +642,57 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
}
+bool RegisteredCache::RemoveExistingEntry(u64 title_id) const {
+ const auto delete_nca = [this](const NcaID& id) {
+ const auto path = GetRelativePathFromNcaID(id, false, true, false);
+
+ const bool isFile = dir->GetFileRelative(path) != nullptr;
+ const bool isDir = dir->GetDirectoryRelative(path) != nullptr;
+
+ if (isFile) {
+ return dir->DeleteFile(path);
+ } else if (isDir) {
+ return dir->DeleteSubdirectoryRecursive(path);
+ }
+
+ return false;
+ };
+
+ // If an entry exists in the registered cache, remove it
+ if (HasEntry(title_id, ContentRecordType::Meta)) {
+ LOG_INFO(Loader,
+ "Previously installed entry (v{}) for title_id={:016X} detected! "
+ "Attempting to remove...",
+ GetEntryVersion(title_id).value_or(0), title_id);
+
+ // Get all the ncas associated with the current CNMT and delete them
+ const auto meta_old_id =
+ GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
+ const auto program_id =
+ GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
+ const auto data_id =
+ GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
+ const auto control_id =
+ GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
+ const auto html_id =
+ GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
+ const auto legal_id =
+ GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
+
+ const auto deleted_meta = delete_nca(meta_old_id);
+ const auto deleted_program = delete_nca(program_id);
+ const auto deleted_data = delete_nca(data_id);
+ const auto deleted_control = delete_nca(control_id);
+ const auto deleted_html = delete_nca(html_id);
+ const auto deleted_legal = delete_nca(legal_id);
+
+ return deleted_meta && (deleted_meta || deleted_program || deleted_data ||
+ deleted_control || deleted_html || deleted_legal);
+ }
+
+ return false;
+}
+
InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
bool overwrite_if_exists,
std::optional<NcaID> override_id) {
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 29cf0d40c..ec1d54f27 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -155,9 +155,6 @@ public:
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
std::optional<u64> title_id = {}) const override;
- // Removes an existing entry based on title id
- bool RemoveExistingEntry(u64 title_id);
-
// Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
// there is a meta NCA and all of them are accessible.
InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
@@ -172,6 +169,9 @@ public:
InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
const VfsCopyFunction& copy = &VfsRawCopy);
+ // Removes an existing entry based on title id
+ bool RemoveExistingEntry(u64 title_id) const;
+
private:
template <typename T>
void IterateAllMetadata(std::vector<T>& out,
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index 86e06ccb9..81413c684 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -70,14 +70,18 @@ NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
NAX::~NAX() = default;
Loader::ResultStatus NAX::Parse(std::string_view path) {
- if (file->ReadObject(header.get()) != sizeof(NAXHeader))
+ if (file == nullptr) {
+ return Loader::ResultStatus::ErrorNullFile;
+ }
+ if (file->ReadObject(header.get()) != sizeof(NAXHeader)) {
return Loader::ResultStatus::ErrorBadNAXHeader;
-
- if (header->magic != Common::MakeMagic('N', 'A', 'X', '0'))
+ }
+ if (header->magic != Common::MakeMagic('N', 'A', 'X', '0')) {
return Loader::ResultStatus::ErrorBadNAXHeader;
-
- if (file->GetSize() < NAX_HEADER_PADDING_SIZE + header->file_size)
+ }
+ if (file->GetSize() < NAX_HEADER_PADDING_SIZE + header->file_size) {
return Loader::ResultStatus::ErrorIncorrectNAXFileSize;
+ }
keys.DeriveSDSeedLazy();
std::array<Core::Crypto::Key256, 2> sd_keys{};
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp
index efc1030c1..645f26e91 100644
--- a/src/core/hardware_interrupt_manager.cpp
+++ b/src/core/hardware_interrupt_manager.cpp
@@ -11,8 +11,8 @@
namespace Core::Hardware {
InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
- gpu_interrupt_event =
- Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, std::chrono::nanoseconds) {
+ gpu_interrupt_event = Core::Timing::CreateEvent(
+ "GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) {
auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
const u32 syncpt = static_cast<u32>(message >> 32);
const u32 value = static_cast<u32>(message);
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 8dd4a2637..cabe8d418 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -145,7 +145,7 @@ struct KernelCore::Impl {
void InitializePreemption(KernelCore& kernel) {
preemption_event = Core::Timing::CreateEvent(
- "PreemptionCallback", [this, &kernel](u64, std::chrono::nanoseconds) {
+ "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) {
{
SchedulerLock lock(kernel);
global_scheduler.PreemptThreads();
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index af22f4c33..7e6391c6c 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -33,8 +33,10 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
std::string name) {
std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
- session->request_event = Core::Timing::CreateEvent(
- name, [session](u64, std::chrono::nanoseconds) { session->CompleteSyncRequest(); });
+ session->request_event =
+ Core::Timing::CreateEvent(name, [session](std::uintptr_t, std::chrono::nanoseconds) {
+ session->CompleteSyncRequest();
+ });
session->name = std::move(name);
session->parent = std::move(parent);
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 88b01b751..95f2446c9 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -16,14 +16,14 @@ namespace Kernel {
TimeManager::TimeManager(Core::System& system_) : system{system_} {
time_manager_event_type = Core::Timing::CreateEvent(
- "Kernel::TimeManagerCallback", [this](u64 thread_handle, std::chrono::nanoseconds) {
- SchedulerLock lock(system.Kernel());
- Handle proper_handle = static_cast<Handle>(thread_handle);
+ "Kernel::TimeManagerCallback",
+ [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
+ const SchedulerLock lock(system.Kernel());
+ const auto proper_handle = static_cast<Handle>(thread_handle);
if (cancelled_events[proper_handle]) {
return;
}
- std::shared_ptr<Thread> thread =
- this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
+ auto thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
thread->OnWakeUp();
});
}
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 4e7a0bec9..ceed20609 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1405,7 +1405,6 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
// Get supported languages from NACP, if possible
// Default to 0 (all languages supported)
u32 supported_languages = 0;
- FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
const auto res = [this] {
const auto title_id = system.CurrentProcess()->GetTitleID();
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index fbe3686ae..289da2619 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -13,11 +13,23 @@
namespace Service::AM::Applets {
+namespace {
+enum class Request : u32 {
+ Finalize = 0x4,
+ SetUserWordInfo = 0x6,
+ SetCustomizeDic = 0x7,
+ Calc = 0xa,
+ SetCustomizedDictionaries = 0xb,
+ UnsetCustomizedDictionaries = 0xc,
+ UnknownD = 0xd,
+ UnknownE = 0xe,
+};
+constexpr std::size_t SWKBD_INLINE_INIT_SIZE = 0x8;
constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8;
constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4;
constexpr std::size_t DEFAULT_MAX_LENGTH = 500;
constexpr bool INTERACTIVE_STATUS_OK = false;
-
+} // Anonymous namespace
static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
KeyboardConfig config, std::u16string initial_text) {
Core::Frontend::SoftwareKeyboardParameters params{};
@@ -47,6 +59,7 @@ SoftwareKeyboard::~SoftwareKeyboard() = default;
void SoftwareKeyboard::Initialize() {
complete = false;
+ is_inline = false;
initial_text.clear();
final_data.clear();
@@ -56,6 +69,11 @@ void SoftwareKeyboard::Initialize() {
ASSERT(keyboard_config_storage != nullptr);
const auto& keyboard_config = keyboard_config_storage->GetData();
+ if (keyboard_config.size() == SWKBD_INLINE_INIT_SIZE) {
+ is_inline = true;
+ return;
+ }
+
ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
@@ -87,16 +105,32 @@ void SoftwareKeyboard::ExecuteInteractive() {
const auto storage = broker.PopInteractiveDataToApplet();
ASSERT(storage != nullptr);
const auto data = storage->GetData();
- const auto status = static_cast<bool>(data[0]);
-
- if (status == INTERACTIVE_STATUS_OK) {
- complete = true;
+ if (!is_inline) {
+ const auto status = static_cast<bool>(data[0]);
+ if (status == INTERACTIVE_STATUS_OK) {
+ complete = true;
+ } else {
+ std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
+ std::memcpy(string.data(), data.data() + 4, string.size() * 2);
+ frontend.SendTextCheckDialog(
+ Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
+ [this] { broker.SignalStateChanged(); });
+ }
} else {
- std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
- std::memcpy(string.data(), data.data() + 4, string.size() * 2);
- frontend.SendTextCheckDialog(
- Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
- [this] { broker.SignalStateChanged(); });
+ Request request{};
+ std::memcpy(&request, data.data(), sizeof(Request));
+
+ switch (request) {
+ case Request::Calc: {
+ broker.PushNormalDataFromApplet(
+ std::make_shared<IStorage>(std::move(std::vector<u8>{1})));
+ broker.SignalStateChanged();
+ break;
+ }
+ default:
+ UNIMPLEMENTED_MSG("Request {:X} is not implemented", request);
+ break;
+ }
}
}
@@ -108,9 +142,10 @@ void SoftwareKeyboard::Execute() {
}
const auto parameters = ConvertToFrontendParameters(config, initial_text);
-
- frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(std::move(text)); },
- parameters);
+ if (!is_inline) {
+ frontend.RequestText(
+ [this](std::optional<std::u16string> text) { WriteText(std::move(text)); }, parameters);
+ }
}
void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
index ef4801fc6..5a3824b5a 100644
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -78,6 +78,7 @@ private:
KeyboardConfig config;
std::u16string initial_text;
bool complete = false;
+ bool is_inline = false;
std::vector<u8> final_data;
};
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index cb35919e9..ad251ed4a 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -39,33 +39,36 @@ void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing,
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
- cur_entry.attribute.connected.Assign(1);
- auto& pad = cur_entry.pad_state;
- using namespace Settings::NativeButton;
- pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
- pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
- pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
- pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
- pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
- pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
- pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
- pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
- pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
- pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
- pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
- pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
- pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
- pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
+ if (Settings::values.debug_pad_enabled) {
+ cur_entry.attribute.connected.Assign(1);
+ auto& pad = cur_entry.pad_state;
- const auto [stick_l_x_f, stick_l_y_f] =
- analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
- const auto [stick_r_x_f, stick_r_y_f] =
- analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
- cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
- cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
- cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
- cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
+ using namespace Settings::NativeButton;
+ pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
+ pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
+ pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
+ pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
+ pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
+ pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
+ pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
+ pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
+ pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
+ pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
+ pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
+ pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
+ pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
+ pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
+
+ const auto [stick_l_x_f, stick_l_y_f] =
+ analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
+ const auto [stick_r_x_f, stick_r_y_f] =
+ analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
+ cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
+ cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
+ cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
+ cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
+ }
std::memcpy(data, &shared_memory, sizeof(SharedMemory));
}
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index feae89525..0b896d5ad 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -40,15 +40,16 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing,
cur_entry.key.fill(0);
cur_entry.modifier = 0;
-
- for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
- cur_entry.key[i / KEYS_PER_BYTE] |= (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE));
- }
-
- for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
- cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i);
+ if (Settings::values.keyboard_enabled) {
+ for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
+ cur_entry.key[i / KEYS_PER_BYTE] |=
+ (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE));
+ }
+
+ for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
+ cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i);
+ }
}
-
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
}
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 680290cbd..1e95b7580 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -77,8 +77,9 @@ IAppletResource::IAppletResource(Core::System& system)
// Register update callbacks
pad_update_event = Core::Timing::CreateEvent(
- "HID::UpdatePadCallback", [this](u64 userdata, std::chrono::nanoseconds ns_late) {
- UpdateControllers(userdata, ns_late);
+ "HID::UpdatePadCallback",
+ [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ UpdateControllers(user_data, ns_late);
});
// TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
@@ -108,7 +109,8 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(shared_mem);
}
-void IAppletResource::UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late) {
+void IAppletResource::UpdateControllers(std::uintptr_t user_data,
+ std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index c6f0a2584..efb07547f 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -64,7 +64,7 @@ private:
}
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
- void UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late);
+ void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
std::shared_ptr<Kernel::SharedMemory> shared_mem;
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 789856118..f644a460d 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -67,8 +67,8 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
// Schedule the screen composition events
composition_event = Core::Timing::CreateEvent(
- "ScreenComposition", [this](u64, std::chrono::nanoseconds ns_late) {
- Lock();
+ "ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
+ const auto guard = Lock();
Compose();
const auto ticks = std::chrono::nanoseconds{GetNextTicks()};
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index e4959a9af..ff85cbba6 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -54,12 +54,12 @@ public:
/// Opens the specified display and returns the ID.
///
/// If an invalid display name is provided, then an empty optional is returned.
- std::optional<u64> OpenDisplay(std::string_view name);
+ [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name);
/// Creates a layer on the specified display and returns the layer ID.
///
/// If an invalid display ID is specified, then an empty optional is returned.
- std::optional<u64> CreateLayer(u64 display_id);
+ [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id);
/// Closes a layer on all displays for the given layer ID.
void CloseLayer(u64 layer_id);
@@ -67,41 +67,39 @@ public:
/// Finds the buffer queue ID of the specified layer in the specified display.
///
/// If an invalid display ID or layer ID is provided, then an empty optional is returned.
- std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id) const;
+ [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id) const;
/// Gets the vsync event for the specified display.
///
/// If an invalid display ID is provided, then nullptr is returned.
- std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
+ [[nodiscard]] std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
/// Obtains a buffer queue identified by the ID.
- BufferQueue& FindBufferQueue(u32 id);
+ [[nodiscard]] BufferQueue& FindBufferQueue(u32 id);
/// Obtains a buffer queue identified by the ID.
- const BufferQueue& FindBufferQueue(u32 id) const;
+ [[nodiscard]] const BufferQueue& FindBufferQueue(u32 id) const;
/// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
/// finished.
void Compose();
- s64 GetNextTicks() const;
+ [[nodiscard]] s64 GetNextTicks() const;
- std::unique_lock<std::mutex> Lock() {
- return std::unique_lock{*guard};
- }
+ [[nodiscard]] std::unique_lock<std::mutex> Lock() const { return std::unique_lock{*guard}; }
-private:
- /// Finds the display identified by the specified ID.
- VI::Display* FindDisplay(u64 display_id);
+ private :
+ /// Finds the display identified by the specified ID.
+ [[nodiscard]] VI::Display* FindDisplay(u64 display_id);
/// Finds the display identified by the specified ID.
- const VI::Display* FindDisplay(u64 display_id) const;
+ [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const;
/// Finds the layer identified by the specified ID in the desired display.
- VI::Layer* FindLayer(u64 display_id, u64 layer_id);
+ [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
/// Finds the layer identified by the specified ID in the desired display.
- const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
+ [[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
static void VSyncThread(NVFlinger& nv_flinger);
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index ea7b4ae13..825d11a3f 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -511,7 +511,7 @@ private:
LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
static_cast<u32>(transaction), flags);
- nv_flinger->Lock();
+ const auto guard = nv_flinger->Lock();
auto& buffer_queue = nv_flinger->FindBufferQueue(id);
switch (transaction) {
@@ -551,7 +551,7 @@ private:
[=](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
Kernel::ThreadWakeupReason reason) {
// Repeat TransactParcel DequeueBuffer when a buffer is available
- nv_flinger->Lock();
+ const auto guard = nv_flinger->Lock();
auto& buffer_queue = nv_flinger->FindBufferQueue(id);
auto result = buffer_queue.DequeueBuffer(width, height);
ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index ced41b1fe..eeebdf02e 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -188,11 +188,11 @@ CheatEngine::~CheatEngine() {
}
void CheatEngine::Initialize() {
- event = Core::Timing::CreateEvent("CheatEngine::FrameCallback::" +
- Common::HexToString(metadata.main_nso_build_id),
- [this](u64 userdata, std::chrono::nanoseconds ns_late) {
- FrameCallback(userdata, ns_late);
- });
+ event = Core::Timing::CreateEvent(
+ "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
+ [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ FrameCallback(user_data, ns_late);
+ });
core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event);
metadata.process_id = system.CurrentProcess()->GetProcessID();
@@ -219,7 +219,7 @@ void CheatEngine::Reload(std::vector<CheatEntry> cheats) {
MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70));
-void CheatEngine::FrameCallback(u64, std::chrono::nanoseconds ns_late) {
+void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
if (is_pending_reload.exchange(false)) {
vm.LoadProgram(cheats);
}
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index d4068cf84..fa039a831 100644
--- a/src/core/memory/cheat_engine.h
+++ b/src/core/memory/cheat_engine.h
@@ -72,7 +72,7 @@ public:
void Reload(std::vector<CheatEntry> cheats);
private:
- void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late);
+ void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
DmntCheatVm vm;
CheatProcessMetadata metadata;
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
new file mode 100644
index 000000000..56d173b5e
--- /dev/null
+++ b/src/core/network/network.cpp
@@ -0,0 +1,654 @@
+// Copyright 2020 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <cstring>
+#include <limits>
+#include <utility>
+#include <vector>
+
+#ifdef _WIN32
+#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
+#include <winsock2.h>
+#elif __unix__
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#else
+#error "Unimplemented platform"
+#endif
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "core/network/network.h"
+#include "core/network/sockets.h"
+
+namespace Network {
+
+namespace {
+
+#ifdef _WIN32
+
+using socklen_t = int;
+
+void Initialize() {
+ WSADATA wsa_data;
+ (void)WSAStartup(MAKEWORD(2, 2), &wsa_data);
+}
+
+void Finalize() {
+ WSACleanup();
+}
+
+constexpr IPv4Address TranslateIPv4(in_addr addr) {
+ auto& bytes = addr.S_un.S_un_b;
+ return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
+}
+
+sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
+ sockaddr_in result;
+
+#ifdef __unix__
+ result.sin_len = sizeof(result);
+#endif
+
+ switch (static_cast<Domain>(input.family)) {
+ case Domain::INET:
+ result.sin_family = AF_INET;
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family));
+ result.sin_family = AF_INET;
+ break;
+ }
+
+ result.sin_port = htons(input.portno);
+
+ auto& ip = result.sin_addr.S_un.S_un_b;
+ ip.s_b1 = input.ip[0];
+ ip.s_b2 = input.ip[1];
+ ip.s_b3 = input.ip[2];
+ ip.s_b4 = input.ip[3];
+
+ sockaddr addr;
+ std::memcpy(&addr, &result, sizeof(addr));
+ return addr;
+}
+
+LINGER MakeLinger(bool enable, u32 linger_value) {
+ ASSERT(linger_value <= std::numeric_limits<u_short>::max());
+
+ LINGER value;
+ value.l_onoff = enable ? 1 : 0;
+ value.l_linger = static_cast<u_short>(linger_value);
+ return value;
+}
+
+int LastError() {
+ return WSAGetLastError();
+}
+
+bool EnableNonBlock(SOCKET fd, bool enable) {
+ u_long value = enable ? 1 : 0;
+ return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR;
+}
+
+#elif __unix__ // ^ _WIN32 v __unix__
+
+using SOCKET = int;
+using WSAPOLLFD = pollfd;
+using ULONG = u64;
+
+constexpr SOCKET INVALID_SOCKET = -1;
+constexpr SOCKET SOCKET_ERROR = -1;
+
+constexpr int WSAEWOULDBLOCK = EAGAIN;
+constexpr int WSAENOTCONN = ENOTCONN;
+
+constexpr int SD_RECEIVE = SHUT_RD;
+constexpr int SD_SEND = SHUT_WR;
+constexpr int SD_BOTH = SHUT_RDWR;
+
+void Initialize() {}
+
+void Finalize() {}
+
+constexpr IPv4Address TranslateIPv4(in_addr addr) {
+ const u32 bytes = addr.s_addr;
+ return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),
+ static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)};
+}
+
+sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
+ sockaddr_in result;
+
+ switch (static_cast<Domain>(input.family)) {
+ case Domain::INET:
+ result.sin_family = AF_INET;
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family));
+ result.sin_family = AF_INET;
+ break;
+ }
+
+ result.sin_port = htons(input.portno);
+
+ result.sin_addr.s_addr = input.ip[0] | input.ip[1] << 8 | input.ip[2] << 16 | input.ip[3] << 24;
+
+ sockaddr addr;
+ std::memcpy(&addr, &result, sizeof(addr));
+ return addr;
+}
+
+int WSAPoll(WSAPOLLFD* fds, ULONG nfds, int timeout) {
+ return poll(fds, nfds, timeout);
+}
+
+int closesocket(SOCKET fd) {
+ return close(fd);
+}
+
+linger MakeLinger(bool enable, u32 linger_value) {
+ linger value;
+ value.l_onoff = enable ? 1 : 0;
+ value.l_linger = linger_value;
+ return value;
+}
+
+int LastError() {
+ return errno;
+}
+
+bool EnableNonBlock(int fd, bool enable) {
+ int flags = fcntl(fd, F_GETFD);
+ if (flags == -1) {
+ return false;
+ }
+ if (enable) {
+ flags |= O_NONBLOCK;
+ } else {
+ flags &= ~O_NONBLOCK;
+ }
+ return fcntl(fd, F_SETFD, flags) == 0;
+}
+
+#endif
+
+int TranslateDomain(Domain domain) {
+ switch (domain) {
+ case Domain::INET:
+ return AF_INET;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain));
+ return 0;
+ }
+}
+
+int TranslateType(Type type) {
+ switch (type) {
+ case Type::STREAM:
+ return SOCK_STREAM;
+ case Type::DGRAM:
+ return SOCK_DGRAM;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type));
+ return 0;
+ }
+}
+
+int TranslateProtocol(Protocol protocol) {
+ switch (protocol) {
+ case Protocol::TCP:
+ return IPPROTO_TCP;
+ case Protocol::UDP:
+ return IPPROTO_UDP;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol));
+ return 0;
+ }
+}
+
+SockAddrIn TranslateToSockAddrIn(sockaddr input_) {
+ sockaddr_in input;
+ std::memcpy(&input, &input_, sizeof(input));
+
+ SockAddrIn result;
+
+ switch (input.sin_family) {
+ case AF_INET:
+ result.family = Domain::INET;
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.sin_family);
+ result.family = Domain::INET;
+ break;
+ }
+
+ result.portno = ntohs(input.sin_port);
+
+ result.ip = TranslateIPv4(input.sin_addr);
+
+ return result;
+}
+
+u16 TranslatePollEvents(u16 events) {
+ u16 result = 0;
+
+ if (events & POLL_IN) {
+ events &= ~POLL_IN;
+ result |= POLLIN;
+ }
+ if (events & POLL_PRI) {
+ events &= ~POLL_PRI;
+#ifdef _WIN32
+ LOG_WARNING(Service, "Winsock doesn't support POLLPRI");
+#else
+ result |= POLL_PRI;
+#endif
+ }
+ if (events & POLL_OUT) {
+ events &= ~POLL_OUT;
+ result |= POLLOUT;
+ }
+
+ UNIMPLEMENTED_IF_MSG(events != 0, "Unhandled guest events=0x{:x}", events);
+
+ return result;
+}
+
+u16 TranslatePollRevents(u16 revents) {
+ u16 result = 0;
+ const auto translate = [&result, &revents](int host, unsigned guest) {
+ if (revents & host) {
+ revents &= ~host;
+ result |= guest;
+ }
+ };
+
+ translate(POLLIN, POLL_IN);
+ translate(POLLPRI, POLL_PRI);
+ translate(POLLOUT, POLL_OUT);
+ translate(POLLERR, POLL_ERR);
+ translate(POLLHUP, POLL_HUP);
+
+ UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents);
+
+ return result;
+}
+
+template <typename T>
+Errno SetSockOpt(SOCKET fd, int option, T value) {
+ const int result =
+ setsockopt(fd, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value));
+ if (result != SOCKET_ERROR) {
+ return Errno::SUCCESS;
+ }
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return Errno::SUCCESS;
+}
+
+} // Anonymous namespace
+
+NetworkInstance::NetworkInstance() {
+ Initialize();
+}
+
+NetworkInstance::~NetworkInstance() {
+ Finalize();
+}
+
+std::pair<IPv4Address, Errno> GetHostIPv4Address() {
+ std::array<char, 256> name{};
+ if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) {
+ UNIMPLEMENTED_MSG("Unhandled gethostname error");
+ return {IPv4Address{}, Errno::SUCCESS};
+ }
+
+ hostent* const ent = gethostbyname(name.data());
+ if (!ent) {
+ UNIMPLEMENTED_MSG("Unhandled gethostbyname error");
+ return {IPv4Address{}, Errno::SUCCESS};
+ }
+ if (ent->h_addr_list == nullptr) {
+ UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list");
+ return {IPv4Address{}, Errno::SUCCESS};
+ }
+ if (ent->h_length != sizeof(in_addr)) {
+ UNIMPLEMENTED_MSG("Unexpected size={} in hostent->h_length", ent->h_length);
+ }
+
+ in_addr addr;
+ std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr));
+ return {TranslateIPv4(addr), Errno::SUCCESS};
+}
+
+std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
+ const size_t num = pollfds.size();
+
+ std::vector<WSAPOLLFD> host_pollfds(pollfds.size());
+ std::transform(pollfds.begin(), pollfds.end(), host_pollfds.begin(), [](PollFD fd) {
+ WSAPOLLFD result;
+ result.fd = fd.socket->fd;
+ result.events = TranslatePollEvents(fd.events);
+ result.revents = 0;
+ return result;
+ });
+
+ const int result = WSAPoll(host_pollfds.data(), static_cast<ULONG>(num), timeout);
+ if (result == 0) {
+ ASSERT(std::all_of(host_pollfds.begin(), host_pollfds.end(),
+ [](WSAPOLLFD fd) { return fd.revents == 0; }));
+ return {0, Errno::SUCCESS};
+ }
+
+ for (size_t i = 0; i < num; ++i) {
+ pollfds[i].revents = TranslatePollRevents(host_pollfds[i].revents);
+ }
+
+ if (result > 0) {
+ return {result, Errno::SUCCESS};
+ }
+
+ ASSERT(result == SOCKET_ERROR);
+
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return {-1, Errno::SUCCESS};
+}
+
+Socket::~Socket() {
+ if (fd == INVALID_SOCKET) {
+ return;
+ }
+ (void)closesocket(fd);
+ fd = INVALID_SOCKET;
+}
+
+Socket::Socket(Socket&& rhs) noexcept : fd{std::exchange(rhs.fd, INVALID_SOCKET)} {}
+
+Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
+ fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol));
+ if (fd != INVALID_SOCKET) {
+ return Errno::SUCCESS;
+ }
+
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return Errno::SUCCESS;
+}
+
+std::pair<Socket::AcceptResult, Errno> Socket::Accept() {
+ sockaddr addr;
+ socklen_t addrlen = sizeof(addr);
+ const SOCKET new_socket = accept(fd, &addr, &addrlen);
+
+ if (new_socket == INVALID_SOCKET) {
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return {AcceptResult{}, Errno::SUCCESS};
+ }
+
+ AcceptResult result;
+ result.socket = std::make_unique<Socket>();
+ result.socket->fd = new_socket;
+
+ ASSERT(addrlen == sizeof(sockaddr_in));
+ result.sockaddr_in = TranslateToSockAddrIn(addr);
+
+ return {std::move(result), Errno::SUCCESS};
+}
+
+Errno Socket::Connect(SockAddrIn addr_in) {
+ const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in);
+ if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != INVALID_SOCKET) {
+ return Errno::SUCCESS;
+ }
+
+ switch (const int ec = LastError()) {
+ case WSAEWOULDBLOCK:
+ LOG_DEBUG(Service, "EAGAIN generated");
+ return Errno::AGAIN;
+ default:
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return Errno::SUCCESS;
+ }
+}
+
+std::pair<SockAddrIn, Errno> Socket::GetPeerName() {
+ sockaddr addr;
+ socklen_t addrlen = sizeof(addr);
+ if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) {
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return {SockAddrIn{}, Errno::SUCCESS};
+ }
+
+ ASSERT(addrlen == sizeof(sockaddr_in));
+ return {TranslateToSockAddrIn(addr), Errno::SUCCESS};
+}
+
+std::pair<SockAddrIn, Errno> Socket::GetSockName() {
+ sockaddr addr;
+ socklen_t addrlen = sizeof(addr);
+ if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) {
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return {SockAddrIn{}, Errno::SUCCESS};
+ }
+
+ ASSERT(addrlen == sizeof(sockaddr_in));
+ return {TranslateToSockAddrIn(addr), Errno::SUCCESS};
+}
+
+Errno Socket::Bind(SockAddrIn addr) {
+ const sockaddr addr_in = TranslateFromSockAddrIn(addr);
+ if (bind(fd, &addr_in, sizeof(addr_in)) != SOCKET_ERROR) {
+ return Errno::SUCCESS;
+ }
+
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return Errno::SUCCESS;
+}
+
+Errno Socket::Listen(s32 backlog) {
+ if (listen(fd, backlog) != SOCKET_ERROR) {
+ return Errno::SUCCESS;
+ }
+
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return Errno::SUCCESS;
+}
+
+Errno Socket::Shutdown(ShutdownHow how) {
+ int host_how = 0;
+ switch (how) {
+ case ShutdownHow::RD:
+ host_how = SD_RECEIVE;
+ break;
+ case ShutdownHow::WR:
+ host_how = SD_SEND;
+ break;
+ case ShutdownHow::RDWR:
+ host_how = SD_BOTH;
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented flag how={}", static_cast<int>(how));
+ return Errno::SUCCESS;
+ }
+ if (shutdown(fd, host_how) != SOCKET_ERROR) {
+ return Errno::SUCCESS;
+ }
+
+ switch (const int ec = LastError()) {
+ case WSAENOTCONN:
+ LOG_ERROR(Service, "ENOTCONN generated");
+ return Errno::NOTCONN;
+ default:
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return Errno::SUCCESS;
+ }
+}
+
+std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
+ ASSERT(flags == 0);
+ ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
+
+ const int result =
+ recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0);
+ if (result != SOCKET_ERROR) {
+ return {result, Errno::SUCCESS};
+ }
+
+ switch (const int ec = LastError()) {
+ case WSAEWOULDBLOCK:
+ LOG_DEBUG(Service, "EAGAIN generated");
+ return {-1, Errno::AGAIN};
+ case WSAENOTCONN:
+ LOG_ERROR(Service, "ENOTCONN generated");
+ return {-1, Errno::NOTCONN};
+ default:
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return {0, Errno::SUCCESS};
+ }
+}
+
+std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) {
+ ASSERT(flags == 0);
+ ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
+
+ sockaddr addr_in{};
+ socklen_t addrlen = sizeof(addr_in);
+ socklen_t* const p_addrlen = addr ? &addrlen : nullptr;
+ sockaddr* const p_addr_in = addr ? &addr_in : nullptr;
+
+ const int result = recvfrom(fd, reinterpret_cast<char*>(message.data()),
+ static_cast<int>(message.size()), 0, p_addr_in, p_addrlen);
+ if (result != SOCKET_ERROR) {
+ if (addr) {
+ ASSERT(addrlen == sizeof(addr_in));
+ *addr = TranslateToSockAddrIn(addr_in);
+ }
+ return {result, Errno::SUCCESS};
+ }
+
+ switch (const int ec = LastError()) {
+ case WSAEWOULDBLOCK:
+ LOG_DEBUG(Service, "EAGAIN generated");
+ return {-1, Errno::AGAIN};
+ case WSAENOTCONN:
+ LOG_ERROR(Service, "ENOTCONN generated");
+ return {-1, Errno::NOTCONN};
+ default:
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return {-1, Errno::SUCCESS};
+ }
+}
+
+std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
+ ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
+ ASSERT(flags == 0);
+
+ const int result = send(fd, reinterpret_cast<const char*>(message.data()),
+ static_cast<int>(message.size()), 0);
+ if (result != SOCKET_ERROR) {
+ return {result, Errno::SUCCESS};
+ }
+
+ const int ec = LastError();
+ switch (ec) {
+ case WSAEWOULDBLOCK:
+ LOG_DEBUG(Service, "EAGAIN generated");
+ return {-1, Errno::AGAIN};
+ case WSAENOTCONN:
+ LOG_ERROR(Service, "ENOTCONN generated");
+ return {-1, Errno::NOTCONN};
+ default:
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return {-1, Errno::SUCCESS};
+ }
+}
+
+std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
+ const SockAddrIn* addr) {
+ ASSERT(flags == 0);
+
+ const sockaddr* to = nullptr;
+ const int tolen = addr ? 0 : sizeof(sockaddr);
+ sockaddr host_addr_in;
+
+ if (addr) {
+ host_addr_in = TranslateFromSockAddrIn(*addr);
+ to = &host_addr_in;
+ }
+
+ const int result = sendto(fd, reinterpret_cast<const char*>(message.data()),
+ static_cast<int>(message.size()), 0, to, tolen);
+ if (result != SOCKET_ERROR) {
+ return {result, Errno::SUCCESS};
+ }
+
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return {-1, Errno::SUCCESS};
+}
+
+Errno Socket::Close() {
+ [[maybe_unused]] const int result = closesocket(fd);
+ ASSERT(result == 0);
+ fd = INVALID_SOCKET;
+
+ return Errno::SUCCESS;
+}
+
+Errno Socket::SetLinger(bool enable, u32 linger) {
+ return SetSockOpt(fd, SO_LINGER, MakeLinger(enable, linger));
+}
+
+Errno Socket::SetReuseAddr(bool enable) {
+ return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0);
+}
+
+Errno Socket::SetBroadcast(bool enable) {
+ return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0);
+}
+
+Errno Socket::SetSndBuf(u32 value) {
+ return SetSockOpt(fd, SO_SNDBUF, value);
+}
+
+Errno Socket::SetRcvBuf(u32 value) {
+ return SetSockOpt(fd, SO_RCVBUF, value);
+}
+
+Errno Socket::SetSndTimeo(u32 value) {
+ return SetSockOpt(fd, SO_SNDTIMEO, value);
+}
+
+Errno Socket::SetRcvTimeo(u32 value) {
+ return SetSockOpt(fd, SO_RCVTIMEO, value);
+}
+
+Errno Socket::SetNonBlock(bool enable) {
+ if (EnableNonBlock(fd, enable)) {
+ return Errno::SUCCESS;
+ }
+ const int ec = LastError();
+ UNREACHABLE_MSG("Unhandled host socket error={}", ec);
+ return Errno::SUCCESS;
+}
+
+bool Socket::IsOpened() const {
+ return fd != INVALID_SOCKET;
+}
+
+} // namespace Network
diff --git a/src/core/network/network.h b/src/core/network/network.h
new file mode 100644
index 000000000..0622e4593
--- /dev/null
+++ b/src/core/network/network.h
@@ -0,0 +1,87 @@
+// Copyright 2020 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <utility>
+
+#include "common/common_types.h"
+
+namespace Network {
+
+class Socket;
+
+/// Error code for network functions
+enum class Errno {
+ SUCCESS,
+ BADF,
+ INVAL,
+ MFILE,
+ NOTCONN,
+ AGAIN,
+};
+
+/// Address families
+enum class Domain {
+ INET, ///< Address family for IPv4
+};
+
+/// Socket types
+enum class Type {
+ STREAM,
+ DGRAM,
+ RAW,
+ SEQPACKET,
+};
+
+/// Protocol values for sockets
+enum class Protocol {
+ ICMP,
+ TCP,
+ UDP,
+};
+
+/// Shutdown mode
+enum class ShutdownHow {
+ RD,
+ WR,
+ RDWR,
+};
+
+/// Array of IPv4 address
+using IPv4Address = std::array<u8, 4>;
+
+/// Cross-platform sockaddr structure
+struct SockAddrIn {
+ Domain family;
+ IPv4Address ip;
+ u16 portno;
+};
+
+/// Cross-platform poll fd structure
+struct PollFD {
+ Socket* socket;
+ u16 events;
+ u16 revents;
+};
+
+constexpr u16 POLL_IN = 1 << 0;
+constexpr u16 POLL_PRI = 1 << 1;
+constexpr u16 POLL_OUT = 1 << 2;
+constexpr u16 POLL_ERR = 1 << 3;
+constexpr u16 POLL_HUP = 1 << 4;
+constexpr u16 POLL_NVAL = 1 << 5;
+
+class NetworkInstance {
+public:
+ explicit NetworkInstance();
+ ~NetworkInstance();
+};
+
+/// @brief Returns host's IPv4 address
+/// @return Pair of an array of human ordered IPv4 address (e.g. 192.168.0.1) and an error code
+std::pair<IPv4Address, Errno> GetHostIPv4Address();
+
+} // namespace Network
diff --git a/src/core/network/sockets.h b/src/core/network/sockets.h
new file mode 100644
index 000000000..7bdff0fe4
--- /dev/null
+++ b/src/core/network/sockets.h
@@ -0,0 +1,94 @@
+// Copyright 2020 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <utility>
+
+#if defined(_WIN32)
+#include <winsock.h>
+#elif !defined(__unix__)
+#error "Platform not implemented"
+#endif
+
+#include "common/common_types.h"
+#include "core/network/network.h"
+
+// TODO: C++20 Replace std::vector usages with std::span
+
+namespace Network {
+
+class Socket {
+public:
+ struct AcceptResult {
+ std::unique_ptr<Socket> socket;
+ SockAddrIn sockaddr_in;
+ };
+
+ explicit Socket() = default;
+ ~Socket();
+
+ Socket(const Socket&) = delete;
+ Socket& operator=(const Socket&) = delete;
+
+ Socket(Socket&& rhs) noexcept;
+
+ // Avoid closing sockets implicitly
+ Socket& operator=(Socket&&) noexcept = delete;
+
+ Errno Initialize(Domain domain, Type type, Protocol protocol);
+
+ Errno Close();
+
+ std::pair<AcceptResult, Errno> Accept();
+
+ Errno Connect(SockAddrIn addr_in);
+
+ std::pair<SockAddrIn, Errno> GetPeerName();
+
+ std::pair<SockAddrIn, Errno> GetSockName();
+
+ Errno Bind(SockAddrIn addr);
+
+ Errno Listen(s32 backlog);
+
+ Errno Shutdown(ShutdownHow how);
+
+ std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message);
+
+ std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr);
+
+ std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags);
+
+ std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, const SockAddrIn* addr);
+
+ Errno SetLinger(bool enable, u32 linger);
+
+ Errno SetReuseAddr(bool enable);
+
+ Errno SetBroadcast(bool enable);
+
+ Errno SetSndBuf(u32 value);
+
+ Errno SetRcvBuf(u32 value);
+
+ Errno SetSndTimeo(u32 value);
+
+ Errno SetRcvTimeo(u32 value);
+
+ Errno SetNonBlock(bool enable);
+
+ bool IsOpened() const;
+
+#if defined(_WIN32)
+ SOCKET fd = INVALID_SOCKET;
+#elif defined(__unix__)
+ int fd = -1;
+#endif
+};
+
+std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout);
+
+} // namespace Network
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 44252dd81..416b2d866 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -173,7 +173,6 @@ void RestoreGlobalState() {
values.use_assembly_shaders.SetGlobal(true);
values.use_asynchronous_shaders.SetGlobal(true);
values.use_fast_gpu_time.SetGlobal(true);
- values.force_30fps_mode.SetGlobal(true);
values.bg_red.SetGlobal(true);
values.bg_green.SetGlobal(true);
values.bg_blue.SetGlobal(true);
diff --git a/src/core/settings.h b/src/core/settings.h
index 386233fdf..bb145f193 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -435,7 +435,6 @@ struct Values {
Setting<bool> use_vsync;
Setting<bool> use_assembly_shaders;
Setting<bool> use_asynchronous_shaders;
- Setting<bool> force_30fps_mode;
Setting<bool> use_fast_gpu_time;
Setting<float> bg_red;
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 27b894b51..2003e096f 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -55,10 +55,11 @@ void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 v
Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_)
: core_timing{core_timing_}, memory{memory_} {
- event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback",
- [this](u64 userdata, std::chrono::nanoseconds ns_late) {
- FrameCallback(userdata, ns_late);
- });
+ event = Core::Timing::CreateEvent(
+ "MemoryFreezer::FrameCallback",
+ [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ FrameCallback(user_data, ns_late);
+ });
core_timing.ScheduleEvent(memory_freezer_ns, event);
}
@@ -159,7 +160,7 @@ std::vector<Freezer::Entry> Freezer::GetEntries() const {
return entries;
}
-void Freezer::FrameCallback(u64, std::chrono::nanoseconds ns_late) {
+void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
if (!IsActive()) {
LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events.");
return;
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h
index 8438783d5..2b2326bc4 100644
--- a/src/core/tools/freezer.h
+++ b/src/core/tools/freezer.h
@@ -73,7 +73,7 @@ public:
std::vector<Entry> GetEntries() const;
private:
- void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late);
+ void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void FillEntryReads();
std::atomic_bool active{false};