[vk, opengl] defer checks to topmost call (avoid unnecessary call) (#40)
All checks were successful
eden-build / source (push) Successful in 7m1s
eden-build / linux (push) Successful in 29m14s
eden-build / windows (msvc) (push) Successful in 32m8s
eden-build / android (push) Successful in 34m51s

Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/40
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2025-07-13 03:40:48 +02:00 committed by crueter
parent 03351a4f8b
commit 5091759a47
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
4 changed files with 66 additions and 61 deletions

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-FileCopyrightText: 2015 Citra Emulator Project
// SPDX-FileCopyrightText: 2018 yuzu Emulator Project // SPDX-FileCopyrightText: 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -868,17 +871,15 @@ struct Memory::Impl {
[[nodiscard]] u8* GetPointerImpl(u64 vaddr, auto on_unmapped, auto on_rasterizer) const { [[nodiscard]] u8* GetPointerImpl(u64 vaddr, auto on_unmapped, auto on_rasterizer) const {
// AARCH64 masks the upper 16 bit of all memory accesses // AARCH64 masks the upper 16 bit of all memory accesses
vaddr = vaddr & 0xffffffffffffULL; vaddr = vaddr & 0xffffffffffffULL;
if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] { if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] {
on_unmapped(); on_unmapped();
return nullptr; return nullptr;
} } else {
// Avoid adding any extra logic to this fast-path block // Avoid adding any extra logic to this fast-path block
const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw(); const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw();
if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
return reinterpret_cast<u8*>(pointer + vaddr); return reinterpret_cast<u8*>(pointer + vaddr);
} } else {
switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
case Common::PageType::Unmapped: case Common::PageType::Unmapped:
on_unmapped(); on_unmapped();
@ -898,6 +899,8 @@ struct Memory::Impl {
} }
return nullptr; return nullptr;
} }
}
}
[[nodiscard]] u8* GetPointer(const Common::ProcessAddress vaddr) const { [[nodiscard]] u8* GetPointer(const Common::ProcessAddress vaddr) const {
return GetPointerImpl( return GetPointerImpl(
@ -1149,13 +1152,19 @@ struct Memory::Impl {
gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) {
auto& current_area = rasterizer_write_areas[core]; auto& current_area = rasterizer_write_areas[core];
PAddr subaddress = address >> YUZU_PAGEBITS; PAddr subaddress = address >> YUZU_PAGEBITS;
bool do_collection = current_area.last_address == subaddress; // Performance note:
if (!do_collection) [[unlikely]] { // It may not be a good idea to assume accesses are within the same subaddress (i.e same page)
do_collection = system.GPU().OnCPUWrite(address, size); // It is often the case the games like to access wildly different addresses. Hence why I propose
if (!do_collection) { // we should let the compiler just do it's thing...
if (current_area.last_address != subaddress) {
// Short circuit the need to check for address/size
auto const do_collection = (address != 0 && size != 0)
&& system.GPU().OnCPUWrite(address, size);
if (do_collection) {
current_area.last_address = subaddress;
} else {
return; return;
} }
current_area.last_address = subaddress;
} }
gpu_dirty_managers[core].Collect(address, size); gpu_dirty_managers[core].Collect(address, size);
}); });

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -244,7 +247,7 @@ public:
void InvalidateRegion(DAddr addr, u64 size); void InvalidateRegion(DAddr addr, u64 size);
/// Notify rasterizer that CPU is trying to write this area. It returns true if the area is /// Notify rasterizer that CPU is trying to write this area. It returns true if the area is
/// sensible, false otherwise /// sensible, false otherwise, addr and size must be a valid combination
bool OnCPUWrite(DAddr addr, u64 size); bool OnCPUWrite(DAddr addr, u64 size);
/// Notify rasterizer that any caches of the specified region should be flushed and invalidated /// Notify rasterizer that any caches of the specified region should be flushed and invalidated

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2015 Citra Emulator Project // SPDX-FileCopyrightText: 2015 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -565,22 +568,17 @@ void RasterizerOpenGL::InvalidateRegion(DAddr addr, u64 size, VideoCommon::Cache
bool RasterizerOpenGL::OnCPUWrite(DAddr addr, u64 size) { bool RasterizerOpenGL::OnCPUWrite(DAddr addr, u64 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement); MICROPROFILE_SCOPE(OpenGL_CacheManagement);
if (addr == 0 || size == 0) { DEBUG_ASSERT(addr != 0 || size != 0);
return false;
}
{ {
std::scoped_lock lock{buffer_cache.mutex}; std::scoped_lock lock{buffer_cache.mutex};
if (buffer_cache.OnCPUWrite(addr, size)) { if (buffer_cache.OnCPUWrite(addr, size)) {
return true; return true;
} }
} }
{ {
std::scoped_lock lock{texture_cache.mutex}; std::scoped_lock lock{texture_cache.mutex};
texture_cache.WriteMemory(addr, size); texture_cache.WriteMemory(addr, size);
} }
shader_cache.InvalidateRegion(addr, size); shader_cache.InvalidateRegion(addr, size);
return false; return false;
} }

View file

@ -636,22 +636,17 @@ void RasterizerVulkan::InnerInvalidation(std::span<const std::pair<DAddr, std::s
} }
bool RasterizerVulkan::OnCPUWrite(DAddr addr, u64 size) { bool RasterizerVulkan::OnCPUWrite(DAddr addr, u64 size) {
if (addr == 0 || size == 0) { DEBUG_ASSERT(addr != 0 || size != 0);
return false;
}
{ {
std::scoped_lock lock{buffer_cache.mutex}; std::scoped_lock lock{buffer_cache.mutex};
if (buffer_cache.OnCPUWrite(addr, size)) { if (buffer_cache.OnCPUWrite(addr, size)) {
return true; return true;
} }
} }
{ {
std::scoped_lock lock{texture_cache.mutex}; std::scoped_lock lock{texture_cache.mutex};
texture_cache.WriteMemory(addr, size); texture_cache.WriteMemory(addr, size);
} }
pipeline_cache.InvalidateRegion(addr, size); pipeline_cache.InvalidateRegion(addr, size);
return false; return false;
} }