diff --git a/core/libs/prx/libSceAgc/DcbState/src/Init.cpp b/core/libs/prx/libSceAgc/DcbState/src/Init.cpp index 7ad33c6d9..27f4ec973 100644 --- a/core/libs/prx/libSceAgc/DcbState/src/Init.cpp +++ b/core/libs/prx/libSceAgc/DcbState/src/Init.cpp @@ -7,6 +7,8 @@ #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +static constexpr int SCE_AGC_ERROR_INVALID_ARGUMENT = static_cast(0x80890001); + extern "C" { int APS5_VABI sceAgcInit_0090(std::uint32_t* state, std::uint32_t version) { @@ -16,6 +18,7 @@ int APS5_VABI sceAgcInit_0090(std::uint32_t* state, std::uint32_t version) { } int APS5_VABI sceAgcInit(std::uint32_t version) { + if (version >= 14) return SCE_AGC_ERROR_INVALID_ARGUMENT; Agc::Command::GetRegisterDefaults(version, false, __func__); Agc::Command::GetRegisterDefaults(version, true, __func__); return 0; diff --git a/core/libs/prx/libSceAgc/tests/Commands.cpp b/core/libs/prx/libSceAgc/tests/Commands.cpp index e304b7fdc..03aeff906 100644 --- a/core/libs/prx/libSceAgc/tests/Commands.cpp +++ b/core/libs/prx/libSceAgc/tests/Commands.cpp @@ -50,6 +50,8 @@ extern "C" std::uint32_t* APS5_VABI sceAgcAcbAtomicGds_0900(CommandBuffer* buf, namespace { +constexpr int SCE_AGC_ERROR_INVALID_ARGUMENT = static_cast(0x80890001); + void check(bool condition, const char* message) { if (!condition) { throw std::runtime_error(message); @@ -622,8 +624,10 @@ void testDefaults() { expectFailure([] { sceAgcInit_0090(nullptr, 8); }); expectFailure([&] { sceAgcInit_0090(&state, 14); }); check(sceAgcInit(8) == 0, "AGC version initialization failed"); - expectFailure([] { sceAgcInit(14); }); - expectFailure([] { sceAgcInit(0xffffffffu); }); + check(sceAgcInit(13) == 0, "AGC version 13 initialization failed"); + check(sceAgcInit(14) == SCE_AGC_ERROR_INVALID_ARGUMENT, "unsupported AGC version did not return invalid argument"); + check(sceAgcInit(0xffffffffu) == SCE_AGC_ERROR_INVALID_ARGUMENT, "maximum AGC version did not return invalid argument"); + check(sceAgcInit(0xffffc278u) == SCE_AGC_ERROR_INVALID_ARGUMENT, "pointer-valued AGC argument did not return invalid argument"); for (std::uint32_t version = 0; version < 14; ++version) { for (const bool internal : {false, true}) { auto* first = Agc::Command::GetRegisterDefaults(version, internal, __func__); diff --git a/docs/dev/debt/libSceAgc.md b/docs/dev/debt/libSceAgc.md index 0bbe3d5c1..fbddb208e 100644 --- a/docs/dev/debt/libSceAgc.md +++ b/docs/dev/debt/libSceAgc.md @@ -7,6 +7,7 @@ - [sceAgcDcbSetCfRegisterDirect, sceAgcDcbSetCfRegisterRangeDirect](../../../core/libs/prx/libSceAgc/DcbState/src/Registers.cpp) (libSceAgc) - signatures follow [OpenAGC](https://github.com/OpenAGC/OpenAGC/blob/main/src/game_compat.c) and [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/Agc/SceAgc.cs), which agree; the SET_CONFIG_REG (0x68) packet is OpenAGC's. The driver does not execute SET_CONFIG_REG, so a submitted packet throws - [Command buffer cursors](../../../core/libs/prx/libSceAgc/Command/src/Packet.cpp) (libSceAgc) - a null `cursor_down` is taken as a buffer without downward allocations, whose limit is `top`. PPSA16064 builds one-packet buffers of 8 dwords that way; the console's handling is unconfirmed - [sceAgcGetRegisterDefaultsInternal](../../../core/libs/prx/libSceAgc/Misc/src/RegisterDefaults.cpp) (libSceAgc) - returns the version 0 internal table, as `sceAgcGetRegisterDefaults` returns the version 0 public one; [OpenAGC](https://github.com/OpenAGC/OpenAGC/blob/main/src/game_compat.c) returns the table of the version passed to `sceAgcInit` instead, and null before it +- [sceAgcInit](../../../core/libs/prx/libSceAgc/DcbState/src/Init.cpp) (libSceAgc) - unsupported register-default versions return `0x80890001` following [OpenAGC](https://github.com/OpenAGC/OpenAGC/blob/main/src/game_compat.c); AnyPS5 keeps version 13 support because its register-default tables include it, while that reference accepts only versions 0–12. The upper version accepted by PS5 firmware is unverified - [sceAgcSetSubmitMode](../../../core/libs/prx/libSceAgc/Misc/src/Suspend.cpp) (libSceAgc) - mode values unknown; only 0 is accepted - [sceAgcGetGsOversubscription](../../../core/libs/prx/libSceAgc/Shader/src/GsOversubscription.cpp) (libSceAgc) - signature and occupancy formula (base and expanded vertex/export capacities, budget shift, `GE_PC_ALLOC` / `SPI_SHADER_PGM_RSRC4_GS` encoding) follow KytyPS5 only, not confirmed on hardware or a title; a negative or NaN factor that gives a negative target, a missing GS context register or a zero `GE_MAX_OUTPUT_PER_SUBGROUP` throws - [sceAgcCbCondWrite](../../../core/libs/prx/libSceAgc/Cb/src/Branch.cpp) (libSceAgc) - argument order and the 9-dword COND_WRITE layout follow the clean-room [OpenAGC](https://github.com/OpenAGC/OpenAGC/blob/main/src/game_compat.c) and [sharpemu](https://github.com/sharpemu/sharpemu/blob/main/src/SharpEmu.Libs/Agc/AgcExports.CommandPackets.cs), which agree on them; SharpProspero lists another order. The write space is accepted only as 1 (memory), the one value both encode the same way, and other values throw.