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: Implement cellGcmSysGetLastVBlankTime, add some error checks #8004

Merged
merged 7 commits into from
Apr 11, 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
12 changes: 6 additions & 6 deletions rpcs3/Emu/Cell/Modules/cellGcmSys.cpp
Expand Up @@ -266,7 +266,7 @@ error_code cellGcmBindTile(u8 index)
return CELL_GCM_ERROR_INVALID_VALUE;
}

rsx::get_current_renderer()->tiles[index].binded = true;
rsx::get_current_renderer()->tiles[index].bound = true;

return CELL_OK;
}
Expand All @@ -281,7 +281,7 @@ error_code cellGcmBindZcull(u8 index, u32 offset, u32 width, u32 height, u32 cul
return CELL_GCM_ERROR_INVALID_VALUE;
}

rsx::get_current_renderer()->zculls[index].binded = true;
rsx::get_current_renderer()->zculls[index].bound = true;

return CELL_OK;
}
Expand Down Expand Up @@ -701,7 +701,7 @@ void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
zcull.sFunc = sFunc;
zcull.sRef = sRef;
zcull.sMask = sMask;
zcull.binded = (zCullFormat > 0);
zcull.bound = (zCullFormat > 0);

vm::_ptr<CellGcmZcullInfo>(gcm_cfg->zculls_addr)[index] = zcull.pack();
}
Expand All @@ -715,7 +715,7 @@ error_code cellGcmUnbindTile(u8 index)
return CELL_GCM_ERROR_INVALID_VALUE;
}

rsx::get_current_renderer()->tiles[index].binded = false;
rsx::get_current_renderer()->tiles[index].bound = false;

return CELL_OK;
}
Expand All @@ -729,7 +729,7 @@ error_code cellGcmUnbindZcull(u8 index)
return CELL_GCM_ERROR_INVALID_VALUE;
}

rsx::get_current_renderer()->zculls[index].binded = false;
rsx::get_current_renderer()->zculls[index].bound = false;

return CELL_OK;
}
Expand Down Expand Up @@ -1301,7 +1301,7 @@ error_code cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch
tile.comp = comp;
tile.base = base;
tile.bank = bank;
tile.binded = (pitch > 0);
tile.bound = (pitch > 0);

vm::_ptr<CellGcmTileInfo>(gcm_cfg->tiles_addr)[index] = tile.pack();
return CELL_OK;
Expand Down
129 changes: 115 additions & 14 deletions rpcs3/Emu/Cell/lv2/sys_rsx.cpp
Expand Up @@ -74,7 +74,7 @@ void lv2_rsx_config::send_event(u64 data1, u64 event_flags, u64 data3) const
// Wait a bit before resending event
thread_ctrl::wait_for(100);

if (cpu && cpu->check_state())
if (Emu.IsStopped() || (cpu && cpu->check_state()))
{
error = 0;
break;
Expand Down Expand Up @@ -260,6 +260,7 @@ error_code sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> lpar_d
render->current_display_buffer = 0;
render->label_addr = vm::cast(*lpar_reports, HERE);
render->device_addr = rsx_cfg->device_addr;
render->dma_address = rsx_cfg->dma_address;
render->local_mem_size = rsx_cfg->memory_size;
render->init(vm::cast(*lpar_dma_control, HERE));

Expand Down Expand Up @@ -309,6 +310,11 @@ error_code sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 f
return CELL_EINVAL;
}

if (!render->is_fifo_idle())
{
sys_rsx.warning("sys_rsx_context_iomap(): RSX is not idle while mapping io");
}

vm::reader_lock rlock;

for (u32 addr = ea, end = ea + size; addr < end; addr += 0x100000)
Expand Down Expand Up @@ -355,6 +361,11 @@ error_code sys_rsx_context_iounmap(u32 context_id, u32 io, u32 size)
return CELL_EINVAL;
}

if (!render->is_fifo_idle())
{
sys_rsx.warning("sys_rsx_context_iounmap(): RSX is not idle while unmapping io");
}

vm::reader_lock rlock;

