forked from eden-emu/eden
Compare commits
1 commit
master
...
memory-use
Author | SHA1 | Date | |
---|---|---|---|
6e3a943e74 |
7 changed files with 44 additions and 175 deletions
|
@ -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_USE_FASTER_LD "Check if a faster linker is available" ON "LINUX" OFF)
|
||||||
|
|
||||||
cmake_dependent_option(YUZU_USE_BUNDLED_MOLTENVK "Download bundled MoltenVK lib" ON "APPLE" OFF)
|
cmake_dependent_option(YUZU_APPLE_USE_BUNDLED_MONTENVK "Download bundled MoltenVK lib" ON "APPLE" OFF)
|
||||||
|
|
||||||
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
|
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ Notes:
|
||||||
* Currently, build fails without this
|
* Currently, build fails without this
|
||||||
- `YUZU_USE_FASTER_LD` (ON) Check if a faster linker is available
|
- `YUZU_USE_FASTER_LD` (ON) Check if a faster linker is available
|
||||||
* Only available on UNIX
|
* Only available on UNIX
|
||||||
- `YUZU_USE_BUNDLED_MOLTENVK` (ON, macOS only) Download bundled MoltenVK lib)
|
- `YUZU_APPLE_USE_BUNDLED_MONTENVK` (ON, macOS only) Download bundled MoltenVK lib)
|
||||||
- `YUZU_TZDB_PATH` (string) Path to a pre-downloaded timezone database (useful for nixOS)
|
- `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
|
- `ENABLE_OPENSSL` (ON for Linux and *BSD) Enable OpenSSL backend for the ssl service
|
||||||
* Always enabled if the web service is enabled
|
* Always enabled if the web service is enabled
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#define TITLE_BAR_FORMAT_RUNNING "@TITLE_BAR_FORMAT_RUNNING@"
|
#define TITLE_BAR_FORMAT_RUNNING "@TITLE_BAR_FORMAT_RUNNING@"
|
||||||
#define IS_DEV_BUILD @IS_DEV_BUILD@
|
#define IS_DEV_BUILD @IS_DEV_BUILD@
|
||||||
#define COMPILER_ID "@CXX_COMPILER@"
|
#define COMPILER_ID "@CXX_COMPILER@"
|
||||||
#define BUILD_AUTO_UPDATE_WEBSITE "@BUILD_AUTO_UPDATE_WEBSITE@"
|
#define BUILD_AUTO_UPDATE_WEBISTE "@BUILD_AUTO_UPDATE_WEBISTE@"
|
||||||
#define BUILD_AUTO_UPDATE_API "@BUILD_AUTO_UPDATE_API@"
|
#define BUILD_AUTO_UPDATE_API "@BUILD_AUTO_UPDATE_API@"
|
||||||
#define BUILD_AUTO_UPDATE_REPO "@BUILD_AUTO_UPDATE_REPO@"
|
#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 char g_compiler_id[] = COMPILER_ID;
|
||||||
constexpr const bool g_is_dev_build = IS_DEV_BUILD;
|
constexpr const bool g_is_dev_build = IS_DEV_BUILD;
|
||||||
|
|
||||||
constexpr const char g_build_auto_update_website[] = BUILD_AUTO_UPDATE_WEBSITE;
|
constexpr const char g_build_auto_update_website[] = BUILD_AUTO_UPDATE_WEBISTE;
|
||||||
constexpr const char g_build_auto_update_api[] = BUILD_AUTO_UPDATE_API;
|
constexpr const char g_build_auto_update_api[] = BUILD_AUTO_UPDATE_API;
|
||||||
constexpr const char g_build_auto_update_repo[] = BUILD_AUTO_UPDATE_REPO;
|
constexpr const char g_build_auto_update_repo[] = BUILD_AUTO_UPDATE_REPO;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
@ -681,22 +682,17 @@ struct Memory::Impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] u8* GetPointerImpl(u64 vaddr, auto on_unmapped, auto on_rasterizer) const {
|
template<typename F, typename G>
|
||||||
|
[[nodiscard]] u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const {
|
||||||
// AARCH64 masks the upper 16 bit of all memory accesses
|
// AARCH64 masks the upper 16 bit of all memory accesses
|
||||||
vaddr = vaddr & 0xffffffffffffULL;
|
vaddr &= 0xffffffffffffULL;
|
||||||
if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] {
|
if (AddressSpaceContains(*current_page_table, vaddr, 1)) [[likely]] {
|
||||||
on_unmapped();
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
// Avoid adding any extra logic to this fast-path block
|
// Avoid adding any extra logic to this fast-path block
|
||||||
const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw();
|
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<u8*>(pointer + vaddr);
|
return reinterpret_cast<u8*>(pointer + vaddr);
|
||||||
} else {
|
} else {
|
||||||
switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
|
switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
|
||||||
case Common::PageType::Unmapped:
|
|
||||||
on_unmapped();
|
|
||||||
return nullptr;
|
|
||||||
case Common::PageType::Memory:
|
case Common::PageType::Memory:
|
||||||
ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr);
|
ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -707,11 +703,18 @@ struct Memory::Impl {
|
||||||
on_rasterizer();
|
on_rasterizer();
|
||||||
return host_ptr;
|
return host_ptr;
|
||||||
}
|
}
|
||||||
|
case Common::PageType::Unmapped: [[unlikely]] {
|
||||||
|
on_unmapped();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
on_unmapped();
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,173 +732,39 @@ struct Memory::Impl {
|
||||||
GetInteger(vaddr), []() {}, []() {});
|
GetInteger(vaddr), []() {}, []() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// @brief Reads a particular data type out of memory at the given virtual address.
|
||||||
* 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.
|
||||||
* @param vaddr The virtual address to read the data type from.
|
/// @returns The instance of T read from the specified virtual address.
|
||||||
*
|
|
||||||
* @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.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Read(Common::ProcessAddress vaddr) {
|
inline T Read(Common::ProcessAddress vaddr) requires(std::is_trivially_copyable_v<T>) noexcept {
|
||||||
// Fast path for aligned reads of common sizes
|
|
||||||
const u64 addr = GetInteger(vaddr);
|
const u64 addr = GetInteger(vaddr);
|
||||||
if constexpr (std::is_same_v<T, u8> || std::is_same_v<T, s8>) {
|
if (auto const ptr = GetPointerImpl(addr, [addr]() {
|
||||||
// 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<T>(*ptr);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} else if constexpr (std::is_same_v<T, u16_le> || std::is_same_v<T, s16_le>) {
|
|
||||||
// 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<T>(*reinterpret_cast<const u16*>(ptr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if constexpr (std::is_same_v<T, u32_le> || std::is_same_v<T, s32_le>) {
|
|
||||||
// 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<T>(*reinterpret_cast<const u32*>(ptr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if constexpr (std::is_same_v<T, u64_le> || std::is_same_v<T, s64_le>) {
|
|
||||||
// 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<T>(*reinterpret_cast<const u64*>(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);
|
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr);
|
||||||
},
|
}, [&]() {
|
||||||
[&]() { HandleRasterizerDownload(addr, sizeof(T)); });
|
HandleRasterizerDownload(addr, sizeof(T));
|
||||||
if (ptr) {
|
}); 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));
|
std::memcpy(&result, ptr, sizeof(T));
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
return T{};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/// @brief Writes a particular data type to memory at the given virtual address.
|
||||||
* 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.
|
||||||
* @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.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Write(Common::ProcessAddress vaddr, const T data) {
|
inline void Write(Common::ProcessAddress vaddr, const T data) requires(std::is_trivially_copyable_v<T>) noexcept {
|
||||||
// Fast path for aligned writes of common sizes
|
|
||||||
const u64 addr = GetInteger(vaddr);
|
const u64 addr = GetInteger(vaddr);
|
||||||
if constexpr (std::is_same_v<T, u8> || std::is_same_v<T, s8>) {
|
if (auto const ptr = GetPointerImpl(addr, [addr, data]() {
|
||||||
// 8-bit writes are always aligned
|
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, addr, u64(data));
|
||||||
u8* const ptr = GetPointerImpl(
|
}, [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); ptr) [[likely]]
|
||||||
addr,
|
|
||||||
[addr, data]() {
|
|
||||||
LOG_ERROR(HW_Memory, "Unmapped Write8 @ 0x{:016X} = 0x{:02X}", addr,
|
|
||||||
static_cast<u8>(data));
|
|
||||||
},
|
|
||||||
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
|
|
||||||
if (ptr) {
|
|
||||||
*ptr = static_cast<u8>(data);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else if constexpr (std::is_same_v<T, u16_le> || std::is_same_v<T, s16_le>) {
|
|
||||||
// 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<u16>(data));
|
|
||||||
},
|
|
||||||
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
|
|
||||||
if (ptr) {
|
|
||||||
*reinterpret_cast<u16*>(ptr) = static_cast<u16>(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if constexpr (std::is_same_v<T, u32_le> || std::is_same_v<T, s32_le>) {
|
|
||||||
// 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<u32>(data));
|
|
||||||
},
|
|
||||||
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
|
|
||||||
if (ptr) {
|
|
||||||
*reinterpret_cast<u32*>(ptr) = static_cast<u32>(data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if constexpr (std::is_same_v<T, u64_le> || std::is_same_v<T, s64_le>) {
|
|
||||||
// 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<u64>(data));
|
|
||||||
},
|
|
||||||
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
|
|
||||||
if (ptr) {
|
|
||||||
*reinterpret_cast<u64*>(ptr) = static_cast<u64>(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<u64>(data));
|
|
||||||
},
|
|
||||||
[&]() { HandleRasterizerWrite(addr, sizeof(T)); });
|
|
||||||
if (ptr) {
|
|
||||||
std::memcpy(ptr, &data, sizeof(T));
|
std::memcpy(ptr, &data, sizeof(T));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool WriteExclusive(Common::ProcessAddress vaddr, const T data, const T expected) {
|
bool WriteExclusive(Common::ProcessAddress vaddr, const T data, const T expected) {
|
||||||
|
|
|
@ -366,7 +366,7 @@ if (APPLE)
|
||||||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
|
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
|
||||||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
||||||
|
|
||||||
if (YUZU_USE_BUNDLED_MOLTENVK)
|
if (YUZU_APPLE_USE_BUNDLED_MONTENVK)
|
||||||
set(MOLTENVK_PLATFORM "macOS")
|
set(MOLTENVK_PLATFORM "macOS")
|
||||||
set(MOLTENVK_VERSION "v1.3.0")
|
set(MOLTENVK_VERSION "v1.3.0")
|
||||||
download_moltenvk(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
|
download_moltenvk(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
|
||||||
|
|
|
@ -4204,8 +4204,8 @@ void GMainWindow::OnEmulatorUpdateAvailable() {
|
||||||
}
|
}
|
||||||
#endif
|
#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,
|
||||||
static const std::string build_id = std::string{Common::g_build_id};
|
std::string_view gpu_vendor) {
|
||||||
static const std::string yuzu_title = fmt::format("{} | {} | {}",
|
static const std::string yuzu_title = fmt::format("{} | {} | {}",
|
||||||
std::string{Common::g_build_name},
|
std::string{Common::g_build_name},
|
||||||
std::string{Common::g_build_version},
|
std::string{Common::g_build_version},
|
||||||
|
|
|
@ -58,7 +58,7 @@ std::optional<std::string> UpdateChecker::GetResponse(std::string url, std::stri
|
||||||
|
|
||||||
std::optional<std::string> UpdateChecker::GetLatestRelease(bool include_prereleases)
|
std::optional<std::string> UpdateChecker::GetLatestRelease(bool include_prereleases)
|
||||||
{
|
{
|
||||||
const auto update_check_url = std::string{Common::g_build_auto_update_api};
|
constexpr 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});
|
std::string update_check_path = fmt::format("/repos/{}", std::string{Common::g_build_auto_update_repo});
|
||||||
try {
|
try {
|
||||||
if (include_prereleases) { // This can return either a prerelease or a stable release,
|
if (include_prereleases) { // This can return either a prerelease or a stable release,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue