shader: generalize D16 buffer format component handling

This commit is contained in:
nmzik
2026-10-22 05:06:47 +02:00
parent d7c1896647
commit 753f285198
3 changed files with 47 additions and 27 deletions
@@ -6,13 +6,14 @@ namespace Libs::Graphics::ShaderRecompiler::Decoder {
namespace { namespace {
struct MemoryOpcodeInfo { struct MemoryOpcodeInfo {
uint32_t encoding = 0; uint32_t encoding = 0;
Opcode decoded = Opcode::UNSUPPORTED; Opcode decoded = Opcode::UNSUPPORTED;
uint32_t data_dwords = 1; uint32_t data_dwords = 1;
uint32_t data_bits = 32; uint32_t data_bits = 32;
bool data_signed = false; bool data_signed = false;
bool typed = false; bool typed = false;
bool formatted = false; bool formatted = false;
uint32_t data_components = 0; // D16 formats pack two components per dword
}; };
constexpr MemoryOpcodeInfo SMEM_OPCODE_LIST[] = { constexpr MemoryOpcodeInfo SMEM_OPCODE_LIST[] = {
@@ -73,9 +74,9 @@ constexpr MemoryOpcodeInfo MUBUF_OPCODE_LIST[] = {
{0x71u, Opcode::BUFFER_GL0_INV, 0, 0}, {0x71u, Opcode::BUFFER_GL0_INV, 0, 0},
{0x72u, Opcode::BUFFER_GL1_INV, 0, 0}, {0x72u, Opcode::BUFFER_GL1_INV, 0, 0},
{0x80u, Opcode::BUFFER_LOAD_FORMAT_D16_X, 1, 16, false, false, true}, {0x80u, Opcode::BUFFER_LOAD_FORMAT_D16_X, 1, 16, false, false, true},
{0x83u, Opcode::BUFFER_LOAD_FORMAT_D16_XYZW, 2, 16, false, false, true}, {0x83u, Opcode::BUFFER_LOAD_FORMAT_D16_XYZW, 2, 16, false, false, true, 4},
{0x84u, Opcode::BUFFER_STORE_FORMAT_D16_X, 1, 16, false, false, true}, {0x84u, Opcode::BUFFER_STORE_FORMAT_D16_X, 1, 16, false, false, true},
{0x87u, Opcode::BUFFER_STORE_FORMAT_D16_XYZW, 2, 16, false, false, true}, {0x87u, Opcode::BUFFER_STORE_FORMAT_D16_XYZW, 2, 16, false, false, true, 4},
}; };
constexpr MemoryOpcodeInfo MTBUF_OPCODE_LIST[] = { constexpr MemoryOpcodeInfo MTBUF_OPCODE_LIST[] = {
@@ -158,12 +159,13 @@ void ApplyMemoryInfo(Instruction& inst, const MemoryOpcodeInfo* info) {
inst.opcode = Opcode::UNSUPPORTED; inst.opcode = Opcode::UNSUPPORTED;
return; return;
} }
inst.opcode = info->decoded; inst.opcode = info->decoded;
inst.data_dwords = info->data_dwords; inst.data_dwords = info->data_dwords;
inst.data_bits = info->data_bits; inst.data_bits = info->data_bits;
inst.data_signed = info->data_signed; inst.data_signed = info->data_signed;
inst.typed = info->typed; inst.typed = info->typed;
inst.formatted = info->formatted; inst.formatted = info->formatted;
inst.data_components = info->data_components;
} }
} // namespace } // namespace
@@ -323,12 +325,7 @@ void DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
} }
DecodeVectorGpr(vdata, inst.dst); DecodeVectorGpr(vdata, inst.dst);
if (inst.opcode == Opcode::BUFFER_LOAD_FORMAT_D16_XYZW || if (inst.opcode == Opcode::BUFFER_LOAD_UBYTE_D16 ||
inst.opcode == Opcode::BUFFER_STORE_FORMAT_D16_XYZW) {
inst.data_components = 4u;
}
if (inst.opcode == Opcode::BUFFER_LOAD_FORMAT_D16_X ||
inst.opcode == Opcode::BUFFER_LOAD_UBYTE_D16 ||
inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16 || inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16 ||
inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16_HI) { inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16_HI) {
inst.dst.sdwa_sel = inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16_HI ? 5u : 4u; inst.dst.sdwa_sel = inst.opcode == Opcode::BUFFER_LOAD_SHORT_D16_HI ? 5u : 4u;
@@ -455,12 +455,17 @@ void Translator::BUFFER_LOAD(const Decoder::Instruction& inst) {
AddMemoryInfo(memory, inst.pc)); AddMemoryInfo(memory, inst.pc));
if (bits != 32u) { if (bits != 32u) {
WriteOperand(inst.dst, WidenSubdword(loaded, bits, sign)); WriteOperand(inst.dst, WidenSubdword(loaded, bits, sign));
} else if (memory.data_dwords == 1u) { return;
WriteOperand(inst.dst, loaded); }
} else { for (uint32_t component = 0; component < memory.data_dwords; component++) {
for (uint32_t component = 0; component < memory.data_dwords; component++) { const auto dst = OffsetOperand(inst.dst, component);
WriteOperand(OffsetOperand(inst.dst, component), const auto value =
ir.CompositeExtract(loaded, component)); memory.data_dwords == 1u ? IR::U32(loaded) : ir.CompositeExtract(loaded, component);
// D16 formats with an odd component count keep the high half of their final VGPR.
if (memory.data_bits == 16u && component * 2u + 1u == memory.component_count) {
Write16Bits(dst, value);
} else {
WriteOperand(dst, value);
} }
} }
} }
+18
View File
@@ -16068,6 +16068,23 @@ void TestCapturedBufferStoreFormatD16HiXDecode() {
"captured BUFFER_STORE_FORMAT_D16_HI_X lost its high half, index, or coherence flags"); "captured BUFFER_STORE_FORMAT_D16_HI_X lost its high half, index, or coherence flags");
} }
void TestCapturedBufferLoadD16XyzwDecode() {
namespace Decoder = ShaderRecompiler::Decoder;
const uint32_t code[] = {0xe20c2000u, 0x8001100cu};
Decoder::Instruction inst;
Decoder::DecodeInstruction(code, 0, inst);
Check(inst.opcode == Decoder::Opcode::BUFFER_LOAD_FORMAT_D16_XYZW &&
inst.word_count == 2 && inst.data_dwords == 2 && inst.data_bits == 16 &&
inst.data_components == 4 && inst.formatted && !inst.typed,
"captured D16 XYZW load lost its four components in two packed VGPRs");
Check(inst.dst.kind == Decoder::OperandKind::Vgpr && inst.dst.reg == 16 &&
inst.dst.sdwa_sel == 6 &&
inst.src0.kind == Decoder::OperandKind::Vgpr && inst.src0.reg == 12 &&
inst.src1.kind == Decoder::OperandKind::Sgpr && inst.src1.reg == 4 &&
inst.idxen && !inst.offen,
"captured D16 XYZW load lost its full destination VGPRs or index");
}
void TestCapturedBufferStoreD16XyzwDecode() { void TestCapturedBufferStoreD16XyzwDecode() {
namespace Decoder = ShaderRecompiler::Decoder; namespace Decoder = ShaderRecompiler::Decoder;
const uint32_t code[] = {0xe21c6000u, 0x8002000eu}; const uint32_t code[] = {0xe21c6000u, 0x8002000eu};
@@ -16883,6 +16900,7 @@ int main() {
TestCapturedBufferLoadUbyteD16Decode(); TestCapturedBufferLoadUbyteD16Decode();
TestCapturedBufferStoreShortD16HiDecode(); TestCapturedBufferStoreShortD16HiDecode();
TestCapturedBufferStoreFormatD16HiXDecode(); TestCapturedBufferStoreFormatD16HiXDecode();
TestCapturedBufferLoadD16XyzwDecode();
TestCapturedBufferStoreD16XyzwDecode(); TestCapturedBufferStoreD16XyzwDecode();
TestNewShaderRecompilerUnsupportedMemoryDecode(); TestNewShaderRecompilerUnsupportedMemoryDecode();