diff --git a/dist/dev.eden_emu.eden.svg b/dist/dev.eden_emu.eden.svg index 7711945aa4..f88b52f625 100644 --- a/dist/dev.eden_emu.eden.svg +++ b/dist/dev.eden_emu.eden.svg @@ -1,21 +1,203 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + inkscape:current-layer="svg7" /> + + diff --git a/dist/eden.bmp b/dist/eden.bmp index cffc04b308..888138ccf7 100644 Binary files a/dist/eden.bmp and b/dist/eden.bmp differ diff --git a/dist/eden.ico b/dist/eden.ico index 106742c9ba..45120ef312 100644 Binary files a/dist/eden.ico and b/dist/eden.ico differ diff --git a/dist/qt_themes/default/icons/256x256/eden.png b/dist/qt_themes/default/icons/256x256/eden.png index d7286ac4c6..3c4bd566a1 100644 Binary files a/dist/qt_themes/default/icons/256x256/eden.png and b/dist/qt_themes/default/icons/256x256/eden.png differ diff --git a/src/android/app/src/main/res/drawable/ic_launcher_foreground.png b/src/android/app/src/main/res/drawable/ic_launcher_foreground.png index 8b970cd4cc..53f1cace9b 100644 Binary files a/src/android/app/src/main/res/drawable/ic_launcher_foreground.png and b/src/android/app/src/main/res/drawable/ic_launcher_foreground.png differ diff --git a/src/android/app/src/main/res/drawable/ic_yuzu.png b/src/android/app/src/main/res/drawable/ic_yuzu.png index 7e2461ba24..fce02afa1f 100644 Binary files a/src/android/app/src/main/res/drawable/ic_yuzu.png and b/src/android/app/src/main/res/drawable/ic_yuzu.png differ diff --git a/src/android/app/src/main/res/drawable/ic_yuzu_splash.png b/src/android/app/src/main/res/drawable/ic_yuzu_splash.png index c9404d9937..0e43cb9374 100644 Binary files a/src/android/app/src/main/res/drawable/ic_yuzu_splash.png and b/src/android/app/src/main/res/drawable/ic_yuzu_splash.png differ diff --git a/src/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 74c6677dd9..23bc2897c3 100644 Binary files a/src/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/src/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 31a01461b4..f630e793e3 100644 Binary files a/src/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/src/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/src/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 3f0023f573..1daa3c624f 100644 Binary files a/src/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/src/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 6e28b3d598..7fc64e1393 100644 Binary files a/src/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/src/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 39f583b630..53ed9b9914 100644 Binary files a/src/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/src/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/android/app/src/main/res/values/colors.xml b/src/android/app/src/main/res/values/colors.xml index ad3412ed27..472567b323 100644 --- a/src/android/app/src/main/res/values/colors.xml +++ b/src/android/app/src/main/res/values/colors.xml @@ -1 +1 @@ -#43fcfcff +#1F143C diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 98c1688441..3756140b88 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -66,8 +66,6 @@ add_library( fs/path_util.cpp fs/path_util.h hash.h - heap_tracker.cpp - heap_tracker.h hex_util.cpp hex_util.h host_memory.cpp diff --git a/src/common/heap_tracker.cpp b/src/common/heap_tracker.cpp deleted file mode 100644 index b72abb16d8..0000000000 --- a/src/common/heap_tracker.cpp +++ /dev/null @@ -1,282 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2026 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 - -#include -#include "common/heap_tracker.h" -#include "common/logging.h" -#include "common/assert.h" - -namespace Common { - -namespace { - -s64 GetMaxPermissibleResidentMapCount() { - // Default value. - s64 value = 65530; - - // Try to read how many mappings we can make. - std::ifstream s("/proc/sys/vm/max_map_count"); - s >> value; - - // Print, for debug. - LOG_INFO(HW_Memory, "Current maximum map count: {}", value); - - // Allow 20000 maps for other code and to account for split inaccuracy. - return std::max(value - 20000, 0); -} - -} // namespace - -HeapTracker::HeapTracker(Common::HostMemory& buffer) - : m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {} -HeapTracker::~HeapTracker() = default; - -void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length, - MemoryPermission perm, bool is_separate_heap) { - // When mapping other memory, map pages immediately. - if (!is_separate_heap) { - m_buffer.Map(virtual_offset, host_offset, length, perm, false); - return; - } - - { - // We are mapping part of a separate heap. - std::scoped_lock lk{m_lock}; - - auto* const map = new SeparateHeapMap{ - .vaddr = virtual_offset, - .paddr = host_offset, - .size = length, - .tick = m_tick++, - .perm = perm, - .is_resident = false, - }; - - // Insert into mappings. - m_map_count++; - m_mappings.insert(*map); - } - - // Finally, map. - this->DeferredMapSeparateHeap(virtual_offset); -} - -void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) { - // If this is a separate heap... - if (is_separate_heap) { - std::scoped_lock lk{m_lock}; - - const SeparateHeapMap key{ - .vaddr = virtual_offset, - }; - - // Split at the boundaries of the region we are removing. - this->SplitHeapMapLocked(virtual_offset); - this->SplitHeapMapLocked(virtual_offset + size); - - // Erase all mappings in range. - auto it = m_mappings.find(key); - while (it != m_mappings.end() && it->vaddr < virtual_offset + size) { - // Get underlying item. - auto* const item = std::addressof(*it); - - // If resident, erase from resident map. - if (item->is_resident) { - ASSERT(--m_resident_map_count >= 0); - m_resident_mappings.erase(m_resident_mappings.iterator_to(*item)); - } - - // Erase from map. - ASSERT(--m_map_count >= 0); - it = m_mappings.erase(it); - - // Free the item. - delete item; - } - } - - // Unmap pages. - m_buffer.Unmap(virtual_offset, size, false); -} - -void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission perm) { - // Ensure no rebuild occurs while reprotecting. - std::shared_lock lk{m_rebuild_lock}; - - // Split at the boundaries of the region we are reprotecting. - this->SplitHeapMap(virtual_offset, size); - - // Declare tracking variables. - const VAddr end = virtual_offset + size; - VAddr cur = virtual_offset; - - while (cur < end) { - VAddr next = cur; - bool should_protect = false; - - { - std::scoped_lock lk2{m_lock}; - - const SeparateHeapMap key{ - .vaddr = next, - }; - - // Try to get the next mapping corresponding to this address. - const auto it = m_mappings.nfind(key); - - if (it == m_mappings.end()) { - // There are no separate heap mappings remaining. - next = end; - should_protect = true; - } else if (it->vaddr == cur) { - // We are in range. - // Update permission bits. - it->perm = perm; - - // Determine next address and whether we should protect. - next = cur + it->size; - should_protect = it->is_resident; - } else /* if (it->vaddr > cur) */ { - // We weren't in range, but there is a block coming up that will be. - next = it->vaddr; - should_protect = true; - } - } - - // Clamp to end. - next = (std::min)(next, end); - // Reprotect, if we need to. - if (should_protect) { - m_buffer.Protect(cur, next - cur, perm); - } - - // Advance. - cur = next; - } -} - -bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) { - if (m_buffer.IsInVirtualRange(fault_address)) { - return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer()); - } - - return false; -} - -bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) { - bool rebuild_required = false; - - { - std::scoped_lock lk{m_lock}; - - // Check to ensure this was a non-resident separate heap mapping. - const auto it = this->GetNearestHeapMapLocked(virtual_offset); - if (it == m_mappings.end() || it->is_resident) { - return false; - } - - // Update tick before possible rebuild. - it->tick = m_tick++; - - // Check if we need to rebuild. - if (m_resident_map_count > m_max_resident_map_count) { - rebuild_required = true; - } - - // Map the area. - m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false); - - // This map is now resident. - it->is_resident = true; - m_resident_map_count++; - m_resident_mappings.insert(*it); - } - - if (rebuild_required) { - // A rebuild was required, so perform it now. - this->RebuildSeparateHeapAddressSpace(); - } - - return true; -} - -void HeapTracker::RebuildSeparateHeapAddressSpace() { - std::scoped_lock lk{m_rebuild_lock, m_lock}; - - ASSERT(!m_resident_mappings.empty()); - - // Dump half of the mappings. - // - // Despite being worse in theory, this has proven to be better in practice than more - // regularly dumping a smaller amount, because it significantly reduces average case - // lock contention. - std::size_t const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2; - std::size_t const evict_count = m_resident_map_count - desired_count; - auto it = m_resident_mappings.begin(); - - for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) { - // Unmark and unmap. - it->is_resident = false; - m_buffer.Unmap(it->vaddr, it->size, false); - - // Advance. - ASSERT(--m_resident_map_count >= 0); - it = m_resident_mappings.erase(it); - } -} - -void HeapTracker::SplitHeapMap(VAddr offset, size_t size) { - std::scoped_lock lk{m_lock}; - - this->SplitHeapMapLocked(offset); - this->SplitHeapMapLocked(offset + size); -} - -void HeapTracker::SplitHeapMapLocked(VAddr offset) { - const auto it = this->GetNearestHeapMapLocked(offset); - if (it == m_mappings.end() || it->vaddr == offset) { - // Not contained or no split required. - return; - } - - // Cache the original values. - auto* const left = std::addressof(*it); - const size_t orig_size = left->size; - - // Adjust the left map. - const size_t left_size = offset - left->vaddr; - left->size = left_size; - - // Create the new right map. - auto* const right = new SeparateHeapMap{ - .vaddr = left->vaddr + left_size, - .paddr = left->paddr + left_size, - .size = orig_size - left_size, - .tick = left->tick, - .perm = left->perm, - .is_resident = left->is_resident, - }; - - // Insert the new right map. - m_map_count++; - m_mappings.insert(*right); - - // If resident, also insert into resident map. - if (right->is_resident) { - m_resident_map_count++; - m_resident_mappings.insert(*right); - } -} - -HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) { - const SeparateHeapMap key{ - .vaddr = offset, - }; - - return m_mappings.find(key); -} - -} // namespace Common diff --git a/src/common/heap_tracker.h b/src/common/heap_tracker.h deleted file mode 100644 index ee5b0bf43a..0000000000 --- a/src/common/heap_tracker.h +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include - -#include "common/host_memory.h" -#include "common/intrusive_red_black_tree.h" - -namespace Common { - -struct SeparateHeapMap { - Common::IntrusiveRedBlackTreeNode addr_node{}; - Common::IntrusiveRedBlackTreeNode tick_node{}; - VAddr vaddr{}; - PAddr paddr{}; - size_t size{}; - size_t tick{}; - MemoryPermission perm{}; - bool is_resident{}; -}; - -struct SeparateHeapMapAddrComparator { - static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { - if (lhs.vaddr < rhs.vaddr) { - return -1; - } else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) { - return 0; - } else { - return 1; - } - } -}; - -struct SeparateHeapMapTickComparator { - static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { - if (lhs.tick < rhs.tick) { - return -1; - } else if (lhs.tick > rhs.tick) { - return 1; - } else { - return SeparateHeapMapAddrComparator::Compare(lhs, rhs); - } - } -}; - -class HeapTracker { -public: - explicit HeapTracker(Common::HostMemory& buffer); - ~HeapTracker(); - - void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, - bool is_separate_heap); - void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap); - void Protect(size_t virtual_offset, size_t length, MemoryPermission perm); - u8* VirtualBasePointer() { - return m_buffer.VirtualBasePointer(); - } - - bool DeferredMapSeparateHeap(u8* fault_address); - bool DeferredMapSeparateHeap(size_t virtual_offset); - -private: - using AddrTreeTraits = - Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>; - using AddrTree = AddrTreeTraits::TreeType; - - using TickTreeTraits = - Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>; - using TickTree = TickTreeTraits::TreeType; - - AddrTree m_mappings{}; - TickTree m_resident_mappings{}; - -private: - void SplitHeapMap(VAddr offset, size_t size); - void SplitHeapMapLocked(VAddr offset); - - AddrTree::iterator GetNearestHeapMapLocked(VAddr offset); - - void RebuildSeparateHeapAddressSpace(); - -private: - Common::HostMemory& m_buffer; - const s64 m_max_resident_map_count; - - std::shared_mutex m_rebuild_lock{}; - std::mutex m_lock{}; - s64 m_map_count{}; - s64 m_resident_map_count{}; - size_t m_tick{}; -}; - -} // namespace Common diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 04f3a65778..65bf38aeb0 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -572,9 +572,8 @@ public: if (True(perms & MemoryPermission::Execute)) prot_flags |= PROT_EXEC; #endif - int flags = (fd >= 0 ? MAP_SHARED : MAP_PRIVATE) | MAP_FIXED; - void* ret = mmap(virtual_base + virtual_offset, length, prot_flags, flags, fd, host_offset); - ASSERT_MSG(ret != MAP_FAILED, "mmap: {} {}", strerror(errno), fd); + int ret = mprotect(virtual_base + virtual_offset, length, prot_flags); + ASSERT_MSG(ret == 0, "mprotect: {} {}", strerror(errno), fd); } void Unmap(size_t virtual_offset, size_t length) { @@ -588,8 +587,8 @@ public: auto [merged_pointer, merged_size] = free_manager.FreeBlock(virtual_base + virtual_offset, length); - void* ret = mmap(merged_pointer, merged_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); - ASSERT_MSG(ret != MAP_FAILED, "mmap: {}", strerror(errno)); + int ret = mprotect(merged_pointer, merged_size, PROT_NONE); + ASSERT_MSG(ret == 0, "mmap: {}", strerror(errno)); } void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) { diff --git a/src/common/multi_level_page_table.inc b/src/common/multi_level_page_table.inc index 8ac506fa0a..79125e8e0b 100644 --- a/src/common/multi_level_page_table.inc +++ b/src/common/multi_level_page_table.inc @@ -13,13 +13,13 @@ namespace Common { template -MultiLevelPageTable::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::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,12 +30,9 @@ MultiLevelPageTable::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(base); } @@ -56,29 +53,21 @@ template void MultiLevelPageTable::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 -void MultiLevelPageTable::AllocateLevel(u64 level) { - void* ptr = reinterpret_cast(base_ptr) + level * first_level_chunk_size; +void MultiLevelPageTable::AllocateLevel(u64 index) { + void* ptr = reinterpret_cast(base_ptr) + index * first_level_chunk_size; #ifdef _WIN32 - void* base{VirtualAlloc(ptr, first_level_chunk_size, MEM_COMMIT, PAGE_READWRITE)}; -#else - 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 + void* base = VirtualAlloc(ptr, first_level_chunk_size, MEM_COMMIT, PAGE_READWRITE); ASSERT(base); - - first_level_map[level] = base; +#else + void* base = ptr; +#endif + first_level_map[index] = base; } } // namespace Common diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 3a9ea308a8..ceefc0e0ea 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -16,7 +16,6 @@ #include "common/assert.h" #include "common/atomic_ops.h" #include "common/common_types.h" -#include "common/heap_tracker.h" #include "common/logging.h" #include "common/page_table.h" #include "common/scope_exit.h" @@ -55,37 +54,24 @@ struct Memory::Impl { } else { current_page_table->fastmem_arena = nullptr; } - -#ifdef __ANDROID__ - heap_tracker.emplace(system.DeviceMemory().buffer); - buffer = std::addressof(*heap_tracker); -#else buffer = std::addressof(system.DeviceMemory().buffer); -#endif } - void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, - Common::PhysicalAddress target, Common::MemoryPermission perms, - bool separate_heap) { + void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, Common::PhysicalAddress target, Common::MemoryPermission perms, bool separate_heap) { ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); - ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", - GetInteger(target)); - MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target, - Common::PageType::Memory); + ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", GetInteger(target)); + MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target, Common::PageType::Memory); if (current_page_table->fastmem_arena) { - buffer->Map(GetInteger(base), GetInteger(target) - DramMemoryMap::Base, size, perms, - separate_heap); + buffer->Map(GetInteger(base), GetInteger(target) - DramMemoryMap::Base, size, perms, separate_heap); } } - void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, - bool separate_heap) { + void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, bool separate_heap) { ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); - MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0, - Common::PageType::Unmapped); + MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0, Common::PageType::Unmapped); if (current_page_table->fastmem_arena) { buffer->Unmap(GetInteger(base), size, separate_heap); @@ -857,12 +843,7 @@ struct Memory::Impl { std::array, Core::Hardware::NUM_CPU_CORES> scratch_buffers{}; std::span gpu_dirty_managers; std::mutex sys_core_guard; -#ifdef __ANDROID__ - std::optional heap_tracker; - Common::HeapTracker* buffer{}; -#else Common::HostMemory* buffer{}; -#endif }; Memory::Memory(Core::System& system_) : system{system_} { @@ -1055,30 +1036,14 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { u8* const ptr = impl->GetPointerImpl( GetInteger(vaddr), [&] { - LOG_ERROR(HW_Memory, "Unmapped InvalidateNCE for {} bytes @ {:#x}", size, - GetInteger(vaddr)); + LOG_ERROR(HW_Memory, "Unmapped InvalidateNCE for {} bytes @ {:#x}", size, GetInteger(vaddr)); mapped = false; }, [&] { rasterizer = true; }); if (rasterizer) { impl->InvalidateGPUMemory(ptr, size); } - -#ifdef __ANDROID__ - if (!rasterizer && mapped) { - impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr)); - } -#endif - return mapped && ptr != nullptr; } -bool Memory::InvalidateSeparateHeap(void* fault_address) { -#ifdef __ANDROID__ - return impl->buffer->DeferredMapSeparateHeap(static_cast(fault_address)); -#else - return false; -#endif -} - } // namespace Core::Memory diff --git a/src/core/memory.h b/src/core/memory.h index 7167efbb84..cafbfdded3 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -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 // SPDX-FileCopyrightText: 2014 Citra Emulator Project @@ -490,13 +490,8 @@ public: * marked as debug or non-debug. */ void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); - void SetGPUDirtyManagers(std::span managers); - bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size); - - bool InvalidateSeparateHeap(void* fault_address); - private: Core::System& system; diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp b/src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp index be44207f0a..4a4ebf79d5 100644 --- a/src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp +++ b/src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp @@ -82,8 +82,6 @@ private: std::thread thread; mach_port_t server_port; - - void MessagePump(); }; MachHandler::MachHandler() { @@ -97,7 +95,30 @@ MachHandler::MachHandler() { KCHECK(mach_port_request_notification(mach_task_self(), server_port, MACH_NOTIFY_PORT_DESTROYED, 0, server_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev)); #undef KCHECK - thread = std::thread(&MachHandler::MessagePump, this); + thread = std::thread([this] { + mach_msg_return_t mr; + MachMessage request; + MachMessage reply; + + while (true) { + mr = mach_msg(&request.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(request), server_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (mr != MACH_MSG_SUCCESS) { + fmt::print(stderr, "dynarmic: macOS MachHandler: Failed to receive mach message. error: {:#08x} ({})\n", mr, mach_error_string(mr)); + return; + } + + if (!mach_exc_server(&request.head, &reply.head)) { + fmt::print(stderr, "dynarmic: macOS MachHandler: Unexpected mach message\n"); + return; + } + + mr = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (mr != MACH_MSG_SUCCESS) { + fmt::print(stderr, "dynarmic: macOS MachHandler: Failed to send mach message. error: {:#08x} ({})\n", mr, mach_error_string(mr)); + return; + } + } + }); thread.detach(); } @@ -105,31 +126,6 @@ MachHandler::~MachHandler() { mach_port_deallocate(mach_task_self(), server_port); } -void MachHandler::MessagePump() { - mach_msg_return_t mr; - MachMessage request; - MachMessage reply; - - while (true) { - mr = mach_msg(&request.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(request), server_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - if (mr != MACH_MSG_SUCCESS) { - fmt::print(stderr, "dynarmic: macOS MachHandler: Failed to receive mach message. error: {:#08x} ({})\n", mr, mach_error_string(mr)); - return; - } - - if (!mach_exc_server(&request.head, &reply.head)) { - fmt::print(stderr, "dynarmic: macOS MachHandler: Unexpected mach message\n"); - return; - } - - mr = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - if (mr != MACH_MSG_SUCCESS) { - fmt::print(stderr, "dynarmic: macOS MachHandler: Failed to send mach message. error: {:#08x} ({})\n", mr, mach_error_string(mr)); - return; - } - } -} - #if defined(ARCHITECTURE_x86_64) kern_return_t MachHandler::HandleRequest(x86_thread_state64_t* ts) { std::lock_guard guard(code_block_infos_mutex); diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp index 9f508f72e5..77f050296d 100644 --- a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp +++ b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.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. @@ -46,22 +46,18 @@ class SigHandler { }); } static void SigAction(int sig, siginfo_t* info, void* raw_context); - - bool supports_fast_mem = true; - void* signal_stack_memory = nullptr; + std::vector signal_stack_memory; ankerl::unordered_dense::map code_block_infos; std::shared_mutex code_block_infos_mutex; struct sigaction old_sa_segv; struct sigaction old_sa_bus; - std::size_t signal_stack_size; + bool supports_fast_mem = true; public: SigHandler() noexcept { - signal_stack_size = std::max(SIGSTKSZ, 2 * 1024 * 1024); - signal_stack_memory = mmap(nullptr, signal_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - + signal_stack_memory.resize(std::max(SIGSTKSZ, 2 * 1024 * 1024), 0); stack_t signal_stack{}; - signal_stack.ss_sp = signal_stack_memory; - signal_stack.ss_size = signal_stack_size; + signal_stack.ss_sp = signal_stack_memory.data(); + signal_stack.ss_size = signal_stack_memory.size(); signal_stack.ss_flags = 0; if (sigaltstack(&signal_stack, nullptr) != 0) { fmt::print(stderr, "dynarmic: POSIX SigHandler: init failure at sigaltstack\n"); @@ -88,10 +84,6 @@ public: #endif } - ~SigHandler() noexcept { - munmap(signal_stack_memory, signal_stack_size); - } - void AddCodeBlock(u64 offset, CodeBlockInfo cbi) noexcept { std::unique_lock guard(code_block_infos_mutex); code_block_infos.insert_or_assign(offset, cbi); diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp index 046ecc78d6..a003d3196e 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp @@ -1985,6 +1985,13 @@ void EmitX64::EmitFPVectorToHalf32(EmitContext& ctx, IR::Inst* inst) { // output[i] = FPT(FP::FPToFixed(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr)); // } +template +static void EmitFPVectorToFixedThunk(VectorArray>& output, const VectorArray>& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + using FPT = mcl::unsigned_integer_of_size; + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr)); +} + template void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { const size_t fbits = inst->GetArg(1).GetU8(); @@ -2106,43 +2113,88 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, inst, src); return; } + auto const fpt_fn = [fbits, rounding]() -> void (*)(VectorArray>& output, const VectorArray>& input, FP::FPCR fpcr, FP::FPSR& fpsr) { +#define ROUNDING_MODE_CASE(CASE, N) \ + if (rounding == FP::RoundingMode::CASE && fsize >= (N) && fbits == (N)) return &EmitFPVectorToFixedThunk; +#define ROUNDING_MODE_SWITCH(CASE) \ + ROUNDING_MODE_CASE(CASE, 0x00) \ + ROUNDING_MODE_CASE(CASE, 0x01) \ + ROUNDING_MODE_CASE(CASE, 0x02) \ + ROUNDING_MODE_CASE(CASE, 0x03) \ + ROUNDING_MODE_CASE(CASE, 0x04) \ + ROUNDING_MODE_CASE(CASE, 0x05) \ + ROUNDING_MODE_CASE(CASE, 0x06) \ + ROUNDING_MODE_CASE(CASE, 0x07) \ + ROUNDING_MODE_CASE(CASE, 0x08) \ + ROUNDING_MODE_CASE(CASE, 0x09) \ + ROUNDING_MODE_CASE(CASE, 0x0a) \ + ROUNDING_MODE_CASE(CASE, 0x0b) \ + ROUNDING_MODE_CASE(CASE, 0x0c) \ + ROUNDING_MODE_CASE(CASE, 0x0d) \ + ROUNDING_MODE_CASE(CASE, 0x0e) \ + ROUNDING_MODE_CASE(CASE, 0x0f) \ + ROUNDING_MODE_CASE(CASE, 0x10) \ + ROUNDING_MODE_CASE(CASE, 0x11) \ + ROUNDING_MODE_CASE(CASE, 0x12) \ + ROUNDING_MODE_CASE(CASE, 0x13) \ + ROUNDING_MODE_CASE(CASE, 0x14) \ + ROUNDING_MODE_CASE(CASE, 0x15) \ + ROUNDING_MODE_CASE(CASE, 0x16) \ + ROUNDING_MODE_CASE(CASE, 0x17) \ + ROUNDING_MODE_CASE(CASE, 0x18) \ + ROUNDING_MODE_CASE(CASE, 0x19) \ + ROUNDING_MODE_CASE(CASE, 0x1a) \ + ROUNDING_MODE_CASE(CASE, 0x1b) \ + ROUNDING_MODE_CASE(CASE, 0x1c) \ + ROUNDING_MODE_CASE(CASE, 0x1d) \ + ROUNDING_MODE_CASE(CASE, 0x1e) \ + ROUNDING_MODE_CASE(CASE, 0x1f) \ + ROUNDING_MODE_CASE(CASE, 0x20) \ + ROUNDING_MODE_CASE(CASE, 0x21) \ + ROUNDING_MODE_CASE(CASE, 0x22) \ + ROUNDING_MODE_CASE(CASE, 0x23) \ + ROUNDING_MODE_CASE(CASE, 0x24) \ + ROUNDING_MODE_CASE(CASE, 0x25) \ + ROUNDING_MODE_CASE(CASE, 0x26) \ + ROUNDING_MODE_CASE(CASE, 0x27) \ + ROUNDING_MODE_CASE(CASE, 0x28) \ + ROUNDING_MODE_CASE(CASE, 0x29) \ + ROUNDING_MODE_CASE(CASE, 0x2a) \ + ROUNDING_MODE_CASE(CASE, 0x2b) \ + ROUNDING_MODE_CASE(CASE, 0x2c) \ + ROUNDING_MODE_CASE(CASE, 0x2d) \ + ROUNDING_MODE_CASE(CASE, 0x2e) \ + ROUNDING_MODE_CASE(CASE, 0x2f) \ + ROUNDING_MODE_CASE(CASE, 0x30) \ + ROUNDING_MODE_CASE(CASE, 0x31) \ + ROUNDING_MODE_CASE(CASE, 0x32) \ + ROUNDING_MODE_CASE(CASE, 0x33) \ + ROUNDING_MODE_CASE(CASE, 0x34) \ + ROUNDING_MODE_CASE(CASE, 0x35) \ + ROUNDING_MODE_CASE(CASE, 0x36) \ + ROUNDING_MODE_CASE(CASE, 0x37) \ + ROUNDING_MODE_CASE(CASE, 0x38) \ + ROUNDING_MODE_CASE(CASE, 0x39) \ + ROUNDING_MODE_CASE(CASE, 0x3a) \ + ROUNDING_MODE_CASE(CASE, 0x3b) \ + ROUNDING_MODE_CASE(CASE, 0x3c) \ + ROUNDING_MODE_CASE(CASE, 0x3d) \ + ROUNDING_MODE_CASE(CASE, 0x3e) \ + ROUNDING_MODE_CASE(CASE, 0x3f) - using FPT = mcl::unsigned_integer_of_size; // WORKAROUND: For issue 678 on MSVC - auto const func = [rounding]() -> void(*)(VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - switch (rounding) { - case FP::RoundingMode::ToNearest_TieEven: - return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - for (size_t i = 0; i < output.size(); ++i) - output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieEven, fpsr)); - }; - case FP::RoundingMode::TowardsPlusInfinity: - return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - for (size_t i = 0; i < output.size(); ++i) - output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsPlusInfinity, fpsr)); - }; - case FP::RoundingMode::TowardsMinusInfinity: - return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - for (size_t i = 0; i < output.size(); ++i) - output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsMinusInfinity, fpsr)); - }; - case FP::RoundingMode::TowardsZero: - return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - for (size_t i = 0; i < output.size(); ++i) - output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsZero, fpsr)); - }; - case FP::RoundingMode::ToNearest_TieAwayFromZero: - return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - for (size_t i = 0; i < output.size(); ++i) - output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieAwayFromZero, fpsr)); - }; - case FP::RoundingMode::ToOdd: - return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - for (size_t i = 0; i < output.size(); ++i) - output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToOdd, fpsr)); - }; - } + // FUCK YOU MSVC, FUCKING DEPTH CANT EVEN HANDLE 8+16+32+64 DEPTH OF A ELSE STATMENT YOU FUCKING STUPID + // BURN MSVC BURN IT STUPID COMPILER CAN'T EVEN COMPILE THE MOST BASIC C++ + ROUNDING_MODE_SWITCH(ToNearest_TieEven) + ROUNDING_MODE_SWITCH(TowardsPlusInfinity) + ROUNDING_MODE_SWITCH(TowardsMinusInfinity) + ROUNDING_MODE_SWITCH(TowardsZero) + ROUNDING_MODE_SWITCH(ToNearest_TieAwayFromZero) +#undef ROUNDING_MODE_SWITCH +#undef ROUNDING_MODE_CASE + return nullptr; }(); - EmitTwoOpFallback<3>(code, ctx, inst, func); + + EmitTwoOpFallback<3>(code, ctx, inst, fpt_fn); } void EmitX64::EmitFPVectorToSignedFixed16(EmitContext& ctx, IR::Inst* inst) { diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 71210ffe6e..efae825885 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -2733,7 +2733,9 @@ void TextureCache

::PrepareImage(ImageId image_id, bool is_modification, bool } } else { RefreshContents(image, image_id); - SynchronizeAliases(image_id); + if (!image.aliased_images.empty()) { + SynchronizeAliases(image_id); + } } if (is_modification) { MarkModification(image);