#include "stdafx.h" #include "nv406e.h" #include "nv47_sync.hpp" #include "Emu/RSX/RSXThread.h" #include "context_accessors.define.h" namespace rsx { namespace nv406e { void set_reference(context* ctx, u32 /*reg*/, u32 arg) { RSX(ctx)->sync(); // Write ref+get (get will be written again with the same value at command end) auto& dma = vm::_ref(RSX(ctx)->dma_address); dma.get.release(RSX(ctx)->fifo_ctrl->get_pos()); dma.ref.store(arg); } void semaphore_acquire(context* ctx, u32 /*reg*/, u32 arg) { RSX(ctx)->sync_point_request.release(true); const u32 addr = get_address(REGS(ctx)->semaphore_offset_406e(), REGS(ctx)->semaphore_context_dma_406e()); // Syncronization point, may be associated with memory changes without actually changing addresses RSX(ctx)->m_graphics_state |= rsx::pipeline_state::fragment_program_needs_rehash; const auto& sema = vm::_ref(addr).val; if (sema == arg) { // Flip semaphore doesnt need wake-up delay if (addr != RSX(ctx)->label_addr + 0x10) { RSX(ctx)->flush_fifo(); RSX(ctx)->fifo_wake_delay(2); } return; } else { RSX(ctx)->flush_fifo(); } u64 start = get_system_time(); u64 last_check_val = start; while (sema != arg) { if (RSX(ctx)->test_stopped()) { RSX(ctx)->state += cpu_flag::again; return; } if (const auto tdr = static_cast(g_cfg.video.driver_recovery_timeout)) { const u64 current = get_system_time(); if (current - last_check_val > 20'000) { // Suspicious amnount of time has passed // External pause such as debuggers' pause or operating system sleep may have taken place // Ignore it start += current - last_check_val; } last_check_val = current; if ((current - start) > tdr) { // If longer than driver timeout force exit rsx_log.error("nv406e::semaphore_acquire has timed out. semaphore_address=0x%X", addr); break; } } RSX(ctx)->cpu_wait({}); } RSX(ctx)->fifo_wake_delay(); RSX(ctx)->performance_counters.idle_time += (get_system_time() - start); } void semaphore_release(context* ctx, u32 /*reg*/, u32 arg) { const u32 offset = REGS(ctx)->semaphore_offset_406e(); if (offset % 4) { rsx_log.warning("NV406E semaphore release is using unaligned semaphore, ignoring. (offset=0x%x)", offset); return; } const u32 ctxt = REGS(ctx)->semaphore_context_dma_406e(); // By avoiding doing this on flip's semaphore release // We allow last gcm's registers reset to occur in case of a crash if (const bool is_flip_sema = (offset == 0x10 && ctxt == CELL_GCM_CONTEXT_DMA_SEMAPHORE_R); !is_flip_sema) { RSX(ctx)->sync_point_request.release(true); } const u32 addr = get_address(offset, ctxt); // TODO: Check if possible to write on reservations if (RSX(ctx)->label_addr >> 28 != addr >> 28) { rsx_log.error("NV406E semaphore unexpected address. Please report to the developers. (offset=0x%x, addr=0x%x)", offset, addr); RSX(ctx)->recover_fifo(); return; } if (addr == RSX(ctx)->device_addr + 0x30 && !arg) { // HW flip synchronization related, 1 is not written without display queue command (TODO: make it behave as real hw) arg = 1; } util::write_gcm_label(ctx, addr, arg); } } // namespace nv406e } // namespace rsx