rsx/gcm: Implement rsx dma. Refactor gcm/rsx to not be as codependent

This commit is contained in:
Jake 2017-07-25 21:33:32 -05:00 committed by Ivan
parent 607d2486ea
commit d9a693019b
14 changed files with 315 additions and 181 deletions

View File

@ -26,16 +26,19 @@ const u32 tiled_pitches[] = {
0x00010000
};
struct CellGcmSysConfig {
u32 zculls_addr;
vm::ptr<CellGcmDisplayInfo> gcm_buffers{ vm::null };
u32 tiles_addr;
u32 ctxt_addr;
CellGcmConfig current_config;
CellGcmContextData current_context;
gcmInfo gcm_info;
};
u64 system_mode = 0;
u32 local_size = 0;
u32 local_addr = 0;
u64 system_mode = 0;
CellGcmConfig current_config;
CellGcmContextData current_context;
gcmInfo gcm_info;
u32 map_offset_addr = 0;
u32 map_offset_pos = 0;
// Auxiliary functions
@ -82,7 +85,12 @@ void InitOffsetTable()
u32 cellGcmGetLabelAddress(u8 index)
{
cellGcmSys.trace("cellGcmGetLabelAddress(index=%d)", index);
return gcm_info.label_addr + 0x10 * index;
const auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return 0;
return m_config->gcm_info.label_addr + 0x10 * index;
}
vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 location)
@ -94,7 +102,7 @@ vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 lo
cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong local index (%d)", index);
return vm::null;
}
return vm::ptr<CellGcmReportData>::make(0xC0000000 + index * 0x10);
return vm::ptr<CellGcmReportData>::make(0x40301400 + index * 0x10);
}
if (location == CELL_GCM_LOCATION_MAIN) {
@ -117,7 +125,7 @@ u64 cellGcmGetTimeStamp(u32 index)
cellGcmSys.error("cellGcmGetTimeStamp: Wrong local index (%d)", index);
return 0;
}
return vm::read64(0xC0000000 + index * 0x10);
return vm::read64(0x40301400 + index * 0x10);
}
u32 cellGcmGetCurrentField()
@ -144,7 +152,7 @@ u32 cellGcmGetNotifyDataAddress(u32 index)
*/
vm::ptr<CellGcmReportData> _cellGcmFunc12()
{
return vm::ptr<CellGcmReportData>::make(0xC0000000); // TODO
return vm::ptr<CellGcmReportData>::make(0x40301400); // TODO
}
u32 cellGcmGetReport(u32 type, u32 index)
@ -172,7 +180,7 @@ u32 cellGcmGetReportDataAddress(u32 index)
cellGcmSys.error("cellGcmGetReportDataAddress: Wrong local index (%d)", index);
return 0;
}
return 0xC0000000 + index * 0x10;
return 0x40301400 + index * 0x10;
}
u32 cellGcmGetReportDataLocation(u32 index, u32 location)
@ -192,7 +200,7 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location)
cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong local index (%d)", index);
return 0;
}
return vm::read64(0xC0000000 + index * 0x10);
return vm::read64(0x40301400 + index * 0x10);
}
if (location == CELL_GCM_LOCATION_MAIN) {
@ -214,20 +222,31 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location)
u32 cellGcmGetControlRegister()
{
cellGcmSys.trace("cellGcmGetControlRegister()");
const auto m_config = fxm::get<CellGcmSysConfig>();
return gcm_info.control_addr;
if (!m_config)
return 0;
return m_config->gcm_info.control_addr;
}
u32 cellGcmGetDefaultCommandWordSize()
{
cellGcmSys.trace("cellGcmGetDefaultCommandWordSize()");
return gcm_info.command_size;
const auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return 0;
return m_config->gcm_info.command_size;
}
u32 cellGcmGetDefaultSegmentWordSize()
{
cellGcmSys.trace("cellGcmGetDefaultSegmentWordSize()");
return gcm_info.segment_size;
const auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return 0;
return m_config->gcm_info.segment_size;
}
s32 cellGcmInitDefaultFifoMode(s32 mode)
@ -280,8 +299,10 @@ s32 cellGcmBindZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
void cellGcmGetConfiguration(vm::ptr<CellGcmConfig> config)
{
cellGcmSys.trace("cellGcmGetConfiguration(config=*0x%x)", config);
const auto m_config = fxm::get<CellGcmSysConfig>();
*config = current_config;
if (m_config)
*config = m_config->current_config;
}
u32 cellGcmGetFlipStatus()
@ -297,9 +318,9 @@ u32 cellGcmGetTiledPitchSize(u32 size)
{
cellGcmSys.trace("cellGcmGetTiledPitchSize(size=%d)", size);
for (size_t i=0; i < sizeof(tiled_pitches) / sizeof(tiled_pitches[0]) - 1; i++) {
if (tiled_pitches[i] < size && size <= tiled_pitches[i+1]) {
return tiled_pitches[i+1];
for (size_t i = 0; i < sizeof(tiled_pitches) / sizeof(tiled_pitches[0]) - 1; i++) {
if (tiled_pitches[i] < size && size <= tiled_pitches[i + 1]) {
return tiled_pitches[i + 1];
}
}
return 0;
@ -324,8 +345,12 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
{
cellGcmSys.warning("_cellGcmInitBody(context=**0x%x, cmdSize=0x%x, ioSize=0x%x, ioAddress=0x%x)", context, cmdSize, ioSize, ioAddress);
current_config.ioAddress = 0;
current_config.localAddress = 0;
auto m_config = fxm::make<CellGcmSysConfig>();
if (!m_config)
return CELL_GCM_ERROR_FAILURE;
m_config->current_config.ioAddress = 0;
m_config->current_config.localAddress = 0;
local_size = 0;
local_addr = 0;
@ -356,33 +381,42 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
return CELL_GCM_ERROR_FAILURE;
}
map_offset_addr = 0;
map_offset_pos = 0;
current_config.ioSize = ioSize;
current_config.ioAddress = ioAddress;
current_config.localSize = local_size;
current_config.localAddress = local_addr;
current_config.memoryFrequency = 650000000;
current_config.coreFrequency = 500000000;
m_config->current_config.ioSize = ioSize;
m_config->current_config.ioAddress = ioAddress;
m_config->current_config.localSize = local_size;
m_config->current_config.localAddress = local_addr;
m_config->current_config.memoryFrequency = 650000000;
m_config->current_config.coreFrequency = 500000000;
// Create contexts
u32 addr = vm::falloc(0x40000000, 0x400000);
if (addr == 0 || addr != 0x40000000)
fmt::throw_exception("Failed to alloc 0x40000000.");
g_defaultCommandBufferBegin = ioAddress;
g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024);
gcm_info.context_addr = vm::alloc(0x1000, vm::main);
gcm_info.control_addr = vm::alloc(0x1000, vm::main);
gcm_info.label_addr = vm::alloc(0x1000, vm::main); // ???
m_config->gcm_info.context_addr = 0x40000000;
m_config->gcm_info.control_addr = 0x40100000;
m_config->gcm_info.label_addr = 0x40300000;
current_context.begin.set(g_defaultCommandBufferBegin + 4096); // 4 kb reserved at the beginning
current_context.end.set(g_defaultCommandBufferBegin + 32 * 1024 - 4); // 4b at the end for jump
current_context.current = current_context.begin;
current_context.callback.set(ppu_function_manager::addr + 8 * FIND_FUNC(cellGcmCallback));
m_config->current_context.begin.set(g_defaultCommandBufferBegin + 4096); // 4 kb reserved at the beginning
m_config->current_context.end.set(g_defaultCommandBufferBegin + 32 * 1024 - 4); // 4b at the end for jump
m_config->current_context.current = m_config->current_context.begin;
m_config->current_context.callback.set(ppu_function_manager::addr + 8 * FIND_FUNC(cellGcmCallback));
vm::_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
context->set(gcm_info.context_addr);
m_config->ctxt_addr = context.addr();
m_config->gcm_buffers.set(vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main));
m_config->zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
m_config->tiles_addr = vm::alloc(sizeof(CellGcmTileInfo) * 15, vm::main);
auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr);
vm::_ref<CellGcmContextData>(m_config->gcm_info.context_addr) = m_config->current_context;
context->set(m_config->gcm_info.context_addr);
// 0x40 is to offset CellGcmControl from RsxDmaControl
m_config->gcm_info.control_addr += 0x40;
auto& ctrl = vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr);
ctrl.put = 0;
ctrl.get = 0;
ctrl.ref = -1;
@ -390,15 +424,9 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
const auto render = fxm::get<GSRender>();
render->intr_thread = idm::make_ptr<ppu_thread>("_gcm_intr_thread", 1, 0x4000);
render->intr_thread->run();
render->ctxt_addr = context.addr();
render->gcm_buffers.set(vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main));
render->zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
render->tiles_addr = vm::alloc(sizeof(CellGcmTileInfo) * 15, vm::main);
render->gcm_buffers_count = 0;
render->gcm_current_buffer = 0;
render->main_mem_addr = 0;
render->label_addr = gcm_info.label_addr;
render->init(g_defaultCommandBufferBegin, cmdSize, gcm_info.control_addr, local_addr);
render->label_addr = m_config->gcm_info.label_addr;
render->init(ioAddress, ioSize, m_config->gcm_info.control_addr - 0x40, local_addr);
return CELL_OK;
}
@ -431,6 +459,10 @@ s32 cellGcmSetDisplayBuffer(u8 id, u32 offset, u32 pitch, u32 width, u32 height)
{
cellGcmSys.trace("cellGcmSetDisplayBuffer(id=0x%x, offset=0x%x, pitch=%d, width=%d, height=%d)", id, offset, width ? pitch / width : pitch, width, height);
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return CELL_GCM_ERROR_FAILURE;
if (id > 7)
{
cellGcmSys.error("cellGcmSetDisplayBuffer: CELL_GCM_ERROR_FAILURE");
@ -439,16 +471,21 @@ s32 cellGcmSetDisplayBuffer(u8 id, u32 offset, u32 pitch, u32 width, u32 height)
const auto render = fxm::get<GSRender>();
auto buffers = render->gcm_buffers;
auto buffers = render->display_buffers;
buffers[id].offset = offset;
buffers[id].pitch = pitch;
buffers[id].width = width;
buffers[id].height = height;
if (id + 1 > render->gcm_buffers_count)
m_config->gcm_buffers[id].offset = offset;
m_config->gcm_buffers[id].pitch = pitch;
m_config->gcm_buffers[id].width = width;
m_config->gcm_buffers[id].height = height;
if (id + 1 > render->display_buffers_count)
{
render->gcm_buffers_count = id + 1;
render->display_buffers_count = id + 1;
}
return CELL_OK;
@ -465,17 +502,7 @@ void cellGcmSetFlipMode(u32 mode)
{
cellGcmSys.warning("cellGcmSetFlipMode(mode=%d)", mode);
switch (mode)
{
case CELL_GCM_DISPLAY_HSYNC:
case CELL_GCM_DISPLAY_VSYNC:
case CELL_GCM_DISPLAY_HSYNC_WITH_NOISE:
fxm::get<GSRender>()->flip_mode = mode;
break;
default:
break;
}
fxm::get<GSRender>()->requested_vsync.store(mode == CELL_GCM_DISPLAY_VSYNC);
}
void cellGcmSetFlipStatus()
@ -488,6 +515,9 @@ void cellGcmSetFlipStatus()
s32 cellGcmSetPrepareFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt, u32 id)
{
cellGcmSys.trace("cellGcmSetPrepareFlip(ctxt=*0x%x, id=0x%x)", ctxt, id);
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return CELL_GCM_ERROR_FAILURE;
if (id > 7)
{
@ -506,9 +536,9 @@ s32 cellGcmSetPrepareFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt, u32
const u32 cmd_size = rsx::make_command(ctxt->current, GCM_FLIP_COMMAND, { id });
if (ctxt.addr() == gcm_info.context_addr)
if (ctxt.addr() == m_config->gcm_info.context_addr)
{
vm::_ref<CellGcmControl>(gcm_info.control_addr).put += cmd_size;
vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr).put += cmd_size;
}
return id;
@ -535,15 +565,12 @@ void cellGcmSetSecondVFrequency(u32 freq)
switch (freq)
{
case CELL_GCM_DISPLAY_FREQUENCY_59_94HZ:
render->frequency_mode = freq;
render->fps_limit = 59.94;
break;
case CELL_GCM_DISPLAY_FREQUENCY_SCANOUT:
render->frequency_mode = freq;
cellGcmSys.todo("Unimplemented display frequency: Scanout");
break;
case CELL_GCM_DISPLAY_FREQUENCY_DISABLE:
render->frequency_mode = freq;
cellGcmSys.todo("Unimplemented display frequency: Disabled");
break;
default:
@ -557,6 +584,10 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u
cellGcmSys.warning("cellGcmSetTileInfo(index=%d, location=%d, offset=%d, size=%d, pitch=%d, comp=%d, base=%d, bank=%d)",
index, location, offset, size, pitch, comp, base, bank);
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return CELL_GCM_ERROR_FAILURE;
if (index >= rsx::limits::tiles_count || base >= 2048 || bank >= 4)
{
cellGcmSys.error("cellGcmSetTileInfo: CELL_GCM_ERROR_INVALID_VALUE");
@ -591,7 +622,7 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u
tile.base = base;
tile.bank = bank;
vm::_ptr<CellGcmTileInfo>(render->tiles_addr)[index] = tile.pack();
vm::_ptr<CellGcmTileInfo>(m_config->tiles_addr)[index] = tile.pack();
return CELL_OK;
}
@ -624,7 +655,7 @@ void cellGcmSetWaitFlip(vm::ptr<CellGcmContextData> ctxt)
s32 cellGcmSetWaitFlipUnsafe()
{
cellGcmSys.todo("cellGcmSetWaitFlipUnsafe()");
return CELL_OK;
}
@ -633,6 +664,10 @@ void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
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)",
index, offset, width, height, cullStart, zFormat, aaFormat, zCullDir, zCullFormat, sFunc, sRef, sMask);
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return;
if (index >= rsx::limits::zculls_count)
{
cellGcmSys.error("cellGcmSetZcull: CELL_GCM_ERROR_INVALID_VALUE");
@ -643,7 +678,7 @@ void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
auto& zcull = render->zculls[index];
zcull.offset = offset;
zcull.width = width;
zcull.width = width;
zcull.height = height;
zcull.cullStart = cullStart;
zcull.zFormat = zFormat;
@ -654,7 +689,7 @@ void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
zcull.sRef = sRef;
zcull.sMask = sMask;
vm::_ptr<CellGcmZcullInfo>(render->zculls_addr)[index] = zcull.pack();
vm::_ptr<CellGcmZcullInfo>(m_config->zculls_addr)[index] = zcull.pack();
}
s32 cellGcmUnbindTile(u8 index)
@ -690,26 +725,35 @@ s32 cellGcmUnbindZcull(u8 index)
u32 cellGcmGetTileInfo()
{
cellGcmSys.warning("cellGcmGetTileInfo()");
return fxm::get<GSRender>()->tiles_addr;
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return 0;
return m_config->tiles_addr;
}
u32 cellGcmGetZcullInfo()
{
cellGcmSys.warning("cellGcmGetZcullInfo()");
return fxm::get<GSRender>()->zculls_addr;
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return 0;
return m_config->zculls_addr;
}
u32 cellGcmGetDisplayInfo()
{
cellGcmSys.warning("cellGcmGetDisplayInfo()");
return fxm::get<GSRender>()->gcm_buffers.addr();
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return 0;
return m_config->gcm_buffers.addr();
}
s32 cellGcmGetCurrentDisplayBufferId(vm::ptr<u8> id)
{
cellGcmSys.warning("cellGcmGetCurrentDisplayBufferId(id=*0x%x)", id);
if ((*id = fxm::get<GSRender>()->gcm_current_buffer) > UINT8_MAX)
if ((*id = fxm::get<GSRender>()->current_display_buffer) > UINT8_MAX)
{
fmt::throw_exception("Unexpected" HERE);
}
@ -876,7 +920,7 @@ s32 cellGcmIoOffsetToAddress(u32 ioOffset, vm::ptr<u32> address)
u32 realAddr;
if (!RSXIOMem.getRealAddr(ioOffset, realAddr))
if (!RSXIOMem.getRealAddr(ioOffset, realAddr))
return CELL_GCM_ERROR_FAILURE;
*address = realAddr;
@ -898,7 +942,6 @@ s32 gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict)
{
offsetTable.ioAddress[(ea >> 20) + i] = (io >> 20) + i;
offsetTable.eaAddress[(io >> 20) + i] = (ea >> 20) + i;
render->strict_ordering[(io >> 20) + i] = is_strict;
}
}
else
@ -948,6 +991,7 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr<u32> offset)
{
cellGcmSys.warning("cellGcmMapMainMemory(ea=0x%x, size=0x%x, offset=*0x%x)", ea, size, offset);
if (size == 0) return CELL_OK;
if ((ea & 0xFFFFF) || (size & 0xFFFFF)) return CELL_GCM_ERROR_FAILURE;
u32 io = RSXIOMem.Map(ea, size);
@ -962,7 +1006,6 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr<u32> offset)
{
offsetTable.ioAddress[(ea >> 20) + i] = (u16)((io >> 20) + i);
offsetTable.eaAddress[(io >> 20) + i] = (u16)((ea >> 20) + i);
render->strict_ordering[(io >> 20) + i] = false;
}
*offset = io;
@ -1113,23 +1156,27 @@ s32 cellGcmSetCursorImageOffset(u32 offset)
void cellGcmSetDefaultCommandBuffer()
{
cellGcmSys.warning("cellGcmSetDefaultCommandBuffer()");
vm::write32(fxm::get<GSRender>()->ctxt_addr, gcm_info.context_addr);
auto m_config = fxm::get<CellGcmSysConfig>();
if (m_config)
vm::write32(m_config->ctxt_addr, m_config->gcm_info.context_addr);
}
s32 cellGcmSetDefaultCommandBufferAndSegmentWordSize(u32 bufferSize, u32 segmentSize)
{
cellGcmSys.warning("cellGcmSetDefaultCommandBufferAndSegmentWordSize(bufferSize=0x%x, segmentSize=0x%x)", bufferSize, segmentSize);
const auto& put = vm::_ref<CellGcmControl>(gcm_info.control_addr).put;
const auto& get = vm::_ref<CellGcmControl>(gcm_info.control_addr).get;
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return CELL_GCM_ERROR_FAILURE;
const auto& put = vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr).put;
const auto& get = vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr).get;
if (put != 0x1000 || get != 0x1000 || bufferSize < segmentSize * 2)
{
return CELL_GCM_ERROR_FAILURE;
}
gcm_info.command_size = bufferSize;
gcm_info.segment_size = segmentSize;
m_config->gcm_info.command_size = bufferSize;
m_config->gcm_info.segment_size = segmentSize;
return CELL_OK;
}
@ -1148,9 +1195,11 @@ s32 _cellGcmSetFlipCommand(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctx, u32
s32 _cellGcmSetFlipCommandWithWaitLabel(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id, u32 label_index, u32 label_value)
{
cellGcmSys.trace("cellGcmSetFlipCommandWithWaitLabel(ctx=*0x%x, id=0x%x, label_index=0x%x, label_value=0x%x)", ctx, id, label_index, label_value);
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return CELL_GCM_ERROR_FAILURE;
s32 res = cellGcmSetPrepareFlip(ppu, ctx, id);
vm::write32(gcm_info.label_addr + 0x10 * label_index, label_value);
vm::write32(m_config->gcm_info.label_addr + 0x10 * label_index, label_value);
return res < 0 ? CELL_GCM_ERROR_FAILURE : CELL_OK;
}
@ -1159,6 +1208,10 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co
cellGcmSys.warning("cellGcmSetTile(index=%d, location=%d, offset=%d, size=%d, pitch=%d, comp=%d, base=%d, bank=%d)",
index, location, offset, size, pitch, comp, base, bank);
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return CELL_GCM_ERROR_FAILURE;
// Copied form cellGcmSetTileInfo
if (index >= rsx::limits::tiles_count || base >= 2048 || bank >= 4)
{
@ -1194,7 +1247,7 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co
tile.base = base;
tile.bank = bank;
vm::_ptr<CellGcmTileInfo>(render->tiles_addr)[index] = tile.pack();
vm::_ptr<CellGcmTileInfo>(m_config->tiles_addr)[index] = tile.pack();
return CELL_OK;
}
@ -1286,8 +1339,11 @@ static bool isInCommandBufferExcept(u32 getPos, u32 bufferBegin, u32 bufferEnd)
s32 cellGcmCallback(ppu_thread& ppu, vm::ptr<CellGcmContextData> context, u32 count)
{
cellGcmSys.trace("cellGcmCallback(context=*0x%x, count=0x%x)", context, count);
auto m_config = fxm::get<CellGcmSysConfig>();
if (!m_config)
return CELL_GCM_ERROR_FAILURE;
auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr);
auto& ctrl = vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr);
// Flush command buffer (ie allow RSX to read up to context->current)
ctrl.put.exchange(getOffsetFromAddress(context->current.addr()));
@ -1428,4 +1484,4 @@ DECLARE(ppu_module_manager::cellGcmSys)("cellGcmSys", []()
// Special
REG_FUNC(cellGcmSys, cellGcmCallback).flags = MFF_HIDDEN;
});
});

View File

@ -1,5 +1,44 @@
#pragma once
struct RsxDmaControl {
u8 resv[0x40];
atomic_be_t<u32> put;
atomic_be_t<u32> get;
atomic_be_t<u32> ref;
be_t<u32> unk[2];
be_t<u32> unk1;
};
struct RsxSemaphore {
be_t<u32> val;
be_t<u32> pad;
be_t<u64> timestamp;
};
struct RsxNotify {
be_t<u64> timestamp;
be_t<u64> zero;
};
struct RsxReport {
be_t<u64> timestamp;
be_t<u32> val;
be_t<u32> pad;
};
struct RsxReports {
RsxSemaphore semaphore[0x100];
RsxNotify notify[64];
RsxReport report[2048];
};
struct RsxDisplayInfo {
be_t<u32> offset;
be_t<u32> pitch;
be_t<u32> width;
be_t<u32> height;
};
// SysCalls
s32 sys_rsx_device_open();
s32 sys_rsx_device_close();

View File

@ -786,6 +786,7 @@ namespace vm
std::make_shared<block_t>(0xC0000000, 0x10000000), // video
std::make_shared<block_t>(0xD0000000, 0x10000000), // stack
std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU reserved
std::make_shared<block_t>(0x40000000, 0x10000000), // rsx contexts
};
}
}

