diff --git a/rpcs3/Emu/RSX/NV47/HW/common.cpp b/rpcs3/Emu/RSX/NV47/HW/common.cpp index 60ea4ff632..0f6420928a 100644 --- a/rpcs3/Emu/RSX/NV47/HW/common.cpp +++ b/rpcs3/Emu/RSX/NV47/HW/common.cpp @@ -96,14 +96,8 @@ namespace rsx const u32 count = std::min({ fifo_args_cnt, fifo_read_limit, method_range }); // Clamp by the count of methods this function is responsible to - std::span command_span = RSX(ctx)->fifo_ctrl->get_current_arg_ptr(); - - if (command_span.size() > count) - { - command_span = command_span.subspan(0, count); - } - - ensure(!command_span.empty()); + std::span command_span = RSX(ctx)->fifo_ctrl->get_current_arg_ptr(count); + ensure(!command_span.empty() && command_span.size() <= count); u32* const dst_regs = ®S(ctx)->registers[reg]; diff --git a/rpcs3/Emu/RSX/NV47/HW/nv308a.cpp b/rpcs3/Emu/RSX/NV47/HW/nv308a.cpp index 6a783f26ea..be3fab8830 100644 --- a/rpcs3/Emu/RSX/NV47/HW/nv308a.cpp +++ b/rpcs3/Emu/RSX/NV47/HW/nv308a.cpp @@ -42,7 +42,7 @@ namespace rsx const u32 x = REGS(ctx)->nv308a_x() + index; const u32 y = REGS(ctx)->nv308a_y(); - const auto fifo_span = RSX(ctx)->fifo_ctrl->get_current_arg_ptr(); + const auto fifo_span = RSX(ctx)->fifo_ctrl->get_current_arg_ptr(count); if (fifo_span.size() < count) { diff --git a/rpcs3/Emu/RSX/NV47/HW/nv4097.cpp b/rpcs3/Emu/RSX/NV47/HW/nv4097.cpp index ce7d0130a2..78f01f4059 100644 --- a/rpcs3/Emu/RSX/NV47/HW/nv4097.cpp +++ b/rpcs3/Emu/RSX/NV47/HW/nv4097.cpp @@ -98,7 +98,7 @@ namespace rsx const auto values = ®S(ctx)->transform_constants[load + constant_id][subreg]; - const auto fifo_span = RSX(ctx)->fifo_ctrl->get_current_arg_ptr(); + const auto fifo_span = RSX(ctx)->fifo_ctrl->get_current_arg_ptr(rcount); if (fifo_span.size() < rcount) { @@ -148,7 +148,7 @@ namespace rsx rcount -= max - (max_vertex_program_instructions * 4); } - const auto fifo_span = RSX(ctx)->fifo_ctrl->get_current_arg_ptr(); + const auto fifo_span = RSX(ctx)->fifo_ctrl->get_current_arg_ptr(rcount); if (fifo_span.size() < rcount) { diff --git a/rpcs3/Emu/RSX/RSXFIFO.cpp b/rpcs3/Emu/RSX/RSXFIFO.cpp index f9a63efa6c..f2d279c5bb 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.cpp +++ b/rpcs3/Emu/RSX/RSXFIFO.cpp @@ -223,22 +223,42 @@ namespace rsx m_remaining_commands = 0; } - std::span FIFO_control::get_current_arg_ptr() const + std::span FIFO_control::get_current_arg_ptr(u32 length_in_words) const { if (g_cfg.core.rsx_fifo_accuracy) { // Return a pointer to the cache storage with confined access - return {reinterpret_cast(&m_cache) + (m_internal_get - m_cache_addr) / 4, (m_cache_size - (m_internal_get - m_cache_addr)) / 4}; + const u32 cache_offset_in_words = (m_internal_get - m_cache_addr) / 4; + const u32 cache_size_in_words = m_cache_size / 4; + return {reinterpret_cast(&m_cache) + cache_offset_in_words, cache_size_in_words - cache_offset_in_words}; } - else - { - // Return a raw pointer with no limited access - constexpr u32 _1m = 0x100000; - const u32 base = m_iotable->get_addr(m_internal_get); - const u32 base_1m = m_iotable->get_addr(m_internal_get + _1m); - return {static_cast(vm::base(base)), (base_1m - _1m == base ? _1m : (_1m - (m_internal_get % _1m))) / 4 }; + // Return a raw pointer to contiguous memory + constexpr u32 _1M = 0x100000; + const u32 size = length_in_words * sizeof(u32); + const u32 from = m_iotable->get_addr(m_internal_get); + + for (u32 remaining = size, addr = m_internal_get, ptr = from; remaining > 0;) + { + const u32 next_block = utils::align(addr, _1M); + const u32 available = (next_block - addr); + if (remaining <= available) + { + return { static_cast(vm::base(from)), length_in_words }; + } + + remaining -= available; + const u32 next_ptr = m_iotable->get_addr(next_block); + if (next_ptr != (ptr + available)) + { + return { static_cast(vm::base(from)), (size - remaining) / sizeof(u32)}; + } + + ptr = next_ptr; + addr = next_block; } + + fmt::throw_exception("Unreachable"); } bool FIFO_control::read_unsafe(register_pair& data) diff --git a/rpcs3/Emu/RSX/RSXFIFO.h b/rpcs3/Emu/RSX/RSXFIFO.h index 8eb614b520..d62d32a134 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.h +++ b/rpcs3/Emu/RSX/RSXFIFO.h @@ -159,7 +159,7 @@ namespace rsx u32 get_pos() const { return m_internal_get; } u32 last_cmd() const { return m_cmd; } void sync_get() const; - std::span get_current_arg_ptr() const; + std::span get_current_arg_ptr(u32 length_in_words) const; u32 get_remaining_args_count() const { return m_remaining_commands; } void restore_state(u32 cmd, u32 count); void inc_get(bool wait);