diff --git a/CMakeModules/GenerateSCMRev.cmake b/CMakeModules/GenerateSCMRev.cmake index 5b0adad8dd..adc9902fcf 100644 --- a/CMakeModules/GenerateSCMRev.cmake +++ b/CMakeModules/GenerateSCMRev.cmake @@ -38,13 +38,13 @@ set(GIT_DESC ${BUILD_VERSION}) # Auto-updater metadata! Must somewhat mirror GitHub API endpoint if (NIGHTLY_BUILD) set(BUILD_AUTO_UPDATE_WEBSITE "https://github.com") - set(BUILD_AUTO_UPDATE_API "api.github.com") + set(BUILD_AUTO_UPDATE_API "https://api.github.com") set(BUILD_AUTO_UPDATE_API_PATH "/repos/") set(BUILD_AUTO_UPDATE_REPO "Eden-CI/Nightly") set(REPO_NAME "Eden Nightly") else() set(BUILD_AUTO_UPDATE_WEBSITE "https://git.eden-emu.dev") - set(BUILD_AUTO_UPDATE_API "git.eden-emu.dev") + set(BUILD_AUTO_UPDATE_API "https://git.eden-emu.dev") set(BUILD_AUTO_UPDATE_API_PATH "/api/v1/repos/") set(BUILD_AUTO_UPDATE_REPO "eden-emu/eden") set(REPO_NAME "Eden") diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ContentTypeSelectionDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ContentTypeSelectionDialogFragment.kt index c1d8b9ea5f..880c2ff3bf 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ContentTypeSelectionDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ContentTypeSelectionDialogFragment.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -5,15 +8,18 @@ package org.yuzu.yuzu_emu.fragments import android.app.Dialog import android.content.DialogInterface +import android.net.Uri import android.os.Bundle +import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.DialogFragment import androidx.fragment.app.activityViewModels import androidx.preference.PreferenceManager import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.model.AddonViewModel -import org.yuzu.yuzu_emu.ui.main.MainActivity +import org.yuzu.yuzu_emu.utils.InstallableActions class ContentTypeSelectionDialogFragment : DialogFragment() { private val addonViewModel: AddonViewModel by activityViewModels() @@ -23,6 +29,52 @@ class ContentTypeSelectionDialogFragment : DialogFragment() { private var selectedItem = 0 + private val installGameUpdateLauncher = + registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { documents -> + if (documents.isEmpty()) { + return@registerForActivityResult + } + + val game = addonViewModel.game + if (game == null) { + installContent(documents) + return@registerForActivityResult + } + + ProgressDialogFragment.newInstance( + requireActivity(), + R.string.verifying_content, + false + ) { _, _ -> + var updatesMatchProgram = true + for (document in documents) { + val valid = NativeLibrary.doesUpdateMatchProgram( + game.programId, + document.toString() + ) + if (!valid) { + updatesMatchProgram = false + break + } + } + + requireActivity().runOnUiThread { + if (updatesMatchProgram) { + installContent(documents) + } else { + MessageDialogFragment.newInstance( + requireActivity(), + titleId = R.string.content_install_notice, + descriptionId = R.string.content_install_notice_description, + positiveAction = { installContent(documents) }, + negativeAction = {} + ).show(parentFragmentManager, MessageDialogFragment.TAG) + } + } + return@newInstance Any() + }.show(parentFragmentManager, ProgressDialogFragment.TAG) + } + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val launchOptions = arrayOf(getString(R.string.updates_and_dlc), getString(R.string.mods_and_cheats)) @@ -31,12 +83,11 @@ class ContentTypeSelectionDialogFragment : DialogFragment() { selectedItem = savedInstanceState.getInt(SELECTED_ITEM) } - val mainActivity = requireActivity() as MainActivity return MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.select_content_type) .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> when (selectedItem) { - 0 -> mainActivity.installGameUpdate.launch(arrayOf("*/*")) + 0 -> installGameUpdateLauncher.launch(arrayOf("*/*")) else -> { if (!preferences.getBoolean(MOD_NOTICE_SEEN, false)) { preferences.edit().putBoolean(MOD_NOTICE_SEEN, true).apply() @@ -47,7 +98,7 @@ class ContentTypeSelectionDialogFragment : DialogFragment() { } } } - .setSingleChoiceItems(launchOptions, 0) { _: DialogInterface, i: Int -> + .setSingleChoiceItems(launchOptions, selectedItem) { _: DialogInterface, i: Int -> selectedItem = i } .setNegativeButton(android.R.string.cancel, null) @@ -65,4 +116,13 @@ class ContentTypeSelectionDialogFragment : DialogFragment() { private const val SELECTED_ITEM = "SelectedItem" private const val MOD_NOTICE_SEEN = "ModNoticeSeen" } + + private fun installContent(documents: List) { + InstallableActions.installContent( + activity = requireActivity(), + fragmentManager = parentFragmentManager, + addonViewModel = addonViewModel, + documents = documents + ) + } } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index fc3d9b59d8..b1f7009f26 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -184,8 +184,7 @@ if(ARCHITECTURE_x86_64) x64/native_clock.h x64/rdtsc.cpp x64/rdtsc.h - x64/xbyak_abi.h - x64/xbyak_util.h) + x64/xbyak.h) target_link_libraries(common PRIVATE xbyak::xbyak) endif() diff --git a/src/common/logging.cpp b/src/common/logging.cpp index c2f964af3e..0b82d3e727 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -410,39 +410,48 @@ struct Impl { // Constructor shall NOT depend upon Settings() or whatever // it's ran at global static ctor() time... so BE CAREFUL MFER! -static Common::Log::Impl logging_instance{}; +static std::optional logging_instance{}; void Initialize() { - logging_instance.filter.ParseFilterString(Settings::values.log_filter.GetValue()); + if (logging_instance) { + LOG_WARNING(Log, "Reinitializing logging backend"); + } else { + logging_instance.emplace(); + logging_instance->filter.ParseFilterString(Settings::values.log_filter.GetValue()); #ifndef __OPENORBIS__ - using namespace Common::FS; - const auto& log_dir = GetEdenPath(EdenPath::LogDir); - void(CreateDir(log_dir)); - logging_instance.file_backend.emplace(log_dir / LOG_FILE); + using namespace Common::FS; + const auto& log_dir = GetEdenPath(EdenPath::LogDir); + void(CreateDir(log_dir)); + logging_instance->file_backend.emplace(log_dir / LOG_FILE); #endif + } } void Start() { - logging_instance.StartBackendThread(); + if (logging_instance) + logging_instance->StartBackendThread(); } void Stop() { - logging_instance.StopBackendThread(); + if (logging_instance) + logging_instance->StopBackendThread(); } void SetGlobalFilter(const Filter& filter) { - logging_instance.filter = filter; + if (logging_instance) + logging_instance->filter = filter; } void SetColorConsoleBackendEnabled(bool enabled) { - logging_instance.color_console_backend.enabled = enabled; + if (logging_instance) + logging_instance->color_console_backend.enabled = enabled; } 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 (logging_instance.filter.CheckMessage(log_class, log_level)) { - logging_instance.message_queue.EmplaceWait(Entry{ + if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) { + logging_instance->message_queue.EmplaceWait(Entry{ .message = fmt::vformat(format, args), - .timestamp = std::chrono::duration_cast(std::chrono::steady_clock::now() - logging_instance.time_origin), + .timestamp = std::chrono::duration_cast(std::chrono::steady_clock::now() - logging_instance->time_origin), .log_class = log_class, .log_level = log_level, .filename = TrimSourcePath(filename), diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak.h similarity index 75% rename from src/common/x64/xbyak_abi.h rename to src/common/x64/xbyak.h index 8aea5db583..5ee12576e9 100644 --- a/src/common/x64/xbyak_abi.h +++ b/src/common/x64/xbyak.h @@ -1,13 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include #include #include -#include #include "common/assert.h" +// xbyak hates human beings +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wshadow" +#endif +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wshadow" +#endif + +// You must ensure this matches with src/common/x64/xbyak.h on root dir +#include +#include +#define XBYAK_STD_UNORDERED_SET ankerl::unordered_dense::set +#define XBYAK_STD_UNORDERED_MAP ankerl::unordered_dense::map +#define XBYAK_STD_UNORDERED_MULTIMAP boost::unordered_multimap +#include +#include + +#include + namespace Common::X64 { constexpr size_t RegToIndex(const Xbyak::Reg& reg) { @@ -174,12 +198,13 @@ inline ABIFrameInfo ABI_CalculateFrameSize(std::bitset<32> regs, size_t rsp_alig rsp_alignment -= subtraction; subtraction += rsp_alignment & 0xF; - return ABIFrameInfo{static_cast(subtraction), - static_cast(subtraction - xmm_base_subtraction)}; + return ABIFrameInfo{ + s32(subtraction), + s32(subtraction - xmm_base_subtraction) + }; } -inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bitset<32> regs, - size_t rsp_alignment, size_t needed_frame_size = 0) { +inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bitset<32> regs, size_t rsp_alignment, size_t needed_frame_size = 0) { auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); for (size_t i = 0; i < regs.size(); ++i) { @@ -202,8 +227,7 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::b return ABI_SHADOW_SPACE; } -inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bitset<32> regs, - size_t rsp_alignment, size_t needed_frame_size = 0) { +inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bitset<32> regs, size_t rsp_alignment, size_t needed_frame_size = 0) { auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); for (size_t i = 0; i < regs.size(); ++i) { @@ -226,4 +250,38 @@ inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bits } } +// Constants for use with cmpps/cmpss +enum { + CMP_EQ = 0, + CMP_LT = 1, + CMP_LE = 2, + CMP_UNORD = 3, + CMP_NEQ = 4, + CMP_NLT = 5, + CMP_NLE = 6, + CMP_ORD = 7, +}; + +constexpr bool IsWithin2G(uintptr_t ref, uintptr_t target) { + const u64 distance = target - (ref + 5); + return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL); +} + +inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) { + return IsWithin2G(reinterpret_cast(code.getCurr()), target); +} + +template +inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { + static_assert(std::is_pointer_v, "Argument must be a (function) pointer."); + size_t addr = reinterpret_cast(f); + if (IsWithin2G(code, addr)) { + code.call(f); + } else { + // ABI_RETURN is a safe temp register to use before a call + code.mov(ABI_RETURN, addr); + code.call(ABI_RETURN); + } +} + } // namespace Common::X64 diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h deleted file mode 100644 index 250e5cddb9..0000000000 --- a/src/common/x64/xbyak_util.h +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-FileCopyrightText: 2016 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include "common/x64/xbyak_abi.h" - -namespace Common::X64 { - -// Constants for use with cmpps/cmpss -enum { - CMP_EQ = 0, - CMP_LT = 1, - CMP_LE = 2, - CMP_UNORD = 3, - CMP_NEQ = 4, - CMP_NLT = 5, - CMP_NLE = 6, - CMP_ORD = 7, -}; - -constexpr bool IsWithin2G(uintptr_t ref, uintptr_t target) { - const u64 distance = target - (ref + 5); - return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL); -} - -inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) { - return IsWithin2G(reinterpret_cast(code.getCurr()), target); -} - -template -inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { - static_assert(std::is_pointer_v, "Argument must be a (function) pointer."); - size_t addr = reinterpret_cast(f); - if (IsWithin2G(code, addr)) { - code.call(f); - } else { - // ABI_RETURN is a safe temp register to use before a call - code.mov(ABI_RETURN, addr); - code.call(ABI_RETURN); - } -} - -} // namespace Common::X64 diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 5c2c77e10a..5c57df424c 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -6,7 +6,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include #include #include #include @@ -128,14 +127,83 @@ struct Memory::Impl { } } - [[nodiscard]] inline u8* GetPointerFromRasterizerCachedMemory(u64 vaddr) const { - auto const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr; - return paddr ? system.DeviceMemory().GetPointer(paddr + vaddr) : nullptr; + [[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(u64 vaddr) const { + Common::PhysicalAddress const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr; + if (paddr) + return system.DeviceMemory().GetPointer(paddr + vaddr); + return {}; } - [[nodiscard]] inline u8* GetPointerFromDebugMemory(u64 vaddr) const { - auto const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr; - return paddr ? system.DeviceMemory().GetPointer(paddr + vaddr) : nullptr; + [[nodiscard]] u8* GetPointerFromDebugMemory(u64 vaddr) const { + const Common::PhysicalAddress paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr; + if (paddr != 0) + return system.DeviceMemory().GetPointer(paddr + vaddr); + return {}; + } + + u8 Read8(const Common::ProcessAddress addr) { + return Read(addr); + } + + u16 Read16(const Common::ProcessAddress addr) { + if ((addr & 1) == 0) { + return Read(addr); + } else { + const u32 a{Read(addr)}; + const u32 b{Read(addr + sizeof(u8))}; + return static_cast((b << 8) | a); + } + } + + u32 Read32(const Common::ProcessAddress addr) { + if ((addr & 3) == 0) { + return Read(addr); + } else { + const u32 a{Read16(addr)}; + const u32 b{Read16(addr + sizeof(u16))}; + return (b << 16) | a; + } + } + + u64 Read64(const Common::ProcessAddress addr) { + if ((addr & 7) == 0) { + return Read(addr); + } else { + const u32 a{Read32(addr)}; + const u32 b{Read32(addr + sizeof(u32))}; + return (static_cast(b) << 32) | a; + } + } + + void Write8(const Common::ProcessAddress addr, const u8 data) { + Write(addr, data); + } + + void Write16(const Common::ProcessAddress addr, const u16 data) { + if ((addr & 1) == 0) { + Write(addr, data); + } else { + Write(addr, static_cast(data)); + Write(addr + sizeof(u8), static_cast(data >> 8)); + } + } + + void Write32(const Common::ProcessAddress addr, const u32 data) { + if ((addr & 3) == 0) { + Write(addr, data); + } else { + Write16(addr, static_cast(data)); + Write16(addr + sizeof(u16), static_cast(data >> 16)); + } + } + + void Write64(const Common::ProcessAddress addr, const u64 data) { + if ((addr & 7) == 0) { + Write(addr, data); + } else { + Write32(addr, static_cast(data)); + Write32(addr + sizeof(u32), static_cast(data >> 32)); + } } bool WriteExclusive8(const Common::ProcessAddress addr, const u8 data, const u8 expected) { @@ -590,7 +658,7 @@ struct Memory::Impl { } template - [[nodiscard]] inline u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const { + [[nodiscard]] u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const { // AARCH64 masks the upper 16 bit of all memory accesses vaddr &= 0xffffffffffffULL; if (AddressSpaceContains(*current_page_table, vaddr, 1)) [[likely]] { @@ -645,42 +713,18 @@ struct Memory::Impl { /// @returns The instance of T read from the specified virtual address. template inline T Read(Common::ProcessAddress vaddr) noexcept requires(std::is_trivially_copyable_v) { - auto const addr_c1 = GetInteger(vaddr); - if (!(sizeof(T) > 1 && (addr_c1 & 4095) + sizeof(T) > 4096)) { - if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] { - LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c1); - }, [&] { - HandleRasterizerDownload(addr_c1, sizeof(T)); - }); ptr_c1) { - // 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_c1, sizeof(T)); - return result; - } - } else { - auto const addr_c2 = (addr_c1 & (~0xfff)) + 0x1000; - // page crossing: say if sizeof(T) = 2, vaddr = 4095 - // 4095 + 2 mod 4096 = 1 => 2 - 1 = 1, thus c1=1, c2=1 - auto const count_c2 = (addr_c1 + sizeof(T)) & 4095; - auto const count_c1 = sizeof(T) - count_c2; - if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] { - LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c1); - }, [&] { - HandleRasterizerDownload(addr_c1, count_c1); - }); ptr_c1) { - if (auto const ptr_c2 = GetPointerImpl(addr_c2, [addr_c2] { - LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c2); - }, [&] { - HandleRasterizerDownload(addr_c2, count_c2); - }); ptr_c2) { - std::array result{}; - std::memcpy(result.data() + 0, ptr_c1, count_c1); - std::memcpy(result.data() + count_c1, ptr_c2, count_c2); - return std::bit_cast(result); - } - } + const u64 addr = GetInteger(vaddr); + 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 T{}; } @@ -690,37 +734,11 @@ struct Memory::Impl { /// @tparam T The data type to write to memory. template inline void Write(Common::ProcessAddress vaddr, const T data) noexcept requires(std::is_trivially_copyable_v) { - auto const addr_c1 = GetInteger(vaddr); - if (!(sizeof(T) > 1 && (addr_c1 & 4095) + sizeof(T) > 4096)) { - if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] { - LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c1); - }, [&] { - HandleRasterizerWrite(addr_c1, sizeof(T)); - }); ptr_c1) { - std::memcpy(ptr_c1, &data, sizeof(T)); - } - } else { - auto const addr_c2 = (addr_c1 & (~0xfff)) + 0x1000; - // page crossing: say if sizeof(T) = 2, vaddr = 4095 - // 4095 + 2 mod 4096 = 1 => 2 - 1 = 1, thus c1=1, c2=1 - auto const count_c2 = (addr_c1 + sizeof(T)) & 4095; - auto const count_c1 = sizeof(T) - count_c2; - if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] { - LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X}", sizeof(T) * 8, addr_c1); - }, [&] { - HandleRasterizerWrite(addr_c1, count_c1); - }); ptr_c1) { - if (auto const ptr_c2 = GetPointerImpl(addr_c2, [addr_c2] { - LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X}", sizeof(T) * 8, addr_c2); - }, [&] { - HandleRasterizerWrite(addr_c2, count_c2); - }); ptr_c2) { - std::array tmp = std::bit_cast>(data); - std::memcpy(ptr_c1, tmp.data() + 0, count_c1); - std::memcpy(ptr_c2, tmp.data() + count_c1, count_c2); - } - } - } + const u64 addr = GetInteger(vaddr); + 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 @@ -924,35 +942,35 @@ const u8* Memory::GetPointer(Common::ProcessAddress vaddr) const { } u8 Memory::Read8(const Common::ProcessAddress addr) { - return impl->Read(addr); + return impl->Read8(addr); } u16 Memory::Read16(const Common::ProcessAddress addr) { - return impl->Read(addr); + return impl->Read16(addr); } u32 Memory::Read32(const Common::ProcessAddress addr) { - return impl->Read(addr); + return impl->Read32(addr); } u64 Memory::Read64(const Common::ProcessAddress addr) { - return impl->Read(addr); + return impl->Read64(addr); } void Memory::Write8(Common::ProcessAddress addr, u8 data) { - impl->Write(addr, data); + impl->Write8(addr, data); } void Memory::Write16(Common::ProcessAddress addr, u16 data) { - impl->Write(addr, data); + impl->Write16(addr, data); } void Memory::Write32(Common::ProcessAddress addr, u32 data) { - impl->Write(addr, data); + impl->Write32(addr, data); } void Memory::Write64(Common::ProcessAddress addr, u64 data) { - impl->Write(addr, data); + impl->Write64(addr, data); } bool Memory::WriteExclusive8(Common::ProcessAddress addr, u8 data, u8 expected) { diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index ff82d8b05c..2a39907525 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -222,7 +222,7 @@ void A64EmitX64::GenTerminalHandlers() { terminal_handler_fast_dispatch_hint = code.getCurr(); calculate_location_descriptor(); code.L(rsb_cache_miss); - code.mov(r8, reinterpret_cast(fast_dispatch_table.data())); + code.mov(r8, u64(fast_dispatch_table.data())); //code.mov(r12, qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)]); code.mov(r12, rbx); if (code.HasHostFeature(HostFeature::SSE42)) { @@ -242,7 +242,7 @@ void A64EmitX64::GenTerminalHandlers() { code.align(); fast_dispatch_table_lookup = code.getCurr(); - code.mov(code.ABI_PARAM2, reinterpret_cast(fast_dispatch_table.data())); + code.mov(code.ABI_PARAM2, u64(fast_dispatch_table.data())); if (code.HasHostFeature(HostFeature::SSE42)) { code.crc32(code.ABI_PARAM1, code.ABI_PARAM2); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp index 413af7b557..4de780dc09 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp @@ -26,7 +26,7 @@ struct FrameInfo { }; static_assert(ABI_SHADOW_SPACE <= 32); -static FrameInfo CalculateFrameInfo(const size_t num_gprs, const size_t num_xmms, size_t frame_size) { +static FrameInfo CalculateFrameInfo(const size_t num_gprs, const size_t num_xmms, size_t frame_size) noexcept { // We are initially 8 byte aligned because the return value is pushed onto an aligned stack after a call. const size_t rsp_alignment = (num_gprs % 2 == 0) ? 8 : 0; const size_t total_xmm_size = num_xmms * XMM_SIZE; @@ -40,7 +40,7 @@ static FrameInfo CalculateFrameInfo(const size_t num_gprs, const size_t num_xmms }; } -void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { +static void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> regs) noexcept { using namespace Xbyak::util; const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); @@ -65,7 +65,7 @@ void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, } } -void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> const& regs) { +static void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, std::bitset<32> regs) noexcept { using namespace Xbyak::util; const size_t num_gprs = (ABI_ALL_GPRS & regs).count(); @@ -107,13 +107,13 @@ void ABI_PopCallerSaveRegistersAndAdjustStack(BlockOfCode& code, const std::size // Windows ABI registers are not in the same allocation algorithm as unix's void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) { - std::bitset<32> regs = ABI_ALL_CALLER_SAVE; + auto regs = ABI_ALL_CALLER_SAVE; regs.reset(size_t(exception)); ABI_PushRegistersAndAdjustStack(code, 0, regs); } void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) { - std::bitset<32> regs = ABI_ALL_CALLER_SAVE; + auto regs = ABI_ALL_CALLER_SAVE; regs.reset(size_t(exception)); ABI_PopRegistersAndAdjustStack(code, 0, regs); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/constant_pool.cpp b/src/dynarmic/src/dynarmic/backend/x64/constant_pool.cpp index 7dbd46bc2a..049ad98d35 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/constant_pool.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/constant_pool.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,23 +6,21 @@ * SPDX-License-Identifier: 0BSD */ -#include "dynarmic/backend/x64/constant_pool.h" - #include - #include "dynarmic/common/assert.h" - #include "dynarmic/backend/x64/block_of_code.h" +#include "dynarmic/backend/x64/constant_pool.h" namespace Dynarmic::Backend::X64 { ConstantPool::ConstantPool(BlockOfCode& code, size_t size) - : code(code), insertion_point(0) { + : code(code) + , insertion_point(0) +{ code.EnsureMemoryCommitted(align_size + size); code.int3(); code.align(align_size); - pool = std::span( - reinterpret_cast(code.AllocateFromCodeSpace(size)), size / align_size); + pool = std::span(reinterpret_cast(code.AllocateFromCodeSpace(size)), size / align_size); } Xbyak::Address ConstantPool::GetConstant(const Xbyak::AddressFrame& frame, u64 lower, u64 upper) { diff --git a/src/dynarmic/src/dynarmic/backend/x64/hostloc.h b/src/dynarmic/src/dynarmic/backend/x64/hostloc.h index 2feecf5d5e..8fd97a4ee8 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/hostloc.h +++ b/src/dynarmic/src/dynarmic/backend/x64/hostloc.h @@ -8,8 +8,6 @@ #pragma once #include -#include - #include "dynarmic/common/assert.h" #include "dynarmic/common/common_types.h" #include "dynarmic/backend/x64/xbyak.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/xbyak.h b/src/dynarmic/src/dynarmic/backend/x64/xbyak.h index ee74794fb4..38401678e6 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/xbyak.h +++ b/src/dynarmic/src/dynarmic/backend/x64/xbyak.h @@ -3,13 +3,11 @@ #pragma once -#include -#include - -// TODO: Defining this crashes e v e r y t h i n g -// #define XBYAK_STD_UNORDERED_SET ankerl::unordered_dense::set -// #define XBYAK_STD_UNORDERED_MAP ankerl::unordered_dense::map -// #define XBYAK_STD_UNORDERED_MULTIMAP boost::unordered_multimap - +// You must ensure this matches with src/common/x64/xbyak.h on root dir +#include +#include +#define XBYAK_STD_UNORDERED_SET ankerl::unordered_dense::set +#define XBYAK_STD_UNORDERED_MAP ankerl::unordered_dense::map +#define XBYAK_STD_UNORDERED_MULTIMAP boost::unordered_multimap #include #include diff --git a/src/dynarmic/src/dynarmic/common/fp/op/FPToFixed.cpp b/src/dynarmic/src/dynarmic/common/fp/op/FPToFixed.cpp index 8e3474952a..f966368261 100644 --- a/src/dynarmic/src/dynarmic/common/fp/op/FPToFixed.cpp +++ b/src/dynarmic/src/dynarmic/common/fp/op/FPToFixed.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -79,7 +79,7 @@ u64 FPToFixed(size_t ibits, FPT op, size_t fbits, bool unsigned_, FPCR fpcr, Rou } // Detect Overflow - const int min_exponent_for_overflow = static_cast(ibits) - static_cast(mcl::bit::highest_set_bit(value.mantissa + (round_up ? Safe::LogicalShiftRight(1, exponent) : 0))) - (unsigned_ ? 0 : 1); + const int min_exponent_for_overflow = int(ibits) - int(mcl::bit::highest_set_bit(value.mantissa + (round_up ? Safe::LogicalShiftRight(1, exponent) : 0))) - (unsigned_ ? 0 : 1); if (exponent >= min_exponent_for_overflow) { // Positive overflow if (unsigned_ || !sign) { @@ -88,10 +88,10 @@ u64 FPToFixed(size_t ibits, FPT op, size_t fbits, bool unsigned_, FPCR fpcr, Rou } // Negative overflow - const u64 min_value = Safe::Negate(static_cast(1) << (ibits - 1)); + const u64 min_value = Safe::Negate(u64(1) << (ibits - 1)); if (!(exponent == min_exponent_for_overflow && int_result == min_value)) { FPProcessException(FPExc::InvalidOp, fpcr, fpsr); - return static_cast(1) << (ibits - 1); + return u64(1) << (ibits - 1); } } diff --git a/src/dynarmic/tests/x64_cpu_info.cpp b/src/dynarmic/tests/x64_cpu_info.cpp index 8e67f0fc39..a33d8c013f 100644 --- a/src/dynarmic/tests/x64_cpu_info.cpp +++ b/src/dynarmic/tests/x64_cpu_info.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2020 MerryMage * SPDX-License-Identifier: 0BSD @@ -11,7 +14,7 @@ #include #include -#include +#include "dynarmic/backend/x64/xbyak.h" TEST_CASE("Host CPU supports", "[a64]") { using Cpu = Xbyak::util::Cpu; diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp index 66cea5afbd..996572129c 100644 --- a/src/video_core/macro.cpp +++ b/src/video_core/macro.cpp @@ -11,17 +11,9 @@ #include #include + #ifdef ARCHITECTURE_x86_64 -// xbyak hates human beings -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wshadow" -#endif -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wshadow" -#endif -#include +#include "common/x64/xbyak.h" #endif #include "common/assert.h" @@ -39,10 +31,6 @@ #include "common/assert.h" #include "common/bit_field.h" #include "common/logging.h" -#ifdef ARCHITECTURE_x86_64 -#include "common/x64/xbyak_abi.h" -#include "common/x64/xbyak_util.h" -#endif #include "video_core/engines/maxwell_3d.h" namespace Tegra { diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index c842cce709..74f06427dd 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -109,14 +109,6 @@ VkBufferView Buffer::View(u32 offset, u32 size, VideoCore::Surface::PixelFormat // Null buffer not supported, adjust offset and size offset = 0; size = 0; - } else { - // Align offset down to minTexelBufferOffsetAlignment - const u32 alignment = static_cast(device->GetMinTexelBufferOffsetAlignment()); - if (alignment > 1) { - const u32 aligned_offset = offset & ~(alignment - 1); - size += offset - aligned_offset; - offset = aligned_offset; - } } const auto it{std::ranges::find_if(views, [offset, size, format](const BufferView& view) { return offset == view.offset && size == view.size && format == view.format; diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 7cdb3acadd..656e2c7317 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -880,8 +880,6 @@ private: } has_flushed_end_pending = false; - // Refresh buffer state before ending transform feedback to ensure counters_count is up-to-date. - UpdateBuffers(); if (buffers_count == 0) { LOG_DEBUG(Render_Vulkan, "EndTransformFeedbackEXT called with no counters (buffers_count=0)"); scheduler.Record([](vk::CommandBuffer cmdbuf) { diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index fa0c358069..caf91104df 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -318,11 +318,6 @@ public: return properties.properties.limits.minStorageBufferOffsetAlignment; } - /// Returns texel buffer offset alignment requirement. - VkDeviceSize GetMinTexelBufferOffsetAlignment() const { - return properties.properties.limits.minTexelBufferOffsetAlignment; - } - /// Returns the maximum range for storage buffers. VkDeviceSize GetMaxStorageBufferRange() const { return properties.properties.limits.maxStorageBufferRange;