Major gcm emulation improvements

Improved RSX DMA support (WIP)
This commit is contained in:
DH 2016-07-08 21:15:27 +03:00
parent 816169fe9e
commit 3352e235b6
11 changed files with 1875 additions and 1716 deletions

View file

@ -12,10 +12,42 @@
logs::channel cellGcmSys("cellGcmSys", logs::level::notice);
extern s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count);
extern s32 cellGcmCallback(vm::ptr<rsx::control_t> context, u32 count);
extern void ppu_register_function_at(u32 addr, ppu_function_t ptr);
const u32 tiled_pitches[] = {
namespace gcm
{
struct context_t
{
vm::ps3::bptr<CellGcmContextCallback> callback;
be_t<u32> rtoc;
};
static vm::ptr<context_t> context;
static vm::pptr<rsx::context_t> current_context;
vm::ps3::ptr<CellGcmContextCallback> allocate_callback_function()
{
u32 address = vm::alloc(sizeof(u32) * 2, vm::main);
vm::write32(address + sizeof(u32) * 0, ppu_instructions::HACK(FIND_FUNC(cellGcmCallback)));
vm::write32(address + sizeof(u32) * 1, ppu_instructions::BLR());
ppu_register_function_at(address, BIND_FUNC(cellGcmCallback));
return vm::cast(address);
}
void initialize(vm::pptr<rsx::context_t> current_context)
{
gcm::current_context = current_context;
context = vm::cast(vm::alloc(sizeof(context_t), vm::main));
context->callback = allocate_callback_function();
context->rtoc = 0xabadcafe;
}
}
static const u32 tiled_pitches[] = {
0x00000000, 0x00000200, 0x00000300, 0x00000400,
0x00000500, 0x00000600, 0x00000700, 0x00000800,
0x00000A00, 0x00000C00, 0x00000D00, 0x00000E00,
@ -27,16 +59,10 @@ const u32 tiled_pitches[] = {
0x00010000
};
u32 local_size = 0;
u32 local_addr = 0;
u64 system_mode = 0;
static u64 g_system_mode = 0;
CellGcmConfig current_config;
CellGcmContextData current_context;
gcmInfo gcm_info;
u32 map_offset_addr = 0;
u32 map_offset_pos = 0;
static u32 g_map_offset_addr = 0;
static u32 g_map_offset_pos = 0;
// Auxiliary functions
@ -65,6 +91,19 @@ u32 gcmGetLocalMemorySize(u32 sdk_version)
return 0x0E000000; // 224MB
}
s32 gcmMapLocalMemory()
{
rsx::state.frame_buffer = vm::cast(0xC0000000);
rsx::state.frame_buffer_size = 0xf900000; // TODO: Get sdk_version in _cellGcmFunc15 and pass it to gcmGetLocalMemorySize
if (!vm::falloc(rsx::state.frame_buffer.addr(), rsx::state.frame_buffer_size, vm::video))
{
return CELL_GCM_ERROR_FAILURE;
}
return CELL_OK;
}
CellGcmOffsetTable offsetTable;
void InitOffsetTable()
@ -83,30 +122,35 @@ void InitOffsetTable()
u32 cellGcmGetLabelAddress(u8 index)
{
cellGcmSys.trace("cellGcmGetLabelAddress(index=%d)", index);
return gcm_info.label_addr + 0x10 * index;
return rsx::state.context.ptr(&rsx::context_t::semaphores, index).addr();
}
vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 location)
{
cellGcmSys.warning("cellGcmGetReportDataAddressLocation(index=%d, location=%d)", index, location);
if (location == CELL_GCM_LOCATION_LOCAL) {
if (index >= 2048) {
if (location == CELL_GCM_LOCATION_LOCAL)
{
if (index >= sizeof(rsx::context_t::reports) / sizeof(*rsx::context_t::reports))
{
cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong local index (%d)", index);
return vm::null;
}
return vm::ptr<CellGcmReportData>::make(0xC0000000 + index * 0x10);
return rsx::state.context.ptr(&rsx::context_t::reports, index);
}
if (location == CELL_GCM_LOCATION_MAIN) {
if (index >= 1024 * 1024) {
if (location == CELL_GCM_LOCATION_MAIN)
{
if (index >= sizeof(rsx::frame_buffer_t::reports) / sizeof(*rsx::frame_buffer_t::reports))
{
cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong main index (%d)", index);
return vm::null;
}
return vm::ptr<CellGcmReportData>::make(RSXIOMem.RealAddr(index * 0x10));
return rsx::state.frame_buffer.ptr(&rsx::frame_buffer_t::reports, index);
}
cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong location (%d)", location);
return vm::null;
}
@ -114,11 +158,13 @@ u64 cellGcmGetTimeStamp(u32 index)
{
cellGcmSys.trace("cellGcmGetTimeStamp(index=%d)", index);
if (index >= 2048) {
if (index >= sizeof(rsx::frame_buffer_t::reports) / sizeof(*rsx::frame_buffer_t::reports))
{
cellGcmSys.error("cellGcmGetTimeStamp: Wrong local index (%d)", index);
return 0;
}
return vm::read64(0xC0000000 + index * 0x10);
return rsx::state.frame_buffer->reports[index].timer;
}
s32 cellGcmGetCurrentField()
@ -145,7 +191,7 @@ u32 cellGcmGetNotifyDataAddress(u32 index)
*/
vm::ptr<CellGcmReportData> _cellGcmFunc12()
{
return vm::ptr<CellGcmReportData>::make(0xC0000000); // TODO
return vm::cast(rsx::state.frame_buffer.addr());
}
u32 cellGcmGetReport(u32 type, u32 index)
@ -173,7 +219,7 @@ u32 cellGcmGetReportDataAddress(u32 index)
cellGcmSys.error("cellGcmGetReportDataAddress: Wrong local index (%d)", index);
return 0;
}
return 0xC0000000 + index * 0x10;
return vm::cast(rsx::state.frame_buffer.addr() + index * 0x10);
}
u32 cellGcmGetReportDataLocation(u32 index, u32 location)
@ -216,7 +262,7 @@ u32 cellGcmGetControlRegister()
{
cellGcmSys.trace("cellGcmGetControlRegister()");
return gcm_info.control_addr;
return rsx::state.context.ptr(&rsx::context_t::control).ptr(&rsx::control_t::put).addr();
}
u32 cellGcmGetDefaultCommandWordSize()
@ -257,7 +303,7 @@ s32 cellGcmBindTile(u8 index)
return CELL_GCM_ERROR_INVALID_VALUE;
}
fxm::get<GSRender>()->tiles[index].binded = true;
rsx::state.unpacked_tiles[index].binded = true;
return CELL_OK;
}
@ -272,7 +318,7 @@ s32 cellGcmBindZcull(u8 index)
return CELL_GCM_ERROR_INVALID_VALUE;
}
fxm::get<GSRender>()->zculls[index].binded = true;
rsx::state.unpacked_zculls[index].binded = true;
return CELL_OK;
}
@ -281,14 +327,18 @@ s32 cellGcmGetConfiguration(vm::ptr<CellGcmConfig> config)
{
cellGcmSys.trace("cellGcmGetConfiguration(config=*0x%x)", config);
*config = current_config;
config->localAddress = rsx::state.frame_buffer.addr();
config->localSize = rsx::state.frame_buffer_size;
config->ioSize = rsx::state.io_size;
config->memoryFrequency = 650000000;
config->coreFrequency = 500000000;
return CELL_OK;
}
s32 cellGcmGetFlipStatus()
{
s32 status = fxm::get<GSRender>()->flip_status;
s32 status = rsx::state.flip_status;
cellGcmSys.trace("cellGcmGetFlipStatus() -> %d", status);
@ -319,29 +369,40 @@ void _cellGcmFunc15(vm::ptr<CellGcmContextData> context)
return;
}
u32 g_defaultCommandBufferBegin, g_defaultCommandBufferFragmentCount;
static u32 g_defaultCommandBufferBegin, g_defaultCommandBufferFragmentCount;
// Called by cellGcmInit
s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSize, u32 ioAddress)
s32 _cellGcmInitBody(vm::pptr<rsx::context_t> context, u32 cmdSize, u32 ioSize, u32 ioAddress)
{
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;
local_size = 0;
local_addr = 0;
InitOffsetTable();
if (!local_size && !local_addr)
if (gcmMapEaIoAddress(ioAddress, 0, ioSize, false) != CELL_OK)
{
local_size = 0xf900000; // TODO: Get sdk_version in _cellGcmFunc15 and pass it to gcmGetLocalMemorySize
local_addr = 0xC0000000;
vm::falloc(0xC0000000, local_size, vm::video);
cellGcmSys.error("cellGcmInit: CELL_GCM_ERROR_FAILURE");
return CELL_GCM_ERROR_FAILURE;
}
cellGcmSys.warning("*** local memory(addr=0x%x, size=0x%x)", local_addr, local_size);
gcm::initialize(context);
InitOffsetTable();
if (system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB)
rsx::state.device = vm::cast(vm::alloc(sizeof(rsx::device_t), vm::main));
rsx::state.context = vm::cast(vm::alloc(sizeof(rsx::context_t), vm::main));
//rsx::state.io = vm::cast(ioAddress);
rsx::state.io_size = cmdSize;
rsx::state.display_buffers_count = 0;
rsx::state.current_display_buffer = 0;
rsx::state.display_buffers = vm::cast(vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main));
rsx::state.zculls = vm::cast(vm::alloc(sizeof(CellGcmZcullInfo) * rsx::limits::zculls_count, vm::main));
rsx::state.tiles = vm::cast(vm::alloc(sizeof(CellGcmTileInfo) * rsx::limits::tiles_count, vm::main));
rsx::state.flip_status = 0;
gcmMapLocalMemory();
cellGcmSys.warning("*** local memory(addr=0x%x, size=0x%x)", rsx::state.frame_buffer, rsx::state.frame_buffer_size);
if (g_system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB)
{
cellGcmSys.warning("cellGcmInit(): 512MB io address space used");
RSXIOMem.SetRange(0, 0x20000000 /*512MB*/);
@ -352,59 +413,28 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
RSXIOMem.SetRange(0, 0x10000000 /*256MB*/);
}
if (gcmMapEaIoAddress(ioAddress, 0, ioSize, false) != CELL_OK)
{
cellGcmSys.error("cellGcmInit: CELL_GCM_ERROR_FAILURE");
return CELL_GCM_ERROR_FAILURE;
}
g_map_offset_addr = 0;
g_map_offset_pos = 0;
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;
u32 commandBufferPageSize = 32 * 1024;
// Create contexts
g_defaultCommandBufferBegin = ioAddress + 4096;
g_defaultCommandBufferFragmentCount = cmdSize / commandBufferPageSize;
g_defaultCommandBufferBegin = ioAddress;
g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024);
rsx::state.context->control.begin = vm::cast(g_defaultCommandBufferBegin);
rsx::state.context->control.end = vm::cast(g_defaultCommandBufferBegin + commandBufferPageSize - 4); // 4b at the end for jump
rsx::state.context->control.current = rsx::state.context->control.begin;
rsx::state.context->control.callback = vm::cast(gcm::context.ptr(&gcm::context_t::callback).addr());
rsx::state.context->control.put = 0;
rsx::state.context->control.get = 0;
rsx::state.context->control.ref = -1;
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); // ???
//TODO: send new context
fxm::get<GSRender>()->init();
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(gcm_info.context_addr + 0x40);
rsx::state.context->semaphores[3].value = 1;
vm::write32(gcm_info.context_addr + 0x40, gcm_info.context_addr + 0x48);
vm::write32(gcm_info.context_addr + 0x44, 0xabadcafe);
vm::write32(gcm_info.context_addr + 0x48, ppu_instructions::HACK(FIND_FUNC(cellGcmCallback)));
vm::write32(gcm_info.context_addr + 0x4c, ppu_instructions::BLR());
ppu_register_function_at(gcm_info.context_addr + 0x48, BIND_FUNC(cellGcmCallback));
vm::_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
context->set(gcm_info.context_addr);
auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr);
ctrl.put = 0;
ctrl.get = 0;
ctrl.ref = -1;
const auto render = fxm::get<GSRender>();
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);
*context = rsx::state.context;
return CELL_OK;
}
@ -413,7 +443,7 @@ s32 cellGcmResetFlipStatus()
{
cellGcmSys.trace("cellGcmResetFlipStatus()");
fxm::get<GSRender>()->flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_WAITING;
rsx::state.flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_WAITING;
return CELL_OK;
}
@ -427,7 +457,7 @@ s32 cellGcmSetDebugOutputLevel(s32 level)
case CELL_GCM_DEBUG_LEVEL0:
case CELL_GCM_DEBUG_LEVEL1:
case CELL_GCM_DEBUG_LEVEL2:
fxm::get<GSRender>()->debug_level = level;
rsx::state.debug_level = level;
break;
default: return CELL_EINVAL;
@ -446,18 +476,14 @@ s32 cellGcmSetDisplayBuffer(u32 id, u32 offset, u32 pitch, u32 width, u32 height
return CELL_EINVAL;
}
const auto render = fxm::get<GSRender>();
rsx::state.display_buffers[id].offset = offset;
rsx::state.display_buffers[id].pitch = pitch;
rsx::state.display_buffers[id].width = width;
rsx::state.display_buffers[id].height = height;
auto buffers = render->gcm_buffers;
buffers[id].offset = offset;
buffers[id].pitch = pitch;
buffers[id].width = width;
buffers[id].height = height;
if (id + 1 > render->gcm_buffers_count)
if (id + 1 > rsx::state.display_buffers_count)
{
render->gcm_buffers_count = id + 1;
rsx::state.display_buffers_count = id + 1;
}
return CELL_OK;
@ -467,7 +493,7 @@ void cellGcmSetFlipHandler(vm::ptr<void(u32)> handler)
{
cellGcmSys.warning("cellGcmSetFlipHandler(handler=*0x%x)", handler);
fxm::get<GSRender>()->flip_handler = handler;
rsx::state.flip_handler = handler;
}
s32 cellGcmSetFlipMode(u32 mode)
@ -479,7 +505,7 @@ s32 cellGcmSetFlipMode(u32 mode)
case CELL_GCM_DISPLAY_HSYNC:
case CELL_GCM_DISPLAY_VSYNC:
case CELL_GCM_DISPLAY_HSYNC_WITH_NOISE:
fxm::get<GSRender>()->flip_mode = mode;
rsx::state.flip_mode = mode;
break;
default:
@ -492,11 +518,10 @@ s32 cellGcmSetFlipMode(u32 mode)
void cellGcmSetFlipStatus()
{
cellGcmSys.warning("cellGcmSetFlipStatus()");
fxm::get<GSRender>()->flip_status = 0;
rsx::state.flip_status = 0;
}
s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr<CellGcmContextData> ctxt, u32 id)
s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr<rsx::control_t> ctxt, u32 id)
{
cellGcmSys.trace("cellGcmSetPrepareFlip(ctx=*0x%x, id=0x%x)", ctxt, id);
@ -508,30 +533,28 @@ s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr<CellGcmContextData> ctxt, u32
if (ctxt->current + 2 >= ctxt->end)
{
if (s32 res = ctxt->callback(ppu, ctxt, 8 /* ??? */))
if (s32 res = (*ctxt->callback)(ppu, ctxt.addr(), 8 /* ??? */))
{
cellGcmSys.error("cellGcmSetPrepareFlip: callback failed (0x%08x)", res);
return res;
}
}
const u32 cmd_size = rsx::make_command(ctxt->current, GCM_FLIP_COMMAND, { id });
if (ctxt.addr() == gcm_info.context_addr)
{
vm::_ref<CellGcmControl>(gcm_info.control_addr).put += cmd_size;
}
ctxt->put += rsx::make_command(ctxt->current, GCM_FLIP_COMMAND, { id });
return id;
}
s32 cellGcmSetFlip(PPUThread& ppu, vm::ptr<CellGcmContextData> ctxt, u32 id)
s32 cellGcmSetFlip(PPUThread& ppu, vm::ptr<rsx::control_t> ctxt, u32 id)
{
cellGcmSys.trace("cellGcmSetFlip(ctxt=*0x%x, id=0x%x)", ctxt, id);
if (s32 res = cellGcmSetPrepareFlip(ppu, ctxt, id))
{
if (res < 0) return CELL_GCM_ERROR_FAILURE;
if (res < 0)
{
return CELL_GCM_ERROR_FAILURE;
}
}
return CELL_OK;
@ -591,9 +614,7 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u
cellGcmSys.error("cellGcmSetTileInfo: bad compression mode! (%d)", comp);
}
const auto render = fxm::get<GSRender>();
auto& tile = render->tiles[index];
auto& tile = rsx::state.unpacked_tiles[index];
tile.location = location;
tile.offset = offset;
tile.size = size;
@ -602,7 +623,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();
rsx::state.tiles[index] = tile.pack();
return CELL_OK;
}
@ -610,7 +631,7 @@ void cellGcmSetUserHandler(vm::ptr<void(u32)> handler)
{
cellGcmSys.warning("cellGcmSetUserHandler(handler=*0x%x)", handler);
fxm::get<GSRender>()->user_handler = handler;
rsx::state.user_handler = handler;
}
s32 cellGcmSetUserCommand()
@ -622,7 +643,7 @@ void cellGcmSetVBlankHandler(vm::ptr<void(u32)> handler)
{
cellGcmSys.warning("cellGcmSetVBlankHandler(handler=*0x%x)", handler);
fxm::get<GSRender>()->vblank_handler = handler;
rsx::state.vblank_handler = handler;
}
s32 cellGcmSetWaitFlip(vm::ptr<CellGcmContextData> ctxt)
@ -650,9 +671,7 @@ s32 cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
return CELL_GCM_ERROR_INVALID_VALUE;
}
const auto render = fxm::get<GSRender>();
auto& zcull = render->zculls[index];
auto& zcull = rsx::state.unpacked_zculls[index];
zcull.offset = offset;
zcull.width = width;
zcull.height = height;
@ -665,7 +684,7 @@ s32 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();
rsx::state.zculls[index] = zcull.pack();
return CELL_OK;
}
@ -679,7 +698,7 @@ s32 cellGcmUnbindTile(u8 index)
return CELL_GCM_ERROR_INVALID_VALUE;
}
fxm::get<GSRender>()->tiles[index].binded = false;
rsx::state.unpacked_tiles[index].binded = false;
return CELL_OK;
}
@ -694,37 +713,34 @@ s32 cellGcmUnbindZcull(u8 index)
return CELL_EINVAL;
}
fxm::get<GSRender>()->zculls[index].binded = false;
rsx::state.unpacked_zculls[index].binded = false;
return CELL_OK;
}
u32 cellGcmGetTileInfo()
vm::ptr<CellGcmTileInfo> cellGcmGetTileInfo()
{
cellGcmSys.warning("cellGcmGetTileInfo()");
return fxm::get<GSRender>()->tiles_addr;
return rsx::state.tiles;
}
u32 cellGcmGetZcullInfo()
vm::ptr<CellGcmZcullInfo> cellGcmGetZcullInfo()
{
cellGcmSys.warning("cellGcmGetZcullInfo()");
return fxm::get<GSRender>()->zculls_addr;
return rsx::state.zculls;
}
u32 cellGcmGetDisplayInfo()
vm::ptr<CellGcmDisplayInfo> cellGcmGetDisplayInfo()
{
cellGcmSys.warning("cellGcmGetDisplayInfo()");
return fxm::get<GSRender>()->gcm_buffers.addr();
return rsx::state.display_buffers;
}
s32 cellGcmGetCurrentDisplayBufferId(vm::ptr<u8> id)
{
cellGcmSys.warning("cellGcmGetCurrentDisplayBufferId(id=*0x%x)", id);
if ((*id = fxm::get<GSRender>()->gcm_current_buffer) > UINT8_MAX)
{
throw EXCEPTION("Unexpected");
}
*id = rsx::state.current_display_buffer;
return CELL_OK;
}
@ -756,7 +772,7 @@ u64 cellGcmGetLastFlipTime()
{
cellGcmSys.trace("cellGcmGetLastFlipTime()");
return fxm::get<GSRender>()->last_flip_time;
return rsx::state.last_flip_time;
}
u64 cellGcmGetLastSecondVTime()
@ -769,7 +785,7 @@ u64 cellGcmGetVBlankCount()
{
cellGcmSys.trace("cellGcmGetVBlankCount()");
return fxm::get<GSRender>()->vblank_count;
return rsx::state.vblank_count;
}
s32 cellGcmSysGetLastVBlankTime()
@ -781,7 +797,7 @@ s32 cellGcmInitSystemMode(u64 mode)
{
cellGcmSys.trace("cellGcmInitSystemMode(mode=0x%x)", mode);
system_mode = mode;
g_system_mode = mode;
return CELL_OK;
}
@ -839,7 +855,7 @@ s32 cellGcmAddressToOffset(u32 address, vm::ptr<u32> offset)
cellGcmSys.trace("cellGcmAddressToOffset(address=0x%x, offset=*0x%x)", address, offset);
// Address not on main memory or local memory
if (address >= 0xD0000000)
if (address >= rsx::state.frame_buffer.addr() + rsx::state.frame_buffer_size)
{
return CELL_GCM_ERROR_FAILURE;
}
@ -849,7 +865,7 @@ s32 cellGcmAddressToOffset(u32 address, vm::ptr<u32> offset)
// Address in local memory
if ((address >> 28) == 0xC)
{
result = address - 0xC0000000;
result = address - rsx::state.frame_buffer.addr();
}
// Address in main memory else check
else
@ -946,18 +962,15 @@ s32 cellGcmMapLocalMemory(vm::ptr<u32> address, vm::ptr<u32> size)
{
cellGcmSys.warning("cellGcmMapLocalMemory(address=*0x%x, size=*0x%x)", address, size);
if (!local_addr && !local_size && vm::falloc(local_addr = 0xC0000000, local_size = 0xf900000 /* TODO */, vm::video))
s32 result = gcmMapLocalMemory();
if (result == CELL_OK)
{
*address = local_addr;
*size = local_size;
}
else
{
cellGcmSys.error("RSX local memory already mapped");
return CELL_GCM_ERROR_FAILURE;
*address = rsx::state.frame_buffer.addr();
*size = rsx::state.frame_buffer_size;
}
return CELL_OK;
return result;
}
s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr<u32> offset)
@ -989,8 +1002,6 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr<u32> offset)
return CELL_GCM_ERROR_NO_IO_PAGE_TABLE;
}
render->main_mem_addr = render->ioAddress;
return CELL_OK;
}
@ -1129,7 +1140,8 @@ s32 cellGcmSetCursorImageOffset(u32 offset)
void cellGcmSetDefaultCommandBuffer()
{
cellGcmSys.warning("cellGcmSetDefaultCommandBuffer()");
vm::write32(fxm::get<GSRender>()->ctxt_addr, gcm_info.context_addr);
*gcm::current_context = rsx::state.context;
}
s32 cellGcmSetDefaultCommandBufferAndSegmentWordSize()
@ -1141,19 +1153,21 @@ s32 cellGcmSetDefaultCommandBufferAndSegmentWordSize()
// Other
//------------------------------------------------------------------------
s32 _cellGcmSetFlipCommand(PPUThread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id)
s32 _cellGcmSetFlipCommand(PPUThread& ppu, vm::ptr<rsx::control_t> ctx, u32 id)
{
cellGcmSys.trace("cellGcmSetFlipCommand(ctx=*0x%x, id=0x%x)", ctx, id);
return cellGcmSetPrepareFlip(ppu, ctx, id);
}
s32 _cellGcmSetFlipCommandWithWaitLabel(PPUThread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id, u32 label_index, u32 label_value)
s32 _cellGcmSetFlipCommandWithWaitLabel(PPUThread& ppu, vm::ptr<rsx::context_t> 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);
s32 res = cellGcmSetPrepareFlip(ppu, ctx, id);
vm::write32(gcm_info.label_addr + 0x10 * label_index, label_value);
s32 res = cellGcmSetPrepareFlip(ppu, ctx.ptr(&rsx::context_t::control), id);
ctx->semaphores[label_index].value = label_value;
//TODO: time
return res < 0 ? CELL_GCM_ERROR_FAILURE : CELL_OK;
}
@ -1186,9 +1200,7 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co
cellGcmSys.error("cellGcmSetTile: bad compression mode! (%d)", comp);
}
const auto render = fxm::get<GSRender>();
auto& tile = render->tiles[index];
auto& tile = rsx::state.unpacked_tiles[index];
tile.location = location;
tile.offset = offset;
tile.size = size;
@ -1197,7 +1209,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();
rsx::state.tiles[index] = tile.pack();
return CELL_OK;
}
@ -1283,23 +1295,23 @@ static bool isInCommandBufferExcept(u32 getPos, u32 bufferBegin, u32 bufferEnd)
return true;
}
s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count)
s32 cellGcmCallback(vm::ptr<rsx::control_t> context, u32 count)
{
cellGcmSys.trace("cellGcmCallback(context=*0x%x, count=0x%x)", context, count);
auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr);
auto& ctrl = *context;
const std::chrono::time_point<std::chrono::system_clock> enterWait = std::chrono::system_clock::now();
// Flush command buffer (ie allow RSX to read up to context->current)
ctrl.put.exchange(getOffsetFromAddress(context->current.addr()));
ctrl.put.exchange(getOffsetFromAddress(ctrl.current.addr()));
std::pair<u32, u32> newCommandBuffer = getNextCommandBufferBeginEnd(context->current.addr());
std::pair<u32, u32> newCommandBuffer = getNextCommandBufferBeginEnd(ctrl.current.addr());
u32 offset = getOffsetFromAddress(newCommandBuffer.first);
// Write jump instruction
*context->current = CELL_GCM_METHOD_FLAG_JUMP | offset;
*ctrl.current = CELL_GCM_METHOD_FLAG_JUMP | offset;
// Update current command buffer
context->begin.set(newCommandBuffer.first);
context->current.set(newCommandBuffer.first);
context->end.set(newCommandBuffer.second);
ctrl.begin.set(newCommandBuffer.first);
ctrl.current.set(newCommandBuffer.first);
ctrl.end.set(newCommandBuffer.second);
// Wait for rsx to "release" the new command buffer
while (!Emu.IsStopped())
@ -1319,8 +1331,10 @@ s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count)
//----------------------------------------------------------------------------
DECLARE(ppu_module_manager::cellGcmSys)("cellGcmSys", []()
DECLARE(ppu_module_manager::cellGcmSys)("cellGcmSys", [](ppu_static_module *_this)
{
//_this->on_load.push(&gcm::initialize);
// Data Retrieval
REG_FUNC(cellGcmSys, cellGcmGetCurrentField);
REG_FUNC(cellGcmSys, cellGcmGetLabelAddress);

View file

@ -496,9 +496,9 @@ void D3D12GSRender::flip(int buffer)
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(rsx::state.display_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL);
w = rsx::state.display_buffers[buffer].width;
h = rsx::state.display_buffers[buffer].height;
u8 *src_buffer = vm::ps3::_ptr<u8>(addr);
row_pitch = align(w * 4, 256);

View file

@ -326,12 +326,12 @@ void D3D12GSRender::copy_render_target_to_dma_location()
u32 address_color[] =
{
rsx::get_address(offset_color[0], context_dma_color[0]),
rsx::get_address(offset_color[1], context_dma_color[1]),
rsx::get_address(offset_color[2], context_dma_color[2]),
rsx::get_address(offset_color[3], context_dma_color[3]),
rsx::get_address_dma(offset_color[0], context_dma_color[0]),
rsx::get_address_dma(offset_color[1], context_dma_color[1]),
rsx::get_address_dma(offset_color[2], context_dma_color[2]),
rsx::get_address_dma(offset_color[3], context_dma_color[3]),
};
u32 address_z = rsx::get_address(offset_zeta, m_context_dma_z);
u32 address_z = rsx::get_address_dma(offset_zeta, m_context_dma_z);
bool need_transfer = false;

View file

@ -590,15 +590,24 @@ enum
};
// GPU Class Handles
enum
{
CELL_GCM_CONTEXT_SURFACE2D = 0x313371C3,
CELL_GCM_CONTEXT_SWIZZLE2D = 0x31337A73,
};
enum
{
CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER = 0xFEED0000, // Local memory
CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER = 0xFEED0001, // Main memory
CELL_GCM_CONTEXT_SURFACE2D = 0x313371C3,
CELL_GCM_CONTEXT_SWIZZLE2D = 0x31337A73,
CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT = 0x66626660,
CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN = 0xBAD68000,
CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0 = 0x66604200,
CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0 = 0x6660420F,
CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW = 0x66606660,
CELL_GCM_CONTEXT_DMA_SEMAPHORE_R = 0x66616661,
CELL_GCM_CONTEXT_DMA_DEVICE_RW = 0x56616660,
CELL_GCM_CONTEXT_DMA_DEVICE_R = 0x56616661
};
struct CellGcmControl
@ -627,15 +636,7 @@ struct CellGcmContextData
vm::ps3::bptr<u32> begin;
vm::ps3::bptr<u32> end;
vm::ps3::bptr<u32> current;
vm::ps3::bptr<CellGcmContextCallback> callback;
};
struct gcmInfo
{
u32 config_addr;
u32 context_addr;
u32 control_addr;
u32 label_addr;
vm::ps3::bpptr<CellGcmContextCallback> callback;
};
struct CellGcmSurface

View file

@ -26,13 +26,19 @@ namespace
u32 get_front_face_ccw(u32 ffv)
{
rsx::window_origin shader_window_origin = rsx::to_window_origin((rsx::method_registers[NV4097_SET_SHADER_WINDOW] >> 12) & 0xf);
if (shader_window_origin == rsx::window_origin::bottom)
{
ffv ^= 1;
}
switch (ffv)
{
default: // Disgaea 3 pass some garbage value at startup, this is needed to survive.
case CELL_GCM_CW: return GL_CW;
case CELL_GCM_CCW: return GL_CCW;
}
throw EXCEPTION("Unknown front face value: 0x%X", ffv);
}
}
@ -163,6 +169,7 @@ void GLGSRender::begin()
if (u32 blend_mrt = rsx::method_registers[NV4097_SET_BLEND_ENABLE_MRT])
{
__glcheck enable(blend_mrt & 1, GL_BLEND, 0);
__glcheck enable(blend_mrt & 2, GL_BLEND, 1);
__glcheck enable(blend_mrt & 4, GL_BLEND, 2);
__glcheck enable(blend_mrt & 8, GL_BLEND, 3);
@ -197,7 +204,7 @@ void GLGSRender::begin()
__glcheck glCullFace(rsx::method_registers[NV4097_SET_CULL_FACE]);
}
__glcheck glFrontFace(get_front_face_ccw(rsx::method_registers[NV4097_SET_FRONT_FACE] ^ 1));
__glcheck glFrontFace(get_front_face_ccw(rsx::method_registers[NV4097_SET_FRONT_FACE]));
__glcheck enable(rsx::method_registers[NV4097_SET_POLY_SMOOTH_ENABLE], GL_POLYGON_SMOOTH);
@ -697,7 +704,9 @@ bool GLGSRender::load_program()
RSXFragmentProgram fragment_program = get_current_fragment_program();
GLProgramBuffer prog_buffer;
__glcheck prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr);
m_program = &prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr);
return true;
}
rsx::program_info info = programs_cache.get(get_raw_program(), rsx::decompile_language::glsl);
@ -792,21 +801,21 @@ bool GLGSRender::load_program()
void GLGSRender::flip(int buffer)
{
u32 buffer_width = gcm_buffers[buffer].width;
u32 buffer_height = gcm_buffers[buffer].height;
u32 buffer_pitch = gcm_buffers[buffer].pitch;
u32 buffer_width = rsx::state.display_buffers[buffer].width;
u32 buffer_height = rsx::state.display_buffers[buffer].height;
u32 buffer_pitch = rsx::state.display_buffers[buffer].pitch;
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
rsx::tiled_region buffer_region = get_tiled_address(gcm_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL);
rsx::tiled_region buffer_region = get_tiled_address(rsx::state.display_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL);
u32 absolute_address = buffer_region.address + buffer_region.base;
if (0)
{
LOG_NOTICE(RSX, "flip(%d) -> 0x%x [0x%x]", buffer, absolute_address, rsx::get_address(gcm_buffers[1 - buffer].offset, CELL_GCM_LOCATION_LOCAL));
LOG_NOTICE(RSX, "flip(%d) -> 0x%x [0x%x]", buffer, absolute_address, rsx::get_address(rsx::state.display_buffers[1 - buffer].offset, CELL_GCM_LOCATION_LOCAL));
}
gl::texture *render_target_texture = m_rtts.get_texture_from_render_target_if_applicable(absolute_address);

View file

@ -187,13 +187,13 @@ void GLGSRender::read_buffers()
for (int i = index; i < index + count; ++i)
{
u32 offset = rsx::method_registers[rsx::internals::mr_color_offset[i]];
u32 location = rsx::method_registers[rsx::internals::mr_color_dma[i]];
u32 dma = rsx::method_registers[rsx::internals::mr_color_dma[i]];
u32 pitch = rsx::method_registers[rsx::internals::mr_color_pitch[i]];
if (pitch <= 64)
continue;
rsx::tiled_region color_buffer = get_tiled_address(offset, location & 0xf);
rsx::tiled_region color_buffer = get_tiled_address_dma(offset, dma);
u32 texaddr = (u32)((u64)color_buffer.ptr - (u64)vm::base(0));
bool success = m_gl_texture_cache.explicit_writeback((*std::get<1>(m_rtts.m_bound_render_targets[i])), texaddr, pitch);
@ -254,7 +254,7 @@ void GLGSRender::read_buffers()
if (pitch <= 64)
return;
u32 depth_address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]);
u32 depth_address = rsx::get_address_dma(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]);
bool in_cache = m_gl_texture_cache.explicit_writeback((*std::get<1>(m_rtts.m_bound_depth_stencil)), depth_address, pitch);
if (in_cache)
@ -269,7 +269,7 @@ void GLGSRender::read_buffers()
__glcheck pbo_depth.create(m_surface.width * m_surface.height * pixel_size);
__glcheck pbo_depth.map([&](GLubyte* pixels)
{
u32 depth_address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]);
u32 depth_address = rsx::get_address_dma(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]);
if (m_surface.depth_format == rsx::surface_depth_format::z16)
{
@ -315,13 +315,13 @@ void GLGSRender::write_buffers()
for (int i = index; i < index + count; ++i)
{
u32 offset = rsx::method_registers[rsx::internals::mr_color_offset[i]];
u32 location = rsx::method_registers[rsx::internals::mr_color_dma[i]];
u32 dma = rsx::method_registers[rsx::internals::mr_color_dma[i]];
u32 pitch = rsx::method_registers[rsx::internals::mr_color_pitch[i]];
if (pitch <= 64)
continue;
rsx::tiled_region color_buffer = get_tiled_address(offset, location & 0xf);
rsx::tiled_region color_buffer = get_tiled_address_dma(offset, dma);
u32 texaddr = (u32)((u64)color_buffer.ptr - (u64)vm::base(0));
u32 range = pitch * height;
@ -370,7 +370,7 @@ void GLGSRender::write_buffers()
return;
auto depth_format = rsx::internals::surface_depth_format_to_gl(m_surface.depth_format);
u32 depth_address = rsx::get_address(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]);
u32 depth_address = rsx::get_address_dma(rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET], rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]);
u32 range = std::get<1>(m_rtts.m_bound_depth_stencil)->width() * std::get<1>(m_rtts.m_bound_depth_stencil)->height() * 2;
if (m_surface.depth_format != rsx::surface_depth_format::z16) range *= 2;

View file

@ -34,6 +34,7 @@ namespace vm { using namespace ps3; }
namespace rsx
{
std::function<bool(u32 addr, bool is_writing)> g_access_violation_handler;
state_t state;
std::string old_shaders_cache::shaders_cache::path_to_root()
{
@ -97,27 +98,41 @@ namespace rsx
}
}
u32 get_address(u32 offset, u32 location)
u32 get_address(u32 offset, u8 location)
{
u32 res = 0;
switch (location)
{
case CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER:
case CELL_GCM_LOCATION_LOCAL:
{
//TODO: don't use not named constants like 0xC0000000
res = 0xC0000000 + offset;
break;
return rsx::state.frame_buffer.addr() + offset;
case CELL_GCM_LOCATION_MAIN:
//if (fxm::get<GSRender>()->strict_ordering[offset >> 20])
//{
// _mm_mfence(); // probably doesn't have any effect on current implementation
//}
if (u32 result = RSXIOMem.RealAddr(offset))
{
return result;
}
throw EXCEPTION("%s(offset=0x%x, location=0x%x): RSXIO memory not mapped", __FUNCTION__, offset, location);
}
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER:
case CELL_GCM_LOCATION_MAIN:
throw EXCEPTION("%s(offset=0x%x, location=0x%x): Invalid location", __FUNCTION__, offset, location);
}
u32 get_address_dma(u32 offset, u32 dma)
{
switch (dma)
{
res = (u32)RSXIOMem.RealAddr(offset); // TODO: Error Check?
if (res == 0)
case CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER:
return rsx::state.frame_buffer.addr() + offset;
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER:
if (u32 result = RSXIOMem.RealAddr(offset))
{
throw EXCEPTION("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped", offset, location);
return result;
}
//if (fxm::get<GSRender>()->strict_ordering[offset >> 20])
@ -125,15 +140,31 @@ namespace rsx
// _mm_mfence(); // probably doesn't have any effect on current implementation
//}
throw EXCEPTION("%s(offset=0x%x, dma=0x%x): RSXIO memory not mapped", __FUNCTION__, offset, dma);
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT:
return rsx::state.frame_buffer.ptr(&rsx::frame_buffer_t::reports).addr() + offset;
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN:
return rsx::state.context.ptr(&rsx::context_t::reports).addr() + offset;
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0:
return rsx::state.context.ptr(&rsx::context_t::notifies).addr() + offset;
case CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0:
//TODO
break;
}
default:
{
throw EXCEPTION("Invalid location (offset=0x%x, location=0x%x)", offset, location);
}
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW:
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_R:
return rsx::state.context.ptr(&rsx::context_t::semaphores).addr() + offset;
case CELL_GCM_CONTEXT_DMA_DEVICE_RW:
case CELL_GCM_CONTEXT_DMA_DEVICE_R:
return rsx::state.device.addr() + offset;
}
return res;
throw EXCEPTION("%s(offset=0x%x, dma=0x%x): Invalid dma", __FUNCTION__, offset, dma);
}
u32 get_vertex_type_size_on_host(vertex_base_type type, u32 size)
@ -377,24 +408,24 @@ namespace rsx
reset();
last_flip_time = get_system_time() - 1000000;
rsx::state.last_flip_time = get_system_time() - 1000000;
scope_thread vblank("VBlank Thread", [this]()
{
const u64 start_time = get_system_time();
vblank_count = 0;
rsx::state.vblank_count = 0;
// TODO: exit condition
while (!Emu.IsStopped())
{
if (get_system_time() - start_time > vblank_count * 1000000 / 60)
if (get_system_time() - start_time > rsx::state.vblank_count * 1000000 / 60)
{
vblank_count++;
rsx::state.vblank_count++;
if (vblank_handler)
if (rsx::state.vblank_handler)
{
Emu.GetCallbackManager().Async([func = vblank_handler](PPUThread& ppu)
Emu.GetCallbackManager().Async([func = rsx::state.vblank_handler](PPUThread& ppu)
{
func(ppu, 1);
});
@ -403,17 +434,19 @@ namespace rsx
continue;
}
std::this_thread::sleep_for(1ms); // hack
std::this_thread::yield();
}
});
auto &ctrl = state.context->control;
// TODO: exit condition
while (true)
{
CHECK_EMU_STATUS;
const u32 get = ctrl->get;
const u32 put = ctrl->put;
const u32 get = ctrl.get;
const u32 put = ctrl.put;
if (put == get || !Emu.IsRunning())
{
@ -428,7 +461,7 @@ namespace rsx
{
u32 offs = cmd & 0x1fffffff;
//LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put);
ctrl->get = offs;
ctrl.get = offs;
continue;
}
if (cmd & CELL_GCM_METHOD_FLAG_CALL)
@ -436,7 +469,7 @@ namespace rsx
m_call_stack.push(get + 4);
u32 offs = cmd & ~3;
//LOG_WARNING(RSX, "rsx call(0x%x) #0x%x - 0x%x", offs, cmd, get);
ctrl->get = offs;
ctrl.get = offs;
continue;
}
if (cmd == CELL_GCM_METHOD_FLAG_RETURN)
@ -444,13 +477,13 @@ namespace rsx
u32 get = m_call_stack.top();
m_call_stack.pop();
//LOG_WARNING(RSX, "rsx return(0x%x)", get);
ctrl->get = get;
ctrl.get = get;
continue;
}
if (cmd == 0) //nop
{
ctrl->get = get + 4;
ctrl.get = get + 4;
continue;
}
@ -483,7 +516,7 @@ namespace rsx
}
}
ctrl->get = get + (count + 1) * 4;
ctrl.get = get + (count + 1) * 4;
}
}
@ -576,7 +609,7 @@ namespace rsx
{
if (m_internal_tasks.empty())
{
std::this_thread::sleep_for(1ms);
std::this_thread::yield();
}
else
{
@ -656,10 +689,10 @@ namespace rsx
};
return
{
rsx::get_address(offset_color[0], context_dma_color[0]),
rsx::get_address(offset_color[1], context_dma_color[1]),
rsx::get_address(offset_color[2], context_dma_color[2]),
rsx::get_address(offset_color[3], context_dma_color[3]),
context_dma_color[0] ? rsx::get_address_dma(offset_color[0], context_dma_color[0]) : 0,
context_dma_color[1] ? rsx::get_address_dma(offset_color[1], context_dma_color[1]) : 0,
context_dma_color[2] ? rsx::get_address_dma(offset_color[2], context_dma_color[2]) : 0,
context_dma_color[2] ? rsx::get_address_dma(offset_color[3], context_dma_color[3]) : 0,
};
}
@ -667,7 +700,7 @@ namespace rsx
{
u32 m_context_dma_z = rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA];
u32 offset_zeta = rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET];
return rsx::get_address(offset_zeta, m_context_dma_z);
return offset_zeta ? rsx::get_address_dma(offset_zeta, m_context_dma_z) : 0;
}
RSXVertexProgram thread::get_current_vertex_program() const
@ -923,10 +956,23 @@ namespace rsx
method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] = 0xffffffff;
method_registers[NV4097_SET_CONTEXT_DMA_REPORT] = CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT;
rsx::method_registers[NV4097_SET_TWO_SIDE_LIGHT_EN] = true;
rsx::method_registers[NV4097_SET_ALPHA_FUNC] = CELL_GCM_ALWAYS;
method_registers[NV4097_SET_CONTEXT_DMA_REPORT] = CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT;
method_registers[NV406E_SET_CONTEXT_DMA_SEMAPHORE] = CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW;
method_registers[NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
method_registers[NV309E_SET_CONTEXT_DMA_IMAGE] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_IN] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_OUT] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
method_registers[NV4097_SET_CONTEXT_DMA_COLOR_A] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
method_registers[NV4097_SET_CONTEXT_DMA_COLOR_B] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
method_registers[NV4097_SET_CONTEXT_DMA_COLOR_C] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
method_registers[NV4097_SET_CONTEXT_DMA_COLOR_D] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
method_registers[NV4097_SET_CONTEXT_DMA_ZETA] = CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER;
// Reset vertex attrib array
for (int i = 0; i < limits::vertex_count; i++)
{
@ -945,14 +991,8 @@ namespace rsx
}
}
void thread::init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress)
void thread::init()
{
ctrl = vm::_ptr<CellGcmControl>(ctrlAddress);
this->ioAddress = ioAddress;
this->ioSize = ioSize;
local_mem_addr = localAddress;
flip_status = 0;
m_used_gcm_commands.clear();
on_init_rsx();
@ -961,7 +1001,7 @@ namespace rsx
GcmTileInfo *thread::find_tile(u32 offset, u32 location)
{
for (GcmTileInfo &tile : tiles)
for (GcmTileInfo &tile : state.unpacked_tiles)
{
if (!tile.binded || tile.location != location)
{
@ -977,7 +1017,23 @@ namespace rsx
return nullptr;
}
tiled_region thread::get_tiled_address(u32 offset, u32 location)
tiled_region thread::get_tiled_address_dma(u32 offset, u32 dma)
{
u32 address = get_address_dma(offset, dma);
GcmTileInfo *tile = find_tile(offset, dma & 1);
u32 base = 0;
if (tile)
{
base = offset - tile->offset;
address = get_address_dma(tile->offset, dma);
}
return{ address, base, tile, (u8*)vm::base(address) };
}
tiled_region thread::get_tiled_address(u32 offset, u8 location)
{
u32 address = get_address(offset, location);

View file

@ -87,6 +87,113 @@ namespace rsx
};
}
struct semaphore_t
{
be_t<u32> value;
be_t<u32> padding;
be_t<u64> timestamp;
};
struct notify_t
{
be_t<u64> timestamp;
be_t<u64> zero;
};
union device_t
{
u8 raw[0x1000];
};
union control_t;
using callback_t = s32(u32, u32);
union control_t
{
struct
{
vm::ps3::bptr<u32> begin;
vm::ps3::bptr<u32> end;
vm::ps3::bptr<u32> current;
vm::ps3::bpptr<callback_t> callback;
atomic_be_t<u32> put;
atomic_be_t<u32> get;
atomic_be_t<u32> ref;
};
//for gcm capability
struct
{
CellGcmContextData data;
CellGcmControl control;
};
u8 raw[0x1000];
};
union driver_info_t
{
struct
{
be_t<u32> version_driver;
be_t<u32> version_gpu;
be_t<u32> memory_size;
be_t<u32> hardware_channel;
be_t<u32> nvcore_frequency;
be_t<u32> memory_frequency;
};
u8 raw[0x4000];
};
struct context_t
{
control_t control;
driver_info_t driver_info;
semaphore_t semaphores[0x100];
notify_t notifies[0x40];
CellGcmReportData reports[0x800];
};
struct frame_buffer_t
{
CellGcmReportData reports[0x100000];
};
//TODO: separate gcm and rsx data
struct state_t
{
vm::ps3::ptr<device_t> device;
vm::ps3::ptr<context_t> context; //TODO: support for multiply contexts
vm::ps3::ptr<void(u32)> flip_handler = vm::null;
vm::ps3::ptr<void(u32)> user_handler = vm::null;
vm::ps3::ptr<void(u32)> vblank_handler = vm::null;
u64 last_flip_time;
u64 vblank_count;
u32 flip_status;
u32 flip_mode;
u32 debug_level;
u32 io_size;
vm::ps3::ptr<frame_buffer_t> frame_buffer;
u32 frame_buffer_size;
vm::ps3::ptr<CellGcmTileInfo> tiles;
vm::ps3::ptr<CellGcmZcullInfo> zculls;
vm::ps3::ptr<CellGcmDisplayInfo> display_buffers;
u32 display_buffers_count;
u32 current_display_buffer;
GcmTileInfo unpacked_tiles[limits::tiles_count];
GcmZcullInfo unpacked_zculls[limits::zculls_count];
};
extern state_t state;
namespace old_shaders_cache
{
struct decompiled_shader
@ -139,7 +246,8 @@ namespace rsx
u32 get_vertex_type_size_on_host(vertex_base_type type, u32 size);
u32 get_address(u32 offset, u32 location);
u32 get_address(u32 offset, u8 location);
u32 get_address_dma(u32 offset, u32 dma);
struct tiled_region
{
@ -212,13 +320,8 @@ namespace rsx
old_shaders_cache::shaders_cache shaders_cache;
rsx::programs_cache programs_cache;
CellGcmControl* ctrl = nullptr;
Timer timer_sync;
GcmTileInfo tiles[limits::tiles_count];
GcmZcullInfo zculls[limits::zculls_count];
rsx::texture textures[limits::textures_count];
rsx::vertex_texture vertex_textures[limits::vertex_textures_count];
@ -260,23 +363,11 @@ namespace rsx
void capture_frame(const std::string &name);
public:
u32 ioAddress, ioSize;
int 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;
u32 ctxt_addr;
u32 label_addr;
rsx::draw_command draw_command;
primitive_type draw_mode;
u32 local_mem_addr, main_mem_addr;
bool strict_ordering[0x1000];
bool draw_inline_vertex_array;
@ -295,13 +386,6 @@ namespace rsx
u32 draw_array_first;
double fps_limit = 59.94;
public:
u64 last_flip_time;
vm::ps3::ptr<void(u32)> flip_handler = vm::null;
vm::ps3::ptr<void(u32)> user_handler = vm::null;
vm::ps3::ptr<void(u32)> vblank_handler = vm::null;
u64 vblank_count;
public:
std::set<u32> m_used_gcm_commands;
@ -388,9 +472,10 @@ namespace rsx
struct raw_program get_raw_program() const;
public:
void reset();
void init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress);
void init();
tiled_region get_tiled_address(u32 offset, u32 location);
tiled_region get_tiled_address(u32 offset, u8 location);
tiled_region get_tiled_address_dma(u32 offset, u32 dma);
GcmTileInfo *find_tile(u32 offset, u32 location);
u32 ReadIO32(u32 addr);

File diff suppressed because it is too large Load diff

View file

@ -32,27 +32,31 @@ namespace rsx
namespace nv406e
{
force_inline void set_reference(thread* rsx, u32 arg)
force_inline void set_reference(u32 arg)
{
rsx->ctrl->ref.exchange(arg);
rsx::state.context->control.ref.exchange(arg);
}
force_inline void semaphore_acquire(thread* rsx, u32 arg)
{
//TODO: dma
while (vm::ps3::read32(rsx->label_addr + method_registers[NV406E_SEMAPHORE_OFFSET]) != arg)
vm::ps3::ptr<rsx::semaphore_t> semaphore = vm::cast(get_address_dma(method_registers[NV406E_SEMAPHORE_OFFSET], method_registers[NV406E_SET_CONTEXT_DMA_SEMAPHORE]));
while (semaphore->value != arg)
{
if (Emu.IsStopped())
{
break;
}
std::this_thread::sleep_for(1ms);
std::this_thread::yield();
}
}
force_inline void semaphore_release(thread* rsx, u32 arg)
{
//TODO: dma
vm::ps3::write32(rsx->label_addr + method_registers[NV406E_SEMAPHORE_OFFSET], arg);
vm::ps3::ptr<rsx::semaphore_t> semaphore = vm::cast(get_address_dma(method_registers[NV406E_SEMAPHORE_OFFSET], method_registers[NV406E_SET_CONTEXT_DMA_SEMAPHORE]));
semaphore->timestamp = rsx->timestamp();
semaphore->value = arg;
}
}
@ -60,15 +64,16 @@ namespace rsx
{
force_inline void texture_read_semaphore_release(thread* rsx, u32 arg)
{
//TODO: dma
vm::ps3::write32(rsx->label_addr + method_registers[NV4097_SET_SEMAPHORE_OFFSET], arg);
rsx::semaphore_t& result = rsx::state.context->semaphores[method_registers[NV4097_SET_SEMAPHORE_OFFSET] / sizeof(CellGcmReportData)];
result.timestamp = rsx->timestamp();
result.value = arg;
}
force_inline void back_end_write_semaphore_release(thread* rsx, u32 arg)
{
//TODO: dma
vm::ps3::write32(rsx->label_addr + method_registers[NV4097_SET_SEMAPHORE_OFFSET],
(arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff));
rsx::semaphore_t& result = rsx::state.context->semaphores[method_registers[NV4097_SET_SEMAPHORE_OFFSET] / sizeof(CellGcmReportData)];
result.timestamp = rsx->timestamp();
result.value = (arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff);
}
//fire only when all data passed to rsx cmd buffer
@ -274,18 +279,8 @@ namespace rsx
u8 type = arg >> 24;
u32 offset = arg & 0xffffff;
u32 report_dma = method_registers[NV4097_SET_CONTEXT_DMA_REPORT];
u32 location;
switch (report_dma)
{
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT: location = CELL_GCM_LOCATION_LOCAL; break;
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN: location = CELL_GCM_LOCATION_MAIN; break;
default:
LOG_WARNING(RSX, "nv4097::get_report: bad report dma: 0x%x", report_dma);
return;
}
vm::ps3::ptr<CellGcmReportData> result = vm::cast(get_address(offset, location));
vm::ps3::ptr<CellGcmReportData> result = vm::cast(get_address_dma(offset, report_dma));
result->timer = rsx->timestamp();
@ -356,7 +351,7 @@ namespace rsx
LOG_ERROR(RSX, "%s: y is not null (0x%x)", __FUNCTION__, y);
}
u32 address = get_address(method_registers[NV3062_SET_OFFSET_DESTIN] + (x << 2) + index * 4, method_registers[NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN]);
u32 address = get_address_dma(method_registers[NV3062_SET_OFFSET_DESTIN] + (x << 2) + index * 4, method_registers[NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN]);
vm::ps3::write32(address, arg);
}
};
@ -438,14 +433,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 = state.display_buffers[i].offset;
if (dst_offset < begin || !begin)
{
continue;
}
if (rsx->gcm_buffers[i].width < 720 || rsx->gcm_buffers[i].height < 480)
if (state.display_buffers[i].width < 720 || state.display_buffers[i].height < 480)
{
continue;
}
@ -455,7 +450,7 @@ namespace rsx
return;
}
u32 end = begin + rsx->gcm_buffers[i].height * rsx->gcm_buffers[i].pitch;
u32 end = begin + state.display_buffers[i].height * state.display_buffers[i].pitch;
if (dst_offset < end)
{
@ -470,8 +465,8 @@ namespace rsx
u32 in_offset = u32(in_x * in_bpp + in_pitch * in_y);
u32 out_offset = out_x * out_bpp + out_pitch * out_y;
tiled_region src_region = rsx->get_tiled_address(src_offset + in_offset, src_dma & 0xf);//get_address(src_offset, src_dma);
u32 dst_address = get_address(dst_offset + out_offset, dst_dma);
tiled_region src_region = rsx->get_tiled_address_dma(src_offset + in_offset, src_dma);
u32 dst_address = get_address_dma(dst_offset + out_offset, dst_dma);
if (out_pitch == 0)
{
@ -706,8 +701,8 @@ namespace rsx
u32 dst_offset = method_registers[NV0039_OFFSET_OUT];
u32 dst_dma = method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_OUT];
u8 *dst = (u8*)vm::base(get_address(dst_offset, dst_dma));
const u8 *src = (u8*)vm::base(get_address(src_offset, src_dma));
u8 *dst = (u8*)vm::base(get_address_dma(dst_offset, dst_dma));
const u8 *src = (u8*)vm::base(get_address_dma(src_offset, src_dma));
if (in_pitch == out_pitch && out_pitch == line_length)
{
@ -739,19 +734,18 @@ namespace rsx
Emu.Pause();
}
rsx->gcm_current_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 = 0;
state.last_flip_time = get_system_time() - 1000000;
state.current_display_buffer = arg;
state.flip_status = 0;
if (rsx->flip_handler)
if (state.flip_handler)
{
Emu.GetCallbackManager().Async([func = rsx->flip_handler](PPUThread& ppu)
Emu.GetCallbackManager().Async([func = state.flip_handler](PPUThread& ppu)
{
func(ppu, 1);
});
@ -769,9 +763,9 @@ namespace rsx
void user_command(thread* rsx, u32 arg)
{
if (rsx->user_handler)
if (state.user_handler)
{
Emu.GetCallbackManager().Async([func = rsx->user_handler, arg](PPUThread& ppu)
Emu.GetCallbackManager().Async([func = state.user_handler, arg](PPUThread& ppu)
{
func(ppu, arg);
});

View file

@ -344,7 +344,7 @@ void RSXDebugger::OnClickBuffer(wxMouseEvent& event)
return;
}
const auto buffers = render->gcm_buffers;
const auto buffers = rsx::state.display_buffers;
if(!buffers)
return;
@ -587,7 +587,7 @@ void RSXDebugger::GoToGet(wxCommandEvent& event)
if (const auto render = fxm::get<GSRender>())
{
u32 realAddr;
if (RSXIOMem.getRealAddr(render->ctrl->get.load(), realAddr))
if (RSXIOMem.getRealAddr(rsx::state.context->control.get.load(), realAddr))
{
m_addr = realAddr;
t_addr->SetValue(wxString::Format("%08x", m_addr));
@ -602,7 +602,7 @@ void RSXDebugger::GoToPut(wxCommandEvent& event)
if (const auto render = fxm::get<GSRender>())
{
u32 realAddr;
if (RSXIOMem.getRealAddr(render->ctrl->put.load(), realAddr))
if (RSXIOMem.getRealAddr(rsx::state.context->control.put.load(), realAddr))
{
m_addr = realAddr;
t_addr->SetValue(wxString::Format("%08x", m_addr));
@ -678,15 +678,15 @@ void RSXDebugger::GetBuffers()
return;
}
if (!vm::check_addr(rsx::state.display_buffers.addr()))
return;
// Draw Buffers
// TODO: Currently it only supports color buffers
for (u32 bufferId=0; bufferId < render->gcm_buffers_count; bufferId++)
for (u32 bufferId=0; bufferId < rsx::state.display_buffers_count; bufferId++)
{
if(!vm::check_addr(render->gcm_buffers.addr()))
continue;
auto buffers = render->gcm_buffers;
u32 RSXbuffer_addr = render->local_mem_addr + buffers[bufferId].offset;
auto &buffers = rsx::state.display_buffers;
u32 RSXbuffer_addr = rsx::state.frame_buffer.addr() + buffers[bufferId].offset;
if(!vm::check_addr(RSXbuffer_addr))
continue;