rsx: Resurgence of HLE GCM

This commit is contained in:
Eladash 2022-06-04 20:16:53 +03:00 committed by Megamouse
parent c4459dff40
commit f9bc7458d4
6 changed files with 128 additions and 56 deletions

View file

@ -298,13 +298,32 @@ error_code cellGcmBindZcull(u8 index, u32 offset, u32 width, u32 height, u32 cul
cellGcmSys.warning("cellGcmBindZcull(index=%d, offset=0x%x, width=%d, height=%d, cullStart=0x%x, zFormat=0x%x, aaFormat=0x%x, zCullDir=0x%x, zCullFormat=0x%x, sFunc=0x%x, sRef=0x%x, sMask=0x%x)", cellGcmSys.warning("cellGcmBindZcull(index=%d, offset=0x%x, width=%d, height=%d, cullStart=0x%x, zFormat=0x%x, aaFormat=0x%x, zCullDir=0x%x, zCullFormat=0x%x, sFunc=0x%x, sRef=0x%x, sMask=0x%x)",
index, offset, width, height, cullStart, zFormat, aaFormat, zCullDir, zCullFormat, sFunc, sRef, sMask); index, offset, width, height, cullStart, zFormat, aaFormat, zCullDir, zCullFormat, sFunc, sRef, sMask);
if (index >= rsx::limits::zculls_count) auto& gcm_cfg = g_fxo->get<gcm_config>();
GcmZcullInfo zcull{};
zcull.offset = offset;
zcull.width = width;
zcull.height = height;
zcull.cullStart = cullStart;
zcull.zFormat = zFormat;
zcull.aaFormat = aaFormat;
zcull.zcullDir = zCullDir;
zcull.zcullFormat = zCullFormat;
zcull.sFunc = sFunc;
zcull.sRef = sRef;
zcull.sMask = sMask;
zcull.bound = true;
const auto gcm_zcull = zcull.pack();
std::lock_guard lock(gcm_cfg.gcmio_mutex);
if (auto err = sys_rsx_context_attribute(0x5555'5555, 0x301, index, u64{gcm_zcull.region} << 32 | gcm_zcull.size, u64{gcm_zcull.start} << 32 | gcm_zcull.offset, u64{gcm_zcull.status0} << 32 | gcm_zcull.status1))
{ {
return CELL_GCM_ERROR_INVALID_VALUE; return err;
} }
rsx::get_current_renderer()->zculls[index].bound = true; vm::_ptr<CellGcmZcullInfo>(gcm_cfg.zculls_addr)[index] = gcm_zcull;
return CELL_OK; return CELL_OK;
} }
@ -391,6 +410,12 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> contex
render->main_mem_size = 0x10000000; render->main_mem_size = 0x10000000;
} }
render->isHLE = true;
render->local_mem_size = gcm_cfg.local_size;
ensure(sys_rsx_device_map(ppu, vm::var<u64>{}, vm::null, 0x8) == CELL_OK);
ensure(sys_rsx_context_allocate(ppu, vm::var<u32>{}, vm::var<u64>{}, vm::var<u64>{}, vm::var<u64>{}, 0, gcm_cfg.system_mode) == CELL_OK);
if (gcmMapEaIoAddress(ppu, ioAddress, 0, ioSize, false) != CELL_OK) if (gcmMapEaIoAddress(ppu, ioAddress, 0, ioSize, false) != CELL_OK)
{ {
return CELL_GCM_ERROR_FAILURE; return CELL_GCM_ERROR_FAILURE;
@ -403,18 +428,14 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> contex
gcm_cfg.current_config.memoryFrequency = 650000000; gcm_cfg.current_config.memoryFrequency = 650000000;
gcm_cfg.current_config.coreFrequency = 500000000; gcm_cfg.current_config.coreFrequency = 500000000;
// Create contexts const u32 rsx_ctxaddr = render->device_addr;
const auto area = vm::reserve_map(vm::rsx_context, 0, 0x10000000, 0x403);
const u32 rsx_ctxaddr = area ? area->alloc(0x400000) : 0;
ensure(rsx_ctxaddr); ensure(rsx_ctxaddr);
g_defaultCommandBufferBegin = ioAddress; g_defaultCommandBufferBegin = ioAddress;
g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024); g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024);
gcm_cfg.gcm_info.context_addr = rsx_ctxaddr; gcm_cfg.gcm_info.context_addr = rsx_ctxaddr;
gcm_cfg.gcm_info.control_addr = rsx_ctxaddr + 0x100000; gcm_cfg.gcm_info.control_addr = render->dma_address;
gcm_cfg.gcm_info.label_addr = rsx_ctxaddr + 0x300000;
gcm_cfg.current_context.begin.set(g_defaultCommandBufferBegin + 4096); // 4 kb reserved at the beginning gcm_cfg.current_context.begin.set(g_defaultCommandBufferBegin + 4096); // 4 kb reserved at the beginning
gcm_cfg.current_context.end.set(g_defaultCommandBufferBegin + 32 * 1024 - 4); // 4b at the end for jump gcm_cfg.current_context.end.set(g_defaultCommandBufferBegin + 32 * 1024 - 4); // 4b at the end for jump
gcm_cfg.current_context.current = gcm_cfg.current_context.begin; gcm_cfg.current_context.current = gcm_cfg.current_context.begin;
@ -430,21 +451,13 @@ error_code _cellGcmInitBody(ppu_thread& ppu, vm::pptr<CellGcmContextData> contex
// 0x40 is to offset CellGcmControl from RsxDmaControl // 0x40 is to offset CellGcmControl from RsxDmaControl
gcm_cfg.gcm_info.control_addr += 0x40; gcm_cfg.gcm_info.control_addr += 0x40;
auto& ctrl = vm::_ref<CellGcmControl>(gcm_cfg.gcm_info.control_addr);
ctrl.put = 0;
ctrl.get = 0;
ctrl.ref = 0; // Set later to -1 at RSX initialization
vm::var<u64> _tid; vm::var<u64> _tid;
vm::var<char[]> _name = vm::make_str("_gcm_intr_thread"); vm::var<char[]> _name = vm::make_str("_gcm_intr_thread");
ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, 0x10000, 0, 1, 0x4000, SYS_PPU_THREAD_CREATE_INTERRUPT, +_name); ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, 0x10000, 0, 1, 0x4000, SYS_PPU_THREAD_CREATE_INTERRUPT, +_name);
render->intr_thread = idm::get<named_thread<ppu_thread>>(static_cast<u32>(*_tid)); render->intr_thread = idm::get<named_thread<ppu_thread>>(static_cast<u32>(*_tid));
render->intr_thread->state -= cpu_flag::stop; render->intr_thread->state -= cpu_flag::stop;
render->isHLE = true; thread_ctrl::notify(*render->intr_thread);
render->label_addr = gcm_cfg.gcm_info.label_addr;
render->device_addr = gcm_cfg.gcm_info.context_addr;
render->local_mem_size = gcm_cfg.local_size;
render->init(gcm_cfg.gcm_info.control_addr - 0x40);
return CELL_OK; return CELL_OK;
} }
@ -516,7 +529,10 @@ void cellGcmSetFlipHandler(vm::ptr<void(u32)> handler)
{ {
cellGcmSys.warning("cellGcmSetFlipHandler(handler=*0x%x)", handler); cellGcmSys.warning("cellGcmSetFlipHandler(handler=*0x%x)", handler);
rsx::get_current_renderer()->flip_handler = handler; if (const auto rsx = rsx::get_current_renderer(); rsx->is_inited)
{
rsx->flip_handler = handler;
}
} }
error_code cellGcmSetFlipHandler2() error_code cellGcmSetFlipHandler2()
@ -665,51 +681,69 @@ void cellGcmSetUserHandler(vm::ptr<void(u32)> handler)
{ {
cellGcmSys.warning("cellGcmSetUserHandler(handler=*0x%x)", handler); cellGcmSys.warning("cellGcmSetUserHandler(handler=*0x%x)", handler);
rsx::get_current_renderer()->user_handler = handler; if (const auto rsx = rsx::get_current_renderer(); rsx->is_inited)
{
rsx->user_handler = handler;
}
} }
void cellGcmSetUserCommand(vm::ptr<CellGcmContextData> ctxt, u32 cause) void cellGcmSetUserCommand(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt, u32 cause)
{ {
cellGcmSys.todo("cellGcmSetUserCommand(ctxt=*0x%x, cause=0x%x)", ctxt, cause); cellGcmSys.trace("cellGcmSetUserCommand(ctxt=*0x%x, cause=0x%x)", ctxt, cause);
if (ctxt->current + 2 >= ctxt->end)
{
if (s32 res = ctxt->callback(ppu, ctxt, 8 /* ??? */))
{
cellGcmSys.error("cellGcmSetUserCommand(): callback failed (0x%08x)", res);
return;
}
}
rsx::make_command(ctxt->current, GCM_SET_USER_COMMAND, { cause });
} }
void cellGcmSetVBlankHandler(vm::ptr<void(u32)> handler) void cellGcmSetVBlankHandler(vm::ptr<void(u32)> handler)
{ {
cellGcmSys.warning("cellGcmSetVBlankHandler(handler=*0x%x)", handler); cellGcmSys.warning("cellGcmSetVBlankHandler(handler=*0x%x)", handler);
rsx::get_current_renderer()->vblank_handler = handler; if (const auto rsx = rsx::get_current_renderer(); rsx->is_inited)
{
rsx->vblank_handler = handler;
}
} }
void cellGcmSetWaitFlip(vm::ptr<CellGcmContextData> ctxt) void cellGcmSetWaitFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt)
{ {
cellGcmSys.warning("cellGcmSetWaitFlip(ctxt=*0x%x)", ctxt); cellGcmSys.trace("cellGcmSetWaitFlip(ctxt=*0x%x)", ctxt);
// TODO: emit RSX command for "wait flip" operation if (ctxt->current + 2 >= ctxt->end)
{
if (s32 res = ctxt->callback(ppu, ctxt, 8 /* ??? */))
{
cellGcmSys.error("cellGcmSetWaitFlip(): callback failed (0x%08x)", res);
return;
}
} }
error_code cellGcmSetWaitFlipUnsafe() rsx::make_command(ctxt->current, NV406E_SEMAPHORE_OFFSET, { 0x10u, 0 });
{ }
cellGcmSys.todo("cellGcmSetWaitFlipUnsafe()");
return CELL_OK; void cellGcmSetWaitFlipUnsafe(vm::ptr<CellGcmContextData> ctxt)
{
cellGcmSys.trace("cellGcmSetWaitFlipUnsafe(ctxt=*0x%x)", ctxt);
rsx::make_command(ctxt->current, NV406E_SEMAPHORE_OFFSET, { 0x10u, 0 });
} }
void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart, u32 zFormat, u32 aaFormat, u32 zCullDir, u32 zCullFormat, u32 sFunc, u32 sRef, u32 sMask) void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart, u32 zFormat, u32 aaFormat, u32 zCullDir, u32 zCullFormat, u32 sFunc, u32 sRef, u32 sMask)
{ {
cellGcmSys.todo("cellGcmSetZcull(index=%d, offset=0x%x, width=%d, height=%d, cullStart=0x%x, zFormat=0x%x, aaFormat=0x%x, zCullDir=0x%x, zCullFormat=0x%x, sFunc=0x%x, sRef=0x%x, sMask=0x%x)", cellGcmSys.warning("cellGcmSetZcull(index=%d, offset=0x%x, width=%d, height=%d, cullStart=0x%x, zFormat=0x%x, aaFormat=0x%x, zCullDir=0x%x, zCullFormat=0x%x, sFunc=0x%x, sRef=0x%x, sMask=0x%x)",
index, offset, width, height, cullStart, zFormat, aaFormat, zCullDir, zCullFormat, sFunc, sRef, sMask); index, offset, width, height, cullStart, zFormat, aaFormat, zCullDir, zCullFormat, sFunc, sRef, sMask);
auto& gcm_cfg = g_fxo->get<gcm_config>(); auto& gcm_cfg = g_fxo->get<gcm_config>();
if (index >= rsx::limits::zculls_count) GcmZcullInfo zcull{};
{
cellGcmSys.error("cellGcmSetZcull: CELL_GCM_ERROR_INVALID_VALUE");
return;
}
const auto render = rsx::get_current_renderer();
auto& zcull = render->zculls[index];
zcull.offset = offset; zcull.offset = offset;
zcull.width = width; zcull.width = width;
zcull.height = height; zcull.height = height;
@ -721,9 +755,18 @@ void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
zcull.sFunc = sFunc; zcull.sFunc = sFunc;
zcull.sRef = sRef; zcull.sRef = sRef;
zcull.sMask = sMask; zcull.sMask = sMask;
zcull.bound = (zCullFormat > 0); zcull.bound = true;
vm::_ptr<CellGcmZcullInfo>(gcm_cfg.zculls_addr)[index] = zcull.pack(); const auto gcm_zcull = zcull.pack();
// The second difference between BindZcull and this function (second is no return value) is that this function is not thread-safe
// But take care anyway
std::lock_guard lock(gcm_cfg.gcmio_mutex);
if (!sys_rsx_context_attribute(0x5555'5555, 0x301, index, u64{gcm_zcull.region} << 32 | gcm_zcull.size, u64{gcm_zcull.start} << 32 | gcm_zcull.offset, u64{gcm_zcull.status0} << 32 | gcm_zcull.status1))
{
vm::_ptr<CellGcmZcullInfo>(gcm_cfg.zculls_addr)[index] = gcm_zcull;
}
} }
error_code cellGcmUnbindTile(u8 index) error_code cellGcmUnbindTile(u8 index)
@ -878,7 +921,12 @@ void cellGcmSetGraphicsHandler(vm::ptr<void(u32)> handler)
void cellGcmSetQueueHandler(vm::ptr<void(u32)> handler) void cellGcmSetQueueHandler(vm::ptr<void(u32)> handler)
{ {
cellGcmSys.todo("cellGcmSetQueueHandler(handler=*0x%x)", handler); cellGcmSys.warning("cellGcmSetQueueHandler(handler=*0x%x)", handler);
if (const auto rsx = rsx::get_current_renderer(); rsx->is_inited)
{
rsx->queue_handler = handler;
}
} }
error_code cellGcmSetSecondVHandler(vm::ptr<void(u32)> handler) error_code cellGcmSetSecondVHandler(vm::ptr<void(u32)> handler)
@ -1264,18 +1312,17 @@ error_code _cellGcmSetFlipCommand2()
void _cellGcmSetFlipCommandWithWaitLabel(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id, u32 label_index, u32 label_value) void _cellGcmSetFlipCommandWithWaitLabel(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id, u32 label_index, u32 label_value)
{ {
cellGcmSys.todo("cellGcmSetFlipCommandWithWaitLabel(ctx=*0x%x, id=0x%x, label_index=0x%x, label_value=0x%x)", ctx, id, label_index, label_value); cellGcmSys.warning("cellGcmSetFlipCommandWithWaitLabel(ctx=*0x%x, id=0x%x, label_index=0x%x, label_value=0x%x)", ctx, id, label_index, label_value);
auto& gcm_cfg = g_fxo->get<gcm_config>(); auto& gcm_cfg = g_fxo->get<gcm_config>();
rsx::make_command(ctx->current, NV406E_SEMAPHORE_OFFSET, { label_index * 0x10, label_value });
if (auto error = gcmSetPrepareFlip<true>(ppu, ctx, id); error < 0) if (auto error = gcmSetPrepareFlip<true>(ppu, ctx, id); error < 0)
{ {
// TODO: On actual fw this function doesn't have error checks at all // TODO: On actual fw this function doesn't have error checks at all
cellGcmSys.error("cellGcmSetFlipCommandWithWaitLabel(): gcmSetPrepareFlip failed with %s", CellGcmError{error + 0u}); cellGcmSys.error("cellGcmSetFlipCommandWithWaitLabel(): gcmSetPrepareFlip failed with %s", CellGcmError{error + 0u});
} }
// TODO: Fix this (must enqueue WaitLabel command instead)
vm::write32(gcm_cfg.gcm_info.label_addr + 0x10 * label_index, label_value);
} }
error_code cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 comp, u16 base, u8 bank) error_code cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 comp, u16 base, u8 bank)

