mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
refactor(shader): preserve native wide buffer operations
This commit is contained in:
@@ -13,9 +13,12 @@ IR::ExportFlags Translator::AddExportInfo(const IR::Instruction& inst) {
|
||||
|
||||
bool Translator::TranslateAttributeOperation(const IR::Instruction& inst) {
|
||||
if (inst.op == IR::Opcode::LoadInputF32) {
|
||||
WriteOperand(inst.dst,
|
||||
ir.Emit(IR::ValueOpcode::GetAttribute,
|
||||
{IR::Value(inst.input_info.attr), IR::Value(inst.input_info.chan)}));
|
||||
for (uint32_t component = 0; component < inst.input_info.component_count; component++) {
|
||||
WriteOperand(OffsetOperand(inst.dst, component),
|
||||
ir.Emit(IR::ValueOpcode::GetAttribute,
|
||||
{IR::Value(inst.input_info.attr),
|
||||
IR::Value(inst.input_info.chan + component)}));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (inst.op == IR::Opcode::Export) {
|
||||
|
||||
@@ -12,7 +12,6 @@ bool Translator::TranslateU64MaskOperation(const IR::Instruction& inst) {
|
||||
}
|
||||
|
||||
bool Translator::TranslateInstruction(const IR::Instruction& inst,
|
||||
const BufferAddressValues* address_snapshot,
|
||||
const ScalarMemorySourceValues* scalar_source_snapshot) {
|
||||
switch (IR::GetOpcodeInfo(inst.op).lowering_class) {
|
||||
case IR::LoweringClass::Control: return TranslateControlOperation(inst);
|
||||
@@ -20,7 +19,7 @@ bool Translator::TranslateInstruction(const IR::Instruction& inst,
|
||||
case IR::LoweringClass::Lane: return TranslateLaneOperation(inst);
|
||||
case IR::LoweringClass::State: return TranslateStateOperation(inst);
|
||||
case IR::LoweringClass::Memory:
|
||||
return TranslateMemoryOperation(inst, address_snapshot, scalar_source_snapshot);
|
||||
return TranslateMemoryOperation(inst, scalar_source_snapshot);
|
||||
case IR::LoweringClass::Attribute: return TranslateAttributeOperation(inst);
|
||||
case IR::LoweringClass::IntegerCompare: return TranslateIntegerCompare(inst);
|
||||
case IR::LoweringClass::Integer16Compare: return TranslateInteger16Compare(inst);
|
||||
|
||||
@@ -125,8 +125,8 @@ IR::ValueOpcode Translator::ImageAtomicOpcode(IR::Opcode opcode) {
|
||||
}
|
||||
}
|
||||
|
||||
BufferAddressValues Translator::ReadBufferAddress(const IR::Instruction& inst,
|
||||
uint32_t first_source) {
|
||||
Translator::BufferAddress Translator::ReadBufferAddress(const IR::Instruction& inst,
|
||||
uint32_t first_source) {
|
||||
uint32_t cursor = first_source;
|
||||
const auto next = [&]() {
|
||||
return cursor < inst.src_count ? ReadU32(inst.src[cursor++]) : IR::U32(IR::Value(0u));
|
||||
@@ -201,12 +201,6 @@ IR::ValueOpcode Translator::SharedAtomicOpcode(IR::Opcode opcode, bool gds) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::IsBufferLoadOperation(IR::Opcode opcode) {
|
||||
return opcode == IR::Opcode::BufferLoadUbyte || opcode == IR::Opcode::BufferLoadSbyte ||
|
||||
opcode == IR::Opcode::BufferLoadUshort || opcode == IR::Opcode::BufferLoadSshort ||
|
||||
opcode == IR::Opcode::BufferLoadDword;
|
||||
}
|
||||
|
||||
bool Translator::IsScalarMemoryLoadOperation(IR::Opcode opcode) {
|
||||
return opcode == IR::Opcode::SLoadDword || opcode == IR::Opcode::SBufferLoadDword;
|
||||
}
|
||||
@@ -247,8 +241,7 @@ bool Translator::TranslateScalarMemory(const IR::Instruction& inst,
|
||||
}
|
||||
}
|
||||
|
||||
bool Translator::TranslateBufferLoad(const IR::Instruction& inst,
|
||||
const BufferAddressValues* address_snapshot) {
|
||||
bool Translator::TranslateBufferLoad(const IR::Instruction& inst) {
|
||||
IR::ValueOpcode opcode;
|
||||
uint32_t bits;
|
||||
bool sign;
|
||||
@@ -266,19 +259,33 @@ bool Translator::TranslateBufferLoad(const IR::Instruction& inst,
|
||||
sign = inst.op == IR::Opcode::BufferLoadSshort;
|
||||
break;
|
||||
case IR::Opcode::BufferLoadDword:
|
||||
opcode = IR::ValueOpcode::LoadBufferU32;
|
||||
bits = 32u;
|
||||
sign = false;
|
||||
switch (inst.memory.data_dwords) {
|
||||
case 1u: opcode = IR::ValueOpcode::LoadBufferU32; break;
|
||||
case 2u: opcode = IR::ValueOpcode::LoadBufferU32x2; break;
|
||||
case 3u: opcode = IR::ValueOpcode::LoadBufferU32x3; break;
|
||||
case 4u: opcode = IR::ValueOpcode::LoadBufferU32x4; break;
|
||||
default: return false;
|
||||
}
|
||||
bits = 32u;
|
||||
sign = false;
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
const auto resource = GetBufferResource(inst.memory);
|
||||
const auto address =
|
||||
address_snapshot != nullptr ? *address_snapshot : ReadBufferAddress(inst, 0);
|
||||
const auto address = ReadBufferAddress(inst, 0);
|
||||
const auto loaded =
|
||||
ir.Emit(opcode, {resource, address.index, address.offset, address.soffset, ir.GetExec()},
|
||||
AddMemoryInfo(inst));
|
||||
WriteOperand(inst.dst, bits == 32u ? loaded : WidenSubdword(loaded, bits, sign));
|
||||
if (bits != 32u) {
|
||||
WriteOperand(inst.dst, WidenSubdword(loaded, bits, sign));
|
||||
} else if (inst.memory.data_dwords == 1u) {
|
||||
WriteOperand(inst.dst, loaded);
|
||||
} else {
|
||||
for (uint32_t component = 0; component < inst.memory.data_dwords; component++) {
|
||||
WriteOperand(OffsetOperand(inst.dst, component),
|
||||
ir.CompositeExtract(loaded, component));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -298,8 +305,31 @@ bool Translator::TranslateBufferStore(const IR::Instruction& inst) {
|
||||
value = NarrowSubdword(data, 16u);
|
||||
break;
|
||||
case IR::Opcode::BufferStoreDword:
|
||||
opcode = IR::ValueOpcode::StoreBufferU32;
|
||||
value = data;
|
||||
switch (inst.memory.data_dwords) {
|
||||
case 1u:
|
||||
opcode = IR::ValueOpcode::StoreBufferU32;
|
||||
value = data;
|
||||
break;
|
||||
case 2u:
|
||||
opcode = IR::ValueOpcode::StoreBufferU32x2;
|
||||
value = ir.Emit(IR::ValueOpcode::CompositeConstructU32x2,
|
||||
{data, ReadU32(OffsetOperand(inst.src[0], 1u))});
|
||||
break;
|
||||
case 3u:
|
||||
opcode = IR::ValueOpcode::StoreBufferU32x3;
|
||||
value = ir.Emit(IR::ValueOpcode::CompositeConstructU32x3,
|
||||
{data, ReadU32(OffsetOperand(inst.src[0], 1u)),
|
||||
ReadU32(OffsetOperand(inst.src[0], 2u))});
|
||||
break;
|
||||
case 4u:
|
||||
opcode = IR::ValueOpcode::StoreBufferU32x4;
|
||||
value = ir.Emit(IR::ValueOpcode::CompositeConstructU32x4,
|
||||
{data, ReadU32(OffsetOperand(inst.src[0], 1u)),
|
||||
ReadU32(OffsetOperand(inst.src[0], 2u)),
|
||||
ReadU32(OffsetOperand(inst.src[0], 3u))});
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
@@ -594,7 +624,6 @@ bool Translator::TranslateSharedMemory(const IR::Instruction& inst) {
|
||||
}
|
||||
|
||||
bool Translator::TranslateMemoryOperation(const IR::Instruction& inst,
|
||||
const BufferAddressValues* address_snapshot,
|
||||
const ScalarMemorySourceValues* scalar_source_snapshot) {
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::LoadSrtDword:
|
||||
@@ -606,7 +635,7 @@ bool Translator::TranslateMemoryOperation(const IR::Instruction& inst,
|
||||
case IR::Opcode::BufferLoadSbyte:
|
||||
case IR::Opcode::BufferLoadUshort:
|
||||
case IR::Opcode::BufferLoadSshort:
|
||||
case IR::Opcode::BufferLoadDword: return TranslateBufferLoad(inst, address_snapshot);
|
||||
case IR::Opcode::BufferLoadDword: return TranslateBufferLoad(inst);
|
||||
|
||||
case IR::Opcode::BufferStoreByte:
|
||||
case IR::Opcode::BufferStoreShort:
|
||||
|
||||
@@ -668,26 +668,12 @@ void Translator::WriteCompareResult(const IR::Operand& operand, IR::U1 value) {
|
||||
}
|
||||
|
||||
bool Translator::TranslateBlock(const IR::BasicBlock& source, std::string* error) {
|
||||
BufferAddressValues buffer_address_snapshot {};
|
||||
ScalarMemorySourceValues scalar_source_snapshot {};
|
||||
uint32_t buffer_address_pc = 0;
|
||||
uint32_t scalar_source_pc = 0;
|
||||
bool has_buffer_address_snapshot = false;
|
||||
bool has_scalar_source_snapshot = false;
|
||||
uint32_t scalar_source_pc = 0;
|
||||
bool has_scalar_source_snapshot = false;
|
||||
for (const auto& source_inst: source.instructions) {
|
||||
current_opcode = source_inst.op;
|
||||
current_pc = source_inst.pc;
|
||||
const bool grouped_buffer_load =
|
||||
IsBufferLoadOperation(source_inst.op) && source_inst.memory.component_count > 1u;
|
||||
if (grouped_buffer_load &&
|
||||
(!has_buffer_address_snapshot || buffer_address_pc != source_inst.pc ||
|
||||
source_inst.memory.component_index == 0u)) {
|
||||
buffer_address_snapshot = ReadBufferAddress(source_inst, 0);
|
||||
buffer_address_pc = source_inst.pc;
|
||||
has_buffer_address_snapshot = true;
|
||||
} else if (!grouped_buffer_load) {
|
||||
has_buffer_address_snapshot = false;
|
||||
}
|
||||
const bool grouped_scalar_load =
|
||||
IsScalarMemoryLoadOperation(source_inst.op) && source_inst.memory.component_count > 1u;
|
||||
if (grouped_scalar_load &&
|
||||
@@ -703,7 +689,6 @@ bool Translator::TranslateBlock(const IR::BasicBlock& source, std::string* error
|
||||
return Fail(error, "value IR input opcode is out of range");
|
||||
}
|
||||
if (TranslateInstruction(source_inst,
|
||||
grouped_buffer_load ? &buffer_address_snapshot : nullptr,
|
||||
grouped_scalar_load ? &scalar_source_snapshot : nullptr)) {
|
||||
continue;
|
||||
}
|
||||
@@ -780,11 +765,11 @@ bool TranslateProgram(const IR::Program& source, IR::ValueProgram& result,
|
||||
const uint32_t wave_size = source.wave_size;
|
||||
const bool per_invocation_masks = source.lane_mask_mode == ShaderLaneMaskMode::PerInvocation;
|
||||
uint32_t vector_limit = 1u;
|
||||
const auto include_vector = [&](const IR::Operand& operand) {
|
||||
const auto include_vector = [&](const IR::Operand& operand, uint32_t count = 1u) {
|
||||
if (operand.kind == IR::OperandKind::Register &&
|
||||
operand.reg.file == IR::RegisterFile::Vector) {
|
||||
vector_limit =
|
||||
std::min(IR::NumVectorRegs, std::max(vector_limit, operand.reg.index + 1u));
|
||||
std::min(IR::NumVectorRegs, std::max(vector_limit, operand.reg.index + count));
|
||||
}
|
||||
};
|
||||
for (const auto& block: source.blocks) {
|
||||
@@ -794,6 +779,13 @@ bool TranslateProgram(const IR::Program& source, IR::ValueProgram& result,
|
||||
for (uint32_t index = 0; index < inst.src_count; index++) {
|
||||
include_vector(inst.src[index]);
|
||||
}
|
||||
if (inst.op == IR::Opcode::BufferLoadDword) {
|
||||
include_vector(inst.dst, std::max(inst.memory.data_dwords, 1u));
|
||||
} else if (inst.op == IR::Opcode::BufferStoreDword) {
|
||||
include_vector(inst.src[0], std::max(inst.memory.data_dwords, 1u));
|
||||
} else if (inst.op == IR::Opcode::LoadInputF32) {
|
||||
include_vector(inst.dst, std::max(inst.input_info.component_count, 1u));
|
||||
}
|
||||
}
|
||||
}
|
||||
result.block_storage.reserve(source.blocks.size() + 1u);
|
||||
@@ -846,8 +838,8 @@ bool TranslateProgram(const IR::Program& source, IR::ValueProgram& result,
|
||||
}
|
||||
entry_ir.SetExec(IR::U1(IR::Value(true)));
|
||||
entry_ir.SetExecLo(IR::U32(IR::Value(per_invocation_masks ? 1u : 0xffffffffu)));
|
||||
entry_ir.SetExecHi(IR::U32(IR::Value(
|
||||
!per_invocation_masks && source.wave_size > 32u ? 0xffffffffu : 0u)));
|
||||
entry_ir.SetExecHi(
|
||||
IR::U32(IR::Value(!per_invocation_masks && source.wave_size > 32u ? 0xffffffffu : 0u)));
|
||||
if (source.stage == ShaderType::Compute) {
|
||||
const auto* cs = compute_input_info;
|
||||
const auto thread_ids =
|
||||
|
||||
@@ -7,12 +7,6 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Frontend::Detail {
|
||||
|
||||
struct BufferAddressValues {
|
||||
IR::U32 index;
|
||||
IR::U32 offset;
|
||||
IR::U32 soffset;
|
||||
};
|
||||
|
||||
struct ScalarMemorySourceValues {
|
||||
IR::Value resource;
|
||||
IR::U32 offset;
|
||||
@@ -70,6 +64,11 @@ private:
|
||||
IR::Value low;
|
||||
IR::Value high;
|
||||
};
|
||||
struct BufferAddress {
|
||||
IR::U32 index;
|
||||
IR::U32 offset;
|
||||
IR::U32 soffset;
|
||||
};
|
||||
AddressOperands ReadAddressOperands(const IR::Instruction& inst, uint32_t first_source);
|
||||
IR::U32 GetResourceDword(uint32_t index, uint32_t dword);
|
||||
IR::Value GetBufferResource(const IR::MemoryInfo& memory);
|
||||
@@ -83,18 +82,16 @@ private:
|
||||
void WriteImageComponents(const IR::Operand& dst, IR::Value value, uint32_t dmask,
|
||||
uint32_t component_limit);
|
||||
IR::ValueOpcode ImageAtomicOpcode(IR::Opcode opcode);
|
||||
BufferAddressValues ReadBufferAddress(const IR::Instruction& inst, uint32_t source_offset);
|
||||
IR::U32 WidenSubdword(IR::Value value, uint32_t bits, bool sign);
|
||||
IR::Value NarrowSubdword(IR::U32 value, uint32_t bits);
|
||||
IR::ValueOpcode BufferAtomicOpcode(IR::Opcode opcode);
|
||||
IR::ValueOpcode SharedAtomicOpcode(IR::Opcode opcode, bool gds);
|
||||
bool IsBufferLoadOperation(IR::Opcode opcode);
|
||||
bool IsScalarMemoryLoadOperation(IR::Opcode opcode);
|
||||
BufferAddress ReadBufferAddress(const IR::Instruction& inst, uint32_t source_offset);
|
||||
IR::U32 WidenSubdword(IR::Value value, uint32_t bits, bool sign);
|
||||
IR::Value NarrowSubdword(IR::U32 value, uint32_t bits);
|
||||
IR::ValueOpcode BufferAtomicOpcode(IR::Opcode opcode);
|
||||
IR::ValueOpcode SharedAtomicOpcode(IR::Opcode opcode, bool gds);
|
||||
bool IsScalarMemoryLoadOperation(IR::Opcode opcode);
|
||||
ScalarMemorySourceValues ReadScalarMemorySource(const IR::Instruction& inst);
|
||||
bool TranslateScalarMemory(const IR::Instruction& inst,
|
||||
const ScalarMemorySourceValues* source_snapshot);
|
||||
bool TranslateBufferLoad(const IR::Instruction& inst,
|
||||
const BufferAddressValues* address_snapshot);
|
||||
bool TranslateBufferLoad(const IR::Instruction& inst);
|
||||
bool TranslateBufferStore(const IR::Instruction& inst);
|
||||
bool TranslateAtomicMemory(const IR::Instruction& inst);
|
||||
bool TranslateFlatLoad(const IR::Instruction& inst);
|
||||
@@ -111,7 +108,6 @@ private:
|
||||
IR::U32 PackU16Lanes(IR::U32 low, IR::U32 high);
|
||||
|
||||
bool TranslateInstruction(const IR::Instruction& inst,
|
||||
const BufferAddressValues* address_snapshot,
|
||||
const ScalarMemorySourceValues* scalar_source_snapshot);
|
||||
bool TranslateStateOperation(const IR::Instruction& inst);
|
||||
bool TranslateControlOperation(const IR::Instruction& inst);
|
||||
@@ -119,7 +115,6 @@ private:
|
||||
bool TranslateLaneOperation(const IR::Instruction& inst);
|
||||
bool TranslateAttributeOperation(const IR::Instruction& inst);
|
||||
bool TranslateMemoryOperation(const IR::Instruction& inst,
|
||||
const BufferAddressValues* address_snapshot,
|
||||
const ScalarMemorySourceValues* scalar_source_snapshot);
|
||||
bool TranslateIntegerCompare(const IR::Instruction& inst);
|
||||
bool TranslateInteger16Compare(const IR::Instruction& inst);
|
||||
|
||||
Reference in New Issue
Block a user