diff --git a/src/libs/agc.cpp b/src/libs/agc.cpp index 457249a..b8787cf 100644 --- a/src/libs/agc.cpp +++ b/src/libs/agc.cpp @@ -834,6 +834,104 @@ int KYTY_SYSV_ABI GraphicsUnknownFuseShaderHalves(Shader* fused_result, const Sh return OK; } +static void merge_shader_register_max_field(ShaderRegister* dst, const ShaderRegister* src, + uint32_t shift, uint32_t mask) { + const auto dst_field = (dst->value >> shift) & mask; + const auto src_field = (src->value >> shift) & mask; + const auto field = std::max(dst_field, src_field); + + dst->value &= ~(mask << shift); + dst->value |= field << shift; +} + +int KYTY_SYSV_ABI GraphicsUnknownNApJjpKNBl4(Shader* fused_result, const Shader* front, + const Shader* back, void* scratch_mem) { + PRINT_NAME(); + + LOGF("\t fused_result = 0x%016" PRIx64 "\n" + "\t front = 0x%016" PRIx64 "\n" + "\t back = 0x%016" PRIx64 "\n" + "\t scratch_mem = 0x%016" PRIx64 "\n", + reinterpret_cast(fused_result), reinterpret_cast(front), + reinterpret_cast(back), reinterpret_cast(scratch_mem)); + + const auto front_type = static_cast(front->type); + const auto is_gs = front_type == Prospero::ShaderBinaryType::kGsFront; + const auto is_hs = front_type == Prospero::ShaderBinaryType::kHsFront; + if ((!is_gs && !is_hs) || + (is_gs && back->type != static_cast(Prospero::ShaderBinaryType::kGsBack)) || + (is_hs && back->type != static_cast(Prospero::ShaderBinaryType::kHsBack))) { + return GRAPHICS5_ERROR_INVALID_SHADER_HALVES; + } + + *fused_result = *back; + fused_result->type = static_cast(is_gs ? Prospero::ShaderBinaryType::kGs + : Prospero::ShaderBinaryType::kHs); + + const auto back_stages = back->specials->vgt_shader_stages_en.value; + const auto front_stages = front->specials->vgt_shader_stages_en.value; + const auto mismatch_bit = is_gs ? (1u << 22u) : (1u << 21u); + if (((front_stages ^ back_stages) & mismatch_bit) != 0) { + return GRAPHICS5_ERROR_INVALID_SHADER_HALVES; + } + + if (scratch_mem != nullptr) { + auto* sh_registers = static_cast(scratch_mem); + memcpy(sh_registers, back->sh_registers, + static_cast(back->num_sh_registers) * sizeof(ShaderRegister)); + fused_result->sh_registers = sh_registers; + } + + auto* fused_regs = fused_result->sh_registers; + const auto fused_reg_count = static_cast(fused_result->num_sh_registers); + const auto front_reg_count = static_cast(front->num_sh_registers); + const auto checksum_offset = + is_gs ? Pm4::SPI_SHADER_PGM_CHKSUM_GS : Pm4::SPI_SHADER_PGM_CHKSUM_HS; + const auto* front_checksum0 = + find_shader_register(front->sh_registers, front_reg_count, checksum_offset, 0); + const auto* front_checksum1 = + find_shader_register(front->sh_registers, front_reg_count, checksum_offset, 1); + auto* fused_checksum0 = find_shader_register(fused_regs, fused_reg_count, checksum_offset, 0); + auto* fused_checksum1 = find_shader_register(fused_regs, fused_reg_count, checksum_offset, 1); + fused_checksum0->value = front_checksum0->value; + fused_checksum1->value = front_checksum1->value; + + const auto rsrc1_offset = is_gs ? Pm4::SPI_SHADER_PGM_RSRC1_GS : Pm4::SPI_SHADER_PGM_RSRC1_HS; + const auto rsrc2_offset = is_gs ? Pm4::SPI_SHADER_PGM_RSRC2_GS : Pm4::SPI_SHADER_PGM_RSRC2_HS; + const auto* front_rsrc1 = + find_shader_register(front->sh_registers, front_reg_count, rsrc1_offset); + const auto* front_rsrc2 = + find_shader_register(front->sh_registers, front_reg_count, rsrc2_offset); + auto* fused_rsrc1 = find_shader_register(fused_regs, fused_reg_count, rsrc1_offset); + auto* fused_rsrc2 = find_shader_register(fused_regs, fused_reg_count, rsrc2_offset); + + merge_shader_register_max_field(fused_rsrc1, front_rsrc1, 0, 0x3fu); + merge_shader_register_max_field(fused_rsrc2, front_rsrc2, 28, 0x0fu); + if (is_gs) { + merge_shader_register_max_field(fused_rsrc1, front_rsrc1, 29, 0x03u); + merge_shader_register_max_field(fused_rsrc2, front_rsrc2, 16, 0x03u); + fused_rsrc2->value = + (fused_rsrc2->value & 0xf7ffffc1u) | (front_rsrc2->value & 0x0800003eu); + fused_rsrc2->value = + (fused_rsrc2->value & 0xfffbffffu) | (front_rsrc2->value & 0x00040000u); + } else { + merge_shader_register_max_field(fused_rsrc1, front_rsrc1, 28, 0x03u); + fused_rsrc2->value = + (fused_rsrc2->value & 0xf7ffffc1u) | (front_rsrc2->value & 0x0800003eu); + } + + const auto program_lo_offset = is_gs ? Pm4::SPI_SHADER_PGM_LO_ES : Pm4::SPI_SHADER_PGM_LO_LS; + auto* program_lo = find_shader_register(fused_regs, fused_reg_count, program_lo_offset); + const auto address = reinterpret_cast(front->code); + program_lo->value = static_cast(address >> 8u); + (program_lo + 1)->value &= 0xffffff00u; + (program_lo + 1)->value |= static_cast((address >> 40u) & 0xffu); + + fused_result->user_data = front->user_data; + + return OK; +} + static constexpr int GRAPHICS5_ERROR_INVALID_PACKET = static_cast(0x8a6c000cu); enum class RegIndirectPacket : uint32_t { diff --git a/src/libs/agc.h b/src/libs/agc.h index 45cfe9f..15f7310 100644 --- a/src/libs/agc.h +++ b/src/libs/agc.h @@ -38,6 +38,8 @@ int KYTY_SYSV_ABI GraphicsUnknownGetFusedShaderSize(SizeAlign* dst, const Shad const Shader* back); int KYTY_SYSV_ABI GraphicsUnknownFuseShaderHalves(Shader* fused_result, const Shader* front, const Shader* back, void* scratch_mem); +int KYTY_SYSV_ABI GraphicsUnknownNApJjpKNBl4(Shader* fused_result, const Shader* front, + const Shader* back, void* scratch_mem); int KYTY_SYSV_ABI GraphicsSetCxRegIndirectPatchSetAddress(uint32_t* cmd, const volatile ShaderRegister* regs); int KYTY_SYSV_ABI GraphicsSetShRegIndirectPatchSetAddress(uint32_t* cmd, diff --git a/src/libs/libGraphicsDriver.cpp b/src/libs/libGraphicsDriver.cpp index 5bdeca5..01bef74 100644 --- a/src/libs/libGraphicsDriver.cpp +++ b/src/libs/libGraphicsDriver.cpp @@ -159,6 +159,7 @@ LIB_DEFINE(InitGraphicsDriver_1) { LIB_FUNC("f3dg2CSgRKY", Gen5::GraphicsCreateShader); LIB_FUNC("dolOmWH+huQ", Gen5::GraphicsUnknownGetFusedShaderSize); LIB_FUNC("fd5Bp5tGTgo", Gen5::GraphicsUnknownFuseShaderHalves); + LIB_FUNC("nApJjpKNBl4", Gen5::GraphicsUnknownNApJjpKNBl4); LIB_FUNC("vcmNN+AAXnY", Gen5::GraphicsSetCxRegIndirectPatchSetAddress); LIB_FUNC("Qrj4c+61z4A", Gen5::GraphicsSetShRegIndirectPatchSetAddress); LIB_FUNC("6lNcCp+fxi4", Gen5::GraphicsSetUcRegIndirectPatchSetAddress);