diff --git a/CMakeLists.txt b/CMakeLists.txt index 994bc184fa..411de4620b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -310,7 +310,6 @@ endif() if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX)) set(HAS_NCE 1) add_compile_definitions(HAS_NCE=1) - find_package(oaknut 2.0.1) endif() if (YUZU_ROOM) diff --git a/CMakeModules/Findsirit.cmake b/CMakeModules/Findsirit.cmake new file mode 100644 index 0000000000..83b81b09c5 --- /dev/null +++ b/CMakeModules/Findsirit.cmake @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +include(FindPackageHandleStandardArgs) + +find_package(PkgConfig QUIET) +pkg_search_module(sirit QUIET IMPORTED_TARGET sirit) +find_package_handle_standard_args(sirit + REQUIRED_VARS sirit_LINK_LIBRARIES + VERSION_VAR sirit_VERSION +) diff --git a/externals/cpmfile.json b/externals/cpmfile.json index dcafc8f97d..283da76743 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -10,7 +10,7 @@ "repo": "eden-emulator/sirit", "sha": "db1f1e8ab5", "hash": "73eb3a042848c63a10656545797e85f40d142009dfb7827384548a385e1e28e1ac72f42b25924ce530d58275f8638554281e884d72f9c7aaf4ed08690a414b05", - "find_args": "CONFIG", + "find_args": "MODULE", "options": [ "SIRIT_USE_SYSTEM_SPIRV_HEADERS ON" ] diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index 45c5dfef8c..d31deaa355 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml @@ -27,8 +27,6 @@ SPDX-License-Identifier: GPL-3.0-or-later - - @@ -95,10 +93,6 @@ SPDX-License-Identifier: GPL-3.0-or-later - - - - if (result != null) { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ForegroundService.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ForegroundService.kt deleted file mode 100644 index c181656d99..0000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ForegroundService.kt +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -// Copyright 2023 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -package org.yuzu.yuzu_emu.utils - -import android.app.PendingIntent -import android.app.Service -import android.content.Intent -import android.os.IBinder -import androidx.core.app.NotificationCompat -import androidx.core.app.NotificationManagerCompat -import org.yuzu.yuzu_emu.R -import org.yuzu.yuzu_emu.activities.EmulationActivity - -/** - * A service that shows a permanent notification in the background to avoid the app getting - * cleared from memory by the system. - */ -class ForegroundService : Service() { - companion object { - const val EMULATION_RUNNING_NOTIFICATION = 0x1000 - - const val ACTION_STOP = "stop" - } - - private fun showRunningNotification() { - // Intent is used to resume emulation if the notification is clicked - val contentIntent = PendingIntent.getActivity( - this, - 0, - Intent(this, EmulationActivity::class.java), - PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT - ) - val builder = - NotificationCompat.Builder(this, getString(R.string.app_notification_channel_id)) - .setSmallIcon(R.drawable.ic_stat_notification_logo) - .setContentTitle(getString(R.string.app_name)) - .setContentText(getString(R.string.app_notification_running)) - .setPriority(NotificationCompat.PRIORITY_DEFAULT) - .setOngoing(true) - .setVibrate(null) - .setSound(null) - .setContentIntent(contentIntent) - startForeground(EMULATION_RUNNING_NOTIFICATION, builder.build()) - } - - override fun onBind(intent: Intent): IBinder? { - return null - } - - override fun onCreate() { - showRunningNotification() - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - if (intent?.action == ACTION_STOP) { - try { - NotificationManagerCompat.from(this).cancel(EMULATION_RUNNING_NOTIFICATION) - stopForeground(STOP_FOREGROUND_REMOVE) - } catch (e: Exception) { - Log.error("Failed to stop foreground service") - } - stopSelfResult(startId) - return START_NOT_STICKY - } - - if (intent != null) { - showRunningNotification() - } - return START_STICKY - } - - override fun onDestroy() = - NotificationManagerCompat.from(this).cancel(EMULATION_RUNNING_NOTIFICATION) -} diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 48ea3ed99b..1545576ea8 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -8,11 +8,6 @@ noticesAndErrors Shows notifications when something goes wrong. Notification permission not granted! - Eden - Eden - Eden Switch emulator notifications - Eden is Running - (Enhanced) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 96ea429e5a..7759ea6a21 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -32,6 +32,7 @@ add_library( atomic_ops.h bit_cast.h bit_field.h + bit_set.h bit_util.h bounded_threadsafe_queue.h cityhash.cpp diff --git a/src/common/bit_set.h b/src/common/bit_set.h new file mode 100644 index 0000000000..74754504be --- /dev/null +++ b/src/common/bit_set.h @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "common/alignment.h" +#include "common/bit_util.h" +#include "common/common_types.h" + +namespace Common { + +namespace impl { + +template +class BitSet { + +public: + constexpr BitSet() = default; + + constexpr void SetBit(size_t i) { + this->words[i / FlagsPerWord] |= GetBitMask(i % FlagsPerWord); + } + + constexpr void ClearBit(size_t i) { + this->words[i / FlagsPerWord] &= ~GetBitMask(i % FlagsPerWord); + } + + constexpr size_t CountLeadingZero() const { + for (size_t i = 0; i < NumWords; i++) { + if (this->words[i]) { + return FlagsPerWord * i + CountLeadingZeroImpl(this->words[i]); + } + } + return FlagsPerWord * NumWords; + } + + constexpr size_t GetNextSet(size_t n) const { + for (size_t i = (n + 1) / FlagsPerWord; i < NumWords; i++) { + Storage word = this->words[i]; + if (!IsAligned(n + 1, FlagsPerWord)) { + word &= GetBitMask(n % FlagsPerWord) - 1; + } + if (word) { + return FlagsPerWord * i + CountLeadingZeroImpl(word); + } + } + return FlagsPerWord * NumWords; + } + +private: + static_assert(std::is_unsigned_v); + static_assert(sizeof(Storage) <= sizeof(u64)); + + static constexpr size_t FlagsPerWord = BitSize(); + static constexpr size_t NumWords = AlignUp(N, FlagsPerWord) / FlagsPerWord; + + static constexpr auto CountLeadingZeroImpl(Storage word) { + return std::countl_zero(static_cast(word)) - + (BitSize() - FlagsPerWord); + } + + static constexpr Storage GetBitMask(size_t bit) { + return Storage(1) << (FlagsPerWord - 1 - bit); + } + + std::array words{}; +}; + +} // namespace impl + +template +using BitSet8 = impl::BitSet; + +template +using BitSet16 = impl::BitSet; + +template +using BitSet32 = impl::BitSet; + +template +using BitSet64 = impl::BitSet; + +} // namespace Common diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 11c217fce6..6b64ab7820 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1224,7 +1224,7 @@ if (HAS_NCE) arm/nce/patcher.h arm/nce/visitor_base.h ) - target_link_libraries(core PRIVATE merry::oaknut) + target_link_libraries(core PRIVATE merry::mcl merry::oaknut) endif() if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) diff --git a/src/core/arm/nce/patcher.h b/src/core/arm/nce/patcher.h index 31b122477f..7f54608e3f 100644 --- a/src/core/arm/nce/patcher.h +++ b/src/core/arm/nce/patcher.h @@ -27,11 +27,11 @@ template <> struct std::hash { size_t operator()(const PatchCacheKey& key) const { // Simple XOR hash of first few bytes - size_t hash_ = 0; + size_t hash = 0; for (size_t i = 0; i < key.module_id.size(); ++i) { - hash_ ^= static_cast(key.module_id[i]) << ((i % sizeof(size_t)) * 8); + hash ^= static_cast(key.module_id[i]) << ((i % sizeof(size_t)) * 8); } - return hash_ ^ std::hash{}(key.offset); + return hash ^ std::hash{}(key.offset); } }; diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index 99347b5aef..26677ec65c 100644 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h @@ -1,6 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2025 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 @@ -8,12 +5,10 @@ #include #include -#include #include -#include -#include "common/alignment.h" #include "common/assert.h" +#include "common/bit_set.h" #include "common/common_types.h" #include "common/concepts.h" @@ -164,7 +159,7 @@ public: } if (m_queues[priority].PushBack(core, member)) { - m_available_priorities[core].set(std::size_t(priority)); + m_available_priorities[core].SetBit(priority); } } @@ -177,7 +172,7 @@ public: } if (m_queues[priority].PushFront(core, member)) { - m_available_priorities[core].set(std::size_t(priority)); + m_available_priorities[core].SetBit(priority); } } @@ -190,19 +185,14 @@ public: } if (m_queues[priority].Remove(core, member)) { - m_available_priorities[core].reset(std::size_t(priority)); + m_available_priorities[core].ClearBit(priority); } } constexpr Member* GetFront(s32 core) const { ASSERT(IsValidCore(core)); - const s32 priority = s32([](auto const& e) { - for (size_t i = 0; i < e.size(); ++i) - if (e[i]) - return i; - return e.size(); - }(m_available_priorities[core])); + const s32 priority = static_cast(m_available_priorities[core].CountLeadingZero()); if (priority <= LowestPriority) { return m_queues[priority].GetFront(core); } else { @@ -221,22 +211,16 @@ public: } } - template - constexpr size_t GetNextSet(std::bitset const& bit, size_t n) const { - for (size_t i = n + 1; i < bit.size(); i++) - if (bit[i]) - return i; - return bit.size(); - } - constexpr Member* GetNext(s32 core, const Member* member) const { ASSERT(IsValidCore(core)); Member* next = member->GetPriorityQueueEntry(core).GetNext(); if (next == nullptr) { - s32 priority = s32(GetNextSet(m_available_priorities[core], member->GetPriority())); - if (priority <= LowestPriority) + const s32 priority = static_cast( + m_available_priorities[core].GetNextSet(member->GetPriority())); + if (priority <= LowestPriority) { next = m_queues[priority].GetFront(core); + } } return next; } @@ -266,7 +250,7 @@ public: private: std::array m_queues{}; - std::array, NumCores> m_available_priorities{}; + std::array, NumCores> m_available_priorities{}; }; private: diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index 58efcac747..9e6bd25913 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -374,7 +374,7 @@ endif() target_compile_options(dynarmic PRIVATE ${DYNARMIC_CXX_FLAGS}) target_link_libraries(dynarmic - PUBLIC + PRIVATE fmt::fmt merry::mcl ) diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index eb18a4bd66..94ef1a48df 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -792,11 +792,6 @@ void BufferCache

::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 const u32 size = (std::min)(binding.size, (*channel_state->uniform_buffer_sizes)[stage][index]); Buffer& buffer = slot_buffers[binding.buffer_id]; TouchBuffer(buffer, binding.buffer_id); - const bool sync_buffer = SynchronizeBuffer(buffer, device_addr, size); - if (sync_buffer) { - ++channel_state->uniform_cache_hits[0]; - } - ++channel_state->uniform_cache_shots[0]; const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID && size <= channel_state->uniform_buffer_skip_cache_size && !memory_tracker.IsRegionGpuModified(device_addr, size); @@ -827,6 +822,12 @@ void BufferCache

::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 device_memory.ReadBlockUnsafe(device_addr, span.data(), size); return; } + // Classic cached path + const bool sync_cached = SynchronizeBuffer(buffer, device_addr, size); + if (sync_cached) { + ++channel_state->uniform_cache_hits[0]; + } + ++channel_state->uniform_cache_shots[0]; // Skip binding if it's not needed and if the bound buffer is not the fast version // This exists to avoid instances where the fast buffer is bound and a GPU write happens diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index 3af9758a31..600003953d 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp @@ -31,7 +31,7 @@ struct DescriptorBank { bool DescriptorBankInfo::IsSuperset(const DescriptorBankInfo& subset) const noexcept { return uniform_buffers >= subset.uniform_buffers && storage_buffers >= subset.storage_buffers && texture_buffers >= subset.texture_buffers && image_buffers >= subset.image_buffers && - textures >= subset.textures && images >= subset.images; + textures >= subset.textures && images >= subset.image_buffers; } template