std::scoped_lock lock(s_rsxmem_mtx);
Expand Down Expand Up @@ -488,6 +499,10 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
return SYS_RSX_CONTEXT_ATTRIBUTE_ERROR;
}

std::lock_guard lock(s_rsxmem_mtx);

// Note: no error checking is being done

const u32 width = (a4 >> 32) & 0xFFFFFFFF;
const u32 height = a4 & 0xFFFFFFFF;
const u32 pitch = (a5 >> 32) & 0xFFFFFFFF;
Expand Down Expand Up @@ -545,21 +560,77 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64

verify(HERE), a3 < std::size(render->tiles);

if (!render->is_fifo_idle())
{
sys_rsx.warning("sys_rsx_context_attribute(): RSX is not idle while setting tile");
}

auto& tile = render->tiles[a3];

// When tile is going to be unbinded, we can use it as a hint that the address will no longer be used as a surface and can be removed/invalidated
const u32 location = ((a4 >> 32) & 0x3) - 1;
const u32 offset = ((((a4 >> 32) & 0x7FFFFFFF) >> 16) * 0x10000);
const u32 size = ((((a4 & 0x7FFFFFFF) >> 16) + 1) * 0x10000) - offset;
const u32 pitch = (((a5 >> 32) & 0xFFFFFFFF) >> 8) * 0x100;
const u32 comp = ((a5 & 0xFFFFFFFF) >> 26) & 0xF;
const u32 base = (a5 & 0xFFFFFFFF) & 0x7FF;
const u32 bank = (((a4 >> 32) & 0xFFFFFFFF) >> 4) & 0xF;
const bool bound = ((a4 >> 32) & 0x3) != 0;

const auto range = utils::address_range::start_length(offset, size);

if (bound)
{
if (!size || !pitch)
{
return CELL_EINVAL;
}

u32 limit = UINT32_MAX;

switch (location)
{
case CELL_GCM_LOCATION_MAIN: limit = render->main_mem_size; break;
case CELL_GCM_LOCATION_LOCAL: limit = render->local_mem_size; break;
default: fmt::throw_exception("sys_rsx_context_attribute(): Unexpected location value (location=0x%x)" HERE, location);
}

if (!range.valid() || range.end >= limit)
{
return CELL_EINVAL;
}

// Hardcoded value in gcm
verify(HERE), !!(a5 & (1 << 30));
}

std::lock_guard lock(s_rsxmem_mtx);

// When tile is going to be unbound, we can use it as a hint that the address will no longer be used as a surface and can be removed/invalidated
// Todo: There may be more checks such as format/size/width can could be done
if (tile.binded && a5 == 0)
if (tile.bound && !bound)
render->notify_tile_unbound(static_cast<u32>(a3));

tile.location = ((a4 >> 32) & 0xF) - 1;
tile.offset = ((((a4 >> 32) & 0x7FFFFFFF) >> 16) * 0x10000);
tile.size = ((((a4 & 0x7FFFFFFF) >> 16) + 1) * 0x10000) - tile.offset;
tile.pitch = (((a5 >> 32) & 0xFFFFFFFF) >> 8) * 0x100;
tile.comp = ((a5 & 0xFFFFFFFF) >> 26) & 0xF;
tile.base = (a5 & 0xFFFFFFFF) & 0x7FF;
tile.bank = (((a4 >> 32) & 0xFFFFFFFF) >> 4) & 0xF;
tile.binded = a5 != 0;
if (location == CELL_GCM_LOCATION_MAIN && bound)
{
vm::reader_lock rlock;

for (u32 offs = (offset & ~0xfffff); offs <= range.end; offs += 0x100000)
{
if (render->iomap_table.io[offs >> 20] == umax)
{
return CELL_EINVAL;
}
}
}

tile.location = location;
tile.offset = offset;
tile.size = size;
tile.pitch = pitch;
tile.comp = comp;
tile.base = base;
tile.bank = base;
tile.bound = bound;
}
break;

Expand All @@ -574,19 +645,41 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64

verify(HERE), a3 < std::size(render->zculls);

