mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-18 23:07:07 -05:00
fix(agc): defer registered compute shaders without specials to dispatch
A registered compute shader takes its wave size from its header's specials (dispatch_modifier), and PrepareRegistered read them without a null check. ps5-opengl registers compute headers without specials, since it writes the specials pointer only for linked graphics stages, and passes the wave size in the dispatch initiator instead. Registration then threw "shader metadata is outside the registered header". Such a shader is now deferred like the other shaders that can't be prepared at registration, so it is prepared at its first dispatch with the wave size from the initiator's CS_W32_EN.
This commit is contained in:
1 parent
f6af6d11d3
commit
f752ef4f2b
2 files changed
+29
No files matched your search
@@ -452,6 +452,10 @@ std::unique_ptr<RegisteredPreparation> PlanRegistered(const ShaderSnapshot& snap
|
||||
if (userCount > 32) throw std::runtime_error("AGC driver: static user SGPR count exceeds the register bank");
|
||||
if (stage == Stage::Compute) {
|
||||
compute = Graphics::DecodeComputeStageInfo(state.shader, snapshot.header);
|
||||
if (header.specials == nullptr) {
|
||||
if (deferred != nullptr) return defer("its header has no specials to give its wave size");
|
||||
return {};
|
||||
}
|
||||
const auto special = ReadHeaderArray(snapshot, header.specials, 1).front();
|
||||
wave = (special.dispatch_modifier & 0x8000u) != 0 ? 32u : 64u;
|
||||
} else if (stage == Stage::Fragment) {
|
||||
|
||||
@@ -334,6 +334,30 @@ void UnsupportedTypeRegistration() {
|
||||
AgcDriverRegisterShader_nid_postfix(&header.shader);
|
||||
}
|
||||
|
||||
void RegistrationWithoutSpecials() {
|
||||
alignas(256) std::array<std::uint32_t, 1> code{0xbf810000u};
|
||||
struct Header {
|
||||
Shader shader{};
|
||||
std::array<ShaderRegister, 7> registers{};
|
||||
} header;
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(code.data());
|
||||
header.shader.file_header = 0x34333231u;
|
||||
header.shader.version = 0x18;
|
||||
header.shader.header_size = sizeof(header);
|
||||
header.shader.shader_size = sizeof(code);
|
||||
header.shader.code = code.data();
|
||||
header.shader.sh_registers = header.registers.data();
|
||||
header.shader.num_sh_registers = header.registers.size();
|
||||
header.registers = {{{0x20c, static_cast<std::uint32_t>(address >> 8u)}, {0x20d, static_cast<std::uint32_t>(address >> 40u)}, {0x207, 1}, {0x208, 1}, {0x209, 1}, {0x212, 0}, {0x213, 0}}};
|
||||
AgcDriverRegisterShader_nid_postfix(&header.shader);
|
||||
std::vector<std::uint32_t> commands;
|
||||
for (const auto reg : header.registers) commands.insert(commands.end(), {0xc0017600u, reg.offset, reg.value});
|
||||
for (const std::uint32_t initiator : {0x8041u, 0x41u}) commands.insert(commands.end(), {0xc0031500u, 1, 1, 1, initiator});
|
||||
Packet packet{commands.data(), static_cast<std::uint32_t>(commands.size()), 0, {}};
|
||||
sceAgcDriverSubmitAcb(0x20, &packet);
|
||||
AgcDriverWaitIdle_nid_postfix();
|
||||
}
|
||||
|
||||
void Registration(bool indirect) {
|
||||
UnsupportedTypeRegistration();
|
||||
alignas(256) std::array<std::uint32_t, 1> code{0xbf810000u};
|
||||
@@ -496,6 +520,7 @@ int main(int argc, char** argv) {
|
||||
Require(argc != 2 || std::string_view(argv[1]) != "--fail-before-registration", "injected failure before registration");
|
||||
PrepareMultisampledStorage(*device);
|
||||
device.reset();
|
||||
RegistrationWithoutSpecials();
|
||||
Registration(argc == 2);
|
||||
std::cout << "prepared shader and transactional registration tests passed\n";
|
||||
return 0;
|
||||
|
||||
Reference in new issue
Block a user