From de0816e1b0fdbd1f5637f89cf06677ca3e8d8e98 Mon Sep 17 00:00:00 2001 From: Gutemberg Ribeiro Date: Sun, 19 Jul 2026 04:47:25 +0100 Subject: [PATCH] [HLE] Implement Hades' high-frequency unresolved AGC DCB builders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hades boots with ~1.3k unresolved-import hits that corrupt its GPU command stream — the two hot ones are DCB writers whose garbage return values derail the game's command-buffer cursor: - sceAgcDcbSetShRegisterDirect (pFLArOT53+w, ~1.1k calls/boot): single SET_SH_REG builder; register packed in rsi (low 16 = offset, high dword = byte offset of the dword within a multi-dword write), value in edx. Emits the same 3-dword packet as the plural sceAgcCbSetShRegistersDirect path. - sceAgcDcbWaitOnAddressGetSize (43WJ08sSugE, ~235 calls): size probe for the existing sceAgcDcbWaitRegMem writer; mirrors its dword computation (7 standard, 6/9 for the 32/64-bit polled forms). - pthread_rename_np (9vyP6Z7bqzc): POSIX alias of scePthreadRename. Hades unresolved-import hits drop 1339 -> 6 (two unknown NIDs not in the public name catalog plus one sceNpTrophy2GetTrophyInfoArray call). Still no draws — the DCB stream is now well-formed, which unblocks diagnosing why the game never reaches its render loop. 349 Libs tests pass. --- src/SharpEmu.Libs/Agc/AgcExports.cs | 52 +++++++++++++++++++ .../Kernel/KernelPthreadCompatExports.cs | 7 +++ 2 files changed, 59 insertions(+) diff --git a/src/SharpEmu.Libs/Agc/AgcExports.cs b/src/SharpEmu.Libs/Agc/AgcExports.cs index 2a55726c..ef983f72 100644 --- a/src/SharpEmu.Libs/Agc/AgcExports.cs +++ b/src/SharpEmu.Libs/Agc/AgcExports.cs @@ -1773,6 +1773,58 @@ public static partial class AgcExports return ReturnPointer(ctx, commandAddress); } + // Single-register variant of the SET_SH_REG builders: the register rides + // in rsi as a packed struct (low 16 bits = register offset, high dword = + // byte offset of this dword within a multi-dword register write) and the + // value in edx. Emits the same 3-dword SET_SH_REG packet the plural + // sceAgcCbSetShRegistersDirect path produces per run. Hades calls this + // ~1k times per boot; leaving it unresolved corrupted its DCB stream. + [SysAbiExport( + Nid = "pFLArOT53+w", + ExportName = "sceAgcDcbSetShRegisterDirect", + Target = Generation.Gen5, + LibraryName = "libSceAgc")] + public static int DcbSetShRegisterDirect(CpuContext ctx) + { + var commandBufferAddress = ctx[CpuRegister.Rdi]; + var packedRegister = ctx[CpuRegister.Rsi]; + var value = (uint)ctx[CpuRegister.Rdx]; + if (commandBufferAddress == 0) + { + return ReturnPointer(ctx, 0); + } + + var offset = (uint)(packedRegister & 0xFFFFu) + (uint)((packedRegister >> 32) >> 2); + if (!TryAllocateCommandDwords(ctx, commandBufferAddress, 3, out var commandAddress) || + !TryWriteUInt32(ctx, commandAddress, Pm4(3, ItSetShReg, 0)) || + !TryWriteUInt32(ctx, commandAddress + 4, offset & 0xFFFFu) || + !TryWriteUInt32(ctx, commandAddress + 8, value)) + { + return ReturnPointer(ctx, 0); + } + + TraceAgc($"agc.dcb_set_sh_register_direct buf=0x{commandBufferAddress:X16} reg=0x{offset:X4} value=0x{value:X8}"); + return ReturnPointer(ctx, commandAddress); + } + + // Size probe for the wait-on-address writer below: same argument prefix + // minus the command buffer, returns the byte size the writer will emit so + // the game can reserve DCB space (7 dwords for a standard WAIT_REG_MEM, + // 6/9 for the 32/64-bit polled-NOP forms). + [SysAbiExport( + Nid = "43WJ08sSugE", + ExportName = "sceAgcDcbWaitOnAddressGetSize", + Target = Generation.Gen5, + LibraryName = "libSceAgc")] + public static int DcbWaitOnAddressGetSize(CpuContext ctx) + { + var size = (uint)(ctx[CpuRegister.Rdi] & 0xFF); + var operation = (uint)(ctx[CpuRegister.Rdx] & 0xFF); + var packetDwords = operation is 2 or 3 ? 7u : size == 0 ? 6u : 9u; + ctx[CpuRegister.Rax] = packetDwords * sizeof(uint); + return (int)ctx[CpuRegister.Rax]; + } + [SysAbiExport( Nid = "VmW0Tdpy420", ExportName = "sceAgcDcbWaitRegMem", diff --git a/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs index 3dc89ad5..3db7759c 100644 --- a/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs @@ -119,6 +119,13 @@ public static class KernelPthreadCompatExports return (int)OrbisGen2Result.ORBIS_GEN2_OK; } + [SysAbiExport( + Nid = "9vyP6Z7bqzc", + ExportName = "pthread_rename_np", + Target = Generation.Gen4 | Generation.Gen5, + LibraryName = "libKernel")] + public static int PosixPthreadRenameNp(CpuContext ctx) => PthreadRename(ctx); + [SysAbiExport( Nid = "GBUY7ywdULE", ExportName = "scePthreadRename",