diff --git a/rpcs3/Emu/RSX/Host/MM.cpp b/rpcs3/Emu/RSX/Host/MM.cpp index 53bd558607ec..2533f93643b8 100644 --- a/rpcs3/Emu/RSX/Host/MM.cpp +++ b/rpcs3/Emu/RSX/Host/MM.cpp @@ -121,7 +121,7 @@ namespace rsx return; } - g_deferred_mprotect_queue.push_back({ range, prot }); + g_deferred_mprotect_queue.push_back({ range, prot, rsx::get_shared_tag() }); } void mm_protect(void* ptr, u64 length, utils::protection prot) @@ -222,4 +222,24 @@ namespace rsx auto& rsxdma = g_fxo->get(); rsxdma.backend_ctrl(mm_backend_ctrl::cmd_mm_flush, nullptr); } + + void mm_flush_partial(u64 last_tag) + { + std::lock_guard lock(g_mprotect_queue_lock); + + u32 count = 0; + for (const auto& block : g_deferred_mprotect_queue) + { + if (block.sync_tag > last_tag) + { + break; + } + count++; + } + + if (count) + { + mm_flush_mprotect_queue_internal(count); + } + } } diff --git a/rpcs3/Emu/RSX/Host/MM.h b/rpcs3/Emu/RSX/Host/MM.h index 7ba75e1a3035..95e1f4da670a 100644 --- a/rpcs3/Emu/RSX/Host/MM.h +++ b/rpcs3/Emu/RSX/Host/MM.h @@ -12,6 +12,7 @@ namespace rsx { utils::address_range64 range; utils::protection prot; + u64 sync_tag; inline void merge(const utils::address_range64& other) { @@ -47,5 +48,6 @@ namespace rsx void mm_flush_lazy(); void mm_flush(u32 vm_address); void mm_flush(const rsx::simple_array& ranges); + void mm_flush_partial(u64 tag); void mm_flush(); } diff --git a/rpcs3/Emu/RSX/NV47/HW/nv0039.cpp b/rpcs3/Emu/RSX/NV47/HW/nv0039.cpp index 1608cae5810b..2a507949680b 100644 --- a/rpcs3/Emu/RSX/NV47/HW/nv0039.cpp +++ b/rpcs3/Emu/RSX/NV47/HW/nv0039.cpp @@ -107,7 +107,7 @@ namespace rsx result == rsx::result_zcull_intr) { // This transfer overlaps will zcull data pool - if (RSX(ctx)->copy_zcull_stats(read_address, read_length, write_address) == write_length) + if (RSX(ctx)->copy_zcull_stats(read_address, read_length, write_address) >= write_length) { // All writes deferred return; @@ -126,7 +126,7 @@ namespace rsx u8* dst = vm::_ptr(write_address); const u8* src = vm::_ptr(read_address); - rsx::simple_array flush_mm_ranges = + const rsx::simple_array flush_mm_ranges = { utils::address_range64::start_length(reinterpret_cast(dst), write_length), utils::address_range64::start_length(reinterpret_cast(src), read_length) diff --git a/rpcs3/Emu/RSX/NV47/HW/nv3089.cpp b/rpcs3/Emu/RSX/NV47/HW/nv3089.cpp index 488b66b1da2e..6e2e7162bcfc 100644 --- a/rpcs3/Emu/RSX/NV47/HW/nv3089.cpp +++ b/rpcs3/Emu/RSX/NV47/HW/nv3089.cpp @@ -218,7 +218,7 @@ namespace rsx if (const auto result = RSX(ctx)->read_barrier(src_address, data_length, false); result == rsx::result_zcull_intr) { - if (RSX(ctx)->copy_zcull_stats(src_address, data_length, dst_address) == data_length) + if (RSX(ctx)->copy_zcull_stats(src_address, data_length, dst_address) >= data_length) { // All writes deferred return { false, src_info, dst_info }; diff --git a/rpcs3/Emu/RSX/NV47/HW/nv4097.cpp b/rpcs3/Emu/RSX/NV47/HW/nv4097.cpp index 16fc884288ef..e810839b9da4 100644 --- a/rpcs3/Emu/RSX/NV47/HW/nv4097.cpp +++ b/rpcs3/Emu/RSX/NV47/HW/nv4097.cpp @@ -4,6 +4,7 @@ #include "Emu/RSX/RSXThread.h" #include "Emu/RSX/Common/BufferUtils.h" +#include "Emu/RSX/Host/MM.h" #define RSX(ctx) ctx->rsxthr #define REGS(ctx) (&rsx::method_registers) @@ -719,9 +720,11 @@ namespace rsx } const u32 addr = RSX(ctx)->iomap_table.get_addr(0xf100000 + (index * 0x40)); - ensure(addr != umax); + // Notify ticks are strongly ordered + RSX(ctx)->sync(); + vm::_ptr>(addr)->store( { RSX(ctx)->timestamp(), diff --git a/rpcs3/Emu/RSX/NV47/HW/nv47_sync.hpp b/rpcs3/Emu/RSX/NV47/HW/nv47_sync.hpp index fe2522c31c4a..a77da374dffd 100644 --- a/rpcs3/Emu/RSX/NV47/HW/nv47_sync.hpp +++ b/rpcs3/Emu/RSX/NV47/HW/nv47_sync.hpp @@ -24,17 +24,18 @@ namespace rsx if (vm::_ref(address) == data) { // It's a no-op to write the same value (although there is a delay in real-hw so it's more accurate to allow GPU label in this case) + // There is no possible way for the guest to know that the label has been processed so we can skip MM sync here. return; } if constexpr (FlushDMA || FlushPipe) { - // Release op must be acoompanied by MM flush. - // FlushPipe implicitly does a MM flush but FlushDMA does not. Trigger the flush here - rsx::mm_flush(); - if constexpr (FlushDMA) { + // Release op must be acoompanied by MM flush. + // FlushPipe implicitly does a MM flush but FlushDMA does not. Trigger the flush here + rsx::mm_flush(); + // If the backend handled the request, this call will basically be a NOP g_fxo->get().sync(); } diff --git a/rpcs3/Emu/RSX/RSXZCULL.cpp b/rpcs3/Emu/RSX/RSXZCULL.cpp index 51052c88796a..4db3766034dd 100644 --- a/rpcs3/Emu/RSX/RSXZCULL.cpp +++ b/rpcs3/Emu/RSX/RSXZCULL.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "Core/RSXEngLock.hpp" #include "Core/RSXReservationLock.hpp" +#include "Host/MM.h" #include "RSXThread.h" namespace rsx @@ -155,6 +156,9 @@ namespace rsx if (m_pending_writes.empty()) { + // Immediate write, flush MM queue + rsx::mm_flush(); + // No need to queue this if there is no pending request in the pipeline anyway write(sink, ptimer->timestamp(), type, m_statistics_map[m_statistics_tag_id].result); return; @@ -173,6 +177,7 @@ namespace rsx It->counter_tag = m_statistics_tag_id; It->sink = sink; It->type = type; + It->sync_tag = rsx::get_shared_tag(); if (forwarder != &(*It)) { @@ -369,6 +374,9 @@ namespace rsx void ZCULL_control::write(queued_report_write* writer, u64 timestamp, u32 value) { + // Reports are strongly ordered. + rsx::mm_flush_partial(writer->sync_tag); + write(writer->sink, timestamp, writer->type, value); on_report_completed(writer->sink); @@ -799,6 +807,8 @@ namespace rsx u32 ZCULL_control::copy_reports_to(u32 start, u32 range, u32 dest) { u32 bytes_to_write = 0; + std::unordered_set unique_addresses; + const auto memory_range = utils::address_range32::start_length(start, range); for (auto& writer : m_pending_writes) { @@ -807,8 +817,14 @@ namespace rsx if (!writer.forwarder && memory_range.overlaps(writer.sink)) { - u32 address = (writer.sink - start) + dest; + const u32 address = (writer.sink - start) + dest; writer.sink_alias.push_back(vm::cast(address)); + + if (!unique_addresses.contains(address)) + { + bytes_to_write += sizeof(RsxReport); + unique_addresses.insert(address); + } } } diff --git a/rpcs3/Emu/RSX/RSXZCULL.h b/rpcs3/Emu/RSX/RSXZCULL.h index ec6fd2ad5c98..8823905a9d0f 100644 --- a/rpcs3/Emu/RSX/RSXZCULL.h +++ b/rpcs3/Emu/RSX/RSXZCULL.h @@ -46,6 +46,7 @@ namespace rsx { u32 type = CELL_GCM_ZPASS_PIXEL_CNT; u32 counter_tag; + u64 sync_tag; occlusion_query_info* query; queued_report_write* forwarder;