if (!render->is_fifo_idle())
{
sys_rsx.warning("sys_rsx_context_attribute(): RSX is not idle while setting zcull");
}

const u32 offset = (a5 & 0xFFFFFFFF);
const bool bound = (a6 & 0xFFFFFFFF) != 0;

if (bound)
{
if (offset >= render->local_mem_size)
{
return CELL_EINVAL;
}

// Hardcoded values in gcm
verify(HERE), !!(a4 & (1ull << 32)), (a6 & 0xFFFFFFFF) == 0u + ((0x2000 << 0) | (0x20 << 16));
}

std::lock_guard lock(s_rsxmem_mtx);

auto &zcull = render->zculls[a3];

zcull.zFormat = ((a4 >> 32) >> 4) & 0xF;
zcull.aaFormat = ((a4 >> 32) >> 8) & 0xF;
zcull.width = ((a4 & 0xFFFFFFFF) >> 22) << 6;
zcull.height = (((a4 & 0xFFFFFFFF) >> 6) & 0xFF) << 6;
zcull.cullStart = (a5 >> 32);
zcull.offset = (a5 & 0xFFFFFFFF);
zcull.offset = offset;
zcull.zcullDir = ((a6 >> 32) >> 1) & 0x1;
zcull.zcullFormat = ((a6 >> 32) >> 2) & 0x3FF;
zcull.sFunc = ((a6 >> 32) >> 12) & 0xF;
zcull.sRef = ((a6 >> 32) >> 16) & 0xFF;
zcull.sMask = ((a6 >> 32) >> 24) & 0xFF;
zcull.binded = (a6 & 0xFFFFFFFF) != 0;
zcull.bound = bound;
}
break;

Expand Down Expand Up @@ -625,8 +718,16 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64

// 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;

const u64 current_time = rsxTimeStamp();

driverInfo.head[a3].lastSecondVTime = current_time;

// Note: not atomic
driverInfo.head[a3].lastVTimeLow = static_cast<u32>(current_time);
driverInfo.head[a3].lastVTimeHigh = static_cast<u32>(current_time >> 32);

driverInfo.head[a3].vBlankCount++;
driverInfo.head[a3].lastSecondVTime = rsxTimeStamp();

u64 event_flags = SYS_RSX_EVENT_VBLANK;

Expand Down
11 changes: 8 additions & 3 deletions rpcs3/Emu/Cell/lv2/sys_rsx.h
Expand Up @@ -27,12 +27,12 @@ struct RsxDriverInfo
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<u32> lastVTimeLow; // 0x1C last time for first vhandler freq (low 32-bits)
be_t<u64> lastSecondVTime; // 0x20 last time for second vhandler freq
be_t<u64> unk4; // 0x28
atomic_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
be_t<u32> lastVTimeHigh; // 0x3C last time for first vhandler freq (high 32-bits)
} head[8]; // size = 0x40, 0x200

be_t<u32> unk7; // 0x12B8
Expand Down Expand Up @@ -117,6 +117,11 @@ struct RsxDisplayInfo
be_t<u32> pitch;
be_t<u32> width;
be_t<u32> height;

bool valid() const
{
return height != 0u && width != 0u;
}
};

struct lv2_rsx_config
Expand Down
8 changes: 4 additions & 4 deletions rpcs3/Emu/RSX/Capture/rsx_capture.cpp
Expand Up @@ -371,8 +371,8 @@ namespace rsx
auto& tstate = tilestate.tiles[i];
tstate.tile = tile.tile;
tstate.limit = tile.limit;
tstate.pitch = rsx->tiles[i].binded ? u32{tile.pitch} : 0;
tstate.format = rsx->tiles[i].binded ? u32{tile.format} : 0;
tstate.pitch = rsx->tiles[i].bound ? u32{tile.pitch} : 0;
tstate.format = rsx->tiles[i].bound ? u32{tile.format} : 0;
}

for (u32 i = 0; i < limits::zculls_count; ++i)
Expand All @@ -383,8 +383,8 @@ namespace rsx
zcstate.size = zc.size;
zcstate.start = zc.start;
zcstate.offset = zc.offset;
zcstate.status0 = rsx->zculls[i].binded ? u32{zc.status0} : 0;
zcstate.status1 = rsx->zculls[i].binded ? u32{zc.status1} : 0;
zcstate.status0 = rsx->zculls[i].bound ? u32{zc.status0} : 0;
zcstate.status1 = rsx->zculls[i].bound ? u32{zc.status1} : 0;
}

const u64 tsnum = XXH64(&tilestate, sizeof(frame_capture_data::tile_state), 0);
Expand Down
4 changes: 2 additions & 2 deletions rpcs3/Emu/RSX/Capture/rsx_replay.cpp
Expand Up @@ -200,7 +200,7 @@ namespace rsx
continue;

// wait until rsx idle and at our first 'stop' to apply state
while (!Emu.IsStopped() && (render->ctrl->get != render->ctrl->put) && (render->ctrl->get != fifo_stops[stopIdx]))
while (!Emu.IsStopped() && !render->is_fifo_idle() && (render->ctrl->get != fifo_stops[stopIdx]))
{
while (Emu.IsPaused())
std::this_thread::sleep_for(10ms);
Expand All @@ -222,7 +222,7 @@ namespace rsx
u32 end = fifo_stops.back();
render->ctrl->put = end;

while (render->ctrl->get != end && !Emu.IsStopped())
while (!render->is_fifo_idle() && !Emu.IsStopped())
{
while (Emu.IsPaused())
std::this_thread::sleep_for(10ms);
Expand Down
12 changes: 10 additions & 2 deletions rpcs3/Emu/RSX/Common/texture_cache_helpers.h
Expand Up @@ -189,13 +189,21 @@ namespace rsx
for (u32 i = 0; i < renderer->display_buffers_count; ++i)
{
const auto& buffer = renderer->display_buffers[i];
const u32 pitch = buffer.pitch? static_cast<u32>(buffer.pitch) : g_fxo->get<rsx::avconf>()->get_bpp() * buffer.width;

if (!buffer.valid())
{
continue;
}

const u32 bpp = g_fxo->get<rsx::avconf>()->get_bpp();

const u32 pitch = buffer.pitch ? +buffer.pitch : bpp * buffer.width;
if (pitch != dst_pitch)
{
continue;
}

const auto buffer_range = address_range::start_length(rsx::constants::local_mem_base + buffer.offset, pitch * buffer.height);
const auto buffer_range = address_range::start_length(rsx::get_address(buffer.offset, CELL_GCM_LOCATION_LOCAL, HERE), pitch * (buffer.height - 1) + (buffer.width * bpp));
if (dst_range.inside(buffer_range))
{
// Match found
Expand Down
4 changes: 2 additions & 2 deletions rpcs3/Emu/RSX/GCM.h
Expand Up @@ -111,7 +111,7 @@ struct GcmZcullInfo
u32 sFunc;
u32 sRef;
u32 sMask;
bool binded = false;
bool bound = false;

CellGcmZcullInfo pack() const
{
Expand All @@ -137,7 +137,7 @@ struct GcmTileInfo
u32 comp;
u32 base;
u32 bank;
bool binded = false;
bool bound = false;

CellGcmTileInfo pack() const
{
Expand Down
6 changes: 3 additions & 3 deletions rpcs3/Emu/RSX/GL/GLHelpers.cpp
Expand Up @@ -291,23 +291,23 @@ namespace gl
glReadPixels(coord.x, coord.y, coord.width, coord.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), nullptr);
}

fbo fbo::get_binded_draw_buffer()
fbo fbo::get_bound_draw_buffer()
{
GLint value;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &value);

return{ static_cast<GLuint>(value) };
}

fbo fbo::get_binded_read_buffer()
fbo fbo::get_bound_read_buffer()
{
GLint value;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &value);

return{ static_cast<GLuint>(value) };
}

fbo fbo::get_binded_buffer()
fbo fbo::get_bound_buffer()
{
GLint value;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value);
Expand Down