shader: remove second IR layer

This commit is contained in:
nmzik
2026-08-26 07:42:51 +02:00
parent e2c840cb23
commit ffa69d48de
49 changed files with 3691 additions and 6001 deletions
+39 -36
View File
@@ -1,5 +1,5 @@
#include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/shader/recompiler/ir/ValueProgram.h"
#include "graphics/shader/recompiler/ir/ShaderIR.h"
#include "graphics/shader/recompiler/ir/passes/BindingLayout.h"
#include "graphics/shader/recompiler/ir/passes/DeadCodeElimination.h"
#include "graphics/shader/recompiler/ir/passes/ResourceMaterialization.h"
@@ -35,7 +35,6 @@ struct Fixture {
explicit Fixture(ShaderType stage = ShaderType::Compute) {
program.stage = stage;
program.values = std::make_shared<ValueProgram>();
program.user_data_count = 64;
block = AddBlock();
}
@@ -43,10 +42,10 @@ struct Fixture {
Block *AddBlock() {
auto storage = std::make_unique<Block>();
auto *result = storage.get();
program.values->block_storage.push_back(std::move(storage));
program.values->blocks.push_back(result);
program.values->block_info.push_back(
{.id = static_cast<uint32_t>(program.values->block_info.size())});
program.block_storage.push_back(std::move(storage));
program.blocks.push_back(result);
program.block_info.push_back(
{.id = static_cast<uint32_t>(program.block_info.size())});
return result;
}
@@ -77,8 +76,8 @@ struct Fixture {
MemoryFlags AddMemory(MemoryInfo memory, uint32_t pc) {
const auto index =
static_cast<uint32_t>(program.values->memory_info.size());
program.values->memory_info.push_back(memory);
static_cast<uint32_t>(program.memory_info.size());
program.memory_info.push_back(memory);
return {index, pc};
}
@@ -241,19 +240,19 @@ MakeIndirectImageFixture(bool malformed, uint32_t material_immediate = 0,
void TestInvariantIndirectImageMaterialization() {
auto fixture = MakeIndirectImageFixture(false);
fixture->PlanAndTrack();
EliminateDeadCode(fixture->program.values->blocks);
EliminateDeadCode(fixture->program.blocks);
std::string validation_error;
Check(
ValidateValueProgram(*fixture->program.values, true, &validation_error),
ValidateProgram(fixture->program, true, &validation_error),
"post-tracking dead-code elimination invalidated descriptor provenance");
Check(fixture->program.info.buffers.size() == 1 &&
fixture->program.info.images.size() == 1 &&
fixture->program.values->dynamic_reads.size() == 1,
fixture->program.dynamic_reads.size() == 1,
"indirect image key was not retained as a scalar-buffer read");
const auto source = fixture->program.info.images[0].source;
Check(source < fixture->program.values->descriptor_sources.size() &&
fixture->program.values->descriptor_sources[source]
Check(source < fixture->program.descriptor_sources.size() &&
fixture->program.descriptor_sources[source]
.indirect_image.has_value(),
"indirect image source was not retained for runtime proof");
const auto image_handle =
@@ -407,7 +406,7 @@ void TestInvariantIndirectImageMaterialization() {
auto memory_backed = MakeIndirectImageFixture(false, 0u, true);
memory_backed->PlanAndTrack();
EliminateDeadCode(memory_backed->program.values->blocks);
EliminateDeadCode(memory_backed->program.blocks);
std::array<uint32_t, 11> memory_backed_user_data{0x1000u, 224u << 16u, 2u, 0u,
0x2000u, 16u << 16u, 4u, 0u,
7u, 0x3100u, 0u};
@@ -431,7 +430,7 @@ void TestInvariantIndirectImageMaterialization() {
error.find("ReadFirstLane") != std::string::npos &&
!malformed->program.resource_tracking_complete &&
malformed->program.info.images.empty() &&
malformed->program.values->descriptor_sources.empty(),
malformed->program.descriptor_sources.empty(),
"malformed indirect image pattern was partially accepted");
auto wrapped_immediate = MakeIndirectImageFixture(false, 4u);
@@ -484,7 +483,7 @@ void TestDenseBufferTracking() {
Check(fixture.program.info.buffers.size() == 2,
"typed buffer sources were not densely interned");
Check(fixture.program.values->descriptor_sources.size() == 2,
Check(fixture.program.descriptor_sources.size() == 2,
"descriptor source table did not match dense topology");
const auto &resource = fixture.program.info.buffers[0];
Check(resource.read && resource.written && resource.atomic &&
@@ -494,10 +493,10 @@ void TestDenseBufferTracking() {
Check(first.Instruction()->Flags<uint32_t>() == 0 &&
second.Instruction()->Flags<uint32_t>() == 1,
"typed handles were not assigned dense indices");
Check(fixture.program.values->memory_info[load_flags.index].resource == 0 &&
fixture.program.values->memory_info[store_flags.index].resource ==
Check(fixture.program.memory_info[load_flags.index].resource == 0 &&
fixture.program.memory_info[store_flags.index].resource ==
0 &&
fixture.program.values->memory_info[other_flags.index].resource ==
fixture.program.memory_info[other_flags.index].resource ==
1,
"typed memory metadata was not patched to dense indices");
@@ -531,8 +530,8 @@ void TestScalarAndVectorBufferAlias() {
Check(fixture.program.info.buffers.size() == 1 &&
fixture.program.info.buffers[0].scalar,
"typed scalar and vector uses of one descriptor were split");
Check(fixture.program.values->memory_info[scalar_flags.index].resource == 0 &&
fixture.program.values->memory_info[vector_flags.index].resource ==
Check(fixture.program.memory_info[scalar_flags.index].resource == 0 &&
fixture.program.memory_info[vector_flags.index].resource ==
0,
"scalar/vector alias did not share a dense index");
}
@@ -625,7 +624,7 @@ void TestImagesSamplersAndAliases() {
repeated.second.Instruction()->Flags<uint32_t>() == 0,
"unused sampler border colors prevented source interning");
const auto sampler_source = fixture.program.info.samplers[0].source;
Check(fixture.program.values->descriptor_sources[sampler_source]
Check(fixture.program.descriptor_sources[sampler_source]
.dwords[3]
.U32() == 0,
"unused sampler border color was not canonicalized");
@@ -665,7 +664,7 @@ void TestSampleAdjustSamplerScratch() {
fixture.PlanAndTrack();
const auto source = fixture.program.info.samplers[0].source;
const auto stored = fixture.program.values->descriptor_sources[source]
const auto stored = fixture.program.descriptor_sources[source]
.dwords[3]
.Resolve()
.TryInstruction();
@@ -758,10 +757,10 @@ void TestDynamicStorageMipTracking() {
mip1.first.Instruction()->Flags<uint32_t>() == 1 &&
mip2.first.Instruction()->Flags<uint32_t>() == 1 &&
dynamic.first.Instruction()->Flags<uint32_t>() == 1 &&
fixture.program.values->memory_info[plain.second].resource == 0 &&
fixture.program.values->memory_info[mip1.second].resource == 1 &&
fixture.program.values->memory_info[mip2.second].resource == 1 &&
fixture.program.values->memory_info[dynamic.second].resource == 1,
fixture.program.memory_info[plain.second].resource == 0 &&
fixture.program.memory_info[mip1.second].resource == 1 &&
fixture.program.memory_info[mip2.second].resource == 1 &&
fixture.program.memory_info[dynamic.second].resource == 1,
"dynamic storage mip handles and memory metadata were not patched");
DescriptorValue descriptor{};
@@ -795,7 +794,6 @@ void TestDynamicStorageMipTracking() {
"dynamic storage mip descriptors were not expanded consecutively");
Program null_program;
null_program.values = std::make_shared<ValueProgram>();
null_program.resource_tracking_complete = true;
ImageResource null_image;
null_image.kind = ResourceKind::StorageImage;
@@ -847,12 +845,12 @@ void TestSrtFlatteningAndRuntimeMemoization() {
fixture.AddMemory(buffer, 16));
fixture.PlanAndTrack();
Check(fixture.program.values->srt_reads.size() == 1,
Check(fixture.program.srt_reads.size() == 1,
"shared typed scalar read did not receive one flat SRT slot");
Check(fixture.program.info.buffers.size() == 1 &&
fixture.program.info.addresses.empty(),
"planning-only scalar reads leaked into resource topology");
Check(fixture.program.values->memory_info[0].planning_only,
Check(fixture.program.memory_info[0].planning_only,
"canonical runtime scalar read was not marked planning-only");
std::array<uint32_t, 2> user_data{0x1000u, 0u};
@@ -910,8 +908,8 @@ void TestDynamicSrtReadRemainsExplicit() {
fixture.AddMemory(buffer, 8));
fixture.PlanAndTrack();
Check(fixture.program.values->srt_reads.empty() &&
fixture.program.values->dynamic_reads.size() == 1 &&
Check(fixture.program.srt_reads.empty() &&
fixture.program.dynamic_reads.size() == 1 &&
fixture.program.info.addresses.size() == 1,
"dynamic scalar read was incorrectly flattened or lost");
std::array<uint32_t, 3> user_data{0x1000u, 0u, 4u};
@@ -973,7 +971,7 @@ void TestPhiValidation() {
error.find("control-dependent phi") != std::string::npos &&
!fixture.program.resource_tracking_complete &&
fixture.program.info.buffers.empty() &&
fixture.program.values->descriptor_sources.empty(),
fixture.program.descriptor_sources.empty(),
"control-dependent descriptor phi was not rejected transactionally");
}
@@ -1295,7 +1293,7 @@ void TestResourceLimitIsTransactional() {
error.find("buffer resource limit exceeded") != std::string::npos &&
!fixture.program.resource_tracking_complete &&
fixture.program.info.buffers.empty() &&
fixture.program.values->descriptor_sources.empty(),
fixture.program.descriptor_sources.empty(),
"resource-limit failure partially mutated typed resource state");
}
@@ -1412,13 +1410,18 @@ int main() {
// The full emulator supplies these assertion hooks through common. This focused
// target links only fmt; keep assertion failures observable without widening
// its legacy build manifest.
// its focused build manifest.
namespace Common {
int DbgExitIfHandler(const char *expression, const char *file, int line) {
throw std::runtime_error(std::string("typed IR assertion: ") + expression +
" at " + file + ':' + std::to_string(line));
}
int DbgNotImplementedHandler(const char *expression, const char *file, int line) {
throw std::runtime_error(std::string("typed IR not implemented: ") + expression +
" at " + file + ':' + std::to_string(line));
}
void DbgExit(int) { throw std::runtime_error("typed IR assertion failed"); }
} // namespace Common
@@ -1427,6 +1430,6 @@ void DbgExit(int) { throw std::runtime_error("typed IR assertion failed"); }
#include "graphics/shader/recompiler/ir/Block.cpp"
#include "graphics/shader/recompiler/ir/Type.cpp"
#include "graphics/shader/recompiler/ir/Value.cpp"
#include "graphics/shader/recompiler/ir/ValueProgram.cpp"
#include "graphics/shader/recompiler/ir/Program.cpp"
#include "graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp"
#include "graphics/shader/recompiler/ir/passes/DeadCodeElimination.cpp"
+39 -40
View File
@@ -1,4 +1,4 @@
#include "graphics/shader/recompiler/ir/ValueProgram.h"
#include "graphics/shader/recompiler/ir/ShaderIR.h"
#include "graphics/shader/recompiler/ir/passes/ConstantPropagation.h"
#include "graphics/shader/recompiler/ir/passes/DeadCodeElimination.h"
#include "graphics/shader/recompiler/ir/passes/ReadLaneElimination.h"
@@ -27,16 +27,15 @@ struct Fixture {
program.stage = ShaderType::Compute;
program.shader_hash = 0x12345678u;
program.user_data_base = 2;
program.values = std::make_shared<ValueProgram>();
for (uint32_t index = 0; index < block_count; index++) {
program.values->block_storage.push_back(std::make_unique<Block>());
auto *block = program.values->block_storage.back().get();
program.values->blocks.push_back(block);
program.values->block_info.push_back({.id = index});
program.block_storage.push_back(std::make_unique<Block>());
auto *block = program.block_storage.back().get();
program.blocks.push_back(block);
program.block_info.push_back({.id = index});
}
}
Block &BlockAt(uint32_t index = 0) { return *program.values->blocks[index]; }
Block &BlockAt(uint32_t index = 0) { return *program.blocks[index]; }
Value Emit(ValueOpcode opcode, std::initializer_list<Value> args = {},
uint64_t flags = 0, uint32_t block = 0) {
@@ -55,8 +54,8 @@ struct Fixture {
MemoryInfo info;
info.kind = kind;
info.offset = static_cast<uint32_t>(offset);
program.values->memory_info.push_back(info);
return static_cast<uint32_t>(program.values->memory_info.size() - 1u);
program.memory_info.push_back(info);
return static_cast<uint32_t>(program.memory_info.size() - 1u);
}
void Plan() {
@@ -103,11 +102,11 @@ void TestImmediateFlatteningAndGvn() {
{first, second, Value(16u), Value(0u)});
fixture.Plan();
Check(fixture.program.values->srt_reads.size() == 1,
Check(fixture.program.srt_reads.size() == 1,
"equivalent typed scalar reads were not coalesced");
Check(fixture.program.values->dynamic_reads.empty(),
Check(fixture.program.dynamic_reads.empty(),
"immediate scalar read was classified as dynamic");
Check(fixture.program.values->memory_info[memory].planning_only,
Check(fixture.program.memory_info[memory].planning_only,
"flattened raw read was not kept as a planning-only root");
TestMemory memory_image{{{0x1020u, 0xfeedbeefu}}};
@@ -173,8 +172,8 @@ void TestDynamicReadRemainsTyped() {
{read, Value(0u), Value(16u), Value(0u)});
fixture.Plan();
Check(fixture.program.values->srt_reads.empty() &&
fixture.program.values->dynamic_reads == std::vector<Value>{read},
Check(fixture.program.srt_reads.empty() &&
fixture.program.dynamic_reads == std::vector<Value>{read},
"dynamic scalar read received a fake flattened slot");
}
@@ -209,7 +208,7 @@ void TestShaderBaseAndUserData() {
{Value(static_cast<ScalarReg>(2))});
const auto sum = fixture.Emit(ValueOpcode::IAdd32, {user, Value(4u)});
fixture.Plan();
fixture.program.values->descriptor_sources.push_back(
fixture.program.descriptor_sources.push_back(
{.dwords = {low, high, sum}, .dword_count = 3});
const std::array user_data{0x20u};
@@ -239,7 +238,7 @@ void TestCarryAndBitFields() {
const auto sign = fixture.Emit(ValueOpcode::BitFieldSExtract,
{Value(0x000000f0u), Value(4u), Value(4u)});
fixture.Plan();
fixture.program.values->descriptor_sources.push_back(
fixture.program.descriptor_sources.push_back(
{.dwords = {low, high, inserted, sign}, .dword_count = 4});
DescriptorValue result;
@@ -262,9 +261,9 @@ void TestInvariantAndDivergentPhi() {
divergent.AddPhiOperand(&fixture.BlockAt(0), Value(7u));
divergent.AddPhiOperand(&fixture.BlockAt(1), Value(9u));
fixture.Plan();
fixture.program.values->descriptor_sources.push_back(
fixture.program.descriptor_sources.push_back(
{.dwords = {Value(&invariant)}, .dword_count = 1});
fixture.program.values->descriptor_sources.push_back(
fixture.program.descriptor_sources.push_back(
{.dwords = {Value(&divergent)}, .dword_count = 1});
DescriptorValue result;
@@ -293,10 +292,10 @@ void TestControlDependentStandaloneLoadStaysTyped() {
RawRead(fixture, Address(fixture, Value(&base), Value(0u), 2), Value(0u),
memory, 2);
fixture.Plan();
Check(fixture.program.values->srt_reads.empty() &&
Check(fixture.program.srt_reads.empty() &&
read.ResolveInstruction()->GetOpcode() ==
ValueOpcode::LoadAddressU32 &&
!fixture.program.values->memory_info[memory].planning_only,
!fixture.program.memory_info[memory].planning_only,
"control-dependent standalone scalar load was flattened into a host "
"snapshot");
}
@@ -315,7 +314,7 @@ void TestRuntime64BitDescriptorOps() {
const auto high =
fixture.Emit(ValueOpcode::CompositeExtractU64, {combined, Value(1u)});
fixture.Plan();
fixture.program.values->descriptor_sources.push_back(
fixture.program.descriptor_sources.push_back(
{.dwords = {low, high}, .dword_count = 2});
DescriptorValue result;
@@ -370,7 +369,7 @@ void TestReadLaneElimination() {
{undef, Value(0xdeadbeefu), Value(5u)});
const auto read = fixture.Emit(ValueOpcode::ReadLane, {write, Value(5u)});
const auto use = fixture.Emit(ValueOpcode::IAdd32, {read, Value(1u)});
const auto stats = EliminateReadLane(*fixture.program.values, 64);
const auto stats = EliminateReadLane(fixture.program, 64);
Check(stats.rewritten_reads == 1 &&
use.ResolveInstruction()->Arg(0).Resolve() == Value(0xdeadbeefu),
"fixed-lane typed read was not rewritten from its SSA write chain");
@@ -379,7 +378,7 @@ void TestReadLaneElimination() {
{Value(static_cast<ScalarReg>(2))});
const auto dynamic = fixture.Emit(ValueOpcode::ReadLane, {write, selector});
fixture.Emit(ValueOpcode::IAdd32, {dynamic, Value(1u)});
Check(EliminateReadLane(*fixture.program.values, 64).rewritten_reads == 0,
Check(EliminateReadLane(fixture.program, 64).rewritten_reads == 0,
"dynamic-lane read was rewritten unsafely");
}
@@ -390,9 +389,9 @@ void TestOptimizationPipeline() {
fixture.Emit(ValueOpcode::ReferenceU32, {kept});
fixture.Emit(ValueOpcode::IMul32, {Value(6u), Value(7u)});
ConstantPropagationPass(fixture.program.values->blocks);
RemoveIdentities(fixture.program.values->blocks);
EliminateDeadCode(fixture.program.values->blocks);
ConstantPropagationPass(fixture.program.blocks);
RemoveIdentities(fixture.program.blocks);
EliminateDeadCode(fixture.program.blocks);
const auto &instructions = fixture.BlockAt().Instructions();
Check(instructions.size() == 1 &&
@@ -404,20 +403,20 @@ void TestOptimizationPipeline() {
void TestControlFlowValueSurvivesReadLaneFolding() {
Fixture fixture(3);
auto *entry = fixture.program.values->blocks[0];
auto *taken = fixture.program.values->blocks[1];
auto *other = fixture.program.values->blocks[2];
auto *entry = fixture.program.blocks[0];
auto *taken = fixture.program.blocks[1];
auto *other = fixture.program.blocks[2];
entry->AddBranch(taken);
entry->AddBranch(other);
auto &entry_info = fixture.program.values->block_info[0];
auto &entry_info = fixture.program.block_info[0];
entry_info.terminator.kind =
Libs::Graphics::ShaderRecompiler::CFG::TerminatorKind::ConditionalBranch;
entry_info.terminator.true_block = 1;
entry_info.terminator.false_block = 2;
fixture.program.values->block_info[1].terminator.kind =
fixture.program.block_info[1].terminator.kind =
Libs::Graphics::ShaderRecompiler::CFG::TerminatorKind::Return;
fixture.program.values->block_info[2].terminator.kind =
fixture.program.block_info[2].terminator.kind =
Libs::Graphics::ShaderRecompiler::CFG::TerminatorKind::Return;
const auto undef = fixture.Emit(ValueOpcode::UndefU32);
@@ -429,16 +428,16 @@ void TestControlFlowValueSurvivesReadLaneFolding() {
fixture.Emit(ValueOpcode::IEqual32, {read, Value(42u)});
fixture.Emit(ValueOpcode::Reference, {entry_info.condition});
Check(EliminateReadLane(*fixture.program.values, 64).rewritten_reads == 1,
Check(EliminateReadLane(fixture.program, 64).rewritten_reads == 1,
"control-flow fixture did not eliminate its fixed-lane read");
ConstantPropagationPass(fixture.program.values->blocks);
ResolveControlFlowIdentities(*fixture.program.values);
RemoveIdentities(fixture.program.values->blocks);
EliminateDeadCode(fixture.program.values->blocks);
ConstantPropagationPass(fixture.program.blocks);
ResolveControlFlowIdentities(fixture.program);
RemoveIdentities(fixture.program.blocks);
EliminateDeadCode(fixture.program.blocks);
std::string error;
Check(entry_info.condition == Value(true) &&
ValidateValueProgram(*fixture.program.values, true, &error),
ValidateProgram(fixture.program, true, &error),
error.empty() ? "folded branch condition did not survive identity removal"
: error.c_str());
}
@@ -447,7 +446,7 @@ void TestUndefinedRuntimeValueFails() {
Fixture fixture;
const auto undef = fixture.Emit(ValueOpcode::UndefU32);
fixture.Plan();
fixture.program.values->descriptor_sources.push_back(
fixture.program.descriptor_sources.push_back(
{.dwords = {undef}, .dword_count = 1});
DescriptorValue result;
result.dword_count = 3;
@@ -499,7 +498,7 @@ int main() {
#include "../src/graphics/shader/recompiler/ir/Block.cpp"
#include "../src/graphics/shader/recompiler/ir/Type.cpp"
#include "../src/graphics/shader/recompiler/ir/Value.cpp"
#include "../src/graphics/shader/recompiler/ir/ValueProgram.cpp"
#include "../src/graphics/shader/recompiler/ir/Program.cpp"
#include "../src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp"
#include "../src/graphics/shader/recompiler/ir/passes/ConstantPropagation.cpp"
#include "../src/graphics/shader/recompiler/ir/passes/DeadCodeElimination.cpp"
+88 -117
View File
@@ -38,7 +38,7 @@
#include "graphics/shader/recompiler/backend/spirv/SpirvBuilder.h"
#include "graphics/shader/recompiler/backend/spirv/SpirvEmitter.h"
#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h"
#include "graphics/shader/recompiler/ir/ValueProgram.h"
#include "graphics/shader/recompiler/ir/ShaderIR.h"
#include "graphics/shader/recompiler/ir/passes/BindingLayout.h"
#include "graphics/shader/rectListShader.h"
#include "graphics/shader/shader.h"
@@ -967,7 +967,6 @@ struct TestCase {
std::vector<u32> expected_gds;
std::vector<std::pair<std::string, size_t>> decoded_counts;
std::vector<std::pair<std::string, size_t>> ir_counts;
std::vector<std::pair<std::string, size_t>> native_ir_counts;
u32 expected_storage_mip_descriptors = 0;
};
@@ -1192,32 +1191,6 @@ CompiledShader CompileCase(const TestCase &test) {
text + " count=" + std::to_string(actual) +
", expected=" + std::to_string(expected));
}
if (!test.native_ir_counts.empty()) {
ShaderRecompiler::Decoder::Program decoded;
ShaderRecompiler::CFG::Graph cfg;
ShaderRecompiler::IR::Program native;
std::string native_error;
Require(test.name, "native decode",
ShaderRecompiler::Decoder::DecodeProgram(test.code, decoded,
&native_error),
native_error);
Require(test.name, "native CFG",
ShaderRecompiler::CFG::BuildGraph(decoded, cfg, &native_error) &&
ShaderRecompiler::CFG::Structurize(cfg, &native_error),
native_error);
Require(test.name, "native lowering",
ShaderRecompiler::IR::LowerProgram(decoded, cfg, options.stage,
options.wave_size, native,
&native_error),
native_error);
const auto native_ir = ShaderRecompiler::IR::ProgramToString(native);
for (const auto &[text, expected] : test.native_ir_counts) {
const auto actual = CountText(native_ir, text);
Require(test.name, "native IR", actual == expected,
text + " count=" + std::to_string(actual) +
", expected=" + std::to_string(expected));
}
}
if (test.expected_storage_mip_descriptors != 0) {
const auto image = std::ranges::find_if(
result.program.info.images, [](const auto &resource) {
@@ -1242,7 +1215,7 @@ CompiledShader CompileCase(const TestCase &test) {
"dynamic storage image did not receive one descriptor per mip");
}
if (test.expand_shader_data_storage) {
auto &block = *result.program.values->blocks.front();
auto &block = *result.program.blocks.front();
for (u32 reg = 0; reg < 33; reg++) {
auto &user_data = block.AppendNewInst(
ShaderRecompiler::IR::ValueOpcode::GetUserData,
@@ -7519,8 +7492,6 @@ public:
ShaderRecompiler::IR::Program null_program{};
null_program.stage = ShaderType::Compute;
null_program.values =
std::make_shared<ShaderRecompiler::IR::ValueProgram>();
null_program.resource_tracking_complete = true;
ShaderRecompiler::IR::ImageResource null_resource{};
null_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint;
@@ -7630,8 +7601,6 @@ public:
storage.fields[5] = 0x00700000u;
ShaderRecompiler::IR::Program storage_program{};
storage_program.stage = ShaderType::Vertex;
storage_program.values =
std::make_shared<ShaderRecompiler::IR::ValueProgram>();
storage_program.resource_tracking_complete = true;
ShaderRecompiler::IR::ImageResource storage_resource{};
storage_resource.kind =
@@ -7911,8 +7880,6 @@ public:
ShaderRecompiler::IR::Program sampled_program{};
sampled_program.stage = ShaderType::Pixel;
sampled_program.values =
std::make_shared<ShaderRecompiler::IR::ValueProgram>();
sampled_program.resource_tracking_complete = true;
ShaderRecompiler::IR::ImageResource sampled_resource{};
sampled_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint;
@@ -8003,15 +7970,19 @@ public:
RenderExecutorTestAccess::ResetBindings(executor);
auto vertex_sampled_program =
std::make_shared<ShaderRecompiler::IR::Program>(
*sampled_runtime.program);
std::make_shared<ShaderRecompiler::IR::Program>();
vertex_sampled_program->stage = ShaderType::Vertex;
vertex_sampled_program->resource_tracking_complete = true;
vertex_sampled_program->info.images.push_back(sampled_resource);
allocate_bindings(*vertex_sampled_program);
ShaderStageRuntime vertex_sampled_runtime{
std::move(vertex_sampled_program), sampled_runtime.resources};
auto pixel_storage_program =
std::make_shared<ShaderRecompiler::IR::Program>(
*storage_runtime.program);
std::make_shared<ShaderRecompiler::IR::Program>();
pixel_storage_program->stage = ShaderType::Pixel;
pixel_storage_program->resource_tracking_complete = true;
pixel_storage_program->info.images.push_back(storage_resource);
allocate_bindings(*pixel_storage_program);
ShaderStageRuntime pixel_storage_runtime{std::move(pixel_storage_program),
storage_runtime.resources};
auto writable_alias_bindings =
@@ -8083,8 +8054,6 @@ public:
auto split_program = std::make_shared<ShaderRecompiler::IR::Program>();
split_program->stage = ShaderType::Vertex;
split_program->values =
std::make_shared<ShaderRecompiler::IR::ValueProgram>();
split_program->resource_tracking_complete = true;
split_program->info.images = {storage_resource, sampled_resource};
allocate_bindings(*split_program);
@@ -8459,8 +8428,6 @@ public:
ShaderRecompiler::IR::Program array_program{};
array_program.stage = ShaderType::Compute;
array_program.values =
std::make_shared<ShaderRecompiler::IR::ValueProgram>();
array_program.resource_tracking_complete = true;
ShaderRecompiler::IR::ImageResource array_resource{};
array_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint;
@@ -8544,10 +8511,13 @@ public:
colliding_msaa_descriptor.dwords.begin());
colliding_msaa_descriptor.dword_count = 8;
auto colliding_msaa_program =
std::make_shared<ShaderRecompiler::IR::Program>(
*array_runtime.program);
colliding_msaa_program->info.images[0].dimension =
std::make_shared<ShaderRecompiler::IR::Program>();
colliding_msaa_program->stage = ShaderType::Compute;
colliding_msaa_program->resource_tracking_complete = true;
auto colliding_msaa_resource = array_resource;
colliding_msaa_resource.dimension =
ShaderRecompiler::Decoder::ImageDimension::Dim2DMsaa;
colliding_msaa_program->info.images.push_back(colliding_msaa_resource);
auto colliding_msaa_snapshot =
std::make_shared<ShaderRecompiler::IR::ResourceSnapshot>();
colliding_msaa_snapshot->images.push_back(colliding_msaa_descriptor);
@@ -8604,10 +8574,13 @@ public:
std::copy(std::begin(msaa_texture.fields), std::end(msaa_texture.fields),
msaa_descriptor.dwords.begin());
msaa_descriptor.dword_count = 8;
auto msaa_program = std::make_shared<ShaderRecompiler::IR::Program>(
*array_runtime.program);
msaa_program->info.images[0].dimension =
auto msaa_program = std::make_shared<ShaderRecompiler::IR::Program>();
msaa_program->stage = ShaderType::Compute;
msaa_program->resource_tracking_complete = true;
auto msaa_resource = array_resource;
msaa_resource.dimension =
ShaderRecompiler::Decoder::ImageDimension::Dim2DMsaa;
msaa_program->info.images.push_back(msaa_resource);
auto msaa_snapshot =
std::make_shared<ShaderRecompiler::IR::ResourceSnapshot>();
msaa_snapshot->images.push_back(msaa_descriptor);
@@ -8643,10 +8616,14 @@ public:
std::end(msaa_array_texture.fields),
msaa_array_descriptor.dwords.begin());
msaa_array_descriptor.dword_count = 8;
auto msaa_array_program = std::make_shared<ShaderRecompiler::IR::Program>(
*msaa_runtime.program);
msaa_array_program->info.images[0].dimension =
auto msaa_array_program =
std::make_shared<ShaderRecompiler::IR::Program>();
msaa_array_program->stage = ShaderType::Compute;
msaa_array_program->resource_tracking_complete = true;
auto msaa_array_resource = array_resource;
msaa_array_resource.dimension =
ShaderRecompiler::Decoder::ImageDimension::Dim2DMsaaArray;
msaa_array_program->info.images.push_back(msaa_array_resource);
auto msaa_array_snapshot =
std::make_shared<ShaderRecompiler::IR::ResourceSnapshot>();
msaa_array_snapshot->images.push_back(msaa_array_descriptor);
@@ -8868,7 +8845,6 @@ public:
ShaderRecompiler::IR::Program program{};
program.stage = ShaderType::Compute;
program.values = std::make_shared<ShaderRecompiler::IR::ValueProgram>();
program.resource_tracking_complete = true;
ShaderRecompiler::IR::ImageResource stencil_resource{};
stencil_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint;
@@ -8940,11 +8916,15 @@ public:
RenderExecutorTestAccess::ResetBindings(executor);
auto stencil_storage_program =
std::make_shared<ShaderRecompiler::IR::Program>(*runtime.program);
stencil_storage_program->info.images[0].kind =
std::make_shared<ShaderRecompiler::IR::Program>();
stencil_storage_program->stage = ShaderType::Compute;
stencil_storage_program->resource_tracking_complete = true;
auto stencil_storage_resource = stencil_resource;
stencil_storage_resource.kind =
ShaderRecompiler::IR::ResourceKind::StorageImageUint;
stencil_storage_program->info.images[0].read = false;
stencil_storage_program->info.images[0].written = true;
stencil_storage_resource.read = false;
stencil_storage_resource.written = true;
stencil_storage_program->info.images.push_back(stencil_storage_resource);
auto storage_stencil = stencil;
storage_stencil.fields[5] = 0x00700000u;
ShaderRecompiler::IR::DescriptorValue stencil_storage_descriptor{};
@@ -12132,7 +12112,6 @@ TestCase ScalarWaitcntDepctrCapturedVmVsrc() {
test.opcodes = {O::V_MOV_B32, O::BUFFER_STORE_DWORD, O::S_WAITCNT_DEPCTR,
O::S_ENDPGM};
test.decoded_counts = {{"0x00000010: S_WAITCNT_DEPCTR 0x0000ffe3\n", 1}};
test.native_ir_counts = {{"0x00000010: Waitcnt null, 0x0000ffe3", 1}};
test.forbidden_spirv = {"OpControlBarrier", "OpMemoryBarrier"};
return test;
}
@@ -13289,7 +13268,6 @@ TestCase Vop3Med3I16Captured() {
test.decoded_counts = {{"0x00000020: V_MED3_I16 v3.sdwa(sel=5,sext=0), "
"v5.opsel(lo=1,hi=0,neghi=0), s25, s27\n",
1}};
test.native_ir_counts = {{"IMed3I16", 1}};
test.required_spirv = {"OpSLessThan"};
return test;
}
@@ -15227,8 +15205,6 @@ TestCase VectorVopcCmpxNeU64CapturedExecMask() {
O::S_MOV_B32, O::S_ENDPGM}};
test.decoded_counts = {{"V_CMPX_NE_U64 exec_lo, 0, v7", 2},
{"V_CMPX_NE_U64 exec_lo, 0, v2", 2}};
test.native_ir_counts = {{"CompareNeU64 exec_lo, 0x00000000, v7", 2},
{"CompareNeU64 exec_lo, 0x00000000, v2", 2}};
return test;
}
@@ -15258,7 +15234,6 @@ TestCase VectorVop3CmpxNeI64CapturedExecMask() {
{O::V_MOV_B32, O::V_CMPX_NE_I64, O::BUFFER_STORE_DWORD,
O::S_MOV_B32, O::S_ENDPGM}};
test.decoded_counts = {{"V_CMPX_NE_I64 exec_lo, 0, v7", 2}};
test.native_ir_counts = {{"CompareNeU64 exec_lo, 0x00000000, v7", 2}};
return test;
}
@@ -17738,7 +17713,6 @@ TestCase DsReadU16D16CapturedPreservesHighHalf() {
{O::V_MOV_B32, O::DS_WRITE_B32, O::DS_READ_U16_D16,
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
test.decoded_counts = {{"DS_READ_U16_D16", 2}};
test.native_ir_counts = {{"DsReadUshort", 2}};
return test;
}
@@ -18652,7 +18626,6 @@ TestCase ImageLoadR128IgnoresAdjacentMaskSgprs() {
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32UInt);
test.has_user_data = true;
test.decoded_counts = {{"r128=1", 1}};
test.native_ir_counts = {{"image_r128=1", 1}};
return test;
}
@@ -18974,8 +18947,6 @@ TestCase ImageD16GatherPacksHalfPairs() {
O::S_ENDPGM};
test.sampled_image_rgba = image;
test.decoded_counts = {{"d16=1", 1}};
test.native_ir_counts = {
{"dmask=0x1 data_dwords=2 data_bits=16 component=0/4", 1}};
test.required_spirv = {"OpImageGather", "PackHalf2x16"};
return test;
}
@@ -19196,8 +19167,6 @@ TestCase ImageD16StoreUnpacksHalfPairs() {
test.storage_image_rgba = MakeRgbaImage(4, 4);
test.expected_storage_image_rgba = expected_image;
test.decoded_counts = {{"d16=1", 1}};
test.native_ir_counts = {
{"dmask=0xf data_dwords=2 data_bits=16 component=0/4", 1}};
test.required_spirv = {"UnpackHalf2x16", "OpImageWrite"};
return test;
}
@@ -19213,11 +19182,10 @@ void CheckIndirectImageKeySwitch() {
program.srt_plan_complete = true;
program.resource_tracking_complete = true;
program.shader_info_complete = true;
program.values = std::make_shared<ValueProgram>();
program.values->block_storage.push_back(std::make_unique<Block>());
auto *block = program.values->block_storage.back().get();
program.values->blocks.push_back(block);
program.values->block_info.push_back({.id = 0});
program.block_storage.push_back(std::make_unique<Block>());
auto *block = program.block_storage.back().get();
program.blocks.push_back(block);
program.block_info.push_back({.id = 0});
auto &key = block->AppendNewInst(ValueOpcode::LaneId);
auto &image =
@@ -19242,7 +19210,7 @@ void CheckIndirectImageKeySwitch() {
memory.image_sample_flags = ShaderRecompiler::Decoder::ImageSampleFlagLod;
memory.image_dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
memory.image_address_components = 3;
program.values->memory_info.push_back(memory);
program.memory_info.push_back(memory);
const MemoryFlags memory_flags{0u, 0x10f0u};
uint64_t memory_flag_bits = 0;
std::memcpy(&memory_flag_bits, &memory_flags, sizeof(memory_flags));
@@ -19253,11 +19221,11 @@ void CheckIndirectImageKeySwitch() {
{Value(&sample), Value(0u)});
block->AppendNewInst(ValueOpcode::ReferenceU32, {Value(&sample_x)});
program.values->descriptor_sources.resize(2);
program.values->descriptor_sources[0].dword_count = 8;
program.values->descriptor_sources[0].indirect_image =
program.descriptor_sources.resize(2);
program.descriptor_sources[0].dword_count = 8;
program.descriptor_sources[0].indirect_image =
DescriptorSource::IndirectImage{0u, 0u, 224u, 12u, 0u};
program.values->descriptor_sources[1].dword_count = 4;
program.descriptor_sources[1].dword_count = 4;
ImageResource root{};
root.source = 0;
@@ -20394,8 +20362,8 @@ void CheckPs5GameExampleImageClearRuntimeShape() {
const auto code = MakeCode();
auto positive = Compile("exact Prospero kernel", code);
compute.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(positive.program);
compute.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
std::move(positive.program));
compute.stage.resources =
std::make_shared<const ShaderRecompiler::IR::ResourceSnapshot>(
positive.resources);
@@ -20488,7 +20456,8 @@ void CheckEmbeddedFetchVertexOffset() {
Require(name, "compile",
ShaderRecompiler::TryRecompile(code, options, result, &error),
error);
Require(name, "fetch rewrite", vertex.resource_fetch_components[0] == 4,
Require(name, "fetch rewrite",
result.program.info.vertex_fetch_components[0] == 4,
"encoded fetch sequence was not recognized and rewritten");
return result;
};
@@ -20497,8 +20466,11 @@ void CheckEmbeddedFetchVertexOffset() {
u32 index_offset) {
ShaderVertexInputInfo vertex;
vertex.fetch_embedded = true;
vertex.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(result.program);
auto program = std::make_shared<ShaderRecompiler::IR::Program>();
program->user_data_base = result.program.user_data_base;
program->info.vertex_offset_sgpr =
result.program.info.vertex_offset_sgpr;
vertex.stage.program = std::move(program);
vertex.stage.resources =
std::make_shared<const ShaderRecompiler::IR::ResourceSnapshot>(
result.resources);
@@ -22366,52 +22338,55 @@ void CheckImageSpecializationId() {
HW::ComputeShaderInfo regs{};
regs.cs_regs.data_addr = reinterpret_cast<uint64_t>(code.data());
ShaderRecompiler::IR::Program identity_program;
identity_program.binding_layout_complete = true;
ShaderRecompiler::IR::ImageResource image;
image.kind = ShaderRecompiler::IR::ResourceKind::StorageImage;
image.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
identity_program.info.images.push_back(image);
auto rgb1_program = identity_program;
rgb1_program.info.images[0].shader_swizzle = DstSel(4, 5, 6, 1);
auto converted_program = identity_program;
converted_program.info.images[0].conversion_format =
const auto make_program = [](ShaderRecompiler::IR::ImageResource resource) {
ShaderRecompiler::IR::Program program;
program.binding_layout_complete = true;
program.info.images.push_back(std::move(resource));
return program;
};
auto rgb1_image = image;
rgb1_image.shader_swizzle = DstSel(4, 5, 6, 1);
auto converted_image = image;
converted_image.conversion_format =
Prospero::BufferFormat::k11_11_10UInt;
auto mip1_program = identity_program;
mip1_program.info.images[0].mip_mode =
ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
auto mip3_program = mip1_program;
mip3_program.info.images[0].mip_count = 3;
auto array_program = identity_program;
array_program.info.images[0].dimension =
auto mip1_image = image;
mip1_image.mip_mode = ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
auto mip3_image = mip1_image;
mip3_image.mip_count = 3;
auto array_image = image;
array_image.dimension =
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
auto cube_program = array_program;
cube_program.info.images[0].cube = true;
auto cube_image = array_image;
cube_image.cube = true;
const auto resources =
std::make_shared<const ShaderRecompiler::IR::ResourceSnapshot>();
ShaderComputeInputInfo identity_info;
identity_info.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(identity_program);
identity_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(image));
identity_info.stage.resources = resources;
auto rgb1_info = identity_info;
rgb1_info.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(rgb1_program);
rgb1_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(rgb1_image));
auto converted_info = identity_info;
converted_info.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(converted_program);
std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(converted_image));
auto mip1_info = identity_info;
mip1_info.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(mip1_program);
mip1_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(mip1_image));
auto mip3_info = identity_info;
mip3_info.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(mip3_program);
mip3_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(mip3_image));
auto array_info = identity_info;
array_info.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(array_program);
array_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(array_image));
auto cube_info = identity_info;
cube_info.stage.program =
std::make_shared<const ShaderRecompiler::IR::Program>(cube_program);
cube_info.stage.program = std::make_shared<const ShaderRecompiler::IR::Program>(
make_program(cube_image));
const auto identity_id = ShaderGetIdCS(regs, identity_info, true);
const auto rgb1_id = ShaderGetIdCS(regs, rgb1_info, true);
@@ -22452,8 +22427,6 @@ void CheckImageSpecializationId() {
"forcing point filtering enabled mipmapping on a base-mip sampler");
ShaderRecompiler::IR::Program mixed_sampler_program;
mixed_sampler_program.values =
std::make_shared<ShaderRecompiler::IR::ValueProgram>();
mixed_sampler_program.resource_tracking_complete = true;
ShaderRecompiler::IR::ImageResource sampled_image;
sampled_image.kind = ShaderRecompiler::IR::ResourceKind::Image;
@@ -22500,8 +22473,6 @@ void CheckImageSpecializationId() {
"native variants");
ShaderRecompiler::IR::Program packed_atomic_program;
packed_atomic_program.values =
std::make_shared<ShaderRecompiler::IR::ValueProgram>();
packed_atomic_program.resource_tracking_complete = true;
auto packed_atomic_image = sampled_image;
packed_atomic_image.kind =
@@ -23245,7 +23216,7 @@ void CheckEmbeddedFetchLaneSpill() {
Require("EmbeddedFetchLaneSpill", "compile",
ShaderRecompiler::TryRecompile(code, options, result, &error), error);
Require("EmbeddedFetchLaneSpill", "fetch rewrite",
vertex.resource_fetch_components[0] == 4,
result.program.info.vertex_fetch_components[0] == 4,
"lane-spilled fetch descriptor was not recognized and rewritten");
std::printf("[host] %-32s ok\n", "EmbeddedFetchLaneSpill");
}
+8 -9
View File
@@ -1,4 +1,4 @@
#include "graphics/shader/recompiler/ir/ValueProgram.h"
#include "graphics/shader/recompiler/ir/ShaderIR.h"
#include "graphics/shader/recompiler/ir/passes/ResourceMaterialization.h"
#include "graphics/shader/shader.h"
@@ -23,12 +23,11 @@ bool RejectSpecializationRead(void *userdata, uint64_t, uint32_t *) {
Libs::Graphics::ShaderRecompiler::IR::Block &
AddValueBlock(Libs::Graphics::ShaderRecompiler::IR::Program &program) {
using namespace Libs::Graphics::ShaderRecompiler::IR;
program.values = std::make_shared<ValueProgram>();
auto block = std::make_unique<Block>();
auto *result = block.get();
program.values->blocks.push_back(result);
program.values->block_info.push_back({.id = 0});
program.values->block_storage.push_back(std::move(block));
program.blocks.push_back(result);
program.block_info.push_back({.id = 0});
program.block_storage.push_back(std::move(block));
return *result;
}
@@ -44,7 +43,7 @@ SrtProgram(uint64_t address) {
MemoryInfo memory;
memory.kind = ResourceKind::ScalarAddress;
memory.planning_only = true;
program.values->memory_info.push_back(memory);
program.memory_info.push_back(memory);
const auto low = Value(static_cast<uint32_t>(address));
const auto high = Value(static_cast<uint32_t>(address >> 32u));
auto &handle =
@@ -53,7 +52,7 @@ SrtProgram(uint64_t address) {
ValueOpcode::LoadAddressU32,
{Value(&handle), Value(0u), Value(0u), Value(true)});
raw.SetFlags(MemoryFlags{.index = 0, .pc = 0x40});
program.values->srt_reads.push_back({Value(&raw), 0, 0x40});
program.srt_reads.push_back({Value(&raw), 0, 0x40});
auto &srt = value_block.AppendNewInst(ValueOpcode::GetSrtResource);
auto &flat = value_block.AppendNewInst(ValueOpcode::ReadConst,
@@ -62,7 +61,7 @@ SrtProgram(uint64_t address) {
source.dwords[0] = Value(&flat);
source.dwords[1] = Value(0u);
source.dword_count = 2;
program.values->descriptor_sources.push_back(source);
program.descriptor_sources.push_back(source);
return std::make_shared<const Program>(std::move(program));
}
@@ -141,5 +140,5 @@ int main() {
#include "graphics/shader/recompiler/ir/Block.cpp"
#include "graphics/shader/recompiler/ir/Type.cpp"
#include "graphics/shader/recompiler/ir/Value.cpp"
#include "graphics/shader/recompiler/ir/ValueProgram.cpp"
#include "graphics/shader/recompiler/ir/Program.cpp"
#include "graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp"
+467 -388
View File
File diff suppressed because it is too large Load Diff