From b48f00ed6a1bf548cca19e7eea579782f8a95221 Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 25 Jul 2017 21:33:32 -0500 Subject: [PATCH 1/4] rsx/gcm: Implement rsx dma. Refactor gcm/rsx to not be as codependent --- rpcs3/Emu/Cell/Modules/cellGcmSys.cpp | 236 ++++++++++++++++---------- rpcs3/Emu/Cell/lv2/sys_rsx.h | 39 +++++ rpcs3/Emu/Memory/vm.cpp | 1 + rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp | 7 +- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 8 +- rpcs3/Emu/RSX/RSXThread.cpp | 74 ++++---- rpcs3/Emu/RSX/RSXThread.h | 19 +-- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 6 +- rpcs3/Emu/RSX/gcm_enums.cpp | 2 +- rpcs3/Emu/RSX/gcm_enums.h | 2 +- rpcs3/Emu/RSX/rsx_decode.h | 28 ++- rpcs3/Emu/RSX/rsx_methods.cpp | 56 +++--- rpcs3/Emu/RSX/rsx_methods.h | 5 + rpcs3/rpcs3qt/rsx_debugger.cpp | 11 +- 14 files changed, 314 insertions(+), 180 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 491a97e37d72..872ff381c9c6 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 91caa0b30788..918c9633c3a1 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 ac85fbc58316..5396fed5dd2a 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 9636994c120f..eacdb611ec7a 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 eba37298e8bf..9bcd2e1d8296 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 4a26cdca998e..c81ea661e6b5 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: - { - 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); + } - 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; - //if (fxm::get()->strict_ordering[offset >> 20]) - //{ - // _mm_mfence(); // probably doesn't have any effect on current implementation - //} + case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN: + { + if (u32 result = RSXIOMem.RealAddr(0x0e000000 + offset)) + { + return result; } - case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_REPORT: - return 0x100000 + offset; // TODO: Properly implement - - case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN: - return 0x800 + 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_TO_MEMORY_GET_NOTIFY0: - return 0x40 + 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_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 0x100 + offset; // TODO: Properly implement + case CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW: + case CELL_GCM_CONTEXT_DMA_SEMAPHORE_R: + return 0x40300000 + 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_RW: + 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); + case CELL_GCM_CONTEXT_DMA_DEVICE_R: + return 0x40000000 + offset; - 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 f2963640ac31..03d79a81634d 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 9ab4898c312f..32bcc914a862 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 f2573841db22..cd667e6090c0 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 ae22ce204053..f8e1066cb80f 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 c65b08fdab44..f41e605e1fc3 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 e94abc8bbbc5..d9684be6427d 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 a837decfc120..4605fbf1c43f 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)) From 44c43a1a62b03ba82dc13eb654f4f85a3ea7e884 Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 25 Jul 2017 21:57:43 -0500 Subject: [PATCH 2/4] sys_rsx: implement support for lle-gcm --- rpcs3/Emu/Cell/Modules/cellGcmSys.cpp | 1 + rpcs3/Emu/Cell/Modules/cellSpurs.cpp | 4 +- rpcs3/Emu/Cell/lv2/sys_event.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_event.h | 2 +- rpcs3/Emu/Cell/lv2/sys_rsx.cpp | 275 ++++++++++++++++++++++---- rpcs3/Emu/Cell/lv2/sys_rsx.h | 55 +++++- rpcs3/Emu/RSX/RSXThread.cpp | 4 +- rpcs3/Emu/RSX/RSXThread.h | 4 + rpcs3/Emu/RSX/rsx_methods.cpp | 59 ++++-- 9 files changed, 348 insertions(+), 58 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 872ff381c9c6..ccbf6eb8eb5e 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -425,6 +425,7 @@ s32 _cellGcmInitBody(vm::pptr context, u32 cmdSize, u32 ioSi render->intr_thread = idm::make_ptr("_gcm_intr_thread", 1, 0x4000); render->intr_thread->run(); render->main_mem_addr = 0; + render->isHLE = true; render->label_addr = m_config->gcm_info.label_addr; render->init(ioAddress, ioSize, m_config->gcm_info.control_addr - 0x40, local_addr); diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp index 6cb515683de9..a12e591c7afe 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -880,7 +880,7 @@ s32 _spurs::stop_event_helper(ppu_thread& ppu, vm::ptr spurs) return CELL_SPURS_CORE_ERROR_STAT; } - if (sys_event_port_send(ppu, spurs->eventPort, 0, 1, 0) != CELL_OK) + if (sys_event_port_send(spurs->eventPort, 0, 1, 0) != CELL_OK) { return CELL_SPURS_CORE_ERROR_STAT; } @@ -2794,7 +2794,7 @@ s32 cellSpursEventFlagSet(ppu_thread& ppu, vm::ptr eventFlag // Signal the PPU thread to be woken up eventFlag->pendingRecvTaskEvents[ppuWaitSlot] = ppuEvents; - CHECK_SUCCESS(sys_event_port_send(ppu, eventFlag->eventPortId, 0, 0, 0)); + CHECK_SUCCESS(sys_event_port_send(eventFlag->eventPortId, 0, 0, 0)); } if (pendingRecv) diff --git a/rpcs3/Emu/Cell/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp index 68aad0c06210..3386105aabda 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -418,7 +418,7 @@ error_code sys_event_port_disconnect(u32 eport_id) return CELL_OK; } -error_code sys_event_port_send(ppu_thread& ppu, u32 eport_id, u64 data1, u64 data2, u64 data3) +error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) { sys_event.trace("sys_event_port_send(eport_id=0x%x, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3); diff --git a/rpcs3/Emu/Cell/lv2/sys_event.h b/rpcs3/Emu/Cell/lv2/sys_event.h index ab1ea7ee500e..9f9fff268e65 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.h +++ b/rpcs3/Emu/Cell/lv2/sys_event.h @@ -137,4 +137,4 @@ error_code sys_event_port_create(vm::ps3::ptr eport_id, s32 port_type, u64 error_code sys_event_port_destroy(u32 eport_id); error_code sys_event_port_connect_local(u32 event_port_id, u32 event_queue_id); error_code sys_event_port_disconnect(u32 eport_id); -error_code sys_event_port_send(ppu_thread& ppu, u32 event_port_id, u64 data1, u64 data2, u64 data3); +error_code sys_event_port_send(u32 event_port_id, u64 data1, u64 data2, u64 data3); diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index 2cb5ba9945b7..a2dccee99a74 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -1,14 +1,28 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" - +#include "Emu/Cell/PPUModule.h" +#include "Emu/RSX/GSRender.h" +#include "Emu/IdManager.h" #include "Emu/Cell/ErrorCodes.h" #include "sys_rsx.h" +#include "sys_event.h" namespace vm { using namespace ps3; } logs::channel sys_rsx("sys_rsx"); +extern u64 get_timebased_time(); + +struct SysRsxConfig { + be_t rsx_event_port{ 0 }; + u32 driverInfo{ 0 }; +}; + +u64 rsxTimeStamp() { + return get_timebased_time(); +} + s32 sys_rsx_device_open() { sys_rsx.todo("sys_rsx_device_open()"); @@ -35,7 +49,10 @@ s32 sys_rsx_device_close() */ s32 sys_rsx_memory_allocate(vm::ptr mem_handle, vm::ptr mem_addr, u32 size, u64 flags, u64 a5, u64 a6, u64 a7) { - sys_rsx.todo("sys_rsx_memory_allocate(mem_handle=*0x%x, mem_addr=*0x%x, size=0x%x, flags=0x%llx, a5=0x%llx, a6=0x%llx, a7=0x%llx)", mem_handle, mem_addr, size, flags, a5, a6, a7); + sys_rsx.warning("sys_rsx_memory_allocate(mem_handle=*0x%x, mem_addr=*0x%x, size=0x%x, flags=0x%llx, a5=0x%llx, a6=0x%llx, a7=0x%llx)", mem_handle, mem_addr, size, flags, a5, a6, a7); + + *mem_handle = 1; + *mem_addr = vm::falloc(0xC0000000, size, vm::video); return CELL_OK; } @@ -60,11 +77,86 @@ s32 sys_rsx_memory_free(u32 mem_handle) * @param mem_ctx (IN): mem_ctx given by sys_rsx_memory_allocate * @param system_mode (IN): */ -s32 sys_rsx_context_allocate(vm::ptr context_id, vm::ptr lpar_dma_control, vm::ptr lpar_driver_info, vm::ptr lpar_reports, u64 mem_ctx, u64 system_mode) +s32 sys_rsx_context_allocate(vm::ptr context_id, vm::ptr lpar_dma_control, vm::ptr lpar_driver_info, vm::ptr lpar_reports, u64 mem_ctx, u64 system_mode) { - sys_rsx.todo("sys_rsx_context_allocate(context_id=*0x%x, lpar_dma_control=*0x%x, lpar_driver_info=*0x%x, lpar_reports=*0x%x, mem_ctx=0x%llx, system_mode=0x%llx)", + sys_rsx.warning("sys_rsx_context_allocate(context_id=*0x%x, lpar_dma_control=*0x%x, lpar_driver_info=*0x%x, lpar_reports=*0x%x, mem_ctx=0x%llx, system_mode=0x%llx)", context_id, lpar_dma_control, lpar_driver_info, lpar_reports, mem_ctx, system_mode); + auto m_sysrsx = fxm::make(); + if (!m_sysrsx) + fmt::throw_exception("sys_rsx_context_allocate called twice."); + + u32 addr = vm::falloc(0x40000000, 0x400000); + if (addr == 0 || addr != 0x40000000) + fmt::throw_exception("Failed to alloc 0x40000000."); + + *context_id = 0x55555555; + + *lpar_dma_control = 0x40100000; + *lpar_driver_info = 0x40200000; + *lpar_reports = 0x40300000; + + auto &reports = vm::_ref(*lpar_reports); + std::memset(&reports, 0, sizeof(RsxReports)); + + for (int i = 0; i < 64; ++i) + reports.notify[i].timestamp = (u64)-1; + + for (int i = 0; i < 256; ++i) { + reports.semaphore[i].val = 0x1337C0D3; + reports.semaphore[i].pad = 0x1337BABE; + reports.semaphore[i].timestamp = (u64)-1; // technically different but should be fine + } + + for (int i = 0; i < 2048; ++i) + reports.report[i].timestamp = (u64)-1; + + auto &driverInfo = vm::_ref(*lpar_driver_info); + + std::memset(&driverInfo, 0, sizeof(RsxDriverInfo)); + + driverInfo.version_driver = 0x211; + driverInfo.version_gpu = 0x5c; + driverInfo.memory_size = 0xFE00000; + driverInfo.nvcore_frequency = 500000000; // 0x1DCD6500 + driverInfo.memory_frequency = 650000000; // 0x26BE3680 + driverInfo.reportsNotifyOffset = 0x1000; + driverInfo.reportsOffset = 0; + driverInfo.reportsReportOffset = 0x1400; + driverInfo.systemModeFlags = system_mode; + driverInfo.hardware_channel = 1; // * i think* this 1 for games, 0 for vsh + + m_sysrsx->driverInfo = *lpar_driver_info; + + auto &dmaControl = vm::_ref(*lpar_dma_control); + dmaControl.get = 0; + dmaControl.put = 0; + dmaControl.ref = 0xFFFFFFFF; + + if (false/*system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB*/) + RSXIOMem.SetRange(0, 0x20000000 /*512MB*/); + else + RSXIOMem.SetRange(0, 0x10000000 /*256MB*/); + + sys_event_queue_attribute_t attr; + attr.protocol = SYS_SYNC_PRIORITY; + attr.type = SYS_PPU_QUEUE; + auto queueId = vm::make_var(0); + sys_event_queue_create(queueId, vm::make_var(attr), 0, 0x20); + driverInfo.handler_queue = queueId->value(); + + sys_event_port_create(queueId, SYS_EVENT_PORT_LOCAL, 0); + sys_event_port_connect_local(queueId->value(), driverInfo.handler_queue); + + m_sysrsx->rsx_event_port = queueId->value(); + + const auto render = fxm::get(); + render->display_buffers_count = 0; + render->current_display_buffer = 0; + render->main_mem_addr = 0; + render->label_addr = *lpar_reports; + render->init(0, 0, *lpar_dma_control, 0xC0000000); + return CELL_OK; } @@ -89,9 +181,11 @@ s32 sys_rsx_context_free(u32 context_id) */ s32 sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 flags) { - sys_rsx.todo("sys_rsx_context_iomap(context_id=0x%x, io=0x%x, ea=0x%x, size=0x%x, flags=0x%llx)", context_id, io, ea, size, flags); - - return CELL_OK; + sys_rsx.warning("sys_rsx_context_iomap(context_id=0x%x, io=0x%x, ea=0x%x, size=0x%x, flags=0x%llx)", context_id, io, ea, size, flags); + if (size == 0) return CELL_OK; + if (RSXIOMem.Map(ea, size, io)) + return CELL_OK; + return CELL_EINVAL; } /* @@ -101,58 +195,142 @@ s32 sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 flags) * @param io_addr (IN): IO address. E.g. 0x00600000 (Start page 6) * @param size (IN): Size to unmap in byte. E.g. 0x00200000 */ -s32 sys_rsx_context_iounmap(u32 context_id, u32 a2, u32 io_addr, u32 size) +s32 sys_rsx_context_iounmap(u32 context_id, u32 io_addr, u32 a3, u32 size) { - sys_rsx.todo("sys_rsx_context_iounmap(context_id=0x%x, a2=0x%x, io_addr=0x%x, size=0x%x)", context_id, a2, io_addr, size); - - return CELL_OK; + sys_rsx.warning("sys_rsx_context_iounmap(context_id=0x%x, io_addr=0x%x, a3=0x%x, size=0x%x)", context_id, io_addr, a3, size); + if (RSXIOMem.UnmapAddress(io_addr, size)) + return CELL_OK; + return CELL_EINVAL; } /* * lv2 SysCall 674 (0x2A2): sys_rsx_context_attribute * @param context_id (IN): RSX context, e.g. 0x55555555 - * @param package_id (IN): - * @param a3 (IN): - * @param a4 (IN): - * @param a5 (IN): - * @param a6 (IN): + * @param package_id (IN): + * @param a3 (IN): + * @param a4 (IN): + * @param a5 (IN): + * @param a6 (IN): */ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6) { - sys_rsx.todo("sys_rsx_context_attribute(context_id=0x%x, package_id=0x%x, a3=0x%llx, a4=0x%llx, a5=0x%llx, a6=0x%llx)", context_id, package_id, a3, a4, a5, a6); + // Flip/queue/user command/vblank as trace to help with log spam + if (package_id == 0x102 || package_id == 0x103 || package_id == 0xFED || package_id == 0xFEF) + sys_rsx.trace("sys_rsx_context_attribute(context_id=0x%x, package_id=0x%x, a3=0x%llx, a4=0x%llx, a5=0x%llx, a6=0x%llx)", context_id, package_id, a3, a4, a5, a6); + else + sys_rsx.warning("sys_rsx_context_attribute(context_id=0x%x, package_id=0x%x, a3=0x%llx, a4=0x%llx, a5=0x%llx, a6=0x%llx)", context_id, package_id, a3, a4, a5, a6); + + // todo: these event ports probly 'shouldnt' be here as i think its supposed to be interrupts that are sent from rsx somewhere in lv1 + + const auto render = fxm::get(); + + //hle protection + if (render->isHLE) + return 0; - switch(package_id) + auto m_sysrsx = fxm::get(); + + auto &driverInfo = vm::_ref(m_sysrsx->driverInfo); + switch (package_id) { case 0x001: // FIFO + render->ctrl->get = a3; + render->ctrl->put = a4; break; - + case 0x100: // Display mode set break; - - case 0x101: // Display sync + case 0x101: // Display sync set, cellGcmSetFlipMode + // a4 == 2 is vsync, a4 == 1 is hsync + render->requested_vsync.store(a4 == 2); break; case 0x102: // Display flip + driverInfo.head[a3].flipFlags |= 0x80000000; + driverInfo.head[a3].lastFlipTime = rsxTimeStamp(); // should rsxthread set this? + // lets give this a shot for giving bufferid back to gcm + driverInfo.head[a3].flipBufferId = driverInfo.head[a3].queuedBufferId; + // seems gcmSysWaitLabel uses this offset, so lets set it to 0 every flip + vm::_ref(0x40300010) = 0; + if (a3 == 0) + sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 3), 0); + if (a3 == 1) + sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 4), 0); break; - case 0x103: // ? + case 0x103: // Display Queue + driverInfo.head[a3].queuedBufferId = a4; + driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4); + if (a3 == 0) + sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 5), 0); + if (a3 == 1) + sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 6), 0); break; - case 0x104: // Display buffer + { + u8 id = a3 & 0xFF; + u32 width = (a4 >> 32) & 0xFFFFFFFF; + u32 height = a4 & 0xFFFFFFFF; + u32 pitch = (a5 >> 32) & 0xFFFFFFFF; + u32 offset = a5 & 0xFFFFFFFF; + if (id > 7) + return -17; + render->display_buffers[id].width = width; + render->display_buffers[id].height = height; + render->display_buffers[id].pitch = pitch; + render->display_buffers[id].offset = offset; + + render->display_buffers_count = std::max((u32)id + 1, render->display_buffers_count); + } + break; + case 0x105: // destroy buffer? break; case 0x106: // ? (Used by cellGcmInitPerfMon) break; + case 0x108: // cellGcmSetSecondVFrequency + // a4 == 3, CELL_GCM_DISPLAY_FREQUENCY_59_94HZ + // a4 == 2, CELL_GCM_DISPLAY_FREQUENCY_SCANOUT + // a4 == 4, CELL_GCM_DISPLAY_FREQUENCY_DISABLE + // Note: Scanout/59_94 is ignored currently as we report refresh rate of 59_94hz as it is, so the difference doesnt matter + render->enable_second_vhandler.store(a4 != 4); + break; + case 0x10a: // ? Involved in managing flip status through cellGcmResetFlipStatus + { + if (a3 > 7) + return -17; + u32 flipStatus = driverInfo.head[a3].flipFlags; + flipStatus = (flipStatus & a4) | a5; + driverInfo.head[a3].flipFlags = flipStatus; + } + break; - case 0x10a: // ? + case 0x10D: // Called by cellGcmInitCursor break; case 0x300: // Tiles - break; + { + //a4 high bits = ret.tile = (location + 1) | (bank << 4) | ((offset / 0x10000) << 16) | (location << 31); + //a4 low bits = ret.limit = ((offset + size - 1) / 0x10000) << 16 | (location << 31); + //a5 high bits = ret.pitch = (pitch / 0x100) << 8; + //a5 low bits = ret.format = base | ((base + ((size - 1) / 0x10000)) << 13) | (comp << 26) | (1 << 30); + + auto& tile = render->tiles[a3]; + tile.location = ((a4 >> 32) & 0xF) - 1; + tile.offset = ((((a4 >> 32) & 0xFFFFFFFF) >> 16) * 0x10000); + tile.size = ((((a4 & 0x7FFFFFFF) >> 16) + 1) * 0x10000) - tile.offset; + tile.pitch = (((a5 >> 32) & 0xFFFFFFFF) >> 8) * 0x100; + tile.comp = ((a5 & 0xFFFFFFFF) >> 26) & 0xF; + tile.base = (a5 & 0xFFFFFFFF) & 0x7FF; + tile.bank = (((a4 >> 32) & 0xFFFFFFFF) >> 4) & 0xF; + tile.binded = a5 != 0; + } + break; case 0x301: // Depth-buffer (Z-cull) break; - + case 0x302: // something with zcull + break; case 0x600: // Framebuffer setup break; @@ -162,6 +340,24 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6 case 0x602: // Framebuffer blit sync break; + case 0x603: // Framebuffer close + break; + + case 0xFED: // hack: vblank command + // todo: this is wrong and should be 'second' vblank handler and freq, but since currently everything is reported as being 59.94, this should be fine + driverInfo.head[a3].vBlankCount++; + driverInfo.head[a3].lastSecondVTime = rsxTimeStamp(); + sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 1), 0); + if (render->enable_second_vhandler) + sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 11), 0); // second vhandler + break; + case 0xFEF: // hack: user command + // 'custom' invalid package id for now + // as i think we need custom lv1 interrupts to handle this accurately + // this also should probly be set by rsxthread + driverInfo.userCmdParam = a4; + sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 7), 0); + break; default: return CELL_EINVAL; } @@ -175,19 +371,19 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6 * @param a2 (OUT): Unused? * @param dev_id (IN): An immediate value and always 8. (cellGcmInitPerfMon uses 11, 10, 9, 7, 12 successively). */ -s32 sys_rsx_device_map(vm::ptr addr, vm::ptr a2, u32 dev_id) +s32 sys_rsx_device_map(vm::ptr addr, vm::ptr a2, u32 dev_id) { - sys_rsx.todo("sys_rsx_device_map(addr=*0x%x, a2=*0x%x, dev_id=0x%x)", addr, a2, dev_id); + sys_rsx.warning("sys_rsx_device_map(addr=*0x%x, a2=*0x%x, dev_id=0x%x)", addr, a2, dev_id); - if (dev_id > 15) { - // TODO: Throw RSX error - return CELL_EINVAL; + if (dev_id != 8) { + // TODO: lv1 related + fmt::throw_exception("sys_rsx_device_map: Invalid dev_id %d", dev_id); } - if (dev_id == 0 || dev_id > 8) { - // TODO: lv1 related so we may ignore it. - // if (something) { return CELL_EPERM; } - } + // a2 seems to not be referenced in cellGcmSys + *a2 = 0; + + *addr = 0x40000000; return CELL_OK; } @@ -203,9 +399,12 @@ s32 sys_rsx_device_unmap(u32 dev_id) return CELL_OK; } -s32 sys_rsx_attribute(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5) +/* + * lv2 SysCall 677 (0x2A5): sys_rsx_attribute + */ +s32 sys_rsx_attribute(u32 packageId, u32 a2, u32 a3, u32 a4, u32 a5) { - sys_rsx.todo("sys_rsx_attribute(a1=0x%x, a2=0x%x, a3=0x%x, a4=0x%x, a5=0x%x)", a1, a2, a3, a4, a5); + sys_rsx.warning("sys_rsx_attribute(packageId=0x%x, a2=0x%x, a3=0x%x, a4=0x%x, a5=0x%x)", packageId, a2, a3, a4, a5); return CELL_OK; -} +} \ 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 918c9633c3a1..1883735ecfc4 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.h +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.h @@ -1,5 +1,54 @@ #pragma once +struct RsxDriverInfo { + be_t version_driver; // 0x0 + be_t version_gpu; // 0x4 + be_t memory_size; // 0x8 + be_t hardware_channel; // 0xC + be_t nvcore_frequency; // 0x10 + be_t memory_frequency; // 0x14 + be_t unk1[4]; // 0x18 - 0x24 + be_t unk2; // 0x28 -- pgraph stuff + be_t reportsNotifyOffset;// 0x2C offset to notify memory + be_t reportsOffset; // 0x30 offset to reports memory + be_t reportsReportOffset;// 0x34 offset to reports in reports memory + be_t unk3[6]; // 0x38-0x54 + be_t systemModeFlags; // 0x54 + u8 unk4[0x1064]; // 0x10B8 + struct Head { + be_t lastFlipTime; // 0x0 last flip time + be_t flipFlags; // 0x8 flags to handle flip/queue + be_t unk1; // 0xC + be_t flipBufferId; // 0x10 + be_t queuedBufferId; // 0x14 todo: this is definately not this variable but its 'unused' so im using it for queueId to pass to flip handler + be_t unk3; // 0x18 + be_t unk6; // 0x18 possible low bits of time stamp? used in getlastVBlankTime + be_t lastSecondVTime; // 0x20 last time for second vhandler freq + be_t unk4; // 0x28 + be_t vBlankCount; // 0x30 + be_t unk; // 0x38 possible u32, 'flip field', top/bottom for interlaced + be_t unk5; // 0x3C possible high bits of time stamp? used in getlastVBlankTime + } head[8]; // size = 0x40, 0x200 + be_t unk7; // 0x12B8 + be_t unk8; // 0x12BC + be_t handlers; // 0x12C0 -- flags showing which handlers are set + be_t unk9; // 0x12C4 + be_t unk10; // 0x12C8 + be_t userCmdParam; // 0x12CC + be_t handler_queue; // 0x12D0 + be_t unk11; // 0x12D4 + be_t unk12; // 0x12D8 + be_t unk13; // 0x12DC + be_t unk14; // 0x12E0 + be_t unk15; // 0x12E4 + be_t unk16; // 0x12E8 + be_t unk17; // 0x12F0 + be_t lastError; // 0x12F4 error param for cellGcmSetGraphicsHandler + // todo: theres more to this +}; +static_assert(sizeof(RsxDriverInfo) == 0x12F8, "rsxSizeTest"); +static_assert(sizeof(RsxDriverInfo::Head) == 0x40, "rsxHeadSizeTest"); + struct RsxDmaControl { u8 resv[0x40]; atomic_be_t put; @@ -44,11 +93,11 @@ s32 sys_rsx_device_open(); s32 sys_rsx_device_close(); s32 sys_rsx_memory_allocate(vm::ps3::ptr mem_handle, vm::ps3::ptr mem_addr, u32 size, u64 flags, u64 a5, u64 a6, u64 a7); s32 sys_rsx_memory_free(u32 mem_handle); -s32 sys_rsx_context_allocate(vm::ps3::ptr context_id, vm::ps3::ptr lpar_dma_control, vm::ps3::ptr lpar_driver_info, vm::ps3::ptr lpar_reports, u64 mem_ctx, u64 system_mode); +s32 sys_rsx_context_allocate(vm::ps3::ptr context_id, vm::ps3::ptr lpar_dma_control, vm::ps3::ptr lpar_driver_info, vm::ps3::ptr lpar_reports, u64 mem_ctx, u64 system_mode); s32 sys_rsx_context_free(u32 context_id); s32 sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 flags); s32 sys_rsx_context_iounmap(u32 context_id, u32 a2, u32 io_addr, u32 size); s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6); -s32 sys_rsx_device_map(vm::ps3::ptr addr, vm::ps3::ptr a2, u32 dev_id); +s32 sys_rsx_device_map(vm::ps3::ptr addr, vm::ps3::ptr a2, u32 dev_id); s32 sys_rsx_device_unmap(u32 dev_id); -s32 sys_rsx_attribute(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5); +s32 sys_rsx_attribute(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5); \ No newline at end of file diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index c81ea661e6b5..4cce30ea479b 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -388,7 +388,7 @@ namespace rsx if (get_system_time() - start_time > vblank_count * 1000000 / 60) { vblank_count++; - + sys_rsx_context_attribute(0x55555555, 0xFED, 1, 0, 0, 0); if (vblank_handler) { intr_thread->cmd_list @@ -403,6 +403,8 @@ namespace rsx continue; } + while (Emu.IsPaused()) + std::this_thread::sleep_for(10ms); std::this_thread::sleep_for(1ms); // hack } diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 03d79a81634d..a8e93eb8b7cb 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -131,11 +131,15 @@ namespace rsx public: std::shared_ptr intr_thread; + // I hate this flag, but until hle is closer to lle, its needed + bool isHLE{ false }; + u32 ioAddress, ioSize; u32 flip_status; int debug_level; atomic_t requested_vsync{false}; + atomic_t enable_second_vhandler{false}; RsxDisplayInfo display_buffers[8]; u32 display_buffers_count{0}; diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 81a59b04610d..08a5e73f7eba 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -6,6 +6,7 @@ #include "rsx_utils.h" #include "rsx_decode.h" #include "Emu/Cell/PPUCallback.h" +#include "Emu/Cell/lv2/sys_rsx.h" #include #include @@ -485,6 +486,7 @@ namespace rsx if (in_origin != blit_engine::transfer_origin::corner) { LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown origin (%d)", (u8)in_origin); + return; } if (operation != rsx::blit_engine::transfer_operation::srccopy) @@ -879,7 +881,8 @@ namespace rsx 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(); + if (rsx->isHLE) + rsx->reset(); rsx->last_flip_time = get_system_time() - 1000000; rsx->flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_DONE; @@ -899,6 +902,7 @@ namespace rsx void user_command(thread* rsx, u32, u32 arg) { + sys_rsx_context_attribute(0x55555555, 0xFEF, 0, arg, 0, 0); if (rsx->user_handler) { rsx->intr_thread->cmd_list @@ -912,6 +916,31 @@ namespace rsx } } + namespace gcm + { + // not entirely sure which one should actually do the flip, or if these should be handled seperately, + // so for now lets flip in queue and just let the driver deal with it + template + struct driver_flip + { + static void impl(thread* rsx, u32 _reg, u32 arg) + { + rsx->reset(); + sys_rsx_context_attribute(0x55555555, 0x102, index, arg, 0, 0); + } + }; + + template + struct queue_flip + { + static void impl(thread* rsx, u32 _reg, u32 arg) + { + flip_command(rsx, _reg, arg); + sys_rsx_context_attribute(0x55555555, 0x103, index, arg, 0, 0); + } + }; + } + void rsx_state::reset() { //setup method registers @@ -1093,10 +1122,17 @@ namespace rsx methods[NV4097_SET_SURFACE_COLOR_BOFFSET] = nullptr; methods[NV4097_SET_SURFACE_PITCH_B] = nullptr; methods[NV4097_SET_SURFACE_COLOR_TARGET] = nullptr; + methods[0x224 >> 2] = nullptr; + methods[0x228 >> 2] = nullptr; + methods[0x230 >> 2] = nullptr; methods[NV4097_SET_SURFACE_PITCH_Z] = nullptr; methods[NV4097_INVALIDATE_ZCULL] = nullptr; methods[NV4097_SET_CYLINDRICAL_WRAP] = nullptr; methods[NV4097_SET_CYLINDRICAL_WRAP1] = nullptr; + methods[0x240 >> 2] = nullptr; + methods[0x244 >> 2] = nullptr; + methods[0x248 >> 2] = nullptr; + methods[0x24C >> 2] = nullptr; methods[NV4097_SET_SURFACE_PITCH_C] = nullptr; methods[NV4097_SET_SURFACE_PITCH_D] = nullptr; methods[NV4097_SET_SURFACE_COLOR_COFFSET] = nullptr; @@ -1165,6 +1201,7 @@ namespace rsx methods[NV4097_SET_FOG_MODE] = nullptr; methods[NV4097_SET_FOG_PARAMS] = nullptr; methods[NV4097_SET_FOG_PARAMS + 1] = nullptr; + methods[0x8d8 >> 2] = nullptr; methods[NV4097_SET_SHADER_PROGRAM] = nullptr; methods[NV4097_SET_VERTEX_TEXTURE_OFFSET] = nullptr; methods[NV4097_SET_VERTEX_TEXTURE_FORMAT] = nullptr; @@ -1248,6 +1285,7 @@ namespace rsx methods[NV4097_SET_TEXTURE_BORDER_COLOR] = nullptr; methods[NV4097_SET_VERTEX_DATA4F_M] = nullptr; methods[NV4097_SET_COLOR_KEY_COLOR] = nullptr; + methods[0x1d04 >> 2] = nullptr; methods[NV4097_SET_SHADER_CONTROL] = nullptr; methods[NV4097_SET_INDEXED_CONSTANT_READ_LIMITS] = nullptr; methods[NV4097_SET_SEMAPHORE_OFFSET] = nullptr; @@ -1374,6 +1412,8 @@ namespace rsx bind_array(); bind_array(); + bind_array<(0x400 >> 2), 1, 0x10, nullptr>(); + bind_array<(0x440 >> 2), 1, 0x20, nullptr>(); bind_array(); bind_array(); bind_array(); @@ -1399,16 +1439,6 @@ namespace rsx bind(); bind(); - /* - - // Store previous fbo addresses to detect RTT config changes. - std::array m_previous_color_address = {}; - u32 m_previous_address_z = 0; - u32 m_previous_target = 0; - u32 m_previous_clip_horizontal = 0; - u32 m_previous_clip_vertical = 0; - */ - // NV4097 bind(); bind(); @@ -1467,9 +1497,14 @@ namespace rsx //NV0039 bind(); + // lv1 hypervisor + bind_array(); + bind_range(); + bind_range(); + // custom methods bind(); - bind_array(); + return true; }(); From a640c52c20c0a72b0eccc51a066f789cb4218673 Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 25 Jul 2017 22:00:05 -0500 Subject: [PATCH 3/4] d3d12: Fix 0 sized framebuffer crashes --- rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp index 370be51ea741..b936f58d331a 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp @@ -175,9 +175,16 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis rsx::method_registers.clear_color_b() / 255.f, rsx::method_registers.clear_color_a() / 255.f, }; + + u32 clip_width = rsx::method_registers.surface_clip_width(); + u32 clip_height = rsx::method_registers.surface_clip_height(); + + if (clip_height == 0 || clip_width == 0) + return; + m_rtts.prepare_render_target(copycmdlist, rsx::method_registers.surface_color(), rsx::method_registers.surface_depth_fmt(), - rsx::method_registers.surface_clip_width(), rsx::method_registers.surface_clip_height(), + clip_width, clip_height, rsx::method_registers.surface_color_target(), get_color_surface_addresses(), get_zeta_surface_address(), m_device.Get(), clear_color, 1.f, 0); @@ -322,7 +329,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() { for (u8 i : get_rtt_indexes(rsx::method_registers.surface_color_target())) { - if (!address_color[i]) + if (!address_color[i] || std::get<1>(m_rtts.m_bound_render_targets[i]) == nullptr) continue; color_buffer_offset_in_heap[i] = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, std::get<1>(m_rtts.m_bound_render_targets[i]), rsx::method_registers.surface_color()); invalidate_address(address_color[i]); @@ -374,7 +381,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() for (u8 i : get_rtt_indexes(rsx::method_registers.surface_color_target())) { - if (!address_color[i]) + if (!address_color[i] || std::get<1>(m_rtts.m_bound_render_targets[i]) == nullptr) continue; copy_readback_buffer_to_dest(dest_buffer[i], m_readback_resources, color_buffer_offset_in_heap[i], srcPitch, dstPitch, clip_h); } From 9f34a87ec006bd572ef389e144fffa3f6f270da0 Mon Sep 17 00:00:00 2001 From: Jake Date: Thu, 27 Jul 2017 08:39:06 -0500 Subject: [PATCH 4/4] Add gcm to auto lle / liblv2 --- rpcs3/Emu/Cell/PPUModule.cpp | 1 + rpcs3/Emu/Cell/lv2/sys_prx.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 192d5a1658e1..8431b92cc1cd 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1198,6 +1198,7 @@ void ppu_load_exec(const ppu_exec_object& elf) { "cellFont", "libfont.sprx" }, { "cellFontFT", "libfontFT.sprx" }, { "cellFontFT", "libfreetype.sprx" }, + { "cellGcmSys", "libgcm_sys.sprx" }, { "cellGifDec", "libgifdec.sprx" }, { "cellGifDec", "libsre.sprx" }, { "cellJpgDec", "libjpgdec.sprx" }, diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 95f0ccbac2f1..4b2988d63060 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -25,7 +25,6 @@ static const std::unordered_map s_prx_ignore { "/dev_flash/sys/external/libaudio.sprx", 0 }, { "/dev_flash/sys/external/libbeisobmf.sprx", 0 }, { "/dev_flash/sys/external/libcamera.sprx", 0 }, - { "/dev_flash/sys/external/libgcm_sys.sprx", 0 }, { "/dev_flash/sys/external/libgem.sprx", 0 }, { "/dev_flash/sys/external/libhttp.sprx", 0 }, { "/dev_flash/sys/external/libio.sprx", 0 },