diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index 67557aa6d3..305a440431 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -34,11 +34,46 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -u64 rsxTimeStamp() +static u64 rsx_timeStamp() { return get_timebased_time(); } +static void set_rsx_dmactl(rsx::thread* render, u64 get_put) +{ + { + rsx::eng_lock rlock(render); + render->fifo_ctrl->abort(); + + // Unconditional set + while (!render->new_get_put.compare_and_swap_test(u64{umax}, get_put)) + { + utils::pause(); + } + + // Schedule FIFO interrupt to deal with this immediately + render->m_eng_interrupt_mask |= rsx::dma_control_interrupt; + } + + if (auto cpu = cpu_thread::get_current()) + { + // Wait for the first store to complete (or be aborted) + while (render->new_get_put != usz{umax}) + { + if (Emu.IsStopped()) + { + if (render->new_get_put.compare_and_swap_test(get_put, umax)) + { + // Retry + cpu->state += cpu_flag::again; + } + } + + thread_ctrl::wait_for(1000); + } + } +} + bool rsx::thread::send_event(u64 data1, u64 event_flags, u64 data3) { // Filter event bits, send them only if they are masked by gcm @@ -473,43 +508,9 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 const u64 get = static_cast(a3); const u64 put = static_cast(a4); const u64 get_put = put << 32 | get; - bool changed_value = false; - { - rsx::eng_lock rlock(render); - std::lock_guard lock(render->sys_rsx_mtx); - render->fifo_ctrl->abort(); - - while (render->new_get_put == umax) - { - if (render->new_get_put.compare_and_swap_test(u64{umax}, get_put)) - { - changed_value = true; - break; - } - - // Assume CAS can fail spuriously here - } - } - - // Wait for the first store to complete (or be aborted) - while (render->new_get_put != umax) - { - if (Emu.IsStopped() && changed_value) - { - // Abort - if (render->new_get_put.compare_and_swap_test(get_put, u64{umax})) - { - if (auto cpu = cpu_thread::get_current()) - { - cpu->state += cpu_flag::again; - break; - } - } - } - - thread_ctrl::wait_for(1000); - } + std::lock_guard lock(render->sys_rsx_mtx); + set_rsx_dmactl(render, get_put); break; } @@ -835,7 +836,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 { // we only ever use head 1 for now driverInfo.head[1].flipFlags |= 0x80000000; - driverInfo.head[1].lastFlipTime = rsxTimeStamp(); // should rsxthread set this? + driverInfo.head[1].lastFlipTime = rsx_timeStamp(); // should rsxthread set this? driverInfo.head[1].flipBufferId = static_cast(a3); // seems gcmSysWaitLabel uses this offset, so lets set it to 0 every flip @@ -865,7 +866,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 }); // Time point is supplied in argument 4 (todo: convert it to MFTB rate and use it) - const u64 current_time = rsxTimeStamp(); + const u64 current_time = rsx_timeStamp(); // Note: not atomic diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 01909e97fe..a8241f03a4 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1274,9 +1274,9 @@ namespace rsx handle_emu_flip(async_flip_buffer); } - if (!in_begin_end && state != FIFO::state::lock_wait) + if (state != FIFO::state::lock_wait) { - if (atomic_storage::load(m_invalidated_memory_range.end) != 0) + if (!in_begin_end && atomic_storage::load(m_invalidated_memory_range.end) != 0) { std::lock_guard lock(m_mtx_task); @@ -1285,6 +1285,22 @@ namespace rsx handle_invalidated_memory_range(); } } + + if (m_eng_interrupt_mask & rsx::dma_control_interrupt && !is_stopped()) + { + if (const u64 get_put = new_get_put.exchange(u64{umax}); + get_put != umax) + { + vm::_ref>(dma_address + ::offset32(&RsxDmaControl::put)).release(get_put); + fifo_ctrl->set_get(static_cast(get_put)); + fifo_ctrl->abort(); + fifo_ret_addr = RSX_CALL_STACK_EMPTY; + last_known_code_start = static_cast(get_put); + sync_point_request.release(true); + } + + m_eng_interrupt_mask.clear(rsx::dma_control_interrupt); + } } if (m_eng_interrupt_mask & rsx::pipe_flush_interrupt) @@ -1299,21 +1315,6 @@ namespace rsx m_invalidated_memory_range = utils::address_range::start_end(0x2 << 28, constants::local_mem_base + local_mem_size - 1); handle_invalidated_memory_range(); } - else if (new_get_put != umax && state != FIFO_state::lock_wait) - { - const u64 get_put = new_get_put.exchange(u64{umax}); - - // Recheck in case aborted externally - if (get_put != umax) - { - vm::_ref>(dma_address + ::offset32(&RsxDmaControl::put)).release(get_put); - fifo_ctrl->set_get(static_cast(get_put)); - fifo_ctrl->abort(); - fifo_ret_addr = RSX_CALL_STACK_EMPTY; - last_known_code_start = static_cast(get_put); - sync_point_request.release(true); - } - } } std::array thread::get_color_surface_addresses() const @@ -3268,11 +3269,8 @@ namespace rsx { external_interrupt_lock++; - while (!external_interrupt_ack) + while (!external_interrupt_ack && !is_stopped()) { - if (is_stopped()) - break; - utils::pause(); } } diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index caa74768a0..6da1d2c142 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -98,6 +98,7 @@ namespace rsx memory_config_interrupt = 0x0002, // Memory configuration changed display_interrupt = 0x0004, // Display handling pipe_flush_interrupt = 0x0008, // Flush pipelines + dma_control_interrupt = 0x0010, // DMA interrupt all_interrupt_bits = memory_config_interrupt | backend_interrupt | display_interrupt | pipe_flush_interrupt };