Skip to content
Open
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
6 changes: 4 additions & 2 deletions core/libs/prx/libSceAgc/Command/src/Packet.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include "prx/libSceAgc/Command/include/Packet.hpp"

#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <limits>
#include <stdexcept>
#include <string>
Expand Down Expand Up @@ -96,8 +98,8 @@ std::uint32_t* WriteRegisterRange(CommandBuffer* buffer, std::uint32_t opcode, s
Require(count != 0 && count <= 0x3fffu && offset <= 0xffffu && count <= 0x10000u - offset, function, "invalid register range");
std::vector<std::uint32_t> snapshot;
if (values != nullptr) {
CheckAddress(reinterpret_cast<std::uintptr_t>(values), 4, function);
snapshot.assign(values, values + count);
snapshot.resize(count);
std::memcpy(snapshot.data(), values, static_cast<std::size_t>(count) * sizeof(std::uint32_t));
}
auto* packet = Allocate(buffer, count + 2u, function);
packet[0] = Header(opcode, count + 2u);
Expand Down
10 changes: 8 additions & 2 deletions core/libs/prx/libSceAgc/tests/Commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,14 @@ void testRegisterRange() {
check(packet == storage.words.data() + 6 && storage.buffer.cursor_up == storage.words.data() + 12, "incorrect populated register range allocation");
check(storage.words == expected, "register values were not copied correctly");
const auto* misaligned = reinterpret_cast<const std::uint32_t*>(reinterpret_cast<const unsigned char*>(values.data()) + 1);
expectFailure([&] { sceAgcCbSetShRegisterRangeDirect(&storage.buffer, 0x8c, misaligned, 4); });
check(storage.words == expected && storage.buffer.cursor_up == storage.words.data() + 12, "misaligned register values modified command buffer");
packet = sceAgcCbSetShRegisterRangeDirect(&storage.buffer, 0x8c, misaligned, 3);
expected[12] = 0xc0037600u;
expected[13] = 0x8c;
expected[14] = 0x02000000u;
expected[15] = 0x03000000u;
expected[16] = 0x04000000u;
check(packet == storage.words.data() + 12 && storage.buffer.cursor_up == storage.words.data() + 17, "incorrect misaligned register range allocation");
check(storage.words == expected, "misaligned register values were not read byte for byte");
}

void testPacketPayloadAddress() {
Expand Down
33 changes: 31 additions & 2 deletions core/libs/prx/libSceAgc/tests/RegisterCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
extern "C" {
std::uint32_t* APS5_VABI sceAgcDcbSetCfRegisterDirect(CommandBuffer*, ShaderRegister);
std::uint32_t* APS5_VABI sceAgcDcbSetCfRegisterRangeDirect(CommandBuffer*, std::uint32_t, const std::uint32_t*, std::uint32_t);
std::uint32_t* APS5_VABI sceAgcCbSetShRegisterRangeDirect(CommandBuffer*, std::uint32_t, const std::uint32_t*, std::uint32_t);
std::uint32_t* APS5_VABI sceAgcCbSetUcRegisterRangeDirect(CommandBuffer*, std::uint32_t, const std::uint32_t*, std::uint32_t);
std::uint32_t* APS5_VABI sceAgcDcbSetCxRegisterDirect(CommandBuffer*, ShaderRegister);
std::uint32_t* APS5_VABI sceAgcDcbSetShRegisterDirect(CommandBuffer*, ShaderRegister);
std::uint32_t* APS5_VABI sceAgcDcbSetUcRegisterDirect(CommandBuffer*, ShaderRegister);
Expand Down Expand Up @@ -92,11 +94,37 @@ void testConfig() {
expectFailure([&] { sceAgcDcbSetCfRegisterDirect(nullptr, {0, 1}); });
expectFailure([&] { sceAgcDcbSetCfRegisterRangeDirect(&storage.buffer, 0x100u, values.data(), 0); });
expectFailure([&] { sceAgcDcbSetCfRegisterRangeDirect(&storage.buffer, 0xffffu, values.data(), 2); });
const auto* misaligned = reinterpret_cast<const std::uint32_t*>(reinterpret_cast<const unsigned char*>(values.data()) + 1);
expectFailure([&] { sceAgcDcbSetCfRegisterRangeDirect(&storage.buffer, 0x100u, misaligned, 1); });
check(storage.words == before && storage.buffer.cursor_up == reserved + 4, "invalid config register write modified buffer");
}

void testRangeFromAnyByte() {
const std::array writers{sceAgcCbSetShRegisterRangeDirect, sceAgcCbSetUcRegisterRangeDirect, sceAgcDcbSetCfRegisterRangeDirect};
const std::array headers{0xc0047600u, 0xc0047900u, 0xc0046800u};
alignas(16) std::array<unsigned char, 32> bytes{};
for (std::size_t i = 0; i < bytes.size(); ++i) bytes[i] = static_cast<unsigned char>(0x10u + i);
struct Case {
std::size_t offset;
std::array<std::uint32_t, 4> values;
};
const std::array cases{
Case{1, {0x14131211u, 0x18171615u, 0x1c1b1a19u, 0x201f1e1du}},
Case{2, {0x15141312u, 0x19181716u, 0x1d1c1b1au, 0x21201f1eu}},
Case{3, {0x16151413u, 0x1a191817u, 0x1e1d1c1bu, 0x2221201fu}},
Case{13, {0x201f1e1du, 0x24232221u, 0x28272625u, 0x2c2b2a29u}},
};
for (std::size_t i = 0; i < writers.size(); ++i) {
for (const auto& entry : cases) {
Storage storage;
storage.words.fill(0xabcdef01u);
const auto* values = reinterpret_cast<const std::uint32_t*>(bytes.data() + entry.offset);
auto* packet = writers[i](&storage.buffer, 0x40u, values, 4);
check(packet == storage.words.data() && storage.buffer.cursor_up == packet + 6, "unaligned register range allocation mismatch");
check(packet[0] == headers[i] && packet[1] == 0x40u && std::equal(entry.values.begin(), entry.values.end(), packet + 2), "unaligned register values were not read byte for byte");
check(packet[6] == 0xabcdef01u, "unaligned register range overwrote the following word");
}
}
}

void testIndirect() {
const std::array writers{sceAgcDcbSetCxRegistersIndirect, sceAgcDcbSetShRegistersIndirect, sceAgcDcbSetUcRegistersIndirect};
const std::array sizes{sceAgcDcbSetCxRegistersIndirectGetSize, sceAgcDcbSetShRegistersIndirectGetSize, sceAgcDcbSetUcRegistersIndirectGetSize};
Expand Down Expand Up @@ -210,6 +238,7 @@ int main() {
try {
testDirect();
testConfig();
testRangeFromAnyByte();
testIndirect();
testIndirectPlaceholder();
testDirectList();
Expand Down
Loading