View file

@ -656,7 +656,10 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
//a6 high = status0 = (zcullDir << 1) | (zcullFormat << 2) | ((sFunc & 0xF) << 12) | (sRef << 16) | (sMask << 24); //a6 high = status0 = (zcullDir << 1) | (zcullFormat << 2) | ((sFunc & 0xF) << 12) | (sRef << 16) | (sMask << 24);
//a6 low = status1 = (0x2000 << 0) | (0x20 << 16); //a6 low = status1 = (0x2000 << 0) | (0x20 << 16);
ensure(a3 < std::size(render->zculls)); if (a3 >= std::size(render->zculls))
{
return SYS_RSX_CONTEXT_ATTRIBUTE_ERROR;
}
if (!render->is_fifo_idle()) if (!render->is_fifo_idle())
{ {

View file

@ -39,7 +39,6 @@ struct gcmInfo
u32 config_addr; u32 config_addr;
u32 context_addr; u32 context_addr;
u32 control_addr; u32 control_addr;
u32 label_addr;
u32 command_size = 0x400; u32 command_size = 0x400;
u32 segment_size = 0x100; u32 segment_size = 0x100;
}; };

View file

@ -703,15 +703,16 @@ namespace rsx
if (isHLE) if (isHLE)
{ {
if (vblank_handler) if (auto ptr = vblank_handler)
{ {
intr_thread->cmd_list intr_thread->cmd_list
({ ({
{ ppu_cmd::set_args, 1 }, u64{1}, { ppu_cmd::set_args, 1 }, u64{1},
{ ppu_cmd::lle_call, vblank_handler }, { ppu_cmd::lle_call, ptr },
{ ppu_cmd::sleep, 0 } { ppu_cmd::sleep, 0 }
}); });
intr_thread->cmd_notify++;
intr_thread->cmd_notify.notify_one(); intr_thread->cmd_notify.notify_one();
} }
} }
@ -2183,6 +2184,9 @@ namespace rsx
void thread::reset() void thread::reset()
{ {
rsx::method_registers.reset(); rsx::method_registers.reset();
m_graphics_state = pipeline_state::all_dirty;
m_rtts_dirty = true;
m_framebuffer_state_contested = false;
} }
void thread::init(u32 ctrlAddress) void thread::init(u32 ctrlAddress)
@ -3278,12 +3282,12 @@ namespace rsx
return; return;
} }
if (flip_handler) if (auto ptr = flip_handler)
{ {
intr_thread->cmd_list intr_thread->cmd_list
({ ({
{ ppu_cmd::set_args, 1 }, u64{ 1 }, { ppu_cmd::set_args, 1 }, u64{ 1 },
{ ppu_cmd::lle_call, flip_handler }, { ppu_cmd::lle_call, ptr },
{ ppu_cmd::sleep, 0 } { ppu_cmd::sleep, 0 }
}); });

View file

@ -641,6 +641,7 @@ namespace rsx
vm::ptr<void(u32)> flip_handler = vm::null; vm::ptr<void(u32)> flip_handler = vm::null;
vm::ptr<void(u32)> user_handler = vm::null; vm::ptr<void(u32)> user_handler = vm::null;
vm::ptr<void(u32)> vblank_handler = vm::null; vm::ptr<void(u32)> vblank_handler = vm::null;
vm::ptr<void(u32)> queue_handler = vm::null;
atomic_t<u64> vblank_count{0}; atomic_t<u64> vblank_count{0};
bool capture_current_frame = false; bool capture_current_frame = false;

View file

@ -1768,8 +1768,26 @@ namespace rsx
void flip_command(thread* rsx, u32, u32 arg) void flip_command(thread* rsx, u32, u32 arg)
{ {
ensure(rsx->isHLE); ensure(rsx->isHLE);
if (auto ptr = rsx->queue_handler)
{
rsx->intr_thread->cmd_list
({
{ ppu_cmd::set_args, 1 }, u64{1},
{ ppu_cmd::lle_call, ptr },
{ ppu_cmd::sleep, 0 }
});
rsx->intr_thread->cmd_notify++;
rsx->intr_thread->cmd_notify.notify_one();
}
rsx->reset(); rsx->reset();
nv4097::set_zcull_render_enable(rsx, 0, 0x3);
nv4097::set_render_mode(rsx, 0, 0x0100'0000);
rsx->on_frame_end(arg);
rsx->request_emu_flip(arg); rsx->request_emu_flip(arg);
vm::_ref<atomic_t<u128>>(rsx->label_addr + 0x10).store(u128{});
} }
void user_command(thread* rsx, u32, u32 arg) void user_command(thread* rsx, u32, u32 arg)
@ -1780,12 +1798,12 @@ namespace rsx
return; return;
} }
if (rsx->user_handler) if (auto ptr = rsx->user_handler)
{ {
rsx->intr_thread->cmd_list rsx->intr_thread->cmd_list
({ ({
{ ppu_cmd::set_args, 1 }, u64{arg}, { ppu_cmd::set_args, 1 }, u64{arg},
{ ppu_cmd::lle_call, rsx->user_handler }, { ppu_cmd::lle_call, ptr },
{ ppu_cmd::sleep, 0 } { ppu_cmd::sleep, 0 }
}); });