From 6e3a943e7442a29ef3d8cafe6f39b40baf0764d5 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 1 Oct 2025 08:04:34 +0000 Subject: [PATCH 1/6] [core] use memcpy instead of hand rolling aligned cases Hand rolling memcpy like this is always frowned upon because the compiler has more insight on whats going on (plus the code resolves to a worse version of itself on assembly). This removes some branches that are just straight up redundant. May save stuff especially for systems without fastmem enabled. Signed-off-by: lizzie --- src/core/memory.cpp | 203 ++++++++------------------------------------ 1 file changed, 36 insertions(+), 167 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 2583aae867..f84507d125 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "common/assert.h" @@ -681,22 +682,17 @@ struct Memory::Impl { } } - [[nodiscard]] u8* GetPointerImpl(u64 vaddr, auto on_unmapped, auto on_rasterizer) const { + template + [[nodiscard]] u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const { // AARCH64 masks the upper 16 bit of all memory accesses - vaddr = vaddr & 0xffffffffffffULL; - if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] { - on_unmapped(); - return nullptr; - } else { + vaddr &= 0xffffffffffffULL; + if (AddressSpaceContains(*current_page_table, vaddr, 1)) [[likely]] { // Avoid adding any extra logic to this fast-path block const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw(); - if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { + if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) [[likely]] { return reinterpret_cast(pointer + vaddr); } else { switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { - case Common::PageType::Unmapped: - on_unmapped(); - return nullptr; case Common::PageType::Memory: ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr); return nullptr; @@ -707,11 +703,18 @@ struct Memory::Impl { on_rasterizer(); return host_ptr; } + case Common::PageType::Unmapped: [[unlikely]] { + on_unmapped(); + return nullptr; + } default: UNREACHABLE(); } return nullptr; } + } else { + on_unmapped(); + return nullptr; } } @@ -729,172 +732,38 @@ struct Memory::Impl { GetInteger(vaddr), []() {}, []() {}); } - /** - * Reads a particular data type out of memory at the given virtual address. - * - * @param vaddr The virtual address to read the data type from. - * - * @tparam T The data type to read out of memory. This type *must* be - * trivially copyable, otherwise the behavior of this function - * is undefined. - * - * @returns The instance of T read from the specified virtual address. - */ + /// @brief Reads a particular data type out of memory at the given virtual address. + /// @param vaddr The virtual address to read the data type from. + /// @tparam T The data type to read out of memory. + /// @returns The instance of T read from the specified virtual address. template - T Read(Common::ProcessAddress vaddr) { - // Fast path for aligned reads of common sizes + inline T Read(Common::ProcessAddress vaddr) requires(std::is_trivially_copyable_v) noexcept { const u64 addr = GetInteger(vaddr); - if constexpr (std::is_same_v || std::is_same_v) { - // 8-bit reads are always aligned - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read8 @ 0x{:016X}", addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { - return static_cast(*ptr); - } - return 0; - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 16-bit reads - if ((addr & 1) == 0) { - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read16 @ 0x{:016X}", addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { - return static_cast(*reinterpret_cast(ptr)); - } - } - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 32-bit reads - if ((addr & 3) == 0) { - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read32 @ 0x{:016X}", addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { - return static_cast(*reinterpret_cast(ptr)); - } - } - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 64-bit reads - if ((addr & 7) == 0) { - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read64 @ 0x{:016X}", addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { - return static_cast(*reinterpret_cast(ptr)); - } - } - } - - // Fall back to the general case for other types or unaligned access - T result = 0; - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { + if (auto const ptr = GetPointerImpl(addr, [addr]() { + LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr); + }, [&]() { + HandleRasterizerDownload(addr, sizeof(T)); + }); ptr) [[likely]] { + // It may be tempting to rewrite this particular section to use "reinterpret_cast"; + // afterall, it's trivially copyable so surely it can be copied ov- Alignment. + // Remember, alignment. memcpy() will deal with all the alignment extremely fast. + T result{}; std::memcpy(&result, ptr, sizeof(T)); + return result; } - return result; + return T{}; } - /** - * Writes a particular data type to memory at the given virtual address. - * - * @param vaddr The virtual address to write the data type to. - * - * @tparam T The data type to write to memory. This type *must* be - * trivially copyable, otherwise the behavior of this function - * is undefined. - */ + /// @brief Writes a particular data type to memory at the given virtual address. + /// @param vaddr The virtual address to write the data type to. + /// @tparam T The data type to write to memory. template - void Write(Common::ProcessAddress vaddr, const T data) { - // Fast path for aligned writes of common sizes + inline void Write(Common::ProcessAddress vaddr, const T data) requires(std::is_trivially_copyable_v) noexcept { const u64 addr = GetInteger(vaddr); - if constexpr (std::is_same_v || std::is_same_v) { - // 8-bit writes are always aligned - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write8 @ 0x{:016X} = 0x{:02X}", addr, - static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { - *ptr = static_cast(data); - } - return; - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 16-bit writes - if ((addr & 1) == 0) { - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write16 @ 0x{:016X} = 0x{:04X}", addr, - static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { - *reinterpret_cast(ptr) = static_cast(data); - return; - } - } - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 32-bit writes - if ((addr & 3) == 0) { - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write32 @ 0x{:016X} = 0x{:08X}", addr, - static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { - *reinterpret_cast(ptr) = static_cast(data); - return; - } - } - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 64-bit writes - if ((addr & 7) == 0) { - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write64 @ 0x{:016X} = 0x{:016X}", addr, - static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { - *reinterpret_cast(ptr) = static_cast(data); - return; - } - } - } - - // Fall back to the general case for other types or unaligned access - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, - addr, static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { + if (auto const ptr = GetPointerImpl(addr, [addr, data]() { + LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, addr, u64(data)); + }, [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); ptr) [[likely]] std::memcpy(ptr, &data, sizeof(T)); - } } template From 020f1cdb1f2c60d8caad424c2319b721b167b181 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 1 Oct 2025 12:16:42 +0200 Subject: [PATCH 2/6] [qt] fix ci missing build_id (#2638) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2638 Co-authored-by: lizzie Co-committed-by: lizzie --- src/yuzu/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 71cc0a7e6b..fc7a953d77 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4204,8 +4204,8 @@ void GMainWindow::OnEmulatorUpdateAvailable() { } #endif -void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_view title_version, - std::string_view gpu_vendor) { +void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_view title_version, std::string_view gpu_vendor) { + static const std::string build_id = std::string{Common::g_build_id}; static const std::string yuzu_title = fmt::format("{} | {} | {}", std::string{Common::g_build_name}, std::string{Common::g_build_version}, From 4be6d30cd95634777e0ea0790d7c51a3d09bb773 Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Wed, 1 Oct 2025 16:36:07 +0200 Subject: [PATCH 3/6] [fixup] fix bad variable names (#2642) * Mo[l]tenVK is only for apple, so desc is unnecessary * fix mistipo on BUILD_AUTO_UPDATE_WEB[SI]TE Signed-off-by: Caio Oliveira Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2642 Reviewed-by: MaranBr Reviewed-by: CamilleLaVey Co-authored-by: Caio Oliveira Co-committed-by: Caio Oliveira --- CMakeLists.txt | 2 +- docs/Options.md | 2 +- src/common/scm_rev.cpp.in | 4 ++-- src/yuzu/CMakeLists.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eda6969f31..a9ff2e9458 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,7 +224,7 @@ set(YUZU_TZDB_PATH "" CACHE STRING "Path to a pre-downloaded timezone database") cmake_dependent_option(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "LINUX" OFF) -cmake_dependent_option(YUZU_APPLE_USE_BUNDLED_MONTENVK "Download bundled MoltenVK lib" ON "APPLE" OFF) +cmake_dependent_option(YUZU_USE_BUNDLED_MOLTENVK "Download bundled MoltenVK lib" ON "APPLE" OFF) option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF) diff --git a/docs/Options.md b/docs/Options.md index 6af91e4918..3dd84ea645 100644 --- a/docs/Options.md +++ b/docs/Options.md @@ -31,7 +31,7 @@ Notes: * Currently, build fails without this - `YUZU_USE_FASTER_LD` (ON) Check if a faster linker is available * Only available on UNIX -- `YUZU_APPLE_USE_BUNDLED_MONTENVK` (ON, macOS only) Download bundled MoltenVK lib) +- `YUZU_USE_BUNDLED_MOLTENVK` (ON, macOS only) Download bundled MoltenVK lib) - `YUZU_TZDB_PATH` (string) Path to a pre-downloaded timezone database (useful for nixOS) - `ENABLE_OPENSSL` (ON for Linux and *BSD) Enable OpenSSL backend for the ssl service * Always enabled if the web service is enabled diff --git a/src/common/scm_rev.cpp.in b/src/common/scm_rev.cpp.in index 08b8c68835..60c9c119f9 100644 --- a/src/common/scm_rev.cpp.in +++ b/src/common/scm_rev.cpp.in @@ -18,7 +18,7 @@ #define TITLE_BAR_FORMAT_RUNNING "@TITLE_BAR_FORMAT_RUNNING@" #define IS_DEV_BUILD @IS_DEV_BUILD@ #define COMPILER_ID "@CXX_COMPILER@" -#define BUILD_AUTO_UPDATE_WEBISTE "@BUILD_AUTO_UPDATE_WEBISTE@" +#define BUILD_AUTO_UPDATE_WEBSITE "@BUILD_AUTO_UPDATE_WEBSITE@" #define BUILD_AUTO_UPDATE_API "@BUILD_AUTO_UPDATE_API@" #define BUILD_AUTO_UPDATE_REPO "@BUILD_AUTO_UPDATE_REPO@" @@ -37,7 +37,7 @@ constexpr const char g_title_bar_format_running[] = TITLE_BAR_FORMAT_RUNNING; constexpr const char g_compiler_id[] = COMPILER_ID; constexpr const bool g_is_dev_build = IS_DEV_BUILD; -constexpr const char g_build_auto_update_website[] = BUILD_AUTO_UPDATE_WEBISTE; +constexpr const char g_build_auto_update_website[] = BUILD_AUTO_UPDATE_WEBSITE; constexpr const char g_build_auto_update_api[] = BUILD_AUTO_UPDATE_API; constexpr const char g_build_auto_update_repo[] = BUILD_AUTO_UPDATE_REPO; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index c3d8f5387a..00e03bd935 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -366,7 +366,7 @@ if (APPLE) set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE) set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) - if (YUZU_APPLE_USE_BUNDLED_MONTENVK) + if (YUZU_USE_BUNDLED_MOLTENVK) set(MOLTENVK_PLATFORM "macOS") set(MOLTENVK_VERSION "v1.3.0") download_moltenvk(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION}) From 61adc85c4ba4d87c5dcf99212a94b9d9d4a6fe14 Mon Sep 17 00:00:00 2001 From: Shinmegumi Date: Wed, 1 Oct 2025 21:09:27 +0200 Subject: [PATCH 4/6] [ci] Minor change to fix building (#2644) MSVC did not like that one of our variables was a constexpr since it was defined in the externals as a constexpr. Changed to const auto like the rest to ensure it built properly. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2644 Reviewed-by: MaranBr Reviewed-by: Maufeat Co-authored-by: Shinmegumi Co-committed-by: Shinmegumi --- src/yuzu/update_checker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/update_checker.cpp b/src/yuzu/update_checker.cpp index 76b436d1d1..e54eb8d7f8 100644 --- a/src/yuzu/update_checker.cpp +++ b/src/yuzu/update_checker.cpp @@ -58,7 +58,7 @@ std::optional UpdateChecker::GetResponse(std::string url, std::stri std::optional UpdateChecker::GetLatestRelease(bool include_prereleases) { - constexpr auto update_check_url = std::string{Common::g_build_auto_update_api}; + const auto update_check_url = std::string{Common::g_build_auto_update_api}; std::string update_check_path = fmt::format("/repos/{}", std::string{Common::g_build_auto_update_repo}); try { if (include_prereleases) { // This can return either a prerelease or a stable release, From 76b5d6778ec6245979a9f6963616d7fadb814d76 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 1 Oct 2025 23:18:37 +0200 Subject: [PATCH 5/6] [common/logging] faster logging by avoiding constructing unused strings/results (and filtering first) (#2603) basically std::string would be invoked even when the logging was filtered, then destroyed instantly, invoking malloc/free and polluting mem arenas for no good reason Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2603 Reviewed-by: MaranBr Reviewed-by: crueter Co-authored-by: lizzie Co-committed-by: lizzie --- src/common/logging/backend.cpp | 38 +++++++++++-------- src/common/logging/filter.cpp | 26 ++++++------- src/common/logging/log.h | 21 +++------- .../hle/service/ssl/ssl_backend_openssl.cpp | 5 ++- 4 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 4621771090..c2cbf3f4a5 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -39,9 +39,17 @@ namespace Common::Log { namespace { -/** - * Interface for logging backends. - */ +/// @brief Trims up to and including the last of ../, ..\, src/, src\ in a string +/// do not be fooled this isn't generating new strings on .rodata :) +constexpr const char* TrimSourcePath(std::string_view source) { + const auto rfind = [source](const std::string_view match) { + return source.rfind(match) == source.npos ? 0 : (source.rfind(match) + match.size()); + }; + auto idx = (std::max)({rfind("src/"), rfind("src\\"), rfind("../"), rfind("..\\")}); + return source.data() + idx; +} + +/// @brief Interface for logging backends. class Backend { public: virtual ~Backend() = default; @@ -53,9 +61,7 @@ public: virtual void Flush() = 0; }; -/** - * Backend that writes to stderr and with color - */ +/// @brief Backend that writes to stderr and with color class ColorConsoleBackend final : public Backend { public: explicit ColorConsoleBackend() = default; @@ -84,9 +90,7 @@ private: std::atomic_bool enabled{false}; }; -/** - * Backend that writes to a file passed into the constructor - */ +/// @brief Backend that writes to a file passed into the constructor class FileBackend final : public Backend { public: explicit FileBackend(const std::filesystem::path& filename) { @@ -248,13 +252,14 @@ public: color_console_backend.SetEnabled(enabled); } + bool CanPushEntry(Class log_class, Level log_level) const noexcept { + return filter.CheckMessage(log_class, log_level); + } + void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num, - const char* function, std::string&& message) { - if (!filter.CheckMessage(log_class, log_level)) { - return; - } + const char* function, std::string&& message) noexcept { message_queue.EmplaceWait( - CreateEntry(log_class, log_level, filename, line_num, function, std::move(message))); + CreateEntry(log_class, log_level, TrimSourcePath(filename), line_num, function, std::move(message))); } private: @@ -368,8 +373,9 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, const fmt::format_args& args) { if (!initialization_in_progress_suppress_logging) { - Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function, - fmt::vformat(format, args)); + auto& instance = Impl::Instance(); + if (instance.CanPushEntry(log_class, log_level)) + instance.PushEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args)); } } } // namespace Common::Log diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 4e3a614a45..813e812780 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -9,22 +12,20 @@ namespace Common::Log { namespace { template Level GetLevelByName(const It begin, const It end) { - for (u8 i = 0; i < static_cast(Level::Count); ++i) { - const char* level_name = GetLevelName(static_cast(i)); - if (Common::ComparePartialString(begin, end, level_name)) { - return static_cast(i); - } + for (u32 i = 0; i < u32(Level::Count); ++i) { + const char* level_name = GetLevelName(Level(i)); + if (Common::ComparePartialString(begin, end, level_name)) + return Level(i); } return Level::Count; } template Class GetClassByName(const It begin, const It end) { - for (u8 i = 0; i < static_cast(Class::Count); ++i) { - const char* level_name = GetLogClassName(static_cast(i)); - if (Common::ComparePartialString(begin, end, level_name)) { - return static_cast(i); - } + for (u32 i = 0; i < u32(Class::Count); ++i) { + const char* level_name = GetLogClassName(Class(i)); + if (Common::ComparePartialString(begin, end, level_name)) + return Class(i); } return Class::Count; } @@ -229,13 +230,12 @@ void Filter::ParseFilterString(std::string_view filter_view) { } bool Filter::CheckMessage(Class log_class, Level level) const { - return static_cast(level) >= - static_cast(class_levels[static_cast(log_class)]); + return u8(level) >= u8(class_levels[std::size_t(log_class)]); } bool Filter::IsDebug() const { return std::any_of(class_levels.begin(), class_levels.end(), [](const Level& l) { - return static_cast(l) <= static_cast(Level::Debug); + return u8(l) <= u8(Level::Debug); }); } diff --git a/src/common/logging/log.h b/src/common/logging/log.h index bd7a7d7f49..7b23b59aab 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -16,15 +16,6 @@ namespace Common::Log { -// trims up to and including the last of ../, ..\, src/, src\ in a string -constexpr const char* TrimSourcePath(std::string_view source) { - const auto rfind = [source](const std::string_view match) { - return source.rfind(match) == source.npos ? 0 : (source.rfind(match) + match.size()); - }; - auto idx = (std::max)({rfind("src/"), rfind("src\\"), rfind("../"), rfind("..\\")}); - return source.data() + idx; -} - /// Logs a message to the global logger, using fmt void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, @@ -42,7 +33,7 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig #ifdef _DEBUG #define LOG_TRACE(log_class, ...) \ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Trace, \ - Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \ + __FILE__, __LINE__, __func__, \ __VA_ARGS__) #else #define LOG_TRACE(log_class, fmt, ...) (void(0)) @@ -50,21 +41,21 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig #define LOG_DEBUG(log_class, ...) \ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Debug, \ - Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \ + __FILE__, __LINE__, __func__, \ __VA_ARGS__) #define LOG_INFO(log_class, ...) \ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Info, \ - Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \ + __FILE__, __LINE__, __func__, \ __VA_ARGS__) #define LOG_WARNING(log_class, ...) \ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Warning, \ - Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \ + __FILE__, __LINE__, __func__, \ __VA_ARGS__) #define LOG_ERROR(log_class, ...) \ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Error, \ - Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \ + __FILE__, __LINE__, __func__, \ __VA_ARGS__) #define LOG_CRITICAL(log_class, ...) \ Common::Log::FmtLogMessage(Common::Log::Class::log_class, Common::Log::Level::Critical, \ - Common::Log::TrimSourcePath(__FILE__), __LINE__, __func__, \ + __FILE__, __LINE__, __func__, \ __VA_ARGS__) diff --git a/src/core/hle/service/ssl/ssl_backend_openssl.cpp b/src/core/hle/service/ssl/ssl_backend_openssl.cpp index 5714e6f3c5..795b69a873 100644 --- a/src/core/hle/service/ssl/ssl_backend_openssl.cpp +++ b/src/core/hle/service/ssl/ssl_backend_openssl.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -286,7 +289,7 @@ Result CheckOpenSSLErrors() { msg.append(data); } Common::Log::FmtLogMessage(Common::Log::Class::Service_SSL, Common::Log::Level::Error, - Common::Log::TrimSourcePath(file), line, func, "OpenSSL: {}", + file, line, func, "OpenSSL: {}", msg); } return ResultInternalError; From 613ffac2b97af6c73c7f077c20800f78b02fa87a Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 1 Oct 2025 08:04:34 +0000 Subject: [PATCH 6/6] [core] use memcpy instead of hand rolling aligned cases Hand rolling memcpy like this is always frowned upon because the compiler has more insight on whats going on (plus the code resolves to a worse version of itself on assembly). This removes some branches that are just straight up redundant. May save stuff especially for systems without fastmem enabled. Signed-off-by: lizzie --- src/core/memory.cpp | 203 ++++++++------------------------------------ 1 file changed, 36 insertions(+), 167 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 2583aae867..f84507d125 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "common/assert.h" @@ -681,22 +682,17 @@ struct Memory::Impl { } } - [[nodiscard]] u8* GetPointerImpl(u64 vaddr, auto on_unmapped, auto on_rasterizer) const { + template + [[nodiscard]] u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const { // AARCH64 masks the upper 16 bit of all memory accesses - vaddr = vaddr & 0xffffffffffffULL; - if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] { - on_unmapped(); - return nullptr; - } else { + vaddr &= 0xffffffffffffULL; + if (AddressSpaceContains(*current_page_table, vaddr, 1)) [[likely]] { // Avoid adding any extra logic to this fast-path block const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw(); - if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { + if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) [[likely]] { return reinterpret_cast(pointer + vaddr); } else { switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { - case Common::PageType::Unmapped: - on_unmapped(); - return nullptr; case Common::PageType::Memory: ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr); return nullptr; @@ -707,11 +703,18 @@ struct Memory::Impl { on_rasterizer(); return host_ptr; } + case Common::PageType::Unmapped: [[unlikely]] { + on_unmapped(); + return nullptr; + } default: UNREACHABLE(); } return nullptr; } + } else { + on_unmapped(); + return nullptr; } } @@ -729,172 +732,38 @@ struct Memory::Impl { GetInteger(vaddr), []() {}, []() {}); } - /** - * Reads a particular data type out of memory at the given virtual address. - * - * @param vaddr The virtual address to read the data type from. - * - * @tparam T The data type to read out of memory. This type *must* be - * trivially copyable, otherwise the behavior of this function - * is undefined. - * - * @returns The instance of T read from the specified virtual address. - */ + /// @brief Reads a particular data type out of memory at the given virtual address. + /// @param vaddr The virtual address to read the data type from. + /// @tparam T The data type to read out of memory. + /// @returns The instance of T read from the specified virtual address. template - T Read(Common::ProcessAddress vaddr) { - // Fast path for aligned reads of common sizes + inline T Read(Common::ProcessAddress vaddr) requires(std::is_trivially_copyable_v) noexcept { const u64 addr = GetInteger(vaddr); - if constexpr (std::is_same_v || std::is_same_v) { - // 8-bit reads are always aligned - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read8 @ 0x{:016X}", addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { - return static_cast(*ptr); - } - return 0; - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 16-bit reads - if ((addr & 1) == 0) { - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read16 @ 0x{:016X}", addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { - return static_cast(*reinterpret_cast(ptr)); - } - } - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 32-bit reads - if ((addr & 3) == 0) { - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read32 @ 0x{:016X}", addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { - return static_cast(*reinterpret_cast(ptr)); - } - } - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 64-bit reads - if ((addr & 7) == 0) { - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read64 @ 0x{:016X}", addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { - return static_cast(*reinterpret_cast(ptr)); - } - } - } - - // Fall back to the general case for other types or unaligned access - T result = 0; - const u8* const ptr = GetPointerImpl( - addr, - [addr]() { - LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr); - }, - [&]() { HandleRasterizerDownload(addr, sizeof(T)); }); - if (ptr) { + if (auto const ptr = GetPointerImpl(addr, [addr]() { + LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr); + }, [&]() { + HandleRasterizerDownload(addr, sizeof(T)); + }); ptr) [[likely]] { + // It may be tempting to rewrite this particular section to use "reinterpret_cast"; + // afterall, it's trivially copyable so surely it can be copied ov- Alignment. + // Remember, alignment. memcpy() will deal with all the alignment extremely fast. + T result{}; std::memcpy(&result, ptr, sizeof(T)); + return result; } - return result; + return T{}; } - /** - * Writes a particular data type to memory at the given virtual address. - * - * @param vaddr The virtual address to write the data type to. - * - * @tparam T The data type to write to memory. This type *must* be - * trivially copyable, otherwise the behavior of this function - * is undefined. - */ + /// @brief Writes a particular data type to memory at the given virtual address. + /// @param vaddr The virtual address to write the data type to. + /// @tparam T The data type to write to memory. template - void Write(Common::ProcessAddress vaddr, const T data) { - // Fast path for aligned writes of common sizes + inline void Write(Common::ProcessAddress vaddr, const T data) requires(std::is_trivially_copyable_v) noexcept { const u64 addr = GetInteger(vaddr); - if constexpr (std::is_same_v || std::is_same_v) { - // 8-bit writes are always aligned - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write8 @ 0x{:016X} = 0x{:02X}", addr, - static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { - *ptr = static_cast(data); - } - return; - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 16-bit writes - if ((addr & 1) == 0) { - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write16 @ 0x{:016X} = 0x{:04X}", addr, - static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { - *reinterpret_cast(ptr) = static_cast(data); - return; - } - } - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 32-bit writes - if ((addr & 3) == 0) { - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write32 @ 0x{:016X} = 0x{:08X}", addr, - static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { - *reinterpret_cast(ptr) = static_cast(data); - return; - } - } - } else if constexpr (std::is_same_v || std::is_same_v) { - // Check alignment for 64-bit writes - if ((addr & 7) == 0) { - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write64 @ 0x{:016X} = 0x{:016X}", addr, - static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { - *reinterpret_cast(ptr) = static_cast(data); - return; - } - } - } - - // Fall back to the general case for other types or unaligned access - u8* const ptr = GetPointerImpl( - addr, - [addr, data]() { - LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, - addr, static_cast(data)); - }, - [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); - if (ptr) { + if (auto const ptr = GetPointerImpl(addr, [addr, data]() { + LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, addr, u64(data)); + }, [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); ptr) [[likely]] std::memcpy(ptr, &data, sizeof(T)); - } } template