diff --git a/rpcs3/Emu/RSX/Capture/rsx_capture.cpp b/rpcs3/Emu/RSX/Capture/rsx_capture.cpp index 17bd98dc38..af1082824b 100644 --- a/rpcs3/Emu/RSX/Capture/rsx_capture.cpp +++ b/rpcs3/Emu/RSX/Capture/rsx_capture.cpp @@ -51,10 +51,7 @@ namespace rsx std::unordered_set& mem_changes = frame_capture.replay_commands.back().memory_state; // capture fragment shader mem - const u32 shader_program = method_registers.shader_program_address(); - - const u32 program_location = (shader_program & 0x3) - 1; - const u32 program_offset = (shader_program & ~0x3); + const auto [program_offset, program_location] = method_registers.shader_program_address(); const u32 addr = get_address(program_offset, program_location, HERE); const auto program_info = program_hash_util::fragment_program_utils::analyse_fragment_program(vm::base(addr)); diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index 645401ce6d..2c0f8b5c26 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -230,6 +230,7 @@ struct RSXFragmentProgram void *addr; u32 offset; u32 ucode_length; + u32 total_length; u32 ctrl; u16 unnormalized_coords; u16 redirected_textures; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 79c182c350..1bbca0f33c 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1585,10 +1585,7 @@ namespace rsx m_graphics_state &= ~(rsx::pipeline_state::fragment_program_dirty); auto &result = current_fragment_program = {}; - const u32 shader_program = rsx::method_registers.shader_program_address(); - - const u32 program_location = (shader_program & 0x3) - 1; - const u32 program_offset = (shader_program & ~0x3); + const auto [program_offset, program_location] = method_registers.shader_program_address(); result.addr = vm::base(rsx::get_address(program_offset, program_location, HERE)); current_fp_metadata = program_hash_util::fragment_program_utils::analyse_fragment_program(result.addr); @@ -1596,6 +1593,7 @@ namespace rsx result.addr = (static_cast(result.addr) + current_fp_metadata.program_start_offset); result.offset = program_offset + current_fp_metadata.program_start_offset; result.ucode_length = current_fp_metadata.program_ucode_length; + result.total_length = result.ucode_length + current_fp_metadata.program_start_offset; result.valid = true; result.ctrl = rsx::method_registers.shader_control() & (CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS | CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT); result.texcoord_control_mask = rsx::method_registers.texcoord_control_mask(); @@ -1737,6 +1735,22 @@ namespace rsx } } + bool thread::invalidate_fragment_program(u32 dst_dma, u32 dst_offset, u32 size) + { + const auto [shader_offset, shader_dma] = rsx::method_registers.shader_program_address(); + + if ((dst_dma & CELL_GCM_LOCATION_MAIN) == shader_dma && + address_range::start_length(shader_offset, current_fragment_program.total_length).overlaps( + address_range::start_length(dst_offset, size))) [[unlikely]] + { + // Data overlaps + m_graphics_state |= rsx::pipeline_state::fragment_program_dirty; + return true; + } + + return false; + } + void thread::reset() { rsx::method_registers.reset(); diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 51db0a419a..bb09867911 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -711,6 +711,8 @@ namespace rsx * returns whether surface is a render target and surface pitch in native format */ void get_current_fragment_program(const std::array, rsx::limits::fragment_textures_count>& sampler_descriptors); + public: + bool invalidate_fragment_program(u32 dst_dma, u32 dst_offset, u32 size); public: u64 target_rsx_flip_time = 0; diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 43ff57ac74..38cf196bf8 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -876,16 +876,22 @@ namespace rsx { // Move last 32 bits reinterpret_cast(dst)[0] = reinterpret_cast(src)[count - 1]; - } - else if (dst_dma & CELL_GCM_LOCATION_MAIN) - { - // May overlap - std::memmove(dst, src, data_length); + rsx->invalidate_fragment_program(dst_dma, dst_offset, 4); } else { - // Never overlaps - std::memcpy(dst, src, data_length); + if (dst_dma & CELL_GCM_LOCATION_MAIN) + { + // May overlap + std::memmove(dst, src, data_length); + } + else + { + // Never overlaps + std::memcpy(dst, src, data_length); + } + + rsx->invalidate_fragment_program(dst_dma, dst_offset, count * 4); } break; @@ -912,6 +918,7 @@ namespace rsx { // Move last 16 bits dst[0] = convert(src[count - 1]); + rsx->invalidate_fragment_program(dst_dma, dst_offset, 2); break; } @@ -920,6 +927,7 @@ namespace rsx dst[i] = convert(src[i]); } + rsx->invalidate_fragment_program(dst_dma, dst_offset, count * 2); break; } default: @@ -930,12 +938,6 @@ namespace rsx //res->release(0); - if (!(dst_dma & CELL_GCM_LOCATION_MAIN)) - { - // Set this flag on LOCAL memory transfer - rsx->m_graphics_state |= rsx::pipeline_state::fragment_program_dirty; - } - // Skip "handled methods" rsx->fifo_ctrl->skip_methods(count - 1); } @@ -1086,6 +1088,8 @@ namespace rsx const u32 nb_lines = std::min(clip_h, in_h); const u32 data_length = nb_lines * src_line_length; + rsx->invalidate_fragment_program(dst_dma, dst_offset, data_length); + if (const auto result = rsx->read_barrier(src_address, data_length, false); result == rsx::result_zcull_intr) { @@ -1099,6 +1103,8 @@ namespace rsx else { const u32 data_length = in_pitch * (in_h - 1) + src_line_length; + + rsx->invalidate_fragment_program(dst_dma, dst_offset, data_length); rsx->read_barrier(src_address, data_length, true); } @@ -1437,6 +1443,8 @@ namespace rsx const auto write_address = get_address(dst_offset, dst_dma, HERE); const auto data_length = in_pitch * (line_count - 1) + line_length; + rsx->invalidate_fragment_program(dst_dma, dst_offset, data_length); + if (const auto result = rsx->read_barrier(read_address, data_length, !is_block_transfer); result == rsx::result_zcull_intr) { diff --git a/rpcs3/Emu/RSX/rsx_methods.h b/rpcs3/Emu/RSX/rsx_methods.h index 4ea03957b9..187f8492e4 100644 --- a/rpcs3/Emu/RSX/rsx_methods.h +++ b/rpcs3/Emu/RSX/rsx_methods.h @@ -1331,9 +1331,10 @@ namespace rsx return decode().vertex_data_base_index(); } - u32 shader_program_address() const + std::pair shader_program_address() const { - return decode().shader_program_address(); + const u32 shader_address = decode().shader_program_address(); + return { shader_address & ~3, (shader_address & 3) - 1 }; } u32 transform_program_start() const