diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 491a97e37d..872ff381c9 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -26,16 +26,19 @@ const u32 tiled_pitches[] = { 0x00010000 }; +struct CellGcmSysConfig { + u32 zculls_addr; + vm::ptr 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(); + + if (!m_config) + return 0; + + return m_config->gcm_info.label_addr + 0x10 * index; } vm::ptr cellGcmGetReportDataAddressLocation(u32 index, u32 location) @@ -94,7 +102,7 @@ vm::ptr cellGcmGetReportDataAddressLocation(u32 index, u32 lo cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong local index (%d)", index); return vm::null; } - return vm::ptr::make(0xC0000000 + index * 0x10); + return vm::ptr::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 _cellGcmFunc12() { - return vm::ptr::make(0xC0000000); // TODO + return vm::ptr::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(); - 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(); + + 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(); + + 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 config) { cellGcmSys.trace("cellGcmGetConfiguration(config=*0x%x)", config); + const auto m_config = fxm::get(); - *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 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(); + 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 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(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(gcm_info.control_addr); + vm::_ref(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(m_config->gcm_info.control_addr); ctrl.put = 0; ctrl.get = 0; ctrl.ref = -1; @@ -390,15 +424,9 @@ s32 _cellGcmInitBody(vm::pptr context, u32 cmdSize, u32 ioSi const auto render = fxm::get(); render->intr_thread = idm::make_ptr("_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(); + 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(); - 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()->flip_mode = mode; - break; - - default: - break; - } + fxm::get()->requested_vsync.store(mode == CELL_GCM_DISPLAY_VSYNC); } void cellGcmSetFlipStatus() @@ -488,6 +515,9 @@ void cellGcmSetFlipStatus() s32 cellGcmSetPrepareFlip(ppu_thread& ppu, vm::ptr ctxt, u32 id) { cellGcmSys.trace("cellGcmSetPrepareFlip(ctxt=*0x%x, id=0x%x)", ctxt, id); + auto m_config = fxm::get(); + if (!m_config) + return CELL_GCM_ERROR_FAILURE; if (id > 7) { @@ -506,9 +536,9 @@ s32 cellGcmSetPrepareFlip(ppu_thread& ppu, vm::ptr 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(gcm_info.control_addr).put += cmd_size; + vm::_ref(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(); + 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(render->tiles_addr)[index] = tile.pack(); + vm::_ptr(m_config->tiles_addr)[index] = tile.pack(); return CELL_OK; } @@ -624,7 +655,7 @@ void cellGcmSetWaitFlip(vm::ptr 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(); + 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(render->zculls_addr)[index] = zcull.pack(); + vm::_ptr(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()->tiles_addr; + auto m_config = fxm::get(); + if (!m_config) + return 0; + return m_config->tiles_addr; } u32 cellGcmGetZcullInfo() { cellGcmSys.warning("cellGcmGetZcullInfo()"); - return fxm::get()->zculls_addr; + auto m_config = fxm::get(); + if (!m_config) + return 0; + return m_config->zculls_addr; } u32 cellGcmGetDisplayInfo() { cellGcmSys.warning("cellGcmGetDisplayInfo()"); - return fxm::get()->gcm_buffers.addr(); + auto m_config = fxm::get(); + if (!m_config) + return 0; + return m_config->gcm_buffers.addr(); } s32 cellGcmGetCurrentDisplayBufferId(vm::ptr id) { cellGcmSys.warning("cellGcmGetCurrentDisplayBufferId(id=*0x%x)", id); - if ((*id = fxm::get()->gcm_current_buffer) > UINT8_MAX) + if ((*id = fxm::get()->current_display_buffer) > UINT8_MAX) { fmt::throw_exception("Unexpected" HERE); } @@ -876,7 +920,7 @@ s32 cellGcmIoOffsetToAddress(u32 ioOffset, vm::ptr 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 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 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()->ctxt_addr, gcm_info.context_addr); + auto m_config = fxm::get(); + 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(gcm_info.control_addr).put; - const auto& get = vm::_ref(gcm_info.control_addr).get; + auto m_config = fxm::get(); + if (!m_config) + return CELL_GCM_ERROR_FAILURE; + const auto& put = vm::_ref(m_config->gcm_info.control_addr).put; + const auto& get = vm::_ref(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 ctx, u32 s32 _cellGcmSetFlipCommandWithWaitLabel(ppu_thread& ppu, vm::ptr 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(); + 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(); + 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(render->tiles_addr)[index] = tile.pack(); + vm::_ptr(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 context, u32 count) { cellGcmSys.trace("cellGcmCallback(context=*0x%x, count=0x%x)", context, count); + auto m_config = fxm::get(); + if (!m_config) + return CELL_GCM_ERROR_FAILURE; - auto& ctrl = vm::_ref(gcm_info.control_addr); + auto& ctrl = vm::_ref(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; -}); +}); \ No newline at end of file diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.h b/rpcs3/Emu/Cell/lv2/sys_rsx.h index 91caa0b307..918c9633c3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.h +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.h @@ -1,5 +1,44 @@ #pragma once +struct RsxDmaControl { + u8 resv[0x40]; + atomic_be_t put; + atomic_be_t get; + atomic_be_t ref; + be_t unk[2]; + be_t unk1; +}; + +struct RsxSemaphore { + be_t val; + be_t pad; + be_t timestamp; +}; + +struct RsxNotify { + be_t timestamp; + be_t zero; +}; + +struct RsxReport { + be_t timestamp; + be_t val; + be_t pad; +}; + +struct RsxReports { + RsxSemaphore semaphore[0x100]; + RsxNotify notify[64]; + RsxReport report[2048]; +}; + +struct RsxDisplayInfo { + be_t offset; + be_t pitch; + be_t width; + be_t height; +}; + // SysCalls s32 sys_rsx_device_open(); s32 sys_rsx_device_close(); diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index ac85fbc583..5396fed5dd 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -786,6 +786,7 @@ namespace vm std::make_shared(0xC0000000, 0x10000000), // video std::make_shared(0xD0000000, 0x10000000), // stack std::make_shared(0xE0000000, 0x20000000), // SPU reserved + std::make_shared(0x40000000, 0x10000000), // rsx contexts }; } } diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 9636994c12..eacdb611ec 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -523,10 +523,9 @@ void D3D12GSRender::flip(int buffer) size_t offset = 0; if (false) { - CellGcmDisplayInfo* buffers = nullptr;// = vm::ps3::_ptr(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(addr); row_pitch = align(w * 4, 256); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index eba37298e8..9bcd2e1d82 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -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); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 4a26cdca99..c81ea661e6 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -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()->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(ctrlAddress); + ctrl = vm::_ptr(ctrlAddress); this->ioAddress = ioAddress; this->ioSize = ioSize; local_mem_addr = localAddress; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index f2963640ac..03d79a8163 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -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 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 gcm_buffers = vm::null; - u32 gcm_buffers_count; - u32 gcm_current_buffer; + atomic_t 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); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 9ab4898c31..32bcc914a8 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -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 }); diff --git a/rpcs3/Emu/RSX/gcm_enums.cpp b/rpcs3/Emu/RSX/gcm_enums.cpp index f2573841db..cd667e6090 100644 --- a/rpcs3/Emu/RSX/gcm_enums.cpp +++ b/rpcs3/Emu/RSX/gcm_enums.cpp @@ -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; } diff --git a/rpcs3/Emu/RSX/gcm_enums.h b/rpcs3/Emu/RSX/gcm_enums.h index ae22ce2040..f8e1066cb8 100644 --- a/rpcs3/Emu/RSX/gcm_enums.h +++ b/rpcs3/Emu/RSX/gcm_enums.h @@ -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, diff --git a/rpcs3/Emu/RSX/rsx_decode.h b/rpcs3/Emu/RSX/rsx_decode.h index c65b08fdab..f41e605e1f 100644 --- a/rpcs3/Emu/RSX/rsx_decode.h +++ b/rpcs3/Emu/RSX/rsx_decode.h @@ -1988,6 +1988,32 @@ struct registers_decoder } }; +template<> +struct registers_decoder +{ + 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 { @@ -4600,7 +4626,7 @@ constexpr std::integer_sequencelabel_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(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(rsx->label_addr); + sema.semaphore[index].val = val; + sema.semaphore[index].pad = 0; + sema.semaphore[index].timestamp = rsx->timestamp(); } template @@ -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; diff --git a/rpcs3/Emu/RSX/rsx_methods.h b/rpcs3/Emu/RSX/rsx_methods.h index e94abc8bbb..d9684be642 100644 --- a/rpcs3/Emu/RSX/rsx_methods.h +++ b/rpcs3/Emu/RSX/rsx_methods.h @@ -889,6 +889,11 @@ namespace rsx return decode().primitive(); } + u32 semaphore_context_dma_406e() const + { + return decode().context_dma(); + } + u32 semaphore_offset_406e() const { return decode().semaphore_offset(); diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index a837decfc1..4605fbf1c4 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -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))