diff --git a/Utilities/address_range.h b/Utilities/address_range.h index 1e24fb9d6d..dcccc1a64e 100644 --- a/Utilities/address_range.h +++ b/Utilities/address_range.h @@ -176,9 +176,7 @@ namespace utils void set_min_max(const address_range &other) { - const address_range _range = get_min_max(other); - start = _range.start; - end = _range.end; + *this = get_min_max(other); } bool is_page_range() const diff --git a/rpcs3/Emu/RSX/RSXFIFO.cpp b/rpcs3/Emu/RSX/RSXFIFO.cpp index 93931d721d..1439b54975 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.cpp +++ b/rpcs3/Emu/RSX/RSXFIFO.cpp @@ -537,10 +537,11 @@ namespace rsx break; default: { - static constexpr std::array, 2> ranges + static constexpr std::array, 3> ranges {{ {NV308A_COLOR, 0x700}, - {NV4097_SET_TRANSFORM_PROGRAM, 32} + {NV4097_SET_TRANSFORM_PROGRAM, 32}, + {NV4097_SET_TRANSFORM_CONSTANT, 32} }}; // Use legacy logic - enqueue leading command with count diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index ec906d3a8f..c1f4b5232d 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -422,34 +422,54 @@ namespace rsx template struct set_transform_constant { - static void impl(thread* rsxthr, u32 _reg, u32 arg) + static void impl(thread* rsx, u32 /*_reg*/, u32 /*arg*/) { static constexpr u32 reg = index / 4; static constexpr u8 subreg = index % 4; + // Get real args count + const u32 count = std::min({rsx->fifo_ctrl->get_remaining_args_count() + 1, + static_cast(((rsx->ctrl->put & ~3ull) - (rsx->fifo_ctrl->get_pos() - 4)) / 4), 32 - index}); + const u32 load = rsx::method_registers.transform_constant_load(); - const u32 address = load + reg; - if (address >= 468) + + u32 rcount = count; + if (const u32 max = (load + reg) * 4 + count + subreg; max > 468 * 4) { // Ignore addresses outside the usable [0, 467] range - rsx_log.warning("Invalid transform register index (load=%d, index=%d)", load, index); - return; + rsx_log.warning("Invalid transform register index (load=%u, index=%u, count=%u)", load, index, count); + rcount -= max - (468 * 4); } - auto &value = rsx::method_registers.transform_constants[load + reg][subreg]; - if (value != arg) + alignas(64) u8 buffer[128]; + + const auto values = &rsx::method_registers.transform_constants[load + reg][subreg]; + + if (rsx->m_graphics_state & rsx::pipeline_state::transform_constants_dirty) { - //Transform constants invalidation is expensive (~8k bytes per update) - value = arg; - rsxthr->m_graphics_state |= rsx::pipeline_state::transform_constants_dirty; + // Minor optimization: don't compare values if we already know we need invalidation + stream_data_to_memory_swapped_u32(values, vm::base(rsx->fifo_ctrl->get_current_arg_ptr()), rcount, 4); } + else + { + stream_data_to_memory_swapped_u32(buffer, vm::base(rsx->fifo_ctrl->get_current_arg_ptr()), rcount, 4); + + if (std::memcmp(values, buffer, rcount * 4) != 0) + { + // Transform constants invalidation is expensive (~8k bytes per update) + std::memcpy(values, buffer, rcount * 4); + rsx->m_graphics_state |= rsx::pipeline_state::transform_constants_dirty; + } + } + + rsx->fifo_ctrl->skip_methods(count - 1); } }; template struct set_transform_program { - static void impl(thread* rsx, u32 _reg, u32 arg) + static void impl(thread* rsx, u32 /*_reg*/, u32 /*arg*/) { // Get real args count const u32 count = std::min({rsx->fifo_ctrl->get_remaining_args_count() + 1,