View File

@ -523,10 +523,9 @@ void D3D12GSRender::flip(int buffer)
size_t offset = 0;
if (false)
{
CellGcmDisplayInfo* buffers = nullptr;// = vm::ps3::_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr);
u32 addr = rsx::get_address(gcm_buffers[gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL);
w = gcm_buffers[gcm_current_buffer].width;
h = gcm_buffers[gcm_current_buffer].height;
u32 addr = rsx::get_address(display_buffers[current_display_buffer].offset, CELL_GCM_LOCATION_LOCAL);
w = display_buffers[current_display_buffer].width;
h = display_buffers[current_display_buffer].height;
u8 *src_buffer = vm::ps3::_ptr<u8>(addr);
row_pitch = align(w * 4, 256);

View File

@ -985,9 +985,9 @@ void GLGSRender::flip(int buffer)
return;
}
u32 buffer_width = gcm_buffers[buffer].width;
u32 buffer_height = gcm_buffers[buffer].height;
u32 buffer_pitch = gcm_buffers[buffer].pitch;
u32 buffer_width = display_buffers[buffer].width;
u32 buffer_height = display_buffers[buffer].height;
u32 buffer_pitch = display_buffers[buffer].pitch;
// Calculate blit coordinates
coordi aspect_ratio;
@ -1016,7 +1016,7 @@ void GLGSRender::flip(int buffer)
aspect_ratio.size = new_size;
// Find the source image
rsx::tiled_region buffer_region = get_tiled_address(gcm_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL);
rsx::tiled_region buffer_region = get_tiled_address(display_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL);
u32 absolute_address = buffer_region.address + buffer_region.base;
gl::texture *render_target_texture = m_rtts.get_texture_from_render_target_if_applicable(absolute_address);

View File

@ -34,53 +34,55 @@ namespace rsx
switch (location)
{
case CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER:
case CELL_GCM_LOCATION_LOCAL:
case CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER:
case CELL_GCM_LOCATION_LOCAL:
{
// TODO: Don't use unnamed constants like 0xC0000000
return 0xC0000000 + offset;
}
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER:
case CELL_GCM_LOCATION_MAIN:
{
if (u32 result = RSXIOMem.RealAddr(offset))
{
// TODO: Don't use unnamed constants like 0xC0000000
return 0xC0000000 + offset;
return result;
}
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER:
case CELL_GCM_LOCATION_MAIN:
fmt::throw_exception("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped" HERE, offset, location);
}
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL:
return 0x40301400 + offset;
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN:
{
if (u32 result = RSXIOMem.RealAddr(0x0e000000 + offset))
{
if (u32 result = RSXIOMem.RealAddr(offset))
{
return result;
}
fmt::throw_exception("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped" HERE, offset, location);
//if (fxm::get<GSRender>()->strict_ordering[offset >> 20])
//{
// _mm_mfence(); // probably doesn't have any effect on current implementation
//}
return result;
}
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT:
return 0x100000 + offset; // TODO: Properly implement
fmt::throw_exception("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped" HERE, offset, location);
}
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN:
return 0x800 + offset; // TODO: Properly implement
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0:
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0 (offset=0x%x, location=0x%x)" HERE, offset, location);
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0:
return 0x40 + offset; // TODO: Properly implement
case CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0:
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0 (offset=0x%x, location=0x%x)" HERE, offset, location);
case CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0:
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0 (offset=0x%x, location=0x%x)" HERE, offset, location);
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW:
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_R:
return 0x40300000 + offset;
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW:
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_R:
return 0x100 + offset; // TODO: Properly implement
case CELL_GCM_CONTEXT_DMA_DEVICE_RW:
return 0x40000000 + offset;
case CELL_GCM_CONTEXT_DMA_DEVICE_RW:
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_DEVICE_RW (offset=0x%x, location=0x%x)" HERE, offset, location);
case CELL_GCM_CONTEXT_DMA_DEVICE_R:
return 0x40000000 + offset;
case CELL_GCM_CONTEXT_DMA_DEVICE_R:
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_DEVICE_R (offset=0x%x, location=0x%x)" HERE, offset, location);
default:
fmt::throw_exception("Invalid location (offset=0x%x, location=0x%x)" HERE, offset, location);
default:
fmt::throw_exception("Invalid location (offset=0x%x, location=0x%x)" HERE, offset, location);
}
}
@ -1069,9 +1071,9 @@ namespace rsx
rsx::method_registers.reset();
}
void thread::init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress)
void thread::init(u32 ioAddress, u32 ioSize, u32 ctrlAddress, u32 localAddress)
{
ctrl = vm::_ptr<CellGcmControl>(ctrlAddress);
ctrl = vm::_ptr<RsxDmaControl>(ctrlAddress);
this->ioAddress = ioAddress;
this->ioSize = ioSize;
local_mem_addr = localAddress;

View File

@ -22,6 +22,8 @@
#include "Utilities/variant.hpp"
#include "define_new_memleakdetect.h"
#include "Emu/Cell/lv2/sys_rsx.h"
extern u64 get_system_time();
extern bool user_asked_for_frame_capture;
@ -113,7 +115,7 @@ namespace rsx
std::vector<u32> element_push_buffer;
public:
CellGcmControl* ctrl = nullptr;
RsxDmaControl* ctrl = nullptr;
Timer timer_sync;
@ -131,20 +133,17 @@ namespace rsx
u32 ioAddress, ioSize;
u32 flip_status;
int flip_mode;
int debug_level;
int frequency_mode;
u32 tiles_addr;
u32 zculls_addr;
vm::ps3::ptr<CellGcmDisplayInfo> gcm_buffers = vm::null;
u32 gcm_buffers_count;
u32 gcm_current_buffer;
atomic_t<bool> requested_vsync{false};
RsxDisplayInfo display_buffers[8];
u32 display_buffers_count{0};
u32 current_display_buffer{0};
u32 ctxt_addr;
u32 label_addr;
u32 local_mem_addr, main_mem_addr;
bool strict_ordering[0x1000];
bool m_rtts_dirty;
bool m_transform_constants_dirty;
@ -345,7 +344,7 @@ namespace rsx
public:
void reset();
void init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress);
void init(u32 ioAddress, u32 ioSize, u32 ctrlAddress, u32 localAddress);
tiled_region get_tiled_address(u32 offset, u32 location);
GcmTileInfo *find_tile(u32 offset, u32 location);

View File

@ -2143,9 +2143,9 @@ void VKGSRender::flip(int buffer)
if (!resize_screen)
{
u32 buffer_width = gcm_buffers[buffer].width;
u32 buffer_height = gcm_buffers[buffer].height;
u32 buffer_pitch = gcm_buffers[buffer].pitch;
u32 buffer_width = display_buffers[buffer].width;
u32 buffer_height = display_buffers[buffer].height;
u32 buffer_pitch = display_buffers[buffer].pitch;
areai screen_area = coordi({}, { (int)buffer_width, (int)buffer_height });

View File

@ -968,7 +968,7 @@ rsx::blit_engine::context_dma rsx::blit_engine::to_context_dma(u32 in)
{
switch (in)
{
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT: return rsx::blit_engine::context_dma::to_memory_get_report;
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL: return rsx::blit_engine::context_dma::to_memory_get_report;
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN: return rsx::blit_engine::context_dma::report_location_main;
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER: return rsx::blit_engine::context_dma::memory_host_buffer;
}

View File

@ -704,7 +704,7 @@ enum
{
CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER = 0xFEED0000, // Local memory
CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER = 0xFEED0001, // Main memory
CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT = 0x66626660,
CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL = 0x66626660,
CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN = 0xBAD68000,
CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0 = 0x6660420F,

View File

@ -1988,6 +1988,32 @@ struct registers_decoder<NV4097_SET_TRANSFORM_PROGRAM_START>
}
};
template<>
struct registers_decoder<NV406E_SET_CONTEXT_DMA_SEMAPHORE>
{
struct decoded_type
{
private:
union
{
u32 raw_value;
} m_data;
public:
decoded_type(u32 raw_value) { m_data.raw_value = raw_value; }
u32 context_dma() const
{
return m_data.raw_value;
}
};
static std::string dump(decoded_type &&decoded_values)
{
return "NV406E semaphore: context = " + std::to_string(decoded_values.context_dma());
}
};
template<>
struct registers_decoder<NV406E_SEMAPHORE_OFFSET>
{
@ -4600,7 +4626,7 @@ constexpr std::integer_sequence<u32, NV4097_SET_VIEWPORT_HORIZONTAL, NV4097_SET_
NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK, NV4097_SET_SHADER_CONTROL,
NV4097_SET_VERTEX_DATA_BASE_OFFSET, NV4097_SET_INDEX_ARRAY_ADDRESS,
NV4097_SET_VERTEX_DATA_BASE_INDEX, NV4097_SET_SHADER_PROGRAM,
NV4097_SET_TRANSFORM_PROGRAM_START, NV406E_SEMAPHORE_OFFSET, NV4097_SET_SEMAPHORE_OFFSET,
NV4097_SET_TRANSFORM_PROGRAM_START, NV406E_SET_CONTEXT_DMA_SEMAPHORE, NV406E_SEMAPHORE_OFFSET, NV4097_SET_SEMAPHORE_OFFSET,
NV3089_IMAGE_IN_OFFSET, NV3062_SET_OFFSET_DESTIN, NV309E_SET_OFFSET, NV3089_DS_DX, NV3089_DT_DY,
NV0039_PITCH_IN, NV0039_PITCH_OUT, NV0039_LINE_LENGTH_IN, NV0039_LINE_COUNT, NV0039_OFFSET_OUT,
NV0039_OFFSET_IN, NV4097_SET_VERTEX_ATTRIB_INPUT_MASK, NV4097_SET_FREQUENCY_DIVIDER_OPERATION,

View File

@ -60,9 +60,13 @@ namespace rsx
void semaphore_acquire(thread* rsx, u32 _reg, u32 arg)
{
//TODO: dma
while (vm::ps3::read32(rsx->label_addr + method_registers.semaphore_offset_406e()) != arg)
const u32 addr = get_address(method_registers.semaphore_offset_406e(), method_registers.semaphore_context_dma_406e());
while (vm::ps3::read32(addr) != arg)
{
// todo: LLE: why does this one keep hanging? is it vsh system semaphore? whats actually pushing this to the command buffer?!
if (addr == 0x40000030)
break;
if (Emu.IsStopped())
break;
@ -72,8 +76,8 @@ namespace rsx
void semaphore_release(thread* rsx, u32 _reg, u32 arg)
{
//TODO: dma
vm::ps3::write32(rsx->label_addr + method_registers.semaphore_offset_406e(), arg);
const u32 addr = get_address(method_registers.semaphore_offset_406e(), method_registers.semaphore_context_dma_406e());
vm::ps3::write32(addr, arg);
}
}
@ -100,8 +104,12 @@ namespace rsx
//
}
//TODO: dma
vm::ps3::write32(rsx->label_addr + method_registers.semaphore_offset_4097(), arg);
const u32 index = method_registers.semaphore_offset_4097() >> 4;
auto& sema = vm::ps3::_ref<RsxReports>(rsx->label_addr);
sema.semaphore[index].val = arg;
sema.semaphore[index].pad = 0;
sema.semaphore[index].timestamp = rsx->timestamp();
}
void back_end_write_semaphore_release(thread* rsx, u32 _reg, u32 arg)
@ -111,9 +119,13 @@ namespace rsx
//
}
//TODO: dma
vm::ps3::write32(rsx->label_addr + method_registers.semaphore_offset_4097(),
(arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff));
const u32 index = method_registers.semaphore_offset_4097() >> 4;
u32 val = (arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff);
auto& sema = vm::ps3::_ref<RsxReports>(rsx->label_addr);
sema.semaphore[index].val = val;
sema.semaphore[index].pad = 0;
sema.semaphore[index].timestamp = rsx->timestamp();
}
template<u32 id, u32 index, int count, typename type>
@ -323,10 +335,9 @@ namespace rsx
switch (report_dma)
{
case blit_engine::context_dma::to_memory_get_report: location = CELL_GCM_LOCATION_LOCAL; break;
case blit_engine::context_dma::report_location_main:
case blit_engine::context_dma::memory_host_buffer:
location = CELL_GCM_LOCATION_MAIN; break;
case blit_engine::context_dma::to_memory_get_report: location = CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL; break;
case blit_engine::context_dma::report_location_main: location = CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN; break;
case blit_engine::context_dma::memory_host_buffer: location = CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER; break;
default:
LOG_WARNING(RSX, "nv4097::get_report: bad report dma: 0x%x", (u8)report_dma);
return;
@ -339,12 +350,14 @@ namespace rsx
switch (type)
{
case CELL_GCM_ZPASS_PIXEL_CNT:
// todo: actual zculling, here we just report max, which seems to be enough for most games, but causes them to render *everything*
result->value = 0xFFFFFFFF;
break;
case CELL_GCM_ZCULL_STATS:
case CELL_GCM_ZCULL_STATS1:
case CELL_GCM_ZCULL_STATS2:
case CELL_GCM_ZCULL_STATS3:
result->value = 0;
LOG_WARNING(RSX, "NV4097_GET_REPORT: Unimplemented type %d", type);
break;
default:
@ -352,8 +365,8 @@ namespace rsx
LOG_ERROR(RSX, "NV4097_GET_REPORT: Bad type %d", type);
break;
}
//result->padding = 0;
// This padding is needed to be set to 0, as games may use it for sync
result->padding = 0;
}
void clear_report_value(thread* rsx, u32 _reg, u32 arg)
@ -514,14 +527,14 @@ namespace rsx
//HACK: it's extension of the flip-hack. remove this when textures cache would be properly implemented
for (int i = 0; i < rsx::limits::color_buffers_count; ++i)
{
u32 begin = rsx->gcm_buffers[i].offset;
u32 begin = rsx->display_buffers[i].offset;
if (dst_offset < begin || !begin)
{
continue;
}
if (rsx->gcm_buffers[i].width < 720 || rsx->gcm_buffers[i].height < 480)
if (rsx->display_buffers[i].width < 720 || rsx->display_buffers[i].height < 480)
{
continue;
}
@ -531,7 +544,7 @@ namespace rsx
return;
}
u32 end = begin + rsx->gcm_buffers[i].height * rsx->gcm_buffers[i].pitch;
u32 end = begin + rsx->display_buffers[i].height * rsx->display_buffers[i].pitch;
if (dst_offset < end)
{
@ -862,14 +875,13 @@ namespace rsx
rsx->timer_sync.Start();
}
rsx->gcm_current_buffer = arg;
rsx->current_display_buffer = arg;
rsx->flip(arg);
// After each flip PS3 system is executing a routine that changes registers value to some default.
// Some game use this default state (SH3).
rsx->reset();
rsx->last_flip_time = get_system_time() - 1000000;
rsx->gcm_current_buffer = arg;
rsx->flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_DONE;
if (rsx->flip_handler)
@ -971,7 +983,7 @@ namespace rsx
registers[NV4097_SET_SURFACE_FORMAT] = (8 << 0) | (2 << 5) | (0 << 12) | (1 << 16) | (1 << 24);
// rsx dma initial values
registers[NV4097_SET_CONTEXT_DMA_REPORT] = CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT;
registers[NV4097_SET_CONTEXT_DMA_REPORT] = CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL;
registers[NV406E_SET_CONTEXT_DMA_SEMAPHORE] = CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW;
registers[NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
registers[NV309E_SET_CONTEXT_DMA_IMAGE] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;

View File

@ -889,6 +889,11 @@ namespace rsx
return decode<NV4097_SET_BEGIN_END>().primitive();
}
u32 semaphore_context_dma_406e() const
{
return decode<NV406E_SET_CONTEXT_DMA_SEMAPHORE>().context_dma();
}
u32 semaphore_offset_406e() const
{
return decode<NV406E_SEMAPHORE_OFFSET>().semaphore_offset();

View File

@ -411,9 +411,7 @@ void Buffer::mouseDoubleClickEvent(QMouseEvent* event)
return;
}
const auto buffers = render->gcm_buffers;
if (!buffers)
return;
const auto buffers = render->display_buffers;
// TODO: Is there any better way to choose the color buffers
#define SHOW_BUFFER(id) \
@ -705,12 +703,9 @@ void rsx_debugger::GetBuffers()
// Draw Buffers
// TODO: Currently it only supports color buffers
for (u32 bufferId=0; bufferId < render->gcm_buffers_count; bufferId++)
for (u32 bufferId=0; bufferId < render->display_buffers_count; bufferId++)
{
if(!vm::check_addr(render->gcm_buffers.addr()))
continue;
auto buffers = render->gcm_buffers;
auto buffers = render->display_buffers;
u32 RSXbuffer_addr = render->local_mem_addr + buffers[bufferId].offset;
if(!vm::check_addr(RSXbuffer_addr))