mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-25 12:26:51 +01:00
shader: walk every resource plan with the x86 SRT walker
This commit is contained in:
@@ -60,6 +60,7 @@
|
||||
#include "libs/errno.h"
|
||||
#include "loader/symbolDatabase.h"
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
#include "SrtWalkerTestMemory.h"
|
||||
|
||||
#if __has_include("graphics/host_gpu/renderer/renderTargetBarriers.h")
|
||||
#error "legacy render-target barrier API must remain deleted"
|
||||
@@ -1724,15 +1725,17 @@ CompiledShader CompileCase(const TestCase &test, u32 host_subgroup_size = 64) {
|
||||
const ShaderRecompiler::IR::SrtRuntime runtime{
|
||||
.user_data = options.user_data,
|
||||
.shader_base = reinterpret_cast<uint64_t>(test.code.data()),
|
||||
.read_memory = ReadTestMemory,
|
||||
.userdata = const_cast<std::vector<u32> *>(&test.initial),
|
||||
.read_specialization_memory = ReadTestMemory,
|
||||
.workgroup_counts = workgroup_counts,
|
||||
};
|
||||
Require(test.name, "resource materialization",
|
||||
ShaderRecompiler::IR::MaterializeResources(
|
||||
resource_plan, runtime, resources, specialization),
|
||||
"translated resources could not be materialized");
|
||||
{
|
||||
FakeGuestMemory fake(ReadTestMemory, runtime.userdata);
|
||||
Require(test.name, "resource materialization",
|
||||
ShaderRecompiler::IR::MaterializeResources(
|
||||
resource_plan, runtime, resources, specialization),
|
||||
"translated resources could not be materialized");
|
||||
}
|
||||
auto result = ShaderRecompiler::CompileProgram(
|
||||
std::move(translated), options, specialization);
|
||||
for (const auto &[text, expected] : test.decoded_counts) {
|
||||
@@ -11235,7 +11238,7 @@ public:
|
||||
};
|
||||
const ShaderRecompiler::IR::SrtRuntime runtime{
|
||||
.user_data = user_data, .shader_base = reinterpret_cast<uint64_t>(caller.data()),
|
||||
.read_memory = read, .read_specialization_memory = read};
|
||||
.read_specialization_memory = read};
|
||||
auto source = ShaderRecompiler::PrepareShaderSource(caller, options);
|
||||
auto translated = ShaderRecompiler::TranslateProgram(
|
||||
ShaderRecompiler::RefreshShaderSource(source, runtime), options);
|
||||
@@ -17158,12 +17161,7 @@ public:
|
||||
stencil_compute.stage.resources = &stencil_snapshot;
|
||||
Require(name, "stencil fill materialization",
|
||||
ShaderRecompiler::IR::MaterializeResources(stencil_plan,
|
||||
{.user_data = stencil_userdata, .userdata = &stencil_byte,
|
||||
.read_specialization_memory = +[](void *data, uint64_t address, std::span<uint32_t> words) {
|
||||
if (address != reinterpret_cast<uint64_t>(data) || words.size() != 1u) return false;
|
||||
words[0] = *static_cast<uint32_t *>(data);
|
||||
return true;
|
||||
}}, stencil_snapshot, stencil_specialization),
|
||||
{.user_data = stencil_userdata}, stencil_snapshot, stencil_specialization),
|
||||
"captured stencil shader could not resolve its clear byte");
|
||||
ShaderRecompiler::IR::ApplyResourceSpecialization(stencil_translated.program,
|
||||
stencil_specialization);
|
||||
@@ -39523,25 +39521,25 @@ void CheckRuntimeBufferRecords(VulkanHarness &vulkan) {
|
||||
options.input_info.compute = &test.compute_info;
|
||||
auto translated = ShaderRecompiler::TranslateProgram(test.code, options);
|
||||
auto plan = ExtractResourcePlan(translated.program);
|
||||
struct CountMemory { u32 value = 72; u32 reads = 0; bool clean = true; } memory;
|
||||
SrtRuntime runtime{.user_data = test.user_data, .userdata = &memory};
|
||||
struct CountMemory { u32 value = 72; u32 reads = 0; bool readable = true; } memory;
|
||||
ResourceSnapshot snapshot;
|
||||
ResourceSpecialization specialization;
|
||||
Require(test.name, "strict reader required",
|
||||
!MaterializeResources(plan, runtime, snapshot, specialization),
|
||||
"vector descriptor input bypassed the clean-memory reader");
|
||||
runtime.read_specialization_memory = [](void *data, uint64_t address, std::span<u32> words) {
|
||||
auto &memory = *static_cast<CountMemory *>(data);
|
||||
++memory.reads;
|
||||
if (!memory.clean || address != count_address || words.size() != 1) return false;
|
||||
words[0] = memory.value;
|
||||
return true;
|
||||
const auto materialize = [&] {
|
||||
FakeGuestMemory fake(+[](void *data, uint64_t address, std::span<u32> words) {
|
||||
auto &memory = *static_cast<CountMemory *>(data);
|
||||
++memory.reads;
|
||||
if (!memory.readable || address != count_address) return false;
|
||||
words[0] = memory.value;
|
||||
return true;
|
||||
}, &memory);
|
||||
return MaterializeResources(plan, {.user_data = test.user_data}, snapshot, specialization);
|
||||
};
|
||||
memory.clean = false;
|
||||
Require(test.name, "dirty input rejected",
|
||||
!MaterializeResources(plan, runtime, snapshot, specialization),
|
||||
"GPU-dirty count was accepted for host descriptor evaluation");
|
||||
memory.clean = true;
|
||||
// An unreadable count reads as zero, which leaves no records.
|
||||
memory.readable = false;
|
||||
Require(test.name, "unreadable input",
|
||||
materialize() && memory.reads == 1 && snapshot.buffers[2].dwords[2] == 0,
|
||||
"unreadable count did not read as zero");
|
||||
memory.readable = true;
|
||||
ResourceSpecialization initial_specialization;
|
||||
// Reuse the same resource plan and compiled shader as the count and coverage change.
|
||||
for (const u32 count : {0u, 72u, 512u, 8192u, 262144u}) {
|
||||
@@ -39550,7 +39548,7 @@ void CheckRuntimeBufferRecords(VulkanHarness &vulkan) {
|
||||
const u32 chunk = count < 512 ? 64 : count < 8192 ? 128 : count < 262144 ? 256 : 512;
|
||||
const u32 records = (count + chunk - 1) / chunk;
|
||||
Require(test.name, "cached descriptor refresh",
|
||||
MaterializeResources(plan, runtime, snapshot, specialization) && memory.reads == 1 &&
|
||||
materialize() && memory.reads == 1 &&
|
||||
snapshot.buffers[2].dwords[2] == records &&
|
||||
snapshot.specialization_reads ==
|
||||
std::vector<std::pair<uint64_t, uint64_t>>{{count_address, 4}},
|
||||
@@ -44598,7 +44596,6 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
|
||||
compute.thread_ids_num = 1;
|
||||
compute.workgroup_register = 8;
|
||||
u32 scalar_clear = 0x40404040u;
|
||||
bool clean_scalar = false;
|
||||
|
||||
const auto Compile = [&](const std::vector<u32> &code) {
|
||||
ShaderRecompiler::CompileOptions options;
|
||||
@@ -44616,13 +44613,6 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
|
||||
const ShaderRecompiler::IR::SrtRuntime runtime{
|
||||
.user_data = options.user_data,
|
||||
.shader_base = reinterpret_cast<uint64_t>(code.data()),
|
||||
.userdata = &scalar_clear,
|
||||
.read_specialization_memory = clean_scalar
|
||||
? +[](void *data, uint64_t address, std::span<uint32_t> words) {
|
||||
if (address != reinterpret_cast<uint64_t>(data) || words.size() != 1u) return false;
|
||||
words[0] = *static_cast<uint32_t *>(data);
|
||||
return true;
|
||||
} : nullptr,
|
||||
};
|
||||
Require("Ps5GameExampleImageClear", "resource materialization",
|
||||
ShaderRecompiler::IR::MaterializeResources(
|
||||
@@ -44780,7 +44770,7 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
|
||||
scalar_code.push_back(EncodeMubuf0(0x04u, 0, true, false));
|
||||
scalar_code.push_back(EncodeMubuf1(1, 0, 0));
|
||||
AppendEnd(&scalar_code);
|
||||
clean_scalar = true;
|
||||
// The scalar input is a walker load, so it needs no specialization memory reader.
|
||||
auto loaded = Compile(scalar_code);
|
||||
runtime_resources = loaded;
|
||||
Require("Ps5GameExampleImageClear", "scalar-loaded fill",
|
||||
@@ -44788,12 +44778,6 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
|
||||
packed_clear, size) &&
|
||||
packed_clear == scalar_clear && descriptor.Base48() == 0x200000u,
|
||||
"GTA3's scalar input was confused with its destination");
|
||||
clean_scalar = false;
|
||||
runtime_resources = Compile(scalar_code);
|
||||
Require("Ps5GameExampleImageClear", "unavailable clean scalar",
|
||||
!ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor,
|
||||
packed_clear, size),
|
||||
"a scalar without a clean reader was replaced by a fill");
|
||||
std::printf("[host] %-32s ok\n", "Ps5GameExampleImageClear");
|
||||
}
|
||||
|
||||
@@ -47260,8 +47244,9 @@ void CheckImageSamplerSpecialization() {
|
||||
auto plan = ExtractResourcePlan(translated.program);
|
||||
ResourceSnapshot snapshot;
|
||||
ResourceSpecialization specialization;
|
||||
const SrtRuntime runtime{.user_data = user_data, .read_memory = ReadTestMemory,
|
||||
.userdata = &memory, .read_specialization_memory = ReadTestMemory};
|
||||
const SrtRuntime runtime{.user_data = user_data, .userdata = &memory,
|
||||
.read_specialization_memory = ReadTestMemory};
|
||||
FakeGuestMemory fake(ReadTestMemory, &memory);
|
||||
Require(name, "bounded native material plan",
|
||||
plan.capture_specialization_reads && !translated.program.has_address_writes &&
|
||||
MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||
@@ -47351,10 +47336,8 @@ void CheckResourcePlanHandoff() {
|
||||
auto plan = ExtractResourcePlan(translated.program);
|
||||
ResourceSnapshot snapshot;
|
||||
ResourceSpecialization specialization;
|
||||
const SrtRuntime runtime{.user_data = user_data,
|
||||
.read_memory = ReadTestMemory,
|
||||
.userdata = &memory,
|
||||
.read_specialization_memory = ReadTestMemory};
|
||||
const SrtRuntime runtime{.user_data = user_data};
|
||||
FakeGuestMemory fake(ReadTestMemory, &memory);
|
||||
Require(name, "initial descriptors",
|
||||
MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||
snapshot.buffers.size() == 1 && snapshot.buffers[0].dwords[0] == 0x1000u,
|
||||
|
||||
Reference in New Issue
Block a user