feat(agc): write the measured sceAgcDcbResetQueue packet sequence
Replace the CLEAR_STATE approximation with the envelope and per-op-bit packet groups measured on PS5 firmware 13.60. Emit groups for op bits 0x001, 0x002, 0x004, 0x008, 0x010, 0x020, 0x080, 0x100 and 0x800 in ascending order; throw for 0x040, 0x200 and 0x400 whose packets the driver rejects. state 2 sets the envelope flag and state 3 sets the 0x004 and 0x800 group payload dword.
This commit is contained in:
parent
eb2818f505
commit
73eb8465d6
|
|
@ -6,9 +6,45 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VideoOutput.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<std::uint32_t> resetQueueGroup(std::uint32_t bit, std::uint32_t state) {
|
||||
const std::uint32_t stateThree = state == 3u ? 0x00840f80u : 0x00000000u;
|
||||
switch (bit) {
|
||||
case 0x001u:
|
||||
return {0xc0039f00u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u};
|
||||
case 0x002u:
|
||||
return {0xc0036300u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u};
|
||||
case 0x004u:
|
||||
return {0xc0036400u, 0x00000000u, stateThree, 0x80000000u, 0x00000000u};
|
||||
case 0x008u:
|
||||
return {0xc0002f00u, 0x00000001u};
|
||||
case 0x010u:
|
||||
return {0xc0017a00u, 0x20000243u, 0x00000480u, 0xc0012600u, 0x00000000u, 0x00000000u, 0xc0001300u, 0xffffffffu};
|
||||
case 0x020u:
|
||||
return {0xc0021102u, 0x00000001u, 0x00000000u, 0x00000000u, 0xc0021100u, 0x00000001u, 0x00000000u, 0x00000000u};
|
||||
case 0x080u:
|
||||
return {0xc0004600u, 0x00000407u};
|
||||
case 0x100u:
|
||||
return {0xc0004600u, 0x00000410u};
|
||||
case 0x800u:
|
||||
return {0xc0036400u, 0x00000000u, stateThree, 0x80000000u, 0x00000000u};
|
||||
default:
|
||||
throw std::runtime_error(std::string("sceAgcDcbResetQueue: unsupported op bit ") + std::to_string(bit));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
|
@ -31,7 +67,34 @@ std::uint32_t APS5_VABI sceAgcDcbJumpGetSize() {
|
|||
std::uint32_t* APS5_VABI sceAgcDcbResetQueue(CommandBuffer* buf, std::uint32_t op, std::uint32_t state) {
|
||||
Agc::Command::CheckBits(op, 0xfffu, __func__);
|
||||
Agc::Command::CheckBits(state, 0xfu, __func__);
|
||||
return Agc::Command::Emit(buf, 0x12u, {state}, __func__);
|
||||
|
||||
constexpr std::array<std::uint32_t, 3> unsupported{0x040u, 0x200u, 0x400u};
|
||||
for (const auto bit : unsupported) {
|
||||
if ((op & bit) != 0u) {
|
||||
char message[64];
|
||||
std::snprintf(message, sizeof(message), "unsupported op bit 0x%x", bit);
|
||||
Agc::Command::Require(false, __func__, message);
|
||||
}
|
||||
}
|
||||
|
||||
const std::uint32_t envelopeFlag = state == 2u ? 0x00000008u : 0x00000000u;
|
||||
std::vector<std::uint32_t> words{
|
||||
0xffff1000u,
|
||||
0xc0027904u, 0x00000342u, 0xce200000u | (op & 0xffffu), envelopeFlag};
|
||||
|
||||
constexpr std::array<std::uint32_t, 9> order{0x001u, 0x002u, 0x004u, 0x008u, 0x010u, 0x020u, 0x080u, 0x100u, 0x800u};
|
||||
for (const auto bit : order) {
|
||||
if ((op & bit) != 0u) {
|
||||
const auto group = resetQueueGroup(bit, state);
|
||||
words.insert(words.end(), group.begin(), group.end());
|
||||
}
|
||||
}
|
||||
|
||||
words.insert(words.end(), {0xc0017904u, 0x00000342u, 0xcea00000u});
|
||||
|
||||
auto* packet = Agc::Command::Allocate(buf, static_cast<std::uint32_t>(words.size()), __func__);
|
||||
std::copy(words.begin(), words.end(), packet);
|
||||
return packet;
|
||||
}
|
||||
|
||||
std::uint32_t* APS5_VABI sceAgcDcbClearState(CommandBuffer* buf, std::uint32_t command) {
|
||||
|
|
|
|||
|
|
@ -81,14 +81,46 @@ bool APS5_VABI growReserved(CommandBuffer* buffer, std::uint32_t count, void* us
|
|||
|
||||
void testPackets() {
|
||||
Storage storage;
|
||||
sceAgcDcbResetQueue(&storage.buffer, 0, 3);
|
||||
auto* reset = sceAgcDcbResetQueue(&storage.buffer, 0, 3);
|
||||
sceAgcDcbDrawIndexAuto(&storage.buffer, 17, 0);
|
||||
const std::array<std::uint32_t, 5> expected{0xc0001200u, 3, 0xc0012d00u, 17, 2};
|
||||
check(std::equal(expected.begin(), expected.end(), storage.words.begin()), "reset or draw packet mismatch");
|
||||
const std::array<std::uint32_t, 11> expected{0xffff1000u, 0xc0027904u, 0x00000342u, 0xce200000u, 0x00000000u, 0xc0017904u, 0x00000342u, 0xcea00000u, 0xc0012d00u, 17, 2};
|
||||
check(reset == storage.words.data() && std::equal(expected.begin(), expected.end(), storage.words.begin()), "reset or draw packet mismatch");
|
||||
check(storage.buffer.cursor_up == storage.words.data() + expected.size(), "incorrect packet cursor advance");
|
||||
|
||||
Storage base;
|
||||
const auto* baseReset = sceAgcDcbResetQueue(&base.buffer, 0, 0);
|
||||
const std::array<std::uint32_t, 8> baseEnvelope{0xffff1000u, 0xc0027904u, 0x00000342u, 0xce200000u, 0x00000000u, 0xc0017904u, 0x00000342u, 0xcea00000u};
|
||||
check(baseReset == base.words.data() && std::equal(baseEnvelope.begin(), baseEnvelope.end(), baseReset), "op=0 state=0 envelope mismatch");
|
||||
check(base.buffer.cursor_up == base.words.data() + baseEnvelope.size(), "op=0 state=0 cursor advance mismatch");
|
||||
|
||||
Storage single;
|
||||
sceAgcDcbResetQueue(&single.buffer, 0x001u, 0);
|
||||
const std::array<std::uint32_t, 13> singleExpected{0xffff1000u, 0xc0027904u, 0x00000342u, 0xce200001u, 0x00000000u, 0xc0039f00u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0xc0017904u, 0x00000342u, 0xcea00000u};
|
||||
check(std::equal(singleExpected.begin(), singleExpected.end(), single.words.begin()), "op=0x001 group mismatch");
|
||||
check(single.buffer.cursor_up == single.words.data() + singleExpected.size(), "op=0x001 cursor advance mismatch");
|
||||
|
||||
Storage flagged;
|
||||
sceAgcDcbResetQueue(&flagged.buffer, 0, 2);
|
||||
check(flagged.words[4] == 0x00000008u, "state=2 did not set the envelope flag dword");
|
||||
|
||||
Storage stated;
|
||||
sceAgcDcbResetQueue(&stated.buffer, 0x004u, 3);
|
||||
const std::array<std::uint32_t, 13> statedExpected{0xffff1000u, 0xc0027904u, 0x00000342u, 0xce200004u, 0x00000000u, 0xc0036400u, 0x00000000u, 0x00840f80u, 0x80000000u, 0x00000000u, 0xc0017904u, 0x00000342u, 0xcea00000u};
|
||||
check(std::equal(statedExpected.begin(), statedExpected.end(), stated.words.begin()), "state=3 did not set the 0x004 group payload dword");
|
||||
|
||||
Storage upper;
|
||||
sceAgcDcbResetQueue(&upper.buffer, 0x800u, 0);
|
||||
const std::array<std::uint32_t, 13> upperExpected{0xffff1000u, 0xc0027904u, 0x00000342u, 0xce200800u, 0x00000000u, 0xc0036400u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0xc0017904u, 0x00000342u, 0xcea00000u};
|
||||
check(std::equal(upperExpected.begin(), upperExpected.end(), upper.words.begin()), "op=0x800 group mismatch");
|
||||
check(upper.buffer.cursor_up == upper.words.data() + upperExpected.size(), "op=0x800 cursor advance mismatch");
|
||||
|
||||
const auto before = storage.words;
|
||||
expectFailure([&] { sceAgcDcbResetQueue(&storage.buffer, 0, 16); });
|
||||
check(storage.words == before, "invalid reset modified packet memory");
|
||||
expectFailure([&] { sceAgcDcbResetQueue(&storage.buffer, 0x040u, 0); });
|
||||
expectFailure([&] { sceAgcDcbResetQueue(&storage.buffer, 0x200u, 0); });
|
||||
expectFailure([&] { sceAgcDcbResetQueue(&storage.buffer, 0x400u, 0); });
|
||||
expectFailure([&] { sceAgcDcbResetQueue(&storage.buffer, 0x1000u, 0); });
|
||||
check(storage.words == before && storage.buffer.cursor_up == storage.words.data() + expected.size(), "invalid reset modified packet memory");
|
||||
Storage destination;
|
||||
CommandBuffer empty{nullptr, nullptr, nullptr, nullptr, grow, &destination, 0};
|
||||
Agc::Command::Emit(&empty, 0x15u, {1, 1, 1, 0x41u}, __func__);
|
||||
|
|
|
|||
Loading…
Reference in New Issue