fix(libSceAmpr): sceAmprCommandBufferClearBuffer returns the detached buffer

sceAmprCommandBufferClearBuffer detaches a command buffer's memory and
returns it so the caller can free it. It returned 0. PPSA01289 (Sackboy: A
Big Adventure) frees the result after every streaming read, so each read
leaked its 16 KiB command buffer until the allocator ran out of memory
during the first world load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jdmagic 2026-10-09 01:58:38 -04:00
parent f145139676
commit 8ae350caaa
2 changed files with 14 additions and 2 deletions

View File

@ -320,12 +320,13 @@ int APS5_VABI sceAmprAprCommandBufferResetGatherScatterState(Apr::CommandBufferO
return result;
}
int APS5_VABI sceAmprCommandBufferClearBuffer(Apr::CommandBufferObject* buffer) {
void* APS5_VABI sceAmprCommandBufferClearBuffer(Apr::CommandBufferObject* buffer) {
void* memory = buffer->base;
buffer->base = nullptr;
buffer->size = 0;
buffer->offset = 0;
buffer->numCommands = 0;
return 0;
return memory;
}
int APS5_VABI sceAmprCommandBufferConstructMarker(Apr::CommandBufferObject* buffer, std::uint32_t type, const char* text, const std::uint32_t* color) {

View File

@ -16,6 +16,7 @@ extern "C" {
int APS5_VABI sceAmprCommandBufferConstructor(Apr::CommandBufferObject*);
int APS5_VABI sceAmprAprCommandBufferConstructor(Apr::CommandBufferObject*, std::uint64_t*, std::uint64_t*);
int APS5_VABI sceAmprCommandBufferSetBuffer(Apr::CommandBufferObject*, void*, std::uint32_t);
void* APS5_VABI sceAmprCommandBufferClearBuffer(Apr::CommandBufferObject*);
std::uint32_t APS5_VABI sceAmprCommandBufferGetCurrentOffset(const Apr::CommandBufferObject*);
std::uint32_t APS5_VABI sceAmprCommandBufferGetNumCommands(const Apr::CommandBufferObject*);
int APS5_VABI sceAmprCommandBufferWriteAddressOnCompletion(Apr::CommandBufferObject*, volatile std::uint64_t*, std::uint64_t);
@ -446,6 +447,15 @@ void TestVersionedCounters() {
Require(sceAmprMeasureCommandSizeWriteCounter_04_00(0, size4, 0, 5) == rejected);
}
void TestClearBuffer() {
Recorder recorder;
Require(sceAmprCommandBufferNop(&recorder.buffer, 1) == 0);
Require(recorder.Offset() != 0 && recorder.Commands() == 1);
Require(sceAmprCommandBufferClearBuffer(&recorder.buffer) == recorder.memory.data());
Require(recorder.buffer.base == nullptr && recorder.buffer.size == 0 && recorder.Offset() == 0 && recorder.Commands() == 0);
Require(sceAmprCommandBufferClearBuffer(&recorder.buffer) == nullptr);
}
void TestConstructed() {
Recorder recorder;
const std::uint8_t payload[5] = {1, 2, 3, 4, 5};
@ -937,6 +947,7 @@ int main() {
TestNops();
TestVersionedCommands();
TestVersionedCounters();
TestClearBuffer();
TestConstructed();
TestGatherScatter();
TestAmm();