shader: support packed D16 XYZW formatted buffer stores

Co-authored-by: fxpw <fxpw@outlook.com>
This commit is contained in:
nmzik
2026-10-14 19:35:08 +02:00
parent c914435f20
commit 4843d8d942
8 changed files with 107 additions and 29 deletions
@@ -815,18 +815,23 @@ void StoreFormattedPrepared(ValueEmitContext& ctx, const IR::Inst& inst,
uint32_t components) {
if (resource.object_pointer == 0u) return;
// RDNA2 formatted stores transfer the entire format, zero-filling missing VGPRs.
const auto count = mem.data_bits == 16u ? mem.component_count : components;
const auto plan = PrepareFormattedMemory(ctx, inst, mem, resource, info);
EmitIfCondition(ctx.state, plan.in_bounds, [&]() {
auto packed = ConstantU32(ctx.state, 0);
for (uint32_t component = 0; component < info.component_count; component++) {
auto value = ConstantU32(ctx.state, 0);
if (component < components) {
if (component < count) {
const auto word = mem.data_bits == 16u ? component / 2u : component;
value = data;
if (components != 1u) {
value = ctx.state.builder.AllocateId();
ctx.state.builder.AddFunction(spv::OpCompositeExtract, TypeU32(ctx.state),
value, data, component);
value, data, word);
}
if (mem.data_bits == 16u && (component & 1u) != 0u)
value = Binary(ctx.state, spv::OpShiftRightLogical, TypeU32(ctx.state), value,
ConstantU32(ctx.state, 16u));
}
value = EncodeFormattedStoreComponent(ctx.state, info, component, value, mem.data_bits);
const auto bits = info.component_bits[component];
@@ -70,6 +70,7 @@ constexpr MemoryOpcodeInfo MUBUF_OPCODE_LIST[] = {
{0x80u, Opcode::BUFFER_LOAD_FORMAT_D16_X, 1, 16, false, false, true},
{0x83u, Opcode::BUFFER_LOAD_FORMAT_D16_XYZW, 2, 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},
};
constexpr MemoryOpcodeInfo MTBUF_OPCODE_LIST[] = {
@@ -307,7 +308,8 @@ void DecodeMubuf(uint32_t pc, std::span<const uint32_t> code, uint32_t word_inde
}
DecodeVectorGpr(vdata, inst.dst);
if (inst.opcode == Opcode::BUFFER_LOAD_FORMAT_D16_XYZW) {
if (inst.opcode == Opcode::BUFFER_LOAD_FORMAT_D16_XYZW ||
inst.opcode == Opcode::BUFFER_STORE_FORMAT_D16_XYZW) {
inst.data_components = 4u;
}
if (inst.opcode == Opcode::BUFFER_LOAD_FORMAT_D16_X ||
@@ -637,6 +637,7 @@ std::string InstructionToString(const Instruction& inst) {
case Opcode::BUFFER_STORE_FORMAT_XYZ:
case Opcode::BUFFER_STORE_FORMAT_XYZW:
case Opcode::BUFFER_STORE_FORMAT_D16_X:
case Opcode::BUFFER_STORE_FORMAT_D16_XYZW:
case Opcode::BUFFER_LOAD_UBYTE:
case Opcode::BUFFER_LOAD_UBYTE_D16:
case Opcode::BUFFER_LOAD_USHORT:
@@ -553,6 +553,7 @@ enum class Opcode {
BUFFER_STORE_FORMAT_XYZ,
BUFFER_STORE_FORMAT_XYZW,
BUFFER_STORE_FORMAT_D16_X,
BUFFER_STORE_FORMAT_D16_XYZW,
BUFFER_LOAD_UBYTE,
BUFFER_LOAD_UBYTE_D16,
BUFFER_LOAD_SBYTE,
@@ -187,7 +187,7 @@ Decoder::Operand MemorySourceAt(const Decoder::Instruction& decoded, uint32_t in
if (decoded.family == Decoder::Family::MUBUF || decoded.family == Decoder::Family::MTBUF) {
const bool store_or_atomic =
(decoded.opcode >= Decoder::Opcode::BUFFER_STORE_FORMAT_X &&
decoded.opcode <= Decoder::Opcode::BUFFER_STORE_FORMAT_D16_X) ||
decoded.opcode <= Decoder::Opcode::BUFFER_STORE_FORMAT_D16_XYZW) ||
(decoded.opcode >= Decoder::Opcode::BUFFER_STORE_BYTE &&
decoded.opcode <= Decoder::Opcode::BUFFER_STORE_DWORDX4) ||
(decoded.opcode >= Decoder::Opcode::TBUFFER_STORE_FORMAT_X &&
@@ -1006,6 +1006,7 @@ void Translator::EmitMemory(const Decoder::Instruction& inst) {
case Decoder::Opcode::BUFFER_STORE_FORMAT_XYZ:
case Decoder::Opcode::BUFFER_STORE_FORMAT_XYZW:
case Decoder::Opcode::BUFFER_STORE_FORMAT_D16_X:
case Decoder::Opcode::BUFFER_STORE_FORMAT_D16_XYZW:
case Decoder::Opcode::TBUFFER_STORE_FORMAT_X:
case Decoder::Opcode::TBUFFER_STORE_FORMAT_XY:
case Decoder::Opcode::TBUFFER_STORE_FORMAT_XYZ:
@@ -474,11 +474,12 @@ void ValidateProgram(const Program& program, bool require_ssa) {
return Fail("indirect buffer requires a scalar, raw 8/16-bit, raw DWORD x1/x2/x3/x4, "
"or formatted X load");
}
const bool packed_formatted_load =
BufferAccessOf(inst.GetOpcode()) == BufferAccess::Read && memory.formatted &&
const auto access = BufferAccessOf(inst.GetOpcode());
const bool packed_formatted =
(access == BufferAccess::Read || access == BufferAccess::Write) && memory.formatted &&
memory.data_bits == 16u && memory.component_count == 4u && buffer_components == 2u;
if (buffer_components > 1u &&
(!vector_buffer || (memory.data_bits != 32u && !packed_formatted_load) ||
(!vector_buffer || (memory.data_bits != 32u && !packed_formatted) ||
memory.data_dwords != buffer_components || memory.component_index != 0u)) {
return Fail(fmt::format("{} has inconsistent native-wide metadata",
ValueOpcodeName(inst.GetOpcode())));