Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sys_rsx: Minor atomicity fixes #7978

Merged
merged 2 commits into from Apr 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
101 changes: 85 additions & 16 deletions rpcs3/Emu/Cell/lv2/sys_rsx.cpp
Expand Up @@ -38,6 +38,57 @@ u64 rsxTimeStamp()
return get_timebased_time();
}

void lv2_rsx_config::send_event(u64 data1, u64 event_flags, u64 data3) const
{
// Filter event bits, send them only if they are masked by gcm
// Except the upper 32-bits, they are reserved for unmapped io events and execute unconditionally
event_flags &= vm::_ref<RsxDriverInfo>(driver_info).handlers | 0xffff'ffffull << 32;

if (!event_flags)
{
// Nothing to do
return;
}

auto error = sys_event_port_send(rsx_event_port, data1, event_flags, data3);

while (error + 0u == CELL_EBUSY)
{
auto cpu = get_current_cpu_thread();

if (cpu && cpu->id_type() != 1)
{
cpu = nullptr;
}

if (cpu)
{
// Deschedule
lv2_obj::sleep(*cpu, 100);
}
else if (const auto rsx = rsx::get_current_renderer(); rsx->is_current_thread())
{
rsx->on_semaphore_acquire_wait();
}

// Wait a bit before resending event
thread_ctrl::wait_for(100);

if (cpu && cpu->check_state())
{
error = 0;
break;
}

error = sys_event_port_send(rsx_event_port, data1, event_flags, data3);
}

if (error)
{
fmt::throw_exception("rsx_event_port_send() Failed to send event! (error=%x)" HERE, +error);
}
}

error_code sys_rsx_device_open()
{
sys_rsx.todo("sys_rsx_device_open()");
Expand Down Expand Up @@ -202,6 +253,8 @@ error_code sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> lpar_d
sys_event_queue_create(vm::get_addr(&driverInfo.handler_queue), attr, 0, 0x20);
sys_event_port_connect_local(rsx_cfg->rsx_event_port, driverInfo.handler_queue);

rsx_cfg->dma_address = vm::cast(*lpar_dma_control, HERE);

const auto render = rsx::get_current_renderer();
render->display_buffers_count = 0;
render->current_display_buffer = 0;
Expand Down Expand Up @@ -350,12 +403,17 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
switch (package_id)
{
case 0x001: // FIFO
{
render->pause();
const u64 get = static_cast<u32>(a3);
const u64 put = static_cast<u32>(a4);
vm::_ref<atomic_be_t<u64>>(rsx_cfg->dma_address + ::offset32(&RsxDmaControl::put)).release(put << 32 | get);
render->ctrl->get = static_cast<u32>(a3);
render->ctrl->put = static_cast<u32>(a4);
render->restore_point = static_cast<u32>(a3);
render->sync_point_request.release(true);
render->unpause();
break;
}

case 0x100: // Display mode set
break;
Expand All @@ -372,6 +430,9 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
// otherwise it contains a display buffer offset
if ((a4 & 0x80000000) != 0)
{
// NOTE: There currently seem to only be 2 active heads on PS3
verify(HERE), a3 < 2;

// last half byte gives buffer, 0xf seems to trigger just last queued
u8 idx_check = a4 & 0xf;
if (idx_check > 7)
Expand Down Expand Up @@ -409,14 +470,13 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64

case 0x103: // Display Queue
{
driverInfo.head[a3].lastQueuedBufferId = static_cast<u32>(a4);
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);

// NOTE: There currently seem to only be 2 active heads on PS3
verify(HERE), a3 < 2;

const u64 shift_offset = (a3 + 5);
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1ull << shift_offset), 0);
driverInfo.head[a3].lastQueuedBufferId = static_cast<u32>(a4);
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);

rsx_cfg->send_event(0, SYS_RSX_EVENT_QUEUE_BASE << a3, 0);

render->on_frame_end(static_cast<u32>(a4));
}
Expand Down Expand Up @@ -465,9 +525,13 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
return SYS_RSX_CONTEXT_ATTRIBUTE_ERROR;
}

u32 flipStatus = driverInfo.head[a3].flipFlags;
flipStatus = (flipStatus & static_cast<u32>(a4)) | static_cast<u32>(a5);
driverInfo.head[a3].flipFlags = flipStatus;
// NOTE: There currently seem to only be 2 active heads on PS3
verify(HERE), a3 < 2;

driverInfo.head[a3].flipFlags.atomic_op([&](be_t<u32>& flipStatus)
{
flipStatus = (flipStatus & static_cast<u32>(a4)) | static_cast<u32>(a5);
});
}
break;

Expand Down Expand Up @@ -540,6 +604,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
break;

case 0xFEC: // hack: flip event notification

// we only ever use head 1 for now
driverInfo.head[1].flipFlags |= 0x80000000;
driverInfo.head[1].lastFlipTime = rsxTimeStamp(); // should rsxthread set this?
Expand All @@ -548,30 +613,34 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
// seems gcmSysWaitLabel uses this offset, so lets set it to 0 every flip
vm::_ref<u32>(render->label_addr + 0x10) = 0;

//if (a3 == 0)
// sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 3), 0);
//if (a3 == 1)
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 4), 0);
rsx_cfg->send_event(0, SYS_RSX_EVENT_FLIP_BASE << 1, 0);
break;

case 0xFED: // hack: vblank command
{
// NOTE: There currently seem to only be 2 active heads on PS3
verify(HERE), a3 < 2;

// todo: this is wrong and should be 'second' vblank handler and freq, but since currently everything is reported as being 59.94, this should be fine
vm::_ref<u32>(render->device_addr + 0x30) = 1;
driverInfo.head[a3].vBlankCount++;
driverInfo.head[a3].lastSecondVTime = rsxTimeStamp();
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 1), 0);

u64 event_flags = SYS_RSX_EVENT_VBLANK;

if (render->enable_second_vhandler)
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 11), 0); // second vhandler
event_flags |= SYS_RSX_EVENT_SECOND_VBLANK_BASE << a3; // second vhandler

rsx_cfg->send_event(0, event_flags, 0);
elad335 marked this conversation as resolved.
Show resolved Hide resolved
break;
}

case 0xFEF: // hack: user command
// 'custom' invalid package id for now
// as i think we need custom lv1 interrupts to handle this accurately
// this also should probly be set by rsxthread
driverInfo.userCmdParam = static_cast<u32>(a4);
sys_event_port_send(rsx_cfg->rsx_event_port, 0, (1 << 7), 0);
rsx_cfg->send_event(0, SYS_RSX_EVENT_USER_CMD, 0);
break;

default:
Expand Down
21 changes: 18 additions & 3 deletions rpcs3/Emu/Cell/lv2/sys_rsx.h
Expand Up @@ -22,22 +22,22 @@ struct RsxDriverInfo
struct Head
{
be_t<u64> lastFlipTime; // 0x0 last flip time
be_t<u32> flipFlags; // 0x8 flags to handle flip/queue
atomic_be_t<u32> flipFlags; // 0x8 flags to handle flip/queue
be_t<u32> offset; // 0xC
be_t<u32> flipBufferId; // 0x10
be_t<u32> lastQueuedBufferId; // 0x14 todo: this is definately not this variable but its 'unused' so im using it for queueId to pass to flip handler
be_t<u32> unk3; // 0x18
be_t<u32> unk6; // 0x18 possible low bits of time stamp? used in getlastVBlankTime
be_t<u64> lastSecondVTime; // 0x20 last time for second vhandler freq
be_t<u64> unk4; // 0x28
be_t<u64> vBlankCount; // 0x30
atomic_be_t<u64> vBlankCount; // 0x30
be_t<u32> unk; // 0x38 possible u32, 'flip field', top/bottom for interlaced
be_t<u32> unk5; // 0x3C possible high bits of time stamp? used in getlastVBlankTime
} head[8]; // size = 0x40, 0x200

be_t<u32> unk7; // 0x12B8
be_t<u32> unk8; // 0x12BC
be_t<u32> handlers; // 0x12C0 -- flags showing which handlers are set
atomic_be_t<u32> handlers; // 0x12C0 -- flags showing which handlers are set
be_t<u32> unk9; // 0x12C4
be_t<u32> unk10; // 0x12C8
be_t<u32> userCmdParam; // 0x12CC
Expand All @@ -62,6 +62,18 @@ enum : u64
SYS_RSX_IO_MAP_IS_STRICT = 1ull << 60
};

// Unofficial event names
enum : u64
{
//SYS_RSX_EVENT_GRAPHICS_ERROR = 1 << 0,
SYS_RSX_EVENT_VBLANK = 1 << 1,
SYS_RSX_EVENT_FLIP_BASE = 1 << 3,
SYS_RSX_EVENT_QUEUE_BASE = 1 << 5,
SYS_RSX_EVENT_USER_CMD = 1 << 7,
SYS_RSX_EVENT_SECOND_VBLANK_BASE = 1 << 10,
SYS_RSX_EVENT_UNMAPPED_BASE = 1ull << 32,
};

struct RsxDmaControl
{
u8 resv[0x40];
Expand Down Expand Up @@ -114,6 +126,9 @@ struct lv2_rsx_config
u32 context_base{};
u32 device_addr{};
u32 driver_info{};
u32 dma_address{};

void send_event(u64, u64, u64) const;
};

// SysCalls
Expand Down
4 changes: 2 additions & 2 deletions rpcs3/Emu/RSX/RSXFIFO.cpp
Expand Up @@ -431,7 +431,7 @@ namespace rsx
if (performance_counters.state == FIFO_state::running)
{
performance_counters.FIFO_idle_timestamp = get_system_time();
sync_point_request = true;
sync_point_request.release(true);
}

performance_counters.state = FIFO_state::spinning;
Expand All @@ -450,7 +450,7 @@ namespace rsx
if (performance_counters.state == FIFO_state::running)
{
performance_counters.FIFO_idle_timestamp = get_system_time();
sync_point_request = true;
sync_point_request.release(true);
}

performance_counters.state = FIFO_state::spinning;
Expand Down
6 changes: 3 additions & 3 deletions rpcs3/Emu/RSX/RSXThread.cpp
Expand Up @@ -615,7 +615,7 @@ namespace rsx
{
restore_point = ctrl->get;
saved_fifo_ret = fifo_ret_addr;
sync_point_request = false;
sync_point_request.release(false);
}

// Execute backend-local tasks first
Expand Down Expand Up @@ -2424,8 +2424,8 @@ namespace rsx
if (u64 to_unmap = unmap_status[i])
{
// Each 64 entries are grouped by a bit
const u64 io_event = 0x100000000ull << i;
sys_event_port_send(g_fxo->get<lv2_rsx_config>()->rsx_event_port, 0, io_event, to_unmap);
const u64 io_event = SYS_RSX_EVENT_UNMAPPED_BASE << i;
g_fxo->get<lv2_rsx_config>()->send_event(0, io_event, to_unmap);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Emu/RSX/RSXThread.h
Expand Up @@ -725,7 +725,7 @@ namespace rsx
bool capture_current_frame = false;

public:
bool sync_point_request = false;
atomic_t<bool> sync_point_request = false;
bool in_begin_end = false;

struct desync_fifo_cmd_info
Expand Down
4 changes: 2 additions & 2 deletions rpcs3/Emu/RSX/rsx_methods.cpp
Expand Up @@ -50,7 +50,7 @@ namespace rsx

void semaphore_acquire(thread* rsx, u32 /*_reg*/, u32 arg)
{
rsx->sync_point_request = true;
rsx->sync_point_request.release(true);
const u32 addr = get_address(method_registers.semaphore_offset_406e(), method_registers.semaphore_context_dma_406e(), HERE);

const auto& sema = vm::_ref<atomic_be_t<u32>>(addr);
Expand Down Expand Up @@ -132,7 +132,7 @@ namespace rsx
if (const bool is_flip_sema = (offset == 0x10 && ctxt == CELL_GCM_CONTEXT_DMA_SEMAPHORE_R);
!is_flip_sema)
{
rsx->sync_point_request = true;
rsx->sync_point_request.release(true);
}

const u32 addr = get_address(offset, ctxt, HERE);
Expand Down