diff --git a/src/core/memory.cpp b/src/core/memory.cpp index b033858bf8..34539cc650 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -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: 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -868,35 +871,35 @@ struct Memory::Impl { [[nodiscard]] u8* GetPointerImpl(u64 vaddr, auto on_unmapped, auto on_rasterizer) const { // AARCH64 masks the upper 16 bit of all memory accesses vaddr = vaddr & 0xffffffffffffULL; - if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] { on_unmapped(); return nullptr; + } else { + // Avoid adding any extra logic to this fast-path block + const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw(); + if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { + return reinterpret_cast(pointer + vaddr); + } else { + switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { + case Common::PageType::Unmapped: + on_unmapped(); + return nullptr; + case Common::PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr); + return nullptr; + case Common::PageType::DebugMemory: + return GetPointerFromDebugMemory(vaddr); + case Common::PageType::RasterizerCachedMemory: { + u8* const host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)}; + on_rasterizer(); + return host_ptr; + } + default: + UNREACHABLE(); + } + return nullptr; + } } - - // Avoid adding any extra logic to this fast-path block - const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw(); - if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { - return reinterpret_cast(pointer + vaddr); - } - switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { - case Common::PageType::Unmapped: - on_unmapped(); - return nullptr; - case Common::PageType::Memory: - ASSERT_MSG(false, "Mapped memory page without a pointer @ 0x{:016X}", vaddr); - return nullptr; - case Common::PageType::DebugMemory: - return GetPointerFromDebugMemory(vaddr); - case Common::PageType::RasterizerCachedMemory: { - u8* const host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)}; - on_rasterizer(); - return host_ptr; - } - default: - UNREACHABLE(); - } - return nullptr; } [[nodiscard]] u8* GetPointer(const Common::ProcessAddress vaddr) const { @@ -1149,13 +1152,19 @@ struct Memory::Impl { gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { auto& current_area = rasterizer_write_areas[core]; PAddr subaddress = address >> YUZU_PAGEBITS; - bool do_collection = current_area.last_address == subaddress; - if (!do_collection) [[unlikely]] { - do_collection = system.GPU().OnCPUWrite(address, size); - if (!do_collection) { + // Performance note: + // It may not be a good idea to assume accesses are within the same subaddress (i.e same page) + // It is often the case the games like to access wildly different addresses. Hence why I propose + // 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; } - current_area.last_address = subaddress; } gpu_dirty_managers[core].Collect(address, size); }); diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 8a06adad79..538c4da85a 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -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-License-Identifier: GPL-2.0-or-later @@ -244,7 +247,7 @@ public: void InvalidateRegion(DAddr addr, u64 size); /// 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); /// Notify rasterizer that any caches of the specified region should be flushed and invalidated diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 19f586518f..4fb193293b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -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-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) { MICROPROFILE_SCOPE(OpenGL_CacheManagement); - if (addr == 0 || size == 0) { - return false; - } - + DEBUG_ASSERT(addr != 0 || size != 0); { std::scoped_lock lock{buffer_cache.mutex}; if (buffer_cache.OnCPUWrite(addr, size)) { return true; } } - { std::scoped_lock lock{texture_cache.mutex}; texture_cache.WriteMemory(addr, size); } - shader_cache.InvalidateRegion(addr, size); return false; } @@ -1204,24 +1202,24 @@ void RasterizerOpenGL::SyncLogicOpState() { } flags[Dirty::LogicOp] = false; - auto& regs = maxwell3d->regs; - - if (device.IsAmd()) { - using namespace Tegra::Engines; - struct In { - const Maxwell3D::Regs::VertexAttribute::Type d; - In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {} - bool operator()(Maxwell3D::Regs::VertexAttribute n) const { - return n.type == d; - } - }; - - bool has_float = - std::any_of(regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(), - In(Maxwell3D::Regs::VertexAttribute::Type::Float)); - regs.logic_op.enable = static_cast(!has_float); - } - + auto& regs = maxwell3d->regs; + + if (device.IsAmd()) { + using namespace Tegra::Engines; + struct In { + const Maxwell3D::Regs::VertexAttribute::Type d; + In(Maxwell3D::Regs::VertexAttribute::Type n) : d(n) {} + bool operator()(Maxwell3D::Regs::VertexAttribute n) const { + return n.type == d; + } + }; + + bool has_float = + std::any_of(regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(), + In(Maxwell3D::Regs::VertexAttribute::Type::Float)); + regs.logic_op.enable = static_cast(!has_float); + } + if (regs.logic_op.enable) { glEnable(GL_COLOR_LOGIC_OP); glLogicOp(MaxwellToGL::LogicOp(regs.logic_op.op)); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 66f4668026..a2492f1d74 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -636,22 +636,17 @@ void RasterizerVulkan::InnerInvalidation(std::span