Compare commits

..

2 Commits

Author SHA1 Message Date
lizzie 943becc541 use e717604a29 2026-04-27 00:02:56 +02:00
lizzie d3f5ec1724 [externals] update ffmpeg to d1d873c003
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-04-27 00:02:56 +02:00
20 changed files with 234 additions and 176 deletions
+2 -2
View File
@@ -208,8 +208,8 @@
},
"ffmpeg": {
"repo": "FFmpeg/FFmpeg",
"sha": "c7b5f1537d",
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
"sha": "e717604a29",
"hash": "403390865aa3c0a947679ec2f24076383c72d308dda66918e64526ddc585e652dfda66b724fc04b1625a28c89d428b13d50ae2c19c7a7f16bd5e50904266f302",
"bundled": true
},
"ffmpeg-ci": {
+1 -1
View File
@@ -244,7 +244,7 @@ else()
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
# BSD make or Solaris make don't support ffmpeg make-j8
if (PLATFORM_LINUX OR ANDROID OR APPLE OR WIN32 OR PLATFORM_FREEBSD)
if (DEFINED SYSTEM_THREADS AND (PLATFORM_LINUX OR ANDROID OR APPLE OR WIN32 OR PLATFORM_FREEBSD))
set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS})
else()
set(FFmpeg_MAKE_ARGS "")
+26 -15
View File
@@ -13,13 +13,13 @@
namespace Common {
template <typename BaseAddr>
MultiLevelPageTable<BaseAddr>::MultiLevelPageTable(std::size_t address_space_bits_, std::size_t first_level_bits_, std::size_t page_bits_)
: address_space_bits{address_space_bits_}
, first_level_bits{first_level_bits_}
, page_bits{page_bits_}
{
MultiLevelPageTable<BaseAddr>::MultiLevelPageTable(std::size_t address_space_bits_,
std::size_t first_level_bits_,
std::size_t page_bits_)
: address_space_bits{address_space_bits_},
first_level_bits{first_level_bits_}, page_bits{page_bits_} {
if (page_bits == 0) {
return;
return;
}
first_level_shift = address_space_bits - first_level_bits;
first_level_chunk_size = (1ULL << (first_level_shift - page_bits)) * sizeof(BaseAddr);
@@ -30,9 +30,12 @@ MultiLevelPageTable<BaseAddr>::MultiLevelPageTable(std::size_t address_space_bit
void* base{VirtualAlloc(nullptr, alloc_size, MEM_RESERVE, PAGE_READWRITE)};
#else
void* base{mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)};
if (base == MAP_FAILED)
if (base == MAP_FAILED) {
base = nullptr;
}
#endif
ASSERT(base);
base_ptr = reinterpret_cast<BaseAddr*>(base);
}
@@ -53,21 +56,29 @@ template <typename BaseAddr>
void MultiLevelPageTable<BaseAddr>::ReserveRange(u64 start, std::size_t size) {
const u64 new_start = start >> first_level_shift;
const u64 new_end = (start + size) >> first_level_shift;
for (u64 i = new_start; i <= new_end; i++)
if (!first_level_map[i])
for (u64 i = new_start; i <= new_end; i++) {
if (!first_level_map[i]) {
AllocateLevel(i);
}
}
}
template <typename BaseAddr>
void MultiLevelPageTable<BaseAddr>::AllocateLevel(u64 index) {
void* ptr = reinterpret_cast<char *>(base_ptr) + index * first_level_chunk_size;
void MultiLevelPageTable<BaseAddr>::AllocateLevel(u64 level) {
void* ptr = reinterpret_cast<char *>(base_ptr) + level * first_level_chunk_size;
#ifdef _WIN32
void* base = VirtualAlloc(ptr, first_level_chunk_size, MEM_COMMIT, PAGE_READWRITE);
ASSERT(base);
void* base{VirtualAlloc(ptr, first_level_chunk_size, MEM_COMMIT, PAGE_READWRITE)};
#else
void* base = ptr;
void* base{mmap(ptr, first_level_chunk_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)};
if (base == MAP_FAILED) {
base = nullptr;
}
#endif
first_level_map[index] = base;
ASSERT(base);
first_level_map[level] = base;
}
} // namespace Common
+4 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
@@ -142,8 +142,10 @@ struct PageTable {
VirtualBuffer<PageEntryData> entries;
static_assert(sizeof(PageEntryData) == 32);
u8* fastmem_arena{};
std::size_t current_address_space_width_in_bits{};
u8* fastmem_arena{};
std::size_t page_size{};
};
+17 -18
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -24,9 +21,7 @@ public:
// "with the current allocator");
constexpr VirtualBuffer() = default;
explicit VirtualBuffer(std::size_t count) noexcept
: alloc_size{count * sizeof(T)}
{
explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} {
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
}
@@ -38,8 +33,8 @@ public:
VirtualBuffer& operator=(const VirtualBuffer&) = delete;
VirtualBuffer(VirtualBuffer&& other) noexcept
: alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr), nullptr}
{}
: alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr),
nullptr} {}
VirtualBuffer& operator=(VirtualBuffer&& other) noexcept {
alloc_size = std::exchange(other.alloc_size, 0);
@@ -47,31 +42,35 @@ public:
return *this;
}
void resize(std::size_t count) noexcept {
if (auto const new_size = count * sizeof(T); new_size != alloc_size) {
FreeMemoryPages(base_ptr, alloc_size);
alloc_size = new_size;
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
void resize(std::size_t count) {
const auto new_size = count * sizeof(T);
if (new_size == alloc_size) {
return;
}
FreeMemoryPages(base_ptr, alloc_size);
alloc_size = new_size;
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
}
[[nodiscard]] constexpr const T& operator[](std::size_t index) const noexcept {
[[nodiscard]] constexpr const T& operator[](std::size_t index) const {
return base_ptr[index];
}
[[nodiscard]] constexpr T& operator[](std::size_t index) noexcept {
[[nodiscard]] constexpr T& operator[](std::size_t index) {
return base_ptr[index];
}
[[nodiscard]] constexpr T* data() noexcept {
[[nodiscard]] constexpr T* data() {
return base_ptr;
}
[[nodiscard]] constexpr const T* data() const noexcept {
[[nodiscard]] constexpr const T* data() const {
return base_ptr;
}
[[nodiscard]] constexpr std::size_t size() const noexcept {
[[nodiscard]] constexpr std::size_t size() const {
return alloc_size / sizeof(T);
}
+2 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
@@ -283,7 +283,7 @@ std::string_view GDBStubA32::GetTargetXML() const {
<reg name="r11" bitsize="32" type="uint32"/>
<reg name="r12" bitsize="32" type="uint32"/>
<reg name="sp" bitsize="32" type="data_ptr"/>
<reg name="lr" bitsize="32"/>
<reg name="lr" bitsize="32" type="code_ptr"/>
<reg name="pc" bitsize="32" type="code_ptr"/>
<!-- The CPSR is register 25, rather than register 16, because
the FPA registers historically were placed between the PC
+32 -16
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -191,7 +191,8 @@ Result KPageTableBase::InitializeForKernel(bool is_64_bit, KVirtualAddress start
m_cached_physical_heap_region = nullptr;
// Initialize our implementation.
m_impl.Resize(m_address_space_width, PageBits);
m_impl = std::make_unique<Common::PageTable>();
m_impl->Resize(m_address_space_width, PageBits);
// Set the tracking memory.
m_memory = std::addressof(memory);
@@ -201,7 +202,13 @@ Result KPageTableBase::InitializeForKernel(bool is_64_bit, KVirtualAddress start
m_memory_block_slab_manager));
}
Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource* system_resource, KResourceLimit* resource_limit, Core::Memory::Memory& memory, KProcessAddress aslr_space_start) {
Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool enable_aslr,
bool enable_das_merge, bool from_back,
KMemoryManager::Pool pool, KProcessAddress code_address,
size_t code_size, KSystemResource* system_resource,
KResourceLimit* resource_limit,
Core::Memory::Memory& memory,
KProcessAddress aslr_space_start) {
// Calculate region extents.
const size_t as_width = GetAddressSpaceWidth(as_type);
const KProcessAddress start = 0;
@@ -312,10 +319,14 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
// Determine random placements for each region.
size_t alias_rnd = 0, heap_rnd = 0, stack_rnd = 0, kmap_rnd = 0;
if (enable_aslr) {
alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
RegionAlignment;
heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
RegionAlignment;
stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
RegionAlignment;
kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) *
RegionAlignment;
}
// Setup heap and alias regions.
@@ -434,13 +445,15 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
ASSERT(heap_last < kmap_start || kmap_last < heap_start);
// Initialize our implementation.
m_impl.Resize(m_address_space_width, PageBits);
m_impl = std::make_unique<Common::PageTable>();
m_impl->Resize(m_address_space_width, PageBits);
// Set the tracking memory.
m_memory = std::addressof(memory);
// Initialize our memory block manager.
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager));
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end,
m_memory_block_slab_manager));
}
Result KPageTableBase::FinalizeProcess() {
@@ -463,7 +476,7 @@ void KPageTableBase::Finalize() {
this->FinalizeProcess();
auto BlockCallback = [&](KProcessAddress addr, u64 size) {
if (m_impl.fastmem_arena) {
if (m_impl->fastmem_arena) {
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
}
@@ -501,6 +514,9 @@ void KPageTableBase::Finalize() {
m_resource_limit->Release(Svc::LimitableResource::PhysicalMemoryMax,
m_mapped_ipc_server_memory);
}
// Close the backing page table, as the destructor is not called for guest objects.
m_impl.reset();
}
KProcessAddress KPageTableBase::GetRegionAddress(Svc::MemoryState state) const {
@@ -2333,7 +2349,7 @@ Result KPageTableBase::QueryPhysicalAddress(Svc::lp64::PhysicalMemoryInfo* out,
TraversalContext context;
TraversalEntry next_entry;
bool traverse_valid =
m_impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), virt_addr);
m_impl->BeginTraversal(std::addressof(next_entry), std::addressof(context), virt_addr);
R_UNLESS(traverse_valid, ResultInvalidCurrentMemory);
// Set tracking variables.
@@ -2344,7 +2360,7 @@ Result KPageTableBase::QueryPhysicalAddress(Svc::lp64::PhysicalMemoryInfo* out,
while (true) {
// Continue the traversal.
traverse_valid =
m_impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context));
m_impl->ContinueTraversal(std::addressof(next_entry), std::addressof(context));
if (!traverse_valid) {
break;
}
@@ -5714,14 +5730,14 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
// Unmap.
m_memory->UnmapRegion(m_impl, virt_addr, num_pages * PageSize, separate_heap);
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize, separate_heap);
R_SUCCEED();
}
case OperationType::Map: {
ASSERT(virt_addr != 0);
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
m_memory->MapMemoryRegion(m_impl, virt_addr, num_pages * PageSize, phys_addr,
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
ConvertToMemoryPermission(properties.perm), false);
// Open references to pages, if we should.
@@ -5738,7 +5754,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
case OperationType::ChangePermissions:
case OperationType::ChangePermissionsAndRefresh:
case OperationType::ChangePermissionsAndRefreshAndFlush: {
m_memory->ProtectRegion(m_impl, virt_addr, num_pages * PageSize,
m_memory->ProtectRegion(*m_impl, virt_addr, num_pages * PageSize,
ConvertToMemoryPermission(properties.perm));
R_SUCCEED();
}
@@ -5772,7 +5788,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
const size_t size{node.GetNumPages() * PageSize};
// Map the pages.
m_memory->MapMemoryRegion(m_impl, virt_addr, size, node.GetAddress(),
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
ConvertToMemoryPermission(properties.perm), separate_heap);
virt_addr += size;
+22 -7
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -215,7 +215,7 @@ private:
mutable KLightLock m_general_lock;
mutable KLightLock m_map_physical_memory_lock;
KLightLock m_device_map_lock;
Common::PageTable m_impl{};
std::unique_ptr<Common::PageTable> m_impl{};
Core::Memory::Memory* m_memory{};
KMemoryBlockManager m_memory_block_manager{};
u32 m_allocate_option{};
@@ -300,11 +300,26 @@ public:
}
public:
[[nodiscard]] Core::Memory::Memory& GetMemory() noexcept { return *m_memory; }
[[nodiscard]] Core::Memory::Memory const& GetMemory() const noexcept { return *m_memory; }
[[nodiscard]] Common::PageTable& GetImpl() noexcept { return m_impl; }
[[nodiscard]] Common::PageTable const& GetImpl() const noexcept { return m_impl; }
[[nodiscard]] size_t GetNumGuardPages() const noexcept { return this->IsKernel() ? 1 : 4; }
Core::Memory::Memory& GetMemory() {
return *m_memory;
}
Core::Memory::Memory& GetMemory() const {
return *m_memory;
}
Common::PageTable& GetImpl() {
return *m_impl;
}
Common::PageTable& GetImpl() const {
return *m_impl;
}
size_t GetNumGuardPages() const {
return this->IsKernel() ? 1 : 4;
}
protected:
// NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions
// in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived
+16 -5
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -33,10 +33,21 @@ public:
m_page_table.Finalize();
}
[[nodiscard]] Core::Memory::Memory& GetMemory() noexcept { return m_page_table.GetMemory(); }
[[nodiscard]] Core::Memory::Memory const& GetMemory() const noexcept { return m_page_table.GetMemory(); }
[[nodiscard]] Common::PageTable& GetImpl() noexcept { return m_page_table.GetImpl(); }
[[nodiscard]] Common::PageTable const& GetImpl() const noexcept { return m_page_table.GetImpl(); }
Core::Memory::Memory& GetMemory() {
return m_page_table.GetMemory();
}
Core::Memory::Memory& GetMemory() const {
return m_page_table.GetMemory();
}
Common::PageTable& GetImpl() {
return m_page_table.GetImpl();
}
Common::PageTable& GetImpl() const {
return m_page_table.GetImpl();
}
size_t GetNumGuardPages() const {
return m_page_table.GetNumGuardPages();
+5 -23
View File
@@ -50,14 +50,6 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
};
const auto ExitContext = [&]() {
// Save the JIT context back to the thread so the debugger can
// read the current register state. Debug halt paths (step,
// breakpoint, watchpoint) return from RunThread without going
// through the scheduler's Unload/SaveContext.
if (system.DebuggerEnabled()) {
interface->GetContext(thread->GetContext());
}
// Unlock the thread.
interface->UnlockThread(thread);
@@ -105,16 +97,11 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
}
// Determine why we stopped.
// If a step completed successfully, skip other halt reason handlers —
// the step takes priority (e.g. step may also set InstructionBreakpoint
// if the next instruction happens to be a breakpoint).
const bool step_completed = True(hr & Core::HaltReason::StepThread)
&& thread->GetStepState() == StepState::StepPerformed;
const bool supervisor_call = !step_completed && True(hr & Core::HaltReason::SupervisorCall);
const bool prefetch_abort = !step_completed && True(hr & Core::HaltReason::PrefetchAbort);
const bool breakpoint = !step_completed && True(hr & Core::HaltReason::InstructionBreakpoint);
const bool data_abort = !step_completed && True(hr & Core::HaltReason::DataAbort);
const bool interrupt = !step_completed && True(hr & Core::HaltReason::BreakLoop);
const bool supervisor_call = True(hr & Core::HaltReason::SupervisorCall);
const bool prefetch_abort = True(hr & Core::HaltReason::PrefetchAbort);
const bool breakpoint = True(hr & Core::HaltReason::InstructionBreakpoint);
const bool data_abort = True(hr & Core::HaltReason::DataAbort);
const bool interrupt = True(hr & Core::HaltReason::BreakLoop);
// Since scheduling may occur here, we cannot use any cached
// state after returning from calls we make.
@@ -124,11 +111,6 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
if (breakpoint || prefetch_abort) {
if (breakpoint) {
interface->RewindBreakpointInstruction();
// RewindBreakpointInstruction sets the JIT state to the
// saved breakpoint context. Update the thread context to
// match, since ExitContext already saved the post-execution
// state.
interface->GetContext(thread->GetContext());
}
if (system.DebuggerEnabled()) {
system.GetDebugger().NotifyThreadStopped(thread);
@@ -228,8 +228,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
code_size += patch_ctx.GetTotalPatchSize();
// TODO: this is bad form of ASLR, it sucks
std::uintptr_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000;
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
? ::Settings::values.rng_seed.GetValue()
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
// Setup the process code layout
if (process.LoadFromMetadata(metadata, code_size, fastmem_base, aslr_offset, is_hbl).IsError()) {
+3 -2
View File
@@ -89,8 +89,9 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
codeset.DataSegment().size += kip->GetBSSSize();
// TODO: this is bad form of ASLR, it sucks
std::uintptr_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000;
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
? ::Settings::values.rng_seed.GetValue()
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
// Setup the process code layout
if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), codeset.memory.size(), 0, aslr_offset, false).IsError()) {
+3 -2
View File
@@ -242,8 +242,9 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
}();
// TODO: this is bad form of ASLR, it sucks
std::uintptr_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
? ::Settings::values.rng_seed.GetValue() : Common::Random::Random64(0)) << 12) & 0xfff000;
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
? ::Settings::values.rng_seed.GetValue()
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
// Setup the process code layout
if (process
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@@ -39,7 +39,7 @@ bool TranslatorVisitor::BL(Imm<26> imm26) {
ir.PushRSB(ir.current_location->AdvancePC(4));
const u64 target = ir.PC() + offset;
ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location->SetPC(target)});
ir.SetTerm(IR::Term::LinkBlock{ir.current_location->SetPC(target)});
return false;
}
+9 -15
View File
@@ -157,14 +157,11 @@ void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t c
if (!controller.device->IsConnected()) {
return;
}
if (auto* shared_memory = controller.shared_memory; shared_memory) {
const auto& battery_level = controller.device->GetBattery();
shared_memory->battery_level_dual = battery_level.dual.battery_level;
shared_memory->battery_level_left = battery_level.left.battery_level;
shared_memory->battery_level_right = battery_level.right.battery_level;
} else {
LOG_WARNING(Service_HID, "shared_memory is null {}", controller_idx);
}
auto* shared_memory = controller.shared_memory;
const auto& battery_level = controller.device->GetBattery();
shared_memory->battery_level_dual = battery_level.dual.battery_level;
shared_memory->battery_level_left = battery_level.left.battery_level;
shared_memory->battery_level_right = battery_level.right.battery_level;
break;
}
default:
@@ -183,10 +180,6 @@ void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) {
const auto& body_colors = controller.device->GetColors();
const auto& battery_level = controller.device->GetBattery();
auto* shared_memory = controller.shared_memory;
if (!shared_memory) {
LOG_WARNING(Service_HID, "shared_memory is null for npad_id={}", npad_id);
return;
}
if (controller_type == Core::HID::NpadStyleIndex::None) {
npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id);
return;
@@ -808,7 +801,7 @@ Result NPad::DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id) {
auto* shared_memory = controller.shared_memory;
if (!shared_memory) {
LOG_WARNING(Service_HID, "shared_memory is null for npad_id={}", npad_id);
LOG_WARNING(Service_HID, "DisconnectNpad: shared_memory is null for npad_id={}", npad_id);
return ResultSuccess;
}
// Don't reset shared_memory->assignment_mode this value is persistent
@@ -1202,10 +1195,11 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
const auto* shared_memory = GetControllerFromNpadIdType(aruid, npad_id).shared_memory;
const auto& shared_memory = GetControllerFromNpadIdType(aruid, npad_id).shared_memory;
return {
.ui_variant = 0,
.footer = shared_memory ? shared_memory->applet_footer_type : AppletFooterUiType::None,
.footer = shared_memory->applet_footer_type,
};
}
@@ -30,9 +30,8 @@ struct TextureInst {
using TextureInstVector = boost::container::small_vector<TextureInst, 24>;
// TODO: We need to implement scatter/gather CBuf stuff
constexpr u32 DESCRIPTOR_SIZE = 1024;
constexpr u32 DESCRIPTOR_SIZE_SHIFT = u32(std::countr_zero(u32(8)));
constexpr u32 DESCRIPTOR_SIZE = 8;
constexpr u32 DESCRIPTOR_SIZE_SHIFT = static_cast<u32>(std::countr_zero(DESCRIPTOR_SIZE));
IR::Opcode IndexedInstruction(const IR::Inst& inst) {
switch (inst.GetOpcode()) {
@@ -363,7 +362,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
.secondary_offset = 0,
.secondary_shift_left = 0,
.dynamic_offset = dynamic_offset,
.count = DESCRIPTOR_SIZE,
.count = 8,
.has_secondary = false,
};
}
@@ -407,15 +406,15 @@ u32 GetTextureHandle(Environment& env, const ConstBufferAddr& cbuf) {
return lhs_raw | rhs_raw;
}
[[maybe_unused]]TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
[[maybe_unused]]TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
return env.ReadTextureType(GetTextureHandle(env, cbuf));
}
[[maybe_unused]]TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) {
[[maybe_unused]]TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) {
return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
}
[[maybe_unused]]bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
[[maybe_unused]]bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf));
}
@@ -717,7 +716,8 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)};
IR::IREmitter ir{*texture_inst.block, insert_point};
const IR::U32 shift{ir.Imm32(DESCRIPTOR_SIZE_SHIFT)};
inst->SetArg(0, ir.UMin(ir.ShiftRightLogical(cbuf.dynamic_offset, shift), ir.Imm32(DESCRIPTOR_SIZE - 1)));
inst->SetArg(0, ir.UMin(ir.ShiftRightLogical(cbuf.dynamic_offset, shift),
ir.Imm32(DESCRIPTOR_SIZE - 1)));
} else {
inst->SetArg(0, IR::Value{});
}
+45 -30
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -18,37 +15,53 @@ public:
InvalidationAccumulator() = default;
~InvalidationAccumulator() = default;
void Add(GPUVAddr address, size_t size) noexcept {
auto const end_address = start_address + accumulated_size;
if (!(address >= start_address && address + size <= end_address)) {
size = ((address + size + atomicity_size_mask) & atomicity_mask) - address;
address = address & atomicity_mask;
if (start_address == 0) {
start_address = address;
accumulated_size = size;
// will now have collected as this point
} else if (address != end_address) {
void Add(GPUVAddr address, size_t size) {
const auto reset_values = [&]() {
if (has_collected) {
buffer.emplace_back(start_address, accumulated_size);
start_address = address;
accumulated_size = size;
} else {
accumulated_size += size;
}
start_address = address;
accumulated_size = size;
last_collection = start_address + size;
};
if (address >= start_address && address + size <= last_collection) [[likely]] {
return;
}
size = ((address + size + atomicity_size_mask) & atomicity_mask) - address;
address = address & atomicity_mask;
if (!has_collected) [[unlikely]] {
reset_values();
has_collected = true;
return;
}
if (address != last_collection) [[unlikely]] {
reset_values();
return;
}
accumulated_size += size;
last_collection += size;
}
template <typename F>
[[nodiscard]] bool InvalidateAll(F&& f) noexcept {
if (start_address > 0) {
for (auto [address, size] : buffer)
f(address, size);
f(start_address, accumulated_size);
buffer.clear();
start_address = 0;
accumulated_size = 0;
return true;
void Clear() {
buffer.clear();
start_address = 0;
last_collection = 0;
has_collected = false;
}
bool AnyAccumulated() const {
return has_collected;
}
template <typename Func>
void Callback(Func&& func) {
if (!has_collected) {
return;
}
buffer.emplace_back(start_address, accumulated_size);
for (auto& [address, size] : buffer) {
func(address, size);
}
return false;
}
private:
@@ -56,9 +69,11 @@ private:
static constexpr size_t atomicity_size = 1ULL << atomicity_bits;
static constexpr size_t atomicity_size_mask = atomicity_size - 1;
static constexpr size_t atomicity_mask = ~atomicity_size_mask;
GPUVAddr start_address{};
GPUVAddr last_collection{};
size_t accumulated_size{};
bool has_collected{};
std::vector<std::pair<VAddr, size_t>> buffer;
GPUVAddr start_address = 0;
size_t accumulated_size = 0;
};
} // namespace VideoCommon
+25 -19
View File
@@ -26,14 +26,16 @@ using Tegra::Memory::GuestMemoryFlags;
std::atomic<size_t> MemoryManager::unique_identifier_generator{};
MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_, u64 address_space_bits_, GPUVAddr split_address_, u64 big_page_bits_, u64 page_bits_)
: system{system_}, memory{memory_}, address_space_bits{address_space_bits_}
, split_address{split_address_}, page_bits{page_bits_}, big_page_bits{big_page_bits_}
, entries{}, big_entries{}
, page_table{address_space_bits, address_space_bits + page_bits - 38, page_bits != big_page_bits ? page_bits : 0}
, kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add(1, std::memory_order_acq_rel)}
, accumulator{}
{
MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
u64 address_space_bits_, GPUVAddr split_address_, u64 big_page_bits_,
u64 page_bits_)
: system{system_}, memory{memory_}, address_space_bits{address_space_bits_},
split_address{split_address_}, page_bits{page_bits_}, big_page_bits{big_page_bits_},
entries{}, big_entries{}, page_table{address_space_bits, address_space_bits + page_bits - 38,
page_bits != big_page_bits ? page_bits : 0},
kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add(
1, std::memory_order_acq_rel)},
accumulator{std::make_unique<VideoCommon::InvalidationAccumulator>()} {
address_space_size = 1ULL << address_space_bits;
page_size = 1ULL << page_bits;
page_mask = page_size - 1ULL;
@@ -52,9 +54,10 @@ MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager&
entries.resize(page_table_size / 32, 0);
}
MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, GPUVAddr split_address_, u64 big_page_bits_, u64 page_bits_)
: MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, split_address_, big_page_bits_, page_bits_)
{}
MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_,
GPUVAddr split_address_, u64 big_page_bits_, u64 page_bits_)
: MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, split_address_,
big_page_bits_, page_bits_) {}
MemoryManager::~MemoryManager() = default;
@@ -466,9 +469,10 @@ void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buf
WriteBlockImpl<false>(gpu_dest_addr, src_buffer, size, VideoCommon::CacheType::None);
}
void MemoryManager::WriteBlockCached(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size) {
void MemoryManager::WriteBlockCached(GPUVAddr gpu_dest_addr, const void* src_buffer,
std::size_t size) {
WriteBlockImpl<false>(gpu_dest_addr, src_buffer, size, VideoCommon::CacheType::None);
accumulator.Add(gpu_dest_addr, size);
accumulator->Add(gpu_dest_addr, size);
}
void MemoryManager::FlushRegion(GPUVAddr gpu_addr, size_t size,
@@ -752,13 +756,15 @@ void MemoryManager::GetSubmappedRangeImpl(
}
void MemoryManager::FlushCaching() {
// Flush from the invalidate accumulator
if (accumulator.InvalidateAll([this](GPUVAddr addr, size_t size) {
GetSubmappedRangeImpl<false>(addr, size, page_stash2);
})) {
rasterizer->InnerInvalidation(VideoCommon::FixSmallVectorADL(page_stash2));
page_stash2.clear();
if (!accumulator->AnyAccumulated()) {
return;
}
accumulator->Callback([this](GPUVAddr addr, size_t size) {
GetSubmappedRangeImpl<false>(addr, size, page_stash2);
});
rasterizer->InnerInvalidation(VideoCommon::FixSmallVectorADL(page_stash2));
page_stash2.clear();
accumulator->Clear();
}
const u8* MemoryManager::GetSpan(const GPUVAddr src_addr, const std::size_t size) const {
+6 -3
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -18,7 +18,6 @@
#include "common/range_map.h"
#include "common/scratch_buffer.h"
#include "common/virtual_buffer.h"
#include "video_core/invalidation_accumulator.h"
#include "video_core/cache_types.h"
#include "video_core/host1x/gpu_device_memory_manager.h"
#include "video_core/pte_kind.h"
@@ -27,6 +26,10 @@ namespace VideoCore {
class RasterizerInterface;
}
namespace VideoCommon {
class InvalidationAccumulator;
}
namespace Core {
class System;
} // namespace Core
@@ -246,7 +249,7 @@ private:
static constexpr size_t continuous_bits = 64;
const size_t unique_identifier;
VideoCommon::InvalidationAccumulator accumulator;
std::unique_ptr<VideoCommon::InvalidationAccumulator> accumulator;
static std::atomic<size_t> unique_identifier_generator;
@@ -127,8 +127,9 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
texture_cache.SynchronizeComputeDescriptors();
boost::container::small_vector<VideoCommon::ImageViewInOut, 64> views;
boost::container::small_vector<VideoCommon::SamplerId, 64> samplers;
static constexpr size_t max_elements = 64;
boost::container::static_vector<VideoCommon::ImageViewInOut, max_elements> views;
boost::container::static_vector<VideoCommon::SamplerId, max_elements> samplers;
const auto& qmd{kepler_compute.launch_description};
const auto& cbufs{qmd.const_buffer_config};