Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);

}

Expand Down
39 changes: 39 additions & 0 deletions core/libs/prx/libSceAgc/Command/src/RegisterDefaults.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstring>
#include <mutex>
#include <vector>

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

}
5 changes: 5 additions & 0 deletions core/libs/prx/libSceAgc/Misc/include/RegisterDefaults.hpp
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions core/libs/prx/libSceAgc/Misc/src/RegisterDefaults.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

}
5 changes: 0 additions & 5 deletions core/libs/prx/libSceAgc/Unimplemented.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 16 additions & 0 deletions core/libs/prx/libSceAgc/tests/Commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -637,6 +638,21 @@ 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");
constexpr int kInvalidArgument = static_cast<int>(0x80890001u);
std::array<std::uint32_t, 512> flatCxBuffer{};
check(sceAgcGetDefaultCxStateFlat(nullptr, sizeof(flatCxBuffer)) == kInvalidArgument, "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)) == kInvalidArgument, "null command destination was accepted");
check(Agc::Command::GetDefaultCxStateFlat(flatCxBuffer.data(), sizeof(flatCxBuffer)) == 0, "command flat CX state retrieval failed");
expectFailure([] { Agc::Command::GetRegisterDefaults(14, false, __func__); });
expectFailure([] { Agc::Command::GetRegisterDefaults(0xffffffffu, true, __func__); });
}
Expand Down
1 change: 1 addition & 0 deletions docs/dev/debt/libSceAgc.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading