From 89792a3bcac698ef139d183b83961718b711e615 Mon Sep 17 00:00:00 2001 From: nomolao2-cell Date: Fri, 2 Oct 2026 04:37:49 -0600 Subject: [PATCH] Improve Hades II compatibility (#964) Fix Hades II startup and color clears Co-authored-by: nmzik --- .../guest_gpu/command_processor/pm4Dispatch.cpp | 2 ++ .../guest_gpu/command_processor/pm4Handlers.cpp | 12 ++++++++++++ src/graphics/guest_gpu/hardwareContext.h | 9 +++++++++ src/graphics/guest_gpu/pm4.h | 2 ++ .../host_gpu/renderer/cache/textureCache.cpp | 2 +- src/graphics/host_gpu/renderer/image/imageInfo.h | 14 ++++++++++++++ src/libs/libKernel.cpp | 7 +++++++ 7 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp b/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp index 8001f93dd..be6136938 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp @@ -140,6 +140,8 @@ constexpr auto MakeShaderDispatchTable() { g_hw_sh_func[Pm4::COMPUTE_PGM_RSRC3] = HwShSetCsRegisters; g_hw_sh_func[Pm4::COMPUTE_PACE_ID] = HwShSetCsRegisters; g_hw_sh_func[Pm4::SPI_GRAPHICS_SHADER_CONTROL_PS] = HwShSetRegisters; + g_hw_sh_func[Pm4::SPI_SHADER_USER_DATA_ADDR_LO_PS] = HwShSetRegisters; + g_hw_sh_func[Pm4::SPI_SHADER_USER_DATA_ADDR_HI_PS] = HwShSetRegisters; g_hw_sh_func[Pm4::SPI_GRAPHICS_SHADER_CONTROL_GS] = HwShSetRegisters; g_hw_sh_func[Pm4::SPI_SHADER_USER_DATA_ADDR_LO_GS] = HwShSetRegisters; g_hw_sh_func[Pm4::SPI_SHADER_USER_DATA_ADDR_HI_GS] = HwShSetRegisters; diff --git a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp index 8df48e30a..c0dea0df6 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp @@ -3622,6 +3622,18 @@ void GraphicsInitJmpTablesShIndirect() { g_hw_sh_indirect_func[Pm4::SPI_GRAPHICS_SHADER_CONTROL_PS] = [](KYTY_HW_SH_INDIRECT_ARGS) { HwShIgnoreShaderRegister(cmd_offset, value); }; + for (uint32_t offset = Pm4::SPI_SHADER_USER_DATA_ADDR_LO_PS; + offset <= Pm4::SPI_SHADER_USER_DATA_ADDR_HI_PS; offset++) { + g_hw_sh_indirect_func[offset] = [](KYTY_HW_SH_INDIRECT_ARGS) { + cp.GetShCtx().SetPsUserDataAddress(cmd_offset - Pm4::SPI_SHADER_USER_DATA_ADDR_LO_PS, + value); + }; + } + for (uint32_t offset = 4; offset <= 5; offset++) { + g_hw_sh_indirect_func[offset] = [](KYTY_HW_SH_INDIRECT_ARGS) { + cp.GetShCtx().SetPsAuxiliaryTableAddress(cmd_offset - 4, value); + }; + } g_hw_sh_indirect_func[Pm4::SPI_SHADER_PACE_ID_GS] = [](KYTY_HW_SH_INDIRECT_ARGS) { HwShIgnoreShaderRegister(cmd_offset, value); }; diff --git a/src/graphics/guest_gpu/hardwareContext.h b/src/graphics/guest_gpu/hardwareContext.h index bac95878b..82c68baa3 100644 --- a/src/graphics/guest_gpu/hardwareContext.h +++ b/src/graphics/guest_gpu/hardwareContext.h @@ -458,6 +458,9 @@ struct PsShaderResource2 { struct PsStageRegisters { uint64_t data_addr = 0; + uint64_t user_data_addr = 0; + // Hades II uses PS offsets 4:5 for a byte-addressed descriptor table. + uint64_t auxiliary_table_addr = 0; PsShaderResource1 rsrc1; PsShaderResource2 rsrc2; }; @@ -1017,6 +1020,12 @@ public: void SetGsShaderResource2(const GsShaderResource2& rsrc2) { m_vs.gs_regs.rsrc2 = rsrc2; } void SetPsShaderBase(uint64_t addr) { m_ps.ps_regs.data_addr = addr; } + void SetPsUserDataAddress(uint32_t word, uint32_t value) { + SetUserDataAddressWord(m_ps.ps_regs.user_data_addr, word, value); + } + void SetPsAuxiliaryTableAddress(uint32_t word, uint32_t value) { + SetUserDataAddressWord(m_ps.ps_regs.auxiliary_table_addr, word, value); + } void SetPsShaderResource1(const PsShaderResource1& rsrc1) { m_ps.ps_regs.rsrc1 = rsrc1; } void SetPsShaderResource2(const PsShaderResource2& rsrc2) { m_ps.ps_regs.rsrc2 = rsrc2; } diff --git a/src/graphics/guest_gpu/pm4.h b/src/graphics/guest_gpu/pm4.h index 038bd02c2..8c724108d 100644 --- a/src/graphics/guest_gpu/pm4.h +++ b/src/graphics/guest_gpu/pm4.h @@ -697,6 +697,8 @@ constexpr uint32_t CX_NUM = 0x3FF + 1; /* Shader registers */ +constexpr uint32_t SPI_SHADER_USER_DATA_ADDR_LO_PS = 0x2; +constexpr uint32_t SPI_SHADER_USER_DATA_ADDR_HI_PS = 0x3; constexpr uint32_t SPI_SHADER_PACE_ID_PS = 0x6; constexpr uint32_t SPI_GRAPHICS_SHADER_CONTROL_PS = 0x7; constexpr uint32_t SPI_SHADER_PGM_LO_PS = 0x8; diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index 3b654a0eb..6b876056d 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -1533,7 +1533,7 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer& command, uint64_t address auto& image = m_slot_images[selected]; vk::ClearValue clear {}; if (aspect == vk::ImageAspectFlagBits::eColor) { - if (!DecodePackedColorClear(image.info.pixel_format, packed_clear, clear.color)) { + if (!DecodeColorDwordFill(image.info.pixel_format, packed_clear, clear.color)) { return false; } } else { diff --git a/src/graphics/host_gpu/renderer/image/imageInfo.h b/src/graphics/host_gpu/renderer/image/imageInfo.h index 8f5b948b5..313baa317 100644 --- a/src/graphics/host_gpu/renderer/image/imageInfo.h +++ b/src/graphics/host_gpu/renderer/image/imageInfo.h @@ -428,6 +428,20 @@ inline constexpr std::array VIDEO_OUT_FORMAT_POLICIES { return true; } +// Unlike a register clear, a DWORD fill repeats the same word across the entire pixel. +// Keep this separate: the first register word alone cannot describe a 64-bit color. +[[nodiscard]] inline bool DecodeColorDwordFill(vk::Format format, uint32_t packed, + vk::ClearColorValue& clear) { + if (format == vk::Format::eR16G16B16A16Sfloat) { + if (packed != 0) { + return false; + } + clear = vk::ClearColorValue {}; + return true; + } + return DecodePackedColorClear(format, packed, clear); +} + [[nodiscard]] inline bool DecodePackedStencilClear(uint32_t packed, uint8_t& clear) { const auto value = static_cast(packed); if (packed != static_cast(value) * 0x01010101u) { diff --git a/src/libs/libKernel.cpp b/src/libs/libKernel.cpp index 6e16d8a59..37f279aca 100644 --- a/src/libs/libKernel.cpp +++ b/src/libs/libKernel.cpp @@ -1797,6 +1797,12 @@ int KYTY_SYSV_ABI KernelRtldThreadAtexitDecrement(uint64_t* /*c*/) { return 0; } +static uint64_t KYTY_SYSV_ABI KernelGetAvailableCpumask() { + PRINT_NAME(); + + return 0x1fff; +} + static KYTY_SYSV_ABI int KernelGetCurrentCpu() { PRINT_NAME(); @@ -3340,6 +3346,7 @@ LIB_DEFINE(InitLibKernel_1) { LIB_FUNC("vYU8P9Td2Zo", KernelAioInitializeImpl); LIB_FUNC("WhCc1w3EhSI", LibKernel::KernelSetThreadAtexitReport); LIB_FUNC("WkwEd3N7w0Y", LibKernel::KernelInstallExceptionHandler); + LIB_FUNC("La9uyZv4Kvw", LibKernel::KernelGetAvailableCpumask); LIB_FUNC("g0VTBxfJyu0", LibKernel::KernelGetCurrentCpu); LIB_FUNC("wzvqT4UqKX8", LibKernel::KernelLoadStartModule); LIB_FUNC("Xjoosiw+XPI", LibKernel::KernelUuidCreate);