mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-24 21:06:55 +02:00
shader: remove second IR layer
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#include "graphics/shader/recompiler/ir/passes/BindingLayout.h"
|
||||
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@@ -16,7 +16,7 @@ constexpr uint32_t ImageBindingCount =
|
||||
|
||||
bool CollectUserData(const Program& program, std::vector<uint32_t>& result) {
|
||||
std::array<bool, NumScalarRegs> registers {};
|
||||
for (const auto* block: program.values->blocks) {
|
||||
for (const auto* block: program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
if (inst.GetOpcode() != ValueOpcode::GetUserData || !inst.HasUses()) {
|
||||
continue;
|
||||
@@ -47,16 +47,16 @@ void AddBinding(BindingLayout& layout, DescriptorBindingKind kind,
|
||||
|
||||
bool UsesGds(const Program& program, bool& uses_gds) {
|
||||
uses_gds = false;
|
||||
for (const auto* block: program.values->blocks) {
|
||||
for (const auto* block: program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
if (SharedAccessOf(inst.GetOpcode()) == SharedAccess::None) {
|
||||
continue;
|
||||
}
|
||||
const auto index = inst.Flags<MemoryFlags>().index;
|
||||
if (index >= program.values->memory_info.size()) {
|
||||
if (index >= program.memory_info.size()) {
|
||||
return false;
|
||||
}
|
||||
const auto kind = program.values->memory_info[index].kind;
|
||||
const auto kind = program.memory_info[index].kind;
|
||||
if (kind != ResourceKind::Lds && kind != ResourceKind::Gds) {
|
||||
return false;
|
||||
}
|
||||
@@ -76,12 +76,6 @@ bool AllocateBindings(Program& program, uint32_t push_constant_offset, std::stri
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (program.values == nullptr) {
|
||||
if (error != nullptr) {
|
||||
*error = "typed value program is not available";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (push_constant_offset > NativePushConstantSize ||
|
||||
push_constant_offset % sizeof(uint32_t) != 0) {
|
||||
if (error != nullptr) {
|
||||
@@ -171,7 +165,7 @@ bool AllocateBindings(Program& program, uint32_t push_constant_offset, std::stri
|
||||
AddBinding(next, DescriptorBindingKind::AddressMemory, std::move(resources));
|
||||
}
|
||||
const bool uses_flattened_runtime =
|
||||
!program.values->srt_reads.empty() ||
|
||||
!program.srt_reads.empty() ||
|
||||
std::ranges::any_of(program.info.images, [](const ImageResource& image) {
|
||||
return image.indirect_mapping_capacity != 0u;
|
||||
});
|
||||
|
||||
@@ -101,7 +101,7 @@ Value GetRealValue(PhiMap& phi_map, Value source, uint32_t lane, uint32_t wave_s
|
||||
|
||||
} // namespace
|
||||
|
||||
ReadLaneStats EliminateReadLane(ValueProgram& program, uint32_t wave_size) {
|
||||
ReadLaneStats EliminateReadLane(Program& program, uint32_t wave_size) {
|
||||
ReadLaneStats stats;
|
||||
if (wave_size != 32u && wave_size != 64u) {
|
||||
return stats;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::IR {
|
||||
|
||||
@@ -8,6 +8,6 @@ struct ReadLaneStats {
|
||||
uint32_t rewritten_reads = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] ReadLaneStats EliminateReadLane(ValueProgram& program, uint32_t wave_size);
|
||||
[[nodiscard]] ReadLaneStats EliminateReadLane(Program& program, uint32_t wave_size);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::IR
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "graphics/shader/recompiler/ir/passes/ResourceMaterialization.h"
|
||||
|
||||
#include "graphics/guest_gpu/gpu_format.h"
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
#include "graphics/shader/shaderBindings.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -105,10 +105,10 @@ bool DecodeBufferDescriptor(const DescriptorValue& descriptor, ShaderBufferResou
|
||||
}
|
||||
|
||||
const DescriptorSource* Source(const Program& program, uint32_t source) {
|
||||
if (program.values == nullptr || source >= program.values->descriptor_sources.size()) {
|
||||
if (source >= program.descriptor_sources.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &program.values->descriptor_sources[source];
|
||||
return &program.descriptor_sources[source];
|
||||
}
|
||||
|
||||
void MarkCleanFlatSlots(const Program& program, const DescriptorSource* source,
|
||||
@@ -131,7 +131,7 @@ void MarkCleanFlatSlots(const Program& program, const DescriptorSource* source,
|
||||
const auto slot = inst->Arg(1).Resolve();
|
||||
if (slot.IsImmediate() && slot.GetType() == Type::U32 && slot.U32() < slots.size()) {
|
||||
slots[slot.U32()] = 1u;
|
||||
pending.push_back(program.values->srt_reads[slot.U32()].value);
|
||||
pending.push_back(program.srt_reads[slot.U32()].value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -275,7 +275,7 @@ uint64_t AddressSpecialization(const AddressResource& resource,
|
||||
}
|
||||
|
||||
size_t FlattenedRuntimeDwords(const Program& program) {
|
||||
size_t size = program.values != nullptr ? program.values->srt_reads.size() : 0u;
|
||||
size_t size = program.srt_reads.size();
|
||||
for (uint32_t resource = 0; resource < program.info.images.size(); resource++) {
|
||||
const auto& image = program.info.images[resource];
|
||||
if (image.indirect_root == resource) {
|
||||
@@ -305,8 +305,7 @@ bool ValidateResourceSnapshot(const Program& program, const ResourceSnapshot& sn
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (program.values == nullptr ||
|
||||
snapshot.flattened_srt.size() != FlattenedRuntimeDwords(program)) {
|
||||
if (snapshot.flattened_srt.size() != FlattenedRuntimeDwords(program)) {
|
||||
if (error != nullptr) {
|
||||
*error = "flattened SRT snapshot does not match the shader plan";
|
||||
}
|
||||
@@ -549,7 +548,7 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
|
||||
}
|
||||
|
||||
std::vector<DescriptorSourceRequest> requests;
|
||||
std::vector<uint8_t> clean_flat_slots(program.values->srt_reads.size());
|
||||
std::vector<uint8_t> clean_flat_slots(program.srt_reads.size());
|
||||
requests.reserve(program.info.buffers.size() + program.info.images.size() * 2u +
|
||||
program.info.samplers.size() + program.info.addresses.size());
|
||||
for (const auto& buffer: program.info.buffers) {
|
||||
@@ -925,13 +924,7 @@ bool SpecializeResources(Program& program, ResourceSnapshot& snapshot, std::stri
|
||||
}
|
||||
}
|
||||
}
|
||||
if (program.values == nullptr) {
|
||||
if (error != nullptr) {
|
||||
*error = "typed SSA is not ready";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
auto memory_info = program.values->memory_info;
|
||||
auto memory_info = program.memory_info;
|
||||
|
||||
struct SamplerUsage {
|
||||
bool native = false;
|
||||
@@ -980,7 +973,7 @@ bool SpecializeResources(Program& program, ResourceSnapshot& snapshot, std::stri
|
||||
pair.sampler = point_sampler[pair.sampler];
|
||||
}
|
||||
}
|
||||
for (const auto* block: program.values->blocks) {
|
||||
for (const auto* block: program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
const auto image_opcode = ImageOpcodeInfoOf(inst.GetOpcode());
|
||||
if (image_opcode.access == ImageAccess::None) {
|
||||
@@ -1023,7 +1016,7 @@ bool SpecializeResources(Program& program, ResourceSnapshot& snapshot, std::stri
|
||||
}
|
||||
}
|
||||
program.info = std::move(next);
|
||||
program.values->memory_info = std::move(memory_info);
|
||||
program.memory_info = std::move(memory_info);
|
||||
snapshot = std::move(next_snapshot);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "graphics/shader/recompiler/ir/passes/ResourceTracking.h"
|
||||
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
#include "graphics/shader/recompiler/ir/passes/SrtWalker.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
|
||||
@@ -94,8 +94,7 @@ ImageMipMode MipMode(const MemoryInfo& memory) {
|
||||
|
||||
class Tracker {
|
||||
public:
|
||||
Tracker(Program& program, ValueProgram& values)
|
||||
: m_program(program), m_values(values), m_info(program.info) {
|
||||
explicit Tracker(Program& program): m_program(program), m_info(program.info) {
|
||||
m_info.buffers.clear();
|
||||
m_info.addresses.clear();
|
||||
m_info.images.clear();
|
||||
@@ -111,7 +110,7 @@ public:
|
||||
return Fail(0, error, "SRT plan is not ready");
|
||||
}
|
||||
PlanIndirectImages();
|
||||
for (auto* block: m_values.blocks) {
|
||||
for (auto* block: m_program.blocks) {
|
||||
for (auto& inst: *block) {
|
||||
if (!Collect(inst, error)) {
|
||||
return false;
|
||||
@@ -123,7 +122,7 @@ public:
|
||||
patch.handle->SetFlags<uint32_t>(patch.resource);
|
||||
}
|
||||
for (const auto& patch: m_memory_patches) {
|
||||
auto& memory = m_values.memory_info[patch.index];
|
||||
auto& memory = m_program.memory_info[patch.index];
|
||||
memory.resource = patch.resource;
|
||||
if (patch.has_sampler) {
|
||||
memory.sampler = patch.sampler;
|
||||
@@ -138,16 +137,16 @@ public:
|
||||
plan.handle->SetArg(dword, plan.key);
|
||||
}
|
||||
for (const auto index: plan.memory) {
|
||||
m_values.memory_info[index].planning_only = true;
|
||||
m_program.memory_info[index].planning_only = true;
|
||||
}
|
||||
}
|
||||
std::erase_if(m_values.dynamic_reads, [&](Value value) {
|
||||
std::erase_if(m_program.dynamic_reads, [&](Value value) {
|
||||
const auto* inst = value.Resolve().TryInstruction();
|
||||
return std::ranges::any_of(m_indirect_images, [&](const IndirectImagePlan& plan) {
|
||||
return std::ranges::find(plan.reads, inst) != plan.reads.end();
|
||||
});
|
||||
});
|
||||
m_values.descriptor_sources = std::move(m_sources);
|
||||
m_program.descriptor_sources = std::move(m_sources);
|
||||
m_program.info = std::move(m_info);
|
||||
m_program.resource_tracking_complete = true;
|
||||
return true;
|
||||
@@ -208,19 +207,19 @@ private:
|
||||
if (left.value.IsEmpty() || right.value.IsEmpty()) {
|
||||
return require_both ? AddressPart {} : (left.value.IsEmpty() ? right : left);
|
||||
}
|
||||
return EquivalentValue(m_values, left.value, right.value)
|
||||
return EquivalentValue(m_program, left.value, right.value)
|
||||
? AddressPart {left.value, left.rooted || right.rooted}
|
||||
: AddressPart {};
|
||||
};
|
||||
switch (inst->GetOpcode()) {
|
||||
case ValueOpcode::SelectU32:
|
||||
if (EquivalentValue(m_values, inst->Arg(0), active)) {
|
||||
if (EquivalentValue(m_program, inst->Arg(0), active)) {
|
||||
return finish(FindAddressPart(inst->Arg(1), active, visiting));
|
||||
}
|
||||
return finish(merge(FindAddressPart(inst->Arg(1), active, visiting),
|
||||
FindAddressPart(inst->Arg(2), active, visiting), true));
|
||||
case ValueOpcode::Phi: {
|
||||
const auto invariant = ResolveInvariantPhi(m_values, value);
|
||||
const auto invariant = ResolveInvariantPhi(m_program, value);
|
||||
return finish(invariant.IsEmpty() ? AddressPart {}
|
||||
: FindAddressPart(invariant, active, visiting));
|
||||
}
|
||||
@@ -312,7 +311,7 @@ private:
|
||||
}
|
||||
bool same = true;
|
||||
for (uint32_t i = 0; i < descriptor.dword_count; i++) {
|
||||
same = same && EquivalentValue(m_values, current.dwords[i], descriptor.dwords[i]);
|
||||
same = same && EquivalentValue(m_program, current.dwords[i], descriptor.dwords[i]);
|
||||
}
|
||||
if (same) {
|
||||
return candidate;
|
||||
@@ -342,10 +341,10 @@ private:
|
||||
return nullptr;
|
||||
}
|
||||
index = read.Flags<MemoryFlags>().index;
|
||||
if (index >= m_values.memory_info.size()) {
|
||||
if (index >= m_program.memory_info.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto& memory = m_values.memory_info[index];
|
||||
const auto& memory = m_program.memory_info[index];
|
||||
return memory.kind == ResourceKind::ScalarBuffer && memory.data_bits == 32u &&
|
||||
memory.data_dwords == 1u
|
||||
? &memory
|
||||
@@ -353,7 +352,7 @@ private:
|
||||
}
|
||||
|
||||
bool MemoryIndexBelongsTo(uint32_t index, const Inst& owner) const {
|
||||
for (const auto* block: m_values.blocks) {
|
||||
for (const auto* block: m_program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
const auto op = inst.GetOpcode();
|
||||
if ((BufferAccessOf(op) == BufferAccess::None &&
|
||||
@@ -446,7 +445,7 @@ private:
|
||||
heap_handle = current_handle;
|
||||
if (dword == 0u) {
|
||||
heap_offset = heap_reads[dword]->Arg(1).Resolve();
|
||||
} else if (!EquivalentValue(m_values, heap_offset, heap_reads[dword]->Arg(1))) {
|
||||
} else if (!EquivalentValue(m_program, heap_offset, heap_reads[dword]->Arg(1))) {
|
||||
return false;
|
||||
}
|
||||
plan.memory[dword] = memory_index;
|
||||
@@ -537,7 +536,7 @@ private:
|
||||
}
|
||||
|
||||
void PlanIndirectImages() {
|
||||
for (auto* block: m_values.blocks) {
|
||||
for (auto* block: m_program.blocks) {
|
||||
for (auto& inst: *block) {
|
||||
if (ImageOpcodeInfoOf(inst.GetOpcode()).access == ImageAccess::None ||
|
||||
inst.NumArgs() == 0u) {
|
||||
@@ -588,7 +587,7 @@ private:
|
||||
return Fail(pc, error, "GetAddressResource must have two address dwords");
|
||||
}
|
||||
DescriptorSource descriptor;
|
||||
const auto& memory = m_values.memory_info[memory_inst.Flags<MemoryFlags>().index];
|
||||
const auto& memory = m_program.memory_info[memory_inst.Flags<MemoryFlags>().index];
|
||||
if (memory.address_is_full) {
|
||||
const auto active = memory_inst.Arg(memory_inst.NumArgs() - 1u);
|
||||
if (memory.kind != ResourceKind::Flat ||
|
||||
@@ -797,14 +796,14 @@ private:
|
||||
return true;
|
||||
}
|
||||
const auto flags = inst.Flags<MemoryFlags>();
|
||||
if (flags.index >= m_values.memory_info.size()) {
|
||||
if (flags.index >= m_program.memory_info.size()) {
|
||||
return Fail(flags.pc, error,
|
||||
fmt::format("memory metadata index {} is out of range", flags.index));
|
||||
}
|
||||
if (inst.NumArgs() == 0) {
|
||||
return Fail(flags.pc, error, "memory operation has no resource handle");
|
||||
}
|
||||
const auto& memory = m_values.memory_info[flags.index];
|
||||
const auto& memory = m_program.memory_info[flags.index];
|
||||
if (memory.planning_only || IsIndirectPlanningMemory(flags.index)) {
|
||||
return true;
|
||||
}
|
||||
@@ -914,7 +913,7 @@ private:
|
||||
}
|
||||
bool alias = true;
|
||||
for (uint32_t dword = 0; dword < 4; dword++) {
|
||||
alias = alias && EquivalentValue(m_values, buffer_source->dwords[dword],
|
||||
alias = alias && EquivalentValue(m_program, buffer_source->dwords[dword],
|
||||
image_source->dwords[dword]);
|
||||
}
|
||||
if (alias) {
|
||||
@@ -926,7 +925,6 @@ private:
|
||||
}
|
||||
|
||||
Program& m_program;
|
||||
ValueProgram& m_values;
|
||||
ShaderInfo m_info;
|
||||
std::vector<DescriptorSource> m_sources;
|
||||
std::vector<HandlePatch> m_handle_patches;
|
||||
@@ -937,13 +935,7 @@ private:
|
||||
} // namespace
|
||||
|
||||
bool TrackResources(Program& program, std::string* error) {
|
||||
if (program.values == nullptr) {
|
||||
if (error != nullptr) {
|
||||
*error = "shader resource tracking requires typed IR";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return Tracker(program, *program.values).Run(error);
|
||||
return Tracker(program).Run(error);
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::IR
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "graphics/shader/recompiler/ir/passes/ShaderInfoCollection.h"
|
||||
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fmt/format.h>
|
||||
@@ -66,7 +66,7 @@ bool ValidateValueReferences(const Program& program, const ShaderInfoOptions& op
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (const auto* block: program.values->blocks) {
|
||||
for (const auto* block: program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case ValueOpcode::GetAttribute: {
|
||||
@@ -140,7 +140,7 @@ bool ValidateValueReferences(const Program& program, const ShaderInfoOptions& op
|
||||
break;
|
||||
}
|
||||
case ValueOpcode::SetAttribute:
|
||||
if (inst.Flags<ExportFlags>().index >= program.values->export_info.size()) {
|
||||
if (inst.Flags<ExportFlags>().index >= program.export_info.size()) {
|
||||
return Fail("typed export metadata index is out of range");
|
||||
}
|
||||
break;
|
||||
@@ -156,7 +156,7 @@ void CollectVertexInputs(const Program& program, const ShaderVertexInputInfo* ve
|
||||
AddInput(info, StageInputKind::VertexIndex, 0, 1, "gl_VertexIndex");
|
||||
AddInput(info, StageInputKind::InstanceIndex, 0, 1, "gl_InstanceIndex");
|
||||
uint32_t used_components[ShaderVertexInputInfo::RES_MAX] = {};
|
||||
for (const auto* block: program.values->blocks) {
|
||||
for (const auto* block: program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
if (inst.GetOpcode() == ValueOpcode::GetAttribute) {
|
||||
const auto attr = inst.Arg(0).U32();
|
||||
@@ -185,7 +185,7 @@ void CollectPixelInputs(const Program& program, const ShaderPixelInputInfo* pixe
|
||||
}
|
||||
std::array<bool, 32> per_vertex {};
|
||||
std::array<bool, 32> interpolated {};
|
||||
for (const auto* block: program.values->blocks) {
|
||||
for (const auto* block: program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
if (inst.GetOpcode() == ValueOpcode::GetAttribute) {
|
||||
interpolated[inst.Arg(0).U32()] = true;
|
||||
@@ -228,7 +228,7 @@ void CollectComputeInputs(const ShaderComputeInputInfo* compute, ShaderInfo& inf
|
||||
}
|
||||
|
||||
void CollectBuiltinInputs(const Program& program, ShaderInfo& info) {
|
||||
for (const auto* block: program.values->blocks) {
|
||||
for (const auto* block: program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
if (inst.GetOpcode() != ValueOpcode::GetBuiltin) {
|
||||
continue;
|
||||
@@ -277,12 +277,12 @@ bool CollectOutputs(const Program& program, const ShaderVertexInputInfo* vertex,
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (const auto* block: program.values->blocks) {
|
||||
for (const auto* block: program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
if (inst.GetOpcode() != ValueOpcode::SetAttribute) {
|
||||
continue;
|
||||
}
|
||||
const auto& export_info = program.values->export_info[inst.Flags<ExportFlags>().index];
|
||||
const auto& export_info = program.export_info[inst.Flags<ExportFlags>().index];
|
||||
if (export_info.kind == ExportTargetKind::MrtZ) {
|
||||
if (program.stage == ShaderType::Pixel && (export_info.en & 0x1u) != 0 &&
|
||||
pixel->ps_depth_export_enable) {
|
||||
@@ -360,12 +360,6 @@ bool CollectShaderInfo(Program& program, const ShaderInfoOptions& options, std::
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (program.values == nullptr) {
|
||||
if (error != nullptr) {
|
||||
*error = "typed value program is not available";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!ValidateOptions(program, options, error)) {
|
||||
return false;
|
||||
}
|
||||
@@ -377,7 +371,7 @@ bool CollectShaderInfo(Program& program, const ShaderInfoOptions& options, std::
|
||||
next.inputs.clear();
|
||||
next.outputs.clear();
|
||||
next.has_bitwise_xor = std::any_of(
|
||||
program.values->blocks.begin(), program.values->blocks.end(), [](const auto* block) {
|
||||
program.blocks.begin(), program.blocks.end(), [](const auto* block) {
|
||||
return std::any_of(block->begin(), block->end(), [](const auto& inst) {
|
||||
return inst.GetOpcode() == ValueOpcode::BitwiseXor32;
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "graphics/shader/recompiler/ir/passes/SharedMemoryBarrier.h"
|
||||
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <queue>
|
||||
@@ -12,7 +12,7 @@ namespace {
|
||||
|
||||
enum class LdsPhase { None, Read, Write };
|
||||
|
||||
LdsPhase GetLdsPhase(const ValueProgram& program, const Inst& inst) {
|
||||
LdsPhase GetLdsPhase(const Program& program, const Inst& inst) {
|
||||
const auto access = SharedAccessOf(inst.GetOpcode());
|
||||
if (access != SharedAccess::Read && access != SharedAccess::Write) {
|
||||
return LdsPhase::None;
|
||||
@@ -59,7 +59,7 @@ uint32_t InsertBarrier(Block& block, Block::iterator position) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t InsertBlockBarriers(ValueProgram& program, Block& block) {
|
||||
uint32_t InsertBlockBarriers(Program& program, Block& block) {
|
||||
uint32_t inserted = 0;
|
||||
LdsPhase phase = LdsPhase::None;
|
||||
for (auto inst = block.begin(); inst != block.end(); ++inst) {
|
||||
@@ -94,7 +94,7 @@ uint32_t InsertMergeBarrier(Block& block) {
|
||||
|
||||
} // namespace
|
||||
|
||||
SharedMemoryBarrierStats InsertSharedMemoryBarriers(ValueProgram& program, uint32_t wave_size,
|
||||
SharedMemoryBarrierStats InsertSharedMemoryBarriers(Program& program, uint32_t wave_size,
|
||||
const ShaderComputeInputInfo& compute_info) {
|
||||
SharedMemoryBarrierStats stats;
|
||||
const auto threadgroup_size = compute_info.threads_num[0] * compute_info.threads_num[1] *
|
||||
|
||||
@@ -9,7 +9,7 @@ struct SharedMemoryBarrierStats {
|
||||
};
|
||||
|
||||
[[nodiscard]] SharedMemoryBarrierStats
|
||||
InsertSharedMemoryBarriers(ValueProgram& program, uint32_t wave_size,
|
||||
InsertSharedMemoryBarriers(Program& program, uint32_t wave_size,
|
||||
const ShaderComputeInputInfo& compute_info);
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::IR
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "graphics/shader/recompiler/ir/passes/SrtWalker.h"
|
||||
|
||||
#include "graphics/shader/recompiler/ir/ValueProgram.h"
|
||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||
#include "graphics/shader/shader.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -50,7 +50,7 @@ bool AddSignedAddress(uint64_t base, int64_t offset, uint64_t& result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsRawRead(const ValueProgram& values, const Inst& inst) {
|
||||
bool IsRawRead(const Program& values, const Inst& inst) {
|
||||
const auto op = inst.GetOpcode();
|
||||
if (op != ValueOpcode::LoadAddressU32 && op != ValueOpcode::ReadConstBuffer) {
|
||||
return false;
|
||||
@@ -118,8 +118,7 @@ bool IsRuntimeIntegerOp(ValueOpcode op) {
|
||||
|
||||
class RuntimeValidator {
|
||||
public:
|
||||
RuntimeValidator(const Program& program, const ValueProgram& values)
|
||||
: m_program(program), m_values(values) {}
|
||||
explicit RuntimeValidator(const Program& program): m_program(program) {}
|
||||
|
||||
bool Run(Value value, std::string& reason) { return Validate(value, reason); }
|
||||
|
||||
@@ -176,7 +175,7 @@ private:
|
||||
return finish(true);
|
||||
}
|
||||
if (op == ValueOpcode::Phi) {
|
||||
const auto invariant = ResolveInvariantPhi(m_values, value);
|
||||
const auto invariant = ResolveInvariantPhi(m_program, value);
|
||||
if (invariant.IsEmpty()) {
|
||||
reason = "contains a control-dependent phi";
|
||||
return finish(false);
|
||||
@@ -196,7 +195,7 @@ private:
|
||||
inst->Arg(0).Resolve().TryInstruction()->GetOpcode() !=
|
||||
ValueOpcode::GetSrtResource ||
|
||||
!slot.IsImmediate() || slot.GetType() != Type::U32 ||
|
||||
slot.U32() >= m_values.srt_reads.size()) {
|
||||
slot.U32() >= m_program.srt_reads.size()) {
|
||||
reason = "contains a malformed flattened SRT read";
|
||||
return finish(false);
|
||||
}
|
||||
@@ -205,7 +204,7 @@ private:
|
||||
? ValueOpcode::GetAddressResource
|
||||
: ValueOpcode::GetBufferResource;
|
||||
const auto* handle = inst->NumArgs() != 0 ? inst->Arg(0).ResolveInstruction() : nullptr;
|
||||
if (!IsRawRead(m_values, *inst) || handle == nullptr ||
|
||||
if (!IsRawRead(m_program, *inst) || handle == nullptr ||
|
||||
handle->GetOpcode() != expected) {
|
||||
reason = fmt::format("contains a non-scalar {}", ValueOpcodeName(op));
|
||||
return finish(false);
|
||||
@@ -252,24 +251,23 @@ private:
|
||||
}
|
||||
|
||||
const Program& m_program;
|
||||
const ValueProgram& m_values;
|
||||
std::unordered_set<const Inst*> m_visiting;
|
||||
};
|
||||
|
||||
class PlanBuilder {
|
||||
public:
|
||||
PlanBuilder(Program& program, ValueProgram& values): m_program(program), m_values(values) {}
|
||||
explicit PlanBuilder(Program& program): m_program(program) {}
|
||||
|
||||
bool Run(std::string* error) {
|
||||
m_values.srt_reads.clear();
|
||||
m_values.dynamic_reads.clear();
|
||||
for (auto* block: m_values.blocks) {
|
||||
m_program.srt_reads.clear();
|
||||
m_program.dynamic_reads.clear();
|
||||
for (auto* block: m_program.blocks) {
|
||||
for (auto& inst: *block) {
|
||||
const auto op = inst.GetOpcode();
|
||||
if (op == ValueOpcode::LoadAddressU32 || op == ValueOpcode::ReadConstBuffer) {
|
||||
const auto flags = inst.Flags<MemoryFlags>();
|
||||
if (flags.index < m_values.memory_info.size()) {
|
||||
const auto kind = m_values.memory_info[flags.index].kind;
|
||||
if (flags.index < m_program.memory_info.size()) {
|
||||
const auto kind = m_program.memory_info[flags.index].kind;
|
||||
const bool crosswired = (op == ValueOpcode::LoadAddressU32 &&
|
||||
kind == ResourceKind::ScalarBuffer) ||
|
||||
(op == ValueOpcode::ReadConstBuffer &&
|
||||
@@ -290,10 +288,10 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto* block: m_values.blocks) {
|
||||
for (auto* block: m_program.blocks) {
|
||||
for (auto& inst: *block) {
|
||||
std::string reason;
|
||||
if (inst.GetOpcode() == ValueOpcode::LoadAddressU32 && IsRawRead(m_values, inst) &&
|
||||
if (inst.GetOpcode() == ValueOpcode::LoadAddressU32 && IsRawRead(m_program, inst) &&
|
||||
inst.Arg(1).Resolve().IsImmediate() &&
|
||||
ValidateRuntimeValue(m_program, Value(&inst), reason) &&
|
||||
!Collect(Value(&inst), inst.Flags<MemoryFlags>().pc, error)) {
|
||||
@@ -348,25 +346,25 @@ private:
|
||||
}
|
||||
m_visiting.pop_back();
|
||||
m_visited.push_back(inst);
|
||||
if (!IsRawRead(m_values, *inst)) {
|
||||
if (!IsRawRead(m_program, *inst)) {
|
||||
return true;
|
||||
}
|
||||
const auto offset = inst->Arg(1).Resolve();
|
||||
if (!offset.IsImmediate() || offset.GetType() != Type::U32) {
|
||||
if (std::ranges::find(m_values.dynamic_reads, value) == m_values.dynamic_reads.end()) {
|
||||
m_values.dynamic_reads.push_back(value);
|
||||
if (std::ranges::find(m_program.dynamic_reads, value) == m_program.dynamic_reads.end()) {
|
||||
m_program.dynamic_reads.push_back(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
use_pc = inst->Flags<MemoryFlags>().pc;
|
||||
for (uint32_t slot = 0; slot < m_values.srt_reads.size(); slot++) {
|
||||
if (EquivalentValue(m_values, value, m_values.srt_reads[slot].value)) {
|
||||
for (uint32_t slot = 0; slot < m_program.srt_reads.size(); slot++) {
|
||||
if (EquivalentValue(m_program, value, m_program.srt_reads[slot].value)) {
|
||||
m_patches.push_back({inst, slot, false});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto slot = static_cast<uint32_t>(m_values.srt_reads.size());
|
||||
m_values.srt_reads.push_back({value, slot, use_pc});
|
||||
const auto slot = static_cast<uint32_t>(m_program.srt_reads.size());
|
||||
m_program.srt_reads.push_back({value, slot, use_pc});
|
||||
m_patches.push_back({inst, slot, true});
|
||||
return true;
|
||||
}
|
||||
@@ -385,7 +383,7 @@ private:
|
||||
for (const auto& use: uses) {
|
||||
use.user->SetArg(use.operand, flat);
|
||||
}
|
||||
for (auto& info: m_values.block_info) {
|
||||
for (auto& info: m_program.block_info) {
|
||||
if (info.condition.Resolve() == Value(patch.inst)) {
|
||||
info.condition = flat;
|
||||
}
|
||||
@@ -395,8 +393,8 @@ private:
|
||||
}
|
||||
if (patch.keep) {
|
||||
const auto memory = patch.inst->Flags<MemoryFlags>().index;
|
||||
if (memory < m_values.memory_info.size()) {
|
||||
m_values.memory_info[memory].planning_only = true;
|
||||
if (memory < m_program.memory_info.size()) {
|
||||
m_program.memory_info[memory].planning_only = true;
|
||||
}
|
||||
block->AppendNewInst(ValueOpcode::ReferenceU32, {Value(patch.inst)});
|
||||
}
|
||||
@@ -404,7 +402,6 @@ private:
|
||||
}
|
||||
|
||||
Program& m_program;
|
||||
ValueProgram& m_values;
|
||||
std::vector<Inst*> m_visiting;
|
||||
std::vector<Inst*> m_visited;
|
||||
std::vector<Patch> m_patches;
|
||||
@@ -414,7 +411,7 @@ class Evaluator {
|
||||
public:
|
||||
Evaluator(const Program& program, const SrtRuntime& runtime,
|
||||
std::span<const uint8_t> clean_flat_slots = {}, Evaluator* clean_evaluator = nullptr)
|
||||
: m_program(program), m_values(*program.values), m_runtime(runtime),
|
||||
: m_program(program), m_runtime(runtime),
|
||||
m_clean_flat_slots(clean_flat_slots), m_clean_evaluator(clean_evaluator) {}
|
||||
|
||||
void SetUsePc(uint32_t pc) { m_use_pc = pc; }
|
||||
@@ -472,7 +469,7 @@ private:
|
||||
}
|
||||
|
||||
bool EvaluatePhi(const Inst& inst, uint64_t& result, std::string* error) {
|
||||
const auto value = ResolveInvariantPhi(m_values, Value(const_cast<Inst*>(&inst)));
|
||||
const auto value = ResolveInvariantPhi(m_program, Value(const_cast<Inst*>(&inst)));
|
||||
return !value.IsEmpty() ? EvaluateWide(value, result, error)
|
||||
: Fail(error, "typed phi has runtime-dependent values");
|
||||
}
|
||||
@@ -518,10 +515,10 @@ private:
|
||||
|
||||
bool EvaluateRawRead(const Inst& inst, uint64_t& result, std::string* error) {
|
||||
const auto flags = inst.Flags<MemoryFlags>();
|
||||
if (flags.index >= m_values.memory_info.size()) {
|
||||
if (flags.index >= m_program.memory_info.size()) {
|
||||
return Fail(error, "raw scalar read has invalid metadata");
|
||||
}
|
||||
const auto& mem = m_values.memory_info[flags.index];
|
||||
const auto& mem = m_program.memory_info[flags.index];
|
||||
const auto* handle = inst.Arg(0).ResolveInstruction();
|
||||
if (handle == nullptr) {
|
||||
return Fail(error, "raw scalar read has no descriptor handle");
|
||||
@@ -609,20 +606,20 @@ private:
|
||||
case ValueOpcode::ReadConst: {
|
||||
const auto slot = inst.Arg(1).Resolve();
|
||||
if (!slot.IsImmediate() || slot.GetType() != Type::U32 ||
|
||||
slot.U32() >= m_values.srt_reads.size()) {
|
||||
slot.U32() >= m_program.srt_reads.size()) {
|
||||
return Fail(error, "invalid flattened SRT index");
|
||||
}
|
||||
if (slot.U32() < m_clean_flat_slots.size() &&
|
||||
m_clean_flat_slots[slot.U32()] != 0u && m_clean_evaluator != nullptr) {
|
||||
m_clean_evaluator->SetUsePc(m_use_pc);
|
||||
return m_clean_evaluator->EvaluateWide(m_values.srt_reads[slot.U32()].value,
|
||||
return m_clean_evaluator->EvaluateWide(m_program.srt_reads[slot.U32()].value,
|
||||
result, error);
|
||||
}
|
||||
return EvaluateWide(m_values.srt_reads[slot.U32()].value, result, error);
|
||||
return EvaluateWide(m_program.srt_reads[slot.U32()].value, result, error);
|
||||
}
|
||||
case ValueOpcode::LoadAddressU32:
|
||||
case ValueOpcode::ReadConstBuffer:
|
||||
if (IsRawRead(m_values, inst)) {
|
||||
if (IsRawRead(m_program, inst)) {
|
||||
return EvaluateRawRead(inst, result, error);
|
||||
}
|
||||
break;
|
||||
@@ -856,7 +853,6 @@ private:
|
||||
}
|
||||
|
||||
const Program& m_program;
|
||||
const ValueProgram& m_values;
|
||||
const SrtRuntime& m_runtime;
|
||||
std::span<const uint8_t> m_clean_flat_slots;
|
||||
Evaluator* m_clean_evaluator = nullptr;
|
||||
@@ -866,10 +862,10 @@ private:
|
||||
};
|
||||
|
||||
const DescriptorSource* Source(const Program& program, uint32_t source) {
|
||||
if (program.values == nullptr || source >= program.values->descriptor_sources.size()) {
|
||||
if (source >= program.descriptor_sources.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &program.values->descriptor_sources[source];
|
||||
return &program.descriptor_sources[source];
|
||||
}
|
||||
|
||||
bool EvaluateRuntimeSourcesImpl(const Program& program,
|
||||
@@ -877,7 +873,7 @@ bool EvaluateRuntimeSourcesImpl(const Program& program
|
||||
const SrtRuntime& runtime, std::vector<DescriptorValue>& results,
|
||||
std::vector<uint32_t>& flat, bool evaluate_flat,
|
||||
std::span<const uint8_t> clean_flat_slots, std::string* error) {
|
||||
if (program.values == nullptr || !program.srt_plan_complete) {
|
||||
if (!program.srt_plan_complete) {
|
||||
if (error != nullptr) {
|
||||
*error = Diagnostic(program, 0, "typed SRT plan is not ready");
|
||||
}
|
||||
@@ -917,8 +913,8 @@ bool EvaluateRuntimeSourcesImpl(const Program& program
|
||||
}
|
||||
std::vector<uint32_t> flattened;
|
||||
if (evaluate_flat) {
|
||||
flattened.resize(program.values->srt_reads.size());
|
||||
for (const auto& read: program.values->srt_reads) {
|
||||
flattened.resize(program.srt_reads.size());
|
||||
for (const auto& read: program.srt_reads) {
|
||||
const bool clean = read.flat_offset < clean_flat_slots.size() &&
|
||||
clean_flat_slots[read.flat_offset] != 0u;
|
||||
auto& selected = clean ? clean_evaluator : evaluator;
|
||||
@@ -939,23 +935,18 @@ bool EvaluateRuntimeSourcesImpl(const Program& program
|
||||
} // namespace
|
||||
|
||||
bool ValidateRuntimeValue(const Program& program, Value value, std::string& reason) {
|
||||
if (program.values == nullptr) {
|
||||
reason = "typed SSA is not ready";
|
||||
return false;
|
||||
}
|
||||
return RuntimeValidator(program, *program.values).Run(value, reason);
|
||||
return RuntimeValidator(program).Run(value, reason);
|
||||
}
|
||||
|
||||
bool BuildSrtPlan(Program& program, std::string* error) {
|
||||
if (program.values == nullptr || program.resource_tracking_complete) {
|
||||
if (program.resource_tracking_complete) {
|
||||
if (error != nullptr) {
|
||||
*error = program.values == nullptr ? "typed SSA is not ready"
|
||||
: "cannot rebuild SRT after resource tracking";
|
||||
*error = "cannot rebuild SRT after resource tracking";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
program.srt_plan_complete = false;
|
||||
if (!PlanBuilder(program, *program.values).Run(error)) {
|
||||
if (!PlanBuilder(program).Run(error)) {
|
||||
return false;
|
||||
}
|
||||
program.srt_plan_complete = true;
|
||||
|
||||
Reference in New Issue
Block a user