feat(libSceAgc): implement sceAgcGetDefaultCxStateFlat

This commit is contained in:
pushkarreddyy authored and Adrià Franch committed 2026-10-15 15:36:43 +02:00
1 parent 4186f06a9a
commit fd90df41b6
7 files changed
+65 -7

No files matched your search

@@ -6,6 +6,7 @@
namespace Agc::Command {
void* GetRegisterDefaults(std::uint32_t version, bool internal, const char* function);
int GetDefaultCxStateFlat(void* destination, std::uint32_t size);
}
@@ -4,6 +4,7 @@
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstring>
#include <mutex>
#include <vector>
@@ -44,6 +45,33 @@ struct Storage {
std::mutex defaultsMutex;
std::array<std::array<Storage, 14>, 2> storage;
struct AgcContextState {
std::uint32_t data[512];
};
static_assert(sizeof(AgcContextState) == 2048);
std::mutex defaultStateMutex;
AgcContextState defaultState{};
bool defaultStateInitialized = false;
void InitDefaultCxState() {
std::memset(&defaultState, 0, sizeof(defaultState));
const auto* source = agcPublicRegDefaultsByVersion[8];
for (std::size_t bank = 0; bank < 4; ++bank) {
const auto& b = source->banks[bank];
if (b.registers == nullptr) continue;
for (std::uint32_t r = 0; r < b.registerCount; ++r) {
const auto offset = b.registers[r].offset;
const auto value = b.registers[r].value;
if (offset < 512) {
defaultState.data[offset] = value;
}
}
}
defaultStateInitialized = true;
}
}
void* GetRegisterDefaults(std::uint32_t version, bool internal, const char* function) {
@@ -76,4 +104,15 @@ void* GetRegisterDefaults(std::uint32_t version, bool internal, const char* func
return &destination.defaults;
}
int GetDefaultCxStateFlat(void* destination, std::uint32_t size) {
if (destination == nullptr) return static_cast<int>(0x80890001);
std::lock_guard lock(defaultStateMutex);
if (!defaultStateInitialized) {
InitDefaultCxState();
}
const auto copyBytes = std::min(size, static_cast<std::uint32_t>(sizeof(AgcContextState)));
std::memcpy(destination, defaultState.data, copyBytes);
return 0;
}
}
@@ -1,4 +1,9 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_REGISTERDEFAULTS_HPP
#define CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_REGISTERDEFAULTS_HPP
#include "SceTypes.hpp"
#include <cstdint>
extern "C" {
int APS5_VABI sceAgcGetDefaultCxStateFlat(void* out_state, std::uint32_t size);
}
#endif
@@ -26,4 +26,8 @@ void* APS5_VABI sceAgcGetRegisterDefaults2Internal(std::uint32_t version) {
return Agc::Command::GetRegisterDefaults(version, true, __func__);
}
int APS5_VABI sceAgcGetDefaultCxStateFlat(void* out_state, std::uint32_t size) {
return Agc::Command::GetDefaultCxStateFlat(out_state, size);
}
}
@@ -30,11 +30,6 @@ int APS5_VABI sceAgcDcbSetMarkerSpan() {
return 0;
}
int APS5_VABI sceAgcGetDefaultCxStateFlat() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcSetSemaphoreMemory() {
NotImplemented_nid_no_patch(__func__);
return 0;
+15 -2
View File
@@ -21,6 +21,7 @@ extern "C" int APS5_VABI sceAgcInit(std::uint32_t version);
extern "C" void* APS5_VABI sceAgcGetRegisterDefaults();
extern "C" void* APS5_VABI sceAgcGetRegisterDefaultsInternal();
extern "C" void* APS5_VABI sceAgcGetRegisterDefaults2Internal(std::uint32_t version);
extern "C" int APS5_VABI sceAgcGetDefaultCxStateFlat(void* out_state, std::uint32_t size);
extern "C" int APS5_VABI sceAgcInit_0090(std::uint32_t* state, std::uint32_t version);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbDrawIndexAuto(CommandBuffer* buf, std::uint32_t indexCount, std::uint64_t modifier);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbDrawIndexIndirect(CommandBuffer* buf, std::uint32_t dataOffsetInBytes, std::uint64_t modifier);
@@ -637,8 +638,20 @@ void testDefaults() {
auto* internalDefaults = sceAgcGetRegisterDefaultsInternal();
check(internalDefaults != nullptr && internalDefaults == Agc::Command::GetRegisterDefaults(0, true, __func__) && internalDefaults == sceAgcGetRegisterDefaults2Internal(0), "internal register defaults are not the baseline internal table");
check(internalDefaults != sceAgcGetRegisterDefaults(), "internal register defaults returned the public table");
expectFailure([] { Agc::Command::GetRegisterDefaults(14, false, __func__); });
expectFailure([] { Agc::Command::GetRegisterDefaults(0xffffffffu, true, __func__); });
std::array<std::uint32_t, 512> flatCxBuffer{};
check(sceAgcGetDefaultCxStateFlat(nullptr, sizeof(flatCxBuffer)) == SCE_AGC_ERROR_INVALID_ARGUMENT, "null destination was accepted");
check(sceAgcGetDefaultCxStateFlat(flatCxBuffer.data(), 0) == 0, "zero size copy failed");
check(sceAgcGetDefaultCxStateFlat(flatCxBuffer.data(), sizeof(flatCxBuffer)) == 0, "flat CX state default retrieval failed");
check(flatCxBuffer[0x001] == 0x11000100u, "flat CX state register 0x001 mismatch");
check(flatCxBuffer[0x007] == 0x0000ffffu, "flat CX state register 0x007 mismatch");
check(flatCxBuffer[0x12d] == 0x3f800000u, "flat CX state register 0x12d mismatch");
check(flatCxBuffer[0x1e0] == 0x20010001u, "flat CX state register 0x1e0 mismatch");
std::array<std::uint32_t, 513> overBuffer{};
overBuffer[512] = 0x12345678u;
check(sceAgcGetDefaultCxStateFlat(overBuffer.data(), sizeof(overBuffer)) == 0, "oversized copy failed");
check(overBuffer[512] == 0x12345678u, "oversized copy overflowed buffer");
check(Agc::Command::GetDefaultCxStateFlat(nullptr, sizeof(flatCxBuffer)) == SCE_AGC_ERROR_INVALID_ARGUMENT, "null command destination was accepted");
check(Agc::Command::GetDefaultCxStateFlat(flatCxBuffer.data(), sizeof(flatCxBuffer)) == 0, "command flat CX state retrieval failed");
}
void testEventWrite() {
+1
View File
@@ -30,6 +30,7 @@
- [sceAgcDcbSetZPassPredicationEnableGetSize, sceAgcDcbSetPredicationDisableGetSize, sceAgcDcbSetBoolPredicationEnableGetSize](../../../core/libs/prx/libSceAgc/DcbState/src/Predication.cpp) (libSceAgc) - the builders are inline in the SDK and not exported; the size is assumed to be that of the SET_PREDICATION packet `sceAgcDcbSetPredication` writes (16 bytes)
- [vieBRwlh1Lw](../../../core/libs/prx/libSceAgc/Shader/src/InterpolantMapping.cpp) (libSceAgc) follows [OpenAGC](https://github.com/OpenAGC/OpenAGC/blob/3c7e8072f0d7684e930454794fd5c02056946d73/src/game_compat.c) only, not confirmed on hardware: the `dbOlWdppb4o` transform without the identity tail, so it writes one register per pixel shader input and none for a pixel shader without inputs, and a null pixel shader throws. For an `is_f16` 1 or 3 input whose `default_value` and `default_value_hi` differ it throws: OpenAGC takes `DEFAULT_VAL` from `default_value_hi`, while KytyPS5, sharpemu and `dbOlWdppb4o` here take it from `default_value`
- [sceAgcAcbWaitUntilSafeForRendering](../../../core/libs/prx/libSceAgc/Acb/src/Control.cpp) (libSceAgc) - `(buffer, videoOutHandle, displayBufferIndex)`, the declared arguments, which PPSA12544 (01.000.010) passes inside `waitUntilSafeForRendering` and `waitUntilSafeForRendering VR` markers on an asynchronous compute command buffer, ignoring the result. It writes the same rendering-wait packet as `sceAgcDcbWaitUntilSafeForRendering`, which the driver now accepts on compute queues too; the wait blocks only that queue's worker. Whether the console encodes the compute variant differently is not known
- [sceAgcGetDefaultCxStateFlat](../../../core/libs/prx/libSceAgc/Misc/src/RegisterDefaults.cpp) (libSceAgc) - copies up to `size` bytes (clamped to 2048 bytes, the 512-dword `AgcContextState`) from the default context state initialized from the version 8 public register default groups (CX, SH, UC), indexed by register offset, following OpenAGC `src/context_state.c`; returns `0x80890001` on null destination; version selection without `sceAgcInit` is unverified
### Functional