Compare commits

..

8 Commits

Author SHA1 Message Date
PavelBARABANOV aaefd54b45 return release early fences 2026-02-15 02:04:51 +03:00
crueter 19e2dba35a [cmake] CPMUtil: Don't consider system packages if FORCE_BUNDLED is on (#3539)
Thanks, Debian.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3539
2026-02-14 03:33:03 +01:00
crueter 0634b4a278 [externals] Update SDL2 CI (#3538)
https://github.com/eden-emulator/Issue-Reports/issues/327

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3538
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-02-14 03:24:36 +01:00
John ee428deb1e [settings] Set EDS to 2 as default on Windows/FreeBSD (#3532)
<video src="/attachments/9a1b2e43-0acf-4a40-9be5-db93b1164111" title="Regressions" controls></video>

This PR fixes Sonic's broken graphics.

- EDS3 hard coded as _WIN32 default broke graphics and was the issue. Manually adjusting EDS[0-3] per-game/global settings can not fix graphics.
- EDS2 hard coded as _WIN32 default fixes graphical issues. Manually adjusting EDS[0-3] per-game/global settings works as intended.
- EDS0 as _WIN32 default was also tested and works. Old logic behavior before #292 regression.

Co-authored-by: DraVee <dravee@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3532
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: John <john@eden-emu.dev>
Co-committed-by: John <john@eden-emu.dev>
2026-02-13 18:37:42 +01:00
lizzie 07bc77c7e7 [dynarmic] Fix Sonic X shadow regression due to aggresive const prop discarding NZCV side ffects (#3534)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3534
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-02-13 16:10:09 +01:00
lizzie 72973fe582 [dynarmic] fix NSBU regressions (#3533)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3533
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-02-13 11:51:34 +01:00
lizzie c263b6af6f [dynarmic] add current code page cache (#3459)
should make JIT translation a bit faster - especially for non-fastmem
test if thumb still werks

previously:
we read 32-bits one by one, and do translation **for each u32 we read**

now:
one big read of 4096 bytes (aligned of course), only 1 VAddr translation

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3459
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-02-12 02:14:50 +01:00
PavelBARABANOV e46576b4c3 [android] add graphics artifacts warning to bloom fix description (#3471)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3471
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
Co-committed-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
2026-02-12 01:56:16 +01:00
23 changed files with 179 additions and 158 deletions
+5 -1
View File
@@ -84,7 +84,11 @@ function(SystemPackageViable JSON_NAME)
parse_object(${object})
string(REPLACE " " ";" find_args "${find_args}")
find_package(${package} ${version} ${find_args} QUIET NO_POLICY_SCOPE)
if (${package}_FORCE_BUNDLED)
set(${package}_FOUND OFF)
else()
find_package(${package} ${version} ${find_args} QUIET NO_POLICY_SCOPE)
endif()
set(${pkg}_VIABLE ${${package}_FOUND} PARENT_SCOPE)
set(${pkg}_PACKAGE ${package} PARENT_SCOPE)
+1 -3
View File
@@ -150,7 +150,7 @@
"package": "SDL2",
"name": "SDL2",
"repo": "crueter-ci/SDL2",
"version": "2.32.10-a65111bd2d",
"version": "2.32.10-cf5dabd6ea",
"min_version": "2.26.4"
},
"catch2": {
@@ -184,7 +184,6 @@
"repo": "libsdl-org/SDL",
"tag": "release-%VERSION%",
"hash": "d5622d6bb7266f7942a7b8ad43e8a22524893bf0c2ea1af91204838d9b78d32768843f6faa248757427b8404b8c6443776d4afa6b672cd8571a4e0c03a829383",
"key": "generic",
"bundled": true,
"git_version": "2.32.10",
"skip_updates": true
@@ -194,7 +193,6 @@
"repo": "libsdl-org/SDL",
"sha": "cc016b0046",
"hash": "b8d9873446cdb922387471df9968e078714683046674ef0d0edddf8e25da65a539a3bae83d635496b970237f90b07b36a69f8d7855d450de59311d6d6e8c3dbc",
"key": "steamdeck",
"bundled": true,
"skip_updates": "true"
},
@@ -23,6 +23,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"),
RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
RENDERER_EARLY_RELEASE_FENCES("early_release_fences"),
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
@@ -679,6 +679,13 @@ abstract class SettingsItem(
descriptionId = R.string.renderer_asynchronous_shaders_description
)
)
put(
SwitchSetting(
BooleanSetting.RENDERER_EARLY_RELEASE_FENCES,
titleId = R.string.renderer_early_release_fences,
descriptionId = R.string.renderer_early_release_fences_description
)
)
put(
SingleChoiceSetting(
IntSetting.FAST_GPU_TIME,
@@ -285,6 +285,7 @@ class SettingsFragmentPresenter(
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
add(BooleanSetting.RENDERER_EARLY_RELEASE_FENCES.key)
add(SettingsItem.GPU_UNSWIZZLE_COMBINED)
add(HeaderSetting(R.string.extensions))
@@ -507,9 +507,11 @@
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
<string name="fix_bloom_effects">Fix Bloom Effects</string>
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno 700), removes bloom in Burnout</string>
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno 700), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
<string name="renderer_early_release_fences">Release Fences Early</string>
<string name="renderer_early_release_fences_description">Fixes crashes and freezes in some games, may cause issues with Unreal Engine games.</string>
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
<string name="gpu_unswizzle_settings_description">Configure GPU-based texture unswizzling parameters or disable it entirely. Adjust these settings to balance performance and texture loading quality.</string>
<string name="gpu_unswizzle_enable">Enable GPU Unswizzle</string>
+11 -7
View File
@@ -546,6 +546,16 @@ struct Values {
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
Category::RendererHacks};
#ifdef ANDROID
SwitchableSetting<bool> early_release_fences{linkage,
false,
"early_release_fences",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
#endif
SwitchableSetting<GpuUnswizzleSize> gpu_unswizzle_texture_size{linkage,
GpuUnswizzleSize::Large,
"gpu_unswizzle_texture_size",
@@ -568,13 +578,7 @@ struct Values {
Category::RendererHacks};
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
#if defined (_WIN32)
ExtendedDynamicState::EDS3,
#elif defined (__FreeBSD__)
ExtendedDynamicState::EDS3,
#elif defined (ANDROID)
ExtendedDynamicState::Disabled,
#elif defined (__APPLE__)
#if defined (ANDROID) || defined (__APPLE__)
ExtendedDynamicState::Disabled,
#else
ExtendedDynamicState::EDS2,
+8 -2
View File
@@ -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: Copyright 2020 yuzu Emulator Project
@@ -38,10 +38,16 @@ u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) {
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
return m_memory.Read64(vaddr);
}
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
return std::nullopt;
return m_memory.Read32(vaddr);
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
if (last_code_addr != aligned_vaddr) {
m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page));
last_code_addr = aligned_vaddr;
}
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
}
void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
+5 -1
View File
@@ -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: Copyright 2020 yuzu Emulator Project
@@ -7,6 +7,7 @@
#pragma once
#include <dynarmic/interface/A32/a32.h>
#include <dynarmic/interface/code_page.h>
#include "core/arm/arm_interface.h"
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
@@ -49,6 +50,9 @@ public:
u64 GetTicksRemaining() override;
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
void ReturnException(u32 pc, Dynarmic::HaltReason hr);
//
Dynarmic::CodePage cached_code_page;
u64 last_code_addr = 0;
ArmDynarmic32& m_parent;
Core::Memory::Memory& m_memory;
Kernel::KProcess* m_process{};
+9 -2
View File
@@ -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: Copyright 2018 yuzu Emulator Project
@@ -41,10 +41,17 @@ Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
return {m_memory.Read64(vaddr), m_memory.Read64(vaddr + 8)};
}
std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
return std::nullopt;
return m_memory.Read32(vaddr);
// return m_memory.Read32(vaddr);
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
if (last_code_addr != aligned_vaddr) {
m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page));
last_code_addr = aligned_vaddr;
}
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
}
void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
+3
View File
@@ -11,6 +11,7 @@
#include <ankerl/unordered_dense.h>
#include <dynarmic/interface/A64/a64.h>
#include <dynarmic/interface/code_page.h>
#include "common/common_types.h"
#include "common/hash.h"
#include "core/arm/arm_interface.h"
@@ -61,6 +62,8 @@ public:
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
void ReturnException(u64 pc, Dynarmic::HaltReason hr);
Dynarmic::CodePage cached_code_page;
u64 last_code_addr = 0;
ArmDynarmic64& m_parent;
Core::Memory::Memory& m_memory;
u64 m_tpidrro_el0{};
+15 -3
View File
@@ -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: Copyright 2022 yuzu Emulator Project
@@ -10,6 +10,7 @@
#include <boost/icl/interval_set.hpp>
#include <dynarmic/interface/A64/a64.h>
#include <dynarmic/interface/A64/config.h>
#include <dynarmic/interface/code_page.h>
#include "common/alignment.h"
#include "common/common_funcs.h"
@@ -46,6 +47,15 @@ public:
: memory{memory_}, local_memory{local_memory_},
mapped_ranges{mapped_ranges_}, parent{parent_} {}
std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) override {
static_assert(Core::Memory::YUZU_PAGESIZE == Dynarmic::CODE_PAGE_SIZE);
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
if (last_code_addr != aligned_vaddr) {
cached_code_page = ReadMemory<Dynarmic::CodePage>(aligned_vaddr);
last_code_addr = aligned_vaddr;
}
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
}
u8 MemoryRead8(u64 vaddr) override {
return ReadMemory<u8>(vaddr);
}
@@ -116,8 +126,7 @@ public:
return 0;
}
template <class T>
T ReadMemory(u64 vaddr) {
template<typename T> T ReadMemory(u64 vaddr) {
T ret{};
if (boost::icl::contains(mapped_ranges, vaddr)) {
memory.ReadBlock(vaddr, &ret, sizeof(T));
@@ -146,6 +155,9 @@ private:
std::vector<u8>& local_memory;
IntervalSet& mapped_ranges;
JITContextImpl& parent;
Dynarmic::CodePage cached_code_page;
u64 last_code_addr = 0;
};
class JITContextImpl {
+2 -3
View File
@@ -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: 2015 Citra Emulator Project
@@ -36,8 +36,7 @@
namespace Core::Memory {
static inline bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessAddress addr,
const std::size_t size) {
static inline bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessAddress addr, const std::size_t size) {
const Common::ProcessAddress max_addr = 1ULL << table.GetAddressSpaceBits();
return addr + size >= addr && addr + size <= max_addr;
}
@@ -65,11 +65,10 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code)
struct Jit::Impl {
Impl(Jit* jit, A32::UserConfig conf) noexcept
: ir_block{LocationDescriptor(0, PSR(0), FPSCR(0), false)}
, conf(std::move(conf))
, block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
: block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
, emitter(block_of_code, conf, jit)
, polyfill_options(GenPolyfillOptions(block_of_code))
, conf(std::move(conf))
, jit_interface(jit)
{}
@@ -204,8 +203,7 @@ private:
}
A32EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
auto block = emitter.GetBasicBlock(descriptor);
if (block)
if (auto block = emitter.GetBasicBlock(descriptor))
return *block;
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
@@ -215,8 +213,10 @@ private:
}
block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE);
ir_block.Reset(descriptor);
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
// LocationDescriptor ctor() does important ops (like tflags) do not skip
auto const arch_descriptor = A32::LocationDescriptor{descriptor};
ir_block.Reset(arch_descriptor);
A32::Translate(ir_block, arch_descriptor, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
Optimization::Optimize(ir_block, conf, polyfill_options);
return emitter.Emit(ir_block);
}
@@ -243,12 +243,13 @@ private:
}
}
IR::Block ir_block;
const A32::UserConfig conf;
IR::Block ir_block = {LocationDescriptor(0, PSR(0), FPSCR(0), false)};
A32JitState jit_state;
BlockOfCode block_of_code;
A32EmitX64 emitter;
Optimization::PolyfillOptions polyfill_options;
// Keep it here, you don't wanna mess with the fuckery that's initializer lists
const A32::UserConfig conf;
Jit* jit_interface;
// Requests made during execution to invalidate the cache are queued up here.
@@ -62,8 +62,7 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code)
struct Jit::Impl final {
public:
Impl(Jit* jit, UserConfig conf)
: ir_block{LocationDescriptor(0, FP::FPCR(0), false)}
, conf(conf)
: conf(conf)
, block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
, emitter(block_of_code, conf, jit)
, polyfill_options(GenPolyfillOptions(block_of_code))
@@ -257,8 +256,8 @@ private:
return GetBlock(A64::LocationDescriptor{GetCurrentLocation()}.SetSingleStepping(true));
}
CodePtr GetBlock(IR::LocationDescriptor current_location) {
if (auto block = emitter.GetBasicBlock(current_location))
CodePtr GetBlock(IR::LocationDescriptor descriptor) {
if (auto block = emitter.GetBasicBlock(descriptor))
return block->entrypoint;
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
@@ -271,8 +270,10 @@ private:
// JIT Compile
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
ir_block.Reset(current_location);
A64::Translate(ir_block, A64::LocationDescriptor{current_location}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
// LocationDescriptor ctor() does important ops (like tflags) do not skip
auto const arch_descriptor = A64::LocationDescriptor{descriptor};
ir_block.Reset(arch_descriptor);
A64::Translate(ir_block, arch_descriptor, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
Optimization::Optimize(ir_block, conf, polyfill_options);
return emitter.Emit(ir_block).entrypoint;
}
@@ -299,7 +300,7 @@ private:
}
}
IR::Block ir_block;
IR::Block ir_block = {LocationDescriptor(0, FP::FPCR(0), false)};
const UserConfig conf;
A64JitState jit_state;
BlockOfCode block_of_code;
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <cstddef>
#include <cstdint>
namespace Dynarmic {
/// @brief Smallest valid page (may change for Apple?)
constexpr inline uint64_t CODE_PAGE_SIZE = 4096;
struct CodePage {
uint32_t inst[CODE_PAGE_SIZE / sizeof(uint32_t)];
};
}
+24 -12
View File
@@ -22,13 +22,10 @@
namespace Dynarmic::IR {
Block::Block(const LocationDescriptor& location)
: location{location},
end_location{location},
cond{Cond::AL}
{
}
Block::Block(LocationDescriptor location) noexcept
: location{location}
, end_location{location}
{}
/// Prepends a new instruction to this basic block before the insertion point,
/// handling any allocations necessary to do so.
@@ -60,6 +57,21 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode opcode, s
return instructions.insert_before(insertion_point, inst);
}
void Block::Reset(LocationDescriptor location_) noexcept {
mcl::intrusive_list<IR::Inst> tmp = {};
instructions.swap(tmp);
inlined_inst.clear();
pooled_inst.clear();
cond_failed.reset();
location = location_;
end_location = location_;
cond = Cond::AL;
terminal = Term::Invalid{};
cond_failed_cycle_count = 0;
cycle_count = 0;
ASSERT(instructions.size() == 0);
}
static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
struct : boost::static_visitor<std::string> {
std::string operator()(const Term::Invalid&) const {
@@ -123,11 +135,11 @@ std::string DumpBlock(const IR::Block& block) noexcept {
case Type::A32ExtReg: return A32::ExtRegToString(arg.GetA32ExtRegRef());
case Type::A64Reg: return A64::RegToString(arg.GetA64RegRef());
case Type::A64Vec: return A64::VecToString(arg.GetA64VecRef());
case Type::CoprocInfo: return fmt::format("#<coproc>");
case Type::NZCVFlags: return fmt::format("#<NZCV flags>");
case Type::Cond: return fmt::format("#<cond={}>", A32::CondToString(arg.GetCond()));
case Type::Table: return fmt::format("#<table>");
case Type::AccType: return fmt::format("#<acc-type={}>", u32(arg.GetAccType()));
case Type::CoprocInfo: return fmt::format("$coproc{}", arg.GetCoprocInfo()[0]);
case Type::NZCVFlags: return fmt::format("$nzcv");
case Type::Cond: return fmt::format("$cond={}", A32::CondToString(arg.GetCond()));
case Type::Table: return fmt::format("$table");
case Type::AccType: return fmt::format("$acc-type={}", u32(arg.GetAccType()));
default: return fmt::format("<unknown immediate type {}>", arg.GetType());
}
};
+3 -14
View File
@@ -43,7 +43,7 @@ public:
using reverse_iterator = instruction_list_type::reverse_iterator;
using const_reverse_iterator = instruction_list_type::const_reverse_iterator;
explicit Block(const LocationDescriptor& location);
Block(LocationDescriptor location) noexcept;
~Block() = default;
Block(const Block&) = delete;
Block& operator=(const Block&) = delete;
@@ -58,6 +58,7 @@ public:
return PrependNewInst(instructions.end(), opcode, args);
}
iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args) noexcept;
void Reset(LocationDescriptor location_) noexcept;
/// Gets a mutable reference to the instruction list for this basic block.
inline instruction_list_type& Instructions() noexcept {
@@ -140,18 +141,6 @@ public:
return cycle_count;
}
inline void Reset(LocationDescriptor location_) noexcept {
inlined_inst.clear();
pooled_inst.clear();
cond_failed.reset();
location = location_;
terminal = Term::Invalid{};
cond_failed_cycle_count = 0;
cycle_count = 0;
instruction_list_type tmp{};
instructions.swap(tmp);
}
/// "Hot cache" for small blocks so we don't call global allocator
boost::container::static_vector<Inst, 30> inlined_inst;
/// List of instructions in this block.
@@ -165,7 +154,7 @@ public:
/// Description of the end location of this block
LocationDescriptor end_location;
/// Conditional to pass in order to execute this block
Cond cond;
Cond cond = Cond::AL;
/// Terminal instruction of this block.
Terminal terminal = Term::Invalid{};
/// Number of cycles this block takes to execute if the conditional fails.
@@ -1042,6 +1042,11 @@ static void FoldZeroExtendXToLong(IR::Inst& inst) {
static void ConstantPropagation(IR::Block& block) {
for (auto& inst : block.instructions) {
auto const opcode = inst.GetOpcode();
// skip NZCV so we dont end up discarding side effects :)
// TODO(lizzie): hey stupid maybe fix the A64 codegen for folded constants AND
// redirect the mfer properly?!??! just saying :)
if (IR::MayGetNZCVFromOp(opcode) && inst.GetAssociatedPseudoOperation(IR::Opcode::GetNZCVFromOp))
continue;
switch (opcode) {
case Op::LeastSignificantWord:
FoldLeastSignificantWord(inst);
+27 -9
View File
@@ -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: Copyright 2020 yuzu Emulator Project
@@ -72,15 +72,26 @@ public:
}
void SignalFence(std::function<void()>&& func) {
if constexpr (!can_async_check) {
TryReleasePendingFences<false>();
}
#ifdef ANDROID
const bool early_release_fences = Settings::values.early_release_fences.GetValue();
#else
constexpr bool early_release_fences = false;
#endif
const bool should_flush = ShouldFlush();
const bool delay_fence = Settings::IsGPULevelHigh() || (Settings::IsGPULevelMedium() && should_flush);
if (!can_async_check || (!delay_fence && early_release_fences)) {
TryReleasePendingFences<false>();
}
CommitAsyncFlushes();
TFence new_fence = CreateFence(!should_flush);
if constexpr (can_async_check) {
guard.lock();
if (!early_release_fences){
if constexpr (can_async_check) {
guard.lock();
}
} else {
if (delay_fence) {
guard.lock();
}
}
if (delay_fence) {
uncommitted_operations.emplace_back(std::move(func));
@@ -94,9 +105,16 @@ public:
if (should_flush) {
rasterizer.FlushCommands();
}
if constexpr (can_async_check) {
guard.unlock();
cv.notify_all();
if (!early_release_fences){
if constexpr (can_async_check) {
guard.unlock();
cv.notify_all();
}
} else {
if (delay_fence) {
guard.unlock();
cv.notify_all();
}
}
rasterizer.InvalidateGPUCache();
}
@@ -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
@@ -20,7 +20,7 @@
namespace Vulkan {
// Prefer small grow rates to avoid saturating the descriptor pool with barely used pipelines
constexpr size_t SETS_GROW_RATE = 32; //test difference between 16 and 32
constexpr size_t SETS_GROW_RATE = 16;
constexpr s32 SCORE_THRESHOLD = 3;
struct DescriptorBank {
@@ -29,12 +29,9 @@ 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;
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;
}
template <typename Descriptors>
@@ -48,19 +45,6 @@ static u32 Accumulate(const Descriptors& descriptors) {
static DescriptorBankInfo MakeBankInfo(std::span<const Shader::Info> infos) {
DescriptorBankInfo bank;
if (infos.size() == 1) {
const auto& info = infos.front();
const auto acc = [](const auto& ds){ u32 c=0; for (const auto& d: ds) c+=d.count; return c; };
bank.uniform_buffers += acc(info.constant_buffer_descriptors);
bank.storage_buffers += acc(info.storage_buffers_descriptors);
bank.texture_buffers += acc(info.texture_buffer_descriptors);
bank.image_buffers += acc(info.image_buffer_descriptors);
bank.textures += acc(info.texture_descriptors);
bank.images += acc(info.image_descriptors);
bank.score = bank.uniform_buffers + bank.storage_buffers + bank.texture_buffers +
bank.image_buffers + bank.textures + bank.images;
return bank;
}
for (const Shader::Info& info : infos) {
bank.uniform_buffers += Accumulate(info.constant_buffer_descriptors);
bank.storage_buffers += Accumulate(info.storage_buffers_descriptors);
@@ -118,22 +102,13 @@ void DescriptorAllocator::Allocate(size_t begin, size_t end) {
}
vk::DescriptorSets DescriptorAllocator::AllocateDescriptors(size_t count) {
std::array<VkDescriptorSetLayout, 64> stack{};
const VkDescriptorSetLayout* p_layouts = nullptr;
std::vector<VkDescriptorSetLayout> heap;
if (count <= stack.size()) {
stack.fill(layout);
p_layouts = stack.data();
} else {
heap.assign(count, layout);
p_layouts = heap.data();
}
const std::vector<VkDescriptorSetLayout> layouts(count, layout);
VkDescriptorSetAllocateInfo allocate_info{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.pNext = nullptr,
.descriptorPool = *bank->pools.back(),
.descriptorSetCount = static_cast<u32>(count),
.pSetLayouts = p_layouts,
.pSetLayouts = layouts.data(),
};
vk::DescriptorSets new_sets = bank->pools.back().Allocate(allocate_info);
if (!new_sets.IsOutOfPoolMemory()) {
@@ -171,58 +146,21 @@ DescriptorAllocator DescriptorPool::Allocator(VkDescriptorSetLayout layout,
}
DescriptorBank& DescriptorPool::Bank(const DescriptorBankInfo& reqs) {
{
std::scoped_lock lk(cache_mutex);
DescriptorBank* best = nullptr; u64 best_stamp = 0;
for (const auto& e : cache_) {
if (!e.bank) continue;
if (std::abs(e.info.score - reqs.score) < SCORE_THRESHOLD && e.info.IsSuperset(reqs)) {
if (e.stamp >= best_stamp) { best_stamp = e.stamp; best = e.bank; }
}
}
if (best) return *best;
}
std::shared_lock read_lock{banks_mutex};
const auto it = std::ranges::find_if(bank_infos, [&reqs](const DescriptorBankInfo& bank) {
return std::abs(bank.score - reqs.score) < SCORE_THRESHOLD && bank.IsSuperset(reqs);
});
if (it != bank_infos.end()) {
DescriptorBank& found = *banks[std::distance(bank_infos.begin(), it)].get();
read_lock.unlock();
// update cache
std::scoped_lock lk(cache_mutex);
size_t victim = 0; u64 oldest = UINT64_MAX;
for (size_t i=0;i<cache_.size();++i) if (cache_[i].stamp < oldest) { oldest = cache_[i].stamp; victim = i; }
cache_[victim] = CacheEntry{found.info, &found, ++cache_tick_};
return found;
return *banks[std::distance(bank_infos.begin(), it)].get();
}
read_lock.unlock();
std::unique_lock write_lock{banks_mutex};
auto it2 = std::ranges::find_if(bank_infos, [&reqs](const DescriptorBankInfo& bank) {
return std::abs(bank.score - reqs.score) < SCORE_THRESHOLD && bank.IsSuperset(reqs);
});
if (it2 != bank_infos.end()) {
DescriptorBank& found = *banks[std::distance(bank_infos.begin(), it2)].get();
// update cache
std::scoped_lock lk(cache_mutex);
size_t victim = 0; u64 oldest = UINT64_MAX;
for (size_t i=0;i<cache_.size();++i) if (cache_[i].stamp < oldest) { oldest = cache_[i].stamp; victim = i; }
cache_[victim] = CacheEntry{found.info, &found, ++cache_tick_};
return found;
}
bank_infos.push_back(reqs);
auto& bank = *banks.emplace_back(std::make_unique<DescriptorBank>());
bank.info = reqs;
AllocatePool(device, bank);
// update cache
{
std::scoped_lock lk(cache_mutex);
size_t victim = 0; u64 oldest = UINT64_MAX;
for (size_t i=0;i<cache_.size();++i) if (cache_[i].stamp < oldest) { oldest = cache_[i].stamp; victim = i; }
cache_[victim] = CacheEntry{bank.info, &bank, ++cache_tick_};
}
return bank;
}
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -9,8 +6,7 @@
#include <shared_mutex>
#include <span>
#include <vector>
#include <array>
#include <mutex>
#include "shader_recompiler/shader_info.h"
#include "video_core/renderer_vulkan/vk_resource_pool.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
@@ -79,14 +75,6 @@ public:
private:
DescriptorBank& Bank(const DescriptorBankInfo& reqs);
struct CacheEntry {
DescriptorBankInfo info{};
DescriptorBank* bank{nullptr};
u64 stamp{0};
};
std::mutex cache_mutex{};
std::array<CacheEntry, 8> cache_{}; //test and then adjust
u64 cache_tick_{0};
const Device& device;
MasterSemaphore& master_semaphore;
@@ -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: Copyright 2020 yuzu Emulator Project
@@ -243,7 +243,11 @@ void MasterSemaphore::WaitThread(std::stop_token token) {
free_queue.push_front(std::move(fence));
gpu_tick.store(host_tick, std::memory_order_release);
}
#ifdef ANDROID
free_cv.notify_all();
#else
free_cv.notify_one();
#endif
}
}