shader_recompiler: Clean up swizzle handling and handle ImageRead storage swizzle.

This commit is contained in:
squidbus 2024-12-25 14:35:46 -08:00
parent 4e6a7e555e
commit 070c4af208
11 changed files with 284 additions and 56 deletions

View File

@ -694,6 +694,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/ir/post_order.h src/shader_recompiler/ir/post_order.h
src/shader_recompiler/ir/program.cpp src/shader_recompiler/ir/program.cpp
src/shader_recompiler/ir/program.h src/shader_recompiler/ir/program.h
src/shader_recompiler/ir/reinterpret.h
src/shader_recompiler/ir/reg.h src/shader_recompiler/ir/reg.h
src/shader_recompiler/ir/type.cpp src/shader_recompiler/ir/type.cpp
src/shader_recompiler/ir/type.h src/shader_recompiler/ir/type.h

View File

@ -42,6 +42,20 @@ Id EmitCompositeInsertU32x4(EmitContext& ctx, Id composite, Id object, u32 index
return ctx.OpCompositeInsert(ctx.U32[4], object, composite, index); return ctx.OpCompositeInsert(ctx.U32[4], object, composite, index);
} }
Id EmitCompositeShuffleU32x2(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1) {
return ctx.OpVectorShuffle(ctx.U32[2], composite1, composite2, comp0, comp1);
}
Id EmitCompositeShuffleU32x3(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2) {
return ctx.OpVectorShuffle(ctx.U32[3], composite1, composite2, comp0, comp1, comp2);
}
Id EmitCompositeShuffleU32x4(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2, u32 comp3) {
return ctx.OpVectorShuffle(ctx.U32[4], composite1, composite2, comp0, comp1, comp2, comp3);
}
Id EmitCompositeConstructF16x2(EmitContext& ctx, Id e1, Id e2) { Id EmitCompositeConstructF16x2(EmitContext& ctx, Id e1, Id e2) {
return ctx.OpCompositeConstruct(ctx.F16[2], e1, e2); return ctx.OpCompositeConstruct(ctx.F16[2], e1, e2);
} }
@ -78,6 +92,20 @@ Id EmitCompositeInsertF16x4(EmitContext& ctx, Id composite, Id object, u32 index
return ctx.OpCompositeInsert(ctx.F16[4], object, composite, index); return ctx.OpCompositeInsert(ctx.F16[4], object, composite, index);
} }
Id EmitCompositeShuffleF16x2(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1) {
return ctx.OpVectorShuffle(ctx.F16[2], composite1, composite2, comp0, comp1);
}
Id EmitCompositeShuffleF16x3(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2) {
return ctx.OpVectorShuffle(ctx.F16[3], composite1, composite2, comp0, comp1, comp2);
}
Id EmitCompositeShuffleF16x4(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2, u32 comp3) {
return ctx.OpVectorShuffle(ctx.F16[4], composite1, composite2, comp0, comp1, comp2, comp3);
}
Id EmitCompositeConstructF32x2(EmitContext& ctx, Id e1, Id e2) { Id EmitCompositeConstructF32x2(EmitContext& ctx, Id e1, Id e2) {
return ctx.OpCompositeConstruct(ctx.F32[2], e1, e2); return ctx.OpCompositeConstruct(ctx.F32[2], e1, e2);
} }
@ -114,6 +142,20 @@ Id EmitCompositeInsertF32x4(EmitContext& ctx, Id composite, Id object, u32 index
return ctx.OpCompositeInsert(ctx.F32[4], object, composite, index); return ctx.OpCompositeInsert(ctx.F32[4], object, composite, index);
} }
Id EmitCompositeShuffleF32x2(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1) {
return ctx.OpVectorShuffle(ctx.F32[2], composite1, composite2, comp0, comp1);
}
Id EmitCompositeShuffleF32x3(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2) {
return ctx.OpVectorShuffle(ctx.F32[3], composite1, composite2, comp0, comp1, comp2);
}
Id EmitCompositeShuffleF32x4(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2, u32 comp3) {
return ctx.OpVectorShuffle(ctx.F32[4], composite1, composite2, comp0, comp1, comp2, comp3);
}
void EmitCompositeConstructF64x2(EmitContext&) { void EmitCompositeConstructF64x2(EmitContext&) {
UNREACHABLE_MSG("SPIR-V Instruction"); UNREACHABLE_MSG("SPIR-V Instruction");
} }
@ -150,4 +192,18 @@ Id EmitCompositeInsertF64x4(EmitContext& ctx, Id composite, Id object, u32 index
return ctx.OpCompositeInsert(ctx.F64[4], object, composite, index); return ctx.OpCompositeInsert(ctx.F64[4], object, composite, index);
} }
Id EmitCompositeShuffleF64x2(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1) {
return ctx.OpVectorShuffle(ctx.F64[2], composite1, composite2, comp0, comp1);
}
Id EmitCompositeShuffleF64x3(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2) {
return ctx.OpVectorShuffle(ctx.F64[3], composite1, composite2, comp0, comp1, comp2);
}
Id EmitCompositeShuffleF64x4(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2, u32 comp3) {
return ctx.OpVectorShuffle(ctx.F64[4], composite1, composite2, comp0, comp1, comp2, comp3);
}
} // namespace Shader::Backend::SPIRV } // namespace Shader::Backend::SPIRV

View File

@ -127,6 +127,11 @@ Id EmitCompositeExtractU32x4(EmitContext& ctx, Id composite, u32 index);
Id EmitCompositeInsertU32x2(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertU32x2(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeInsertU32x3(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertU32x3(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeInsertU32x4(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertU32x4(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeShuffleU32x2(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1);
Id EmitCompositeShuffleU32x3(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2);
Id EmitCompositeShuffleU32x4(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2, u32 comp3);
Id EmitCompositeConstructF16x2(EmitContext& ctx, Id e1, Id e2); Id EmitCompositeConstructF16x2(EmitContext& ctx, Id e1, Id e2);
Id EmitCompositeConstructF16x3(EmitContext& ctx, Id e1, Id e2, Id e3); Id EmitCompositeConstructF16x3(EmitContext& ctx, Id e1, Id e2, Id e3);
Id EmitCompositeConstructF16x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4); Id EmitCompositeConstructF16x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4);
@ -136,6 +141,11 @@ Id EmitCompositeExtractF16x4(EmitContext& ctx, Id composite, u32 index);
Id EmitCompositeInsertF16x2(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertF16x2(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeInsertF16x3(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertF16x3(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeInsertF16x4(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertF16x4(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeShuffleF16x2(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1);
Id EmitCompositeShuffleF16x3(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2);
Id EmitCompositeShuffleF16x4(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2, u32 comp3);
Id EmitCompositeConstructF32x2(EmitContext& ctx, Id e1, Id e2); Id EmitCompositeConstructF32x2(EmitContext& ctx, Id e1, Id e2);
Id EmitCompositeConstructF32x3(EmitContext& ctx, Id e1, Id e2, Id e3); Id EmitCompositeConstructF32x3(EmitContext& ctx, Id e1, Id e2, Id e3);
Id EmitCompositeConstructF32x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4); Id EmitCompositeConstructF32x4(EmitContext& ctx, Id e1, Id e2, Id e3, Id e4);
@ -145,6 +155,11 @@ Id EmitCompositeExtractF32x4(EmitContext& ctx, Id composite, u32 index);
Id EmitCompositeInsertF32x2(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertF32x2(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeInsertF32x3(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertF32x3(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeInsertF32x4(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertF32x4(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeShuffleF32x2(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1);
Id EmitCompositeShuffleF32x3(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2);
Id EmitCompositeShuffleF32x4(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2, u32 comp3);
void EmitCompositeConstructF64x2(EmitContext& ctx); void EmitCompositeConstructF64x2(EmitContext& ctx);
void EmitCompositeConstructF64x3(EmitContext& ctx); void EmitCompositeConstructF64x3(EmitContext& ctx);
void EmitCompositeConstructF64x4(EmitContext& ctx); void EmitCompositeConstructF64x4(EmitContext& ctx);
@ -154,6 +169,11 @@ void EmitCompositeExtractF64x4(EmitContext& ctx);
Id EmitCompositeInsertF64x2(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertF64x2(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeInsertF64x3(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertF64x3(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeInsertF64x4(EmitContext& ctx, Id composite, Id object, u32 index); Id EmitCompositeInsertF64x4(EmitContext& ctx, Id composite, Id object, u32 index);
Id EmitCompositeShuffleF64x2(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1);
Id EmitCompositeShuffleF64x3(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2);
Id EmitCompositeShuffleF64x4(EmitContext& ctx, Id composite1, Id composite2, u32 comp0, u32 comp1,
u32 comp2, u32 comp3);
Id EmitSelectU1(EmitContext& ctx, Id cond, Id true_value, Id false_value); Id EmitSelectU1(EmitContext& ctx, Id cond, Id true_value, Id false_value);
Id EmitSelectU8(EmitContext& ctx, Id cond, Id true_value, Id false_value); Id EmitSelectU8(EmitContext& ctx, Id cond, Id true_value, Id false_value);
Id EmitSelectU16(EmitContext& ctx, Id cond, Id true_value, Id false_value); Id EmitSelectU16(EmitContext& ctx, Id cond, Id true_value, Id false_value);

View File

@ -10,6 +10,7 @@
#include "shader_recompiler/info.h" #include "shader_recompiler/info.h"
#include "shader_recompiler/ir/attribute.h" #include "shader_recompiler/ir/attribute.h"
#include "shader_recompiler/ir/reg.h" #include "shader_recompiler/ir/reg.h"
#include "shader_recompiler/ir/reinterpret.h"
#include "shader_recompiler/runtime_info.h" #include "shader_recompiler/runtime_info.h"
#include "video_core/amdgpu/resource.h" #include "video_core/amdgpu/resource.h"
#include "video_core/amdgpu/types.h" #include "video_core/amdgpu/types.h"
@ -475,11 +476,12 @@ void Translator::EmitFetch(const GcnInst& inst) {
// Read the V# of the attribute to figure out component number and type. // Read the V# of the attribute to figure out component number and type.
const auto buffer = info.ReadUdReg<AmdGpu::Buffer>(attrib.sgpr_base, attrib.dword_offset); const auto buffer = info.ReadUdReg<AmdGpu::Buffer>(attrib.sgpr_base, attrib.dword_offset);
const std::array components = buffer.DstSelect().Apply<IR::F32>( const auto values =
[&](const u32 index) { return ir.GetAttribute(attr, index); }, ir.CompositeConstruct(ir.GetAttribute(attr, 0), ir.GetAttribute(attr, 1),
[&](const u32 imm) { return ir.Imm32(float(imm)); }); ir.GetAttribute(attr, 2), ir.GetAttribute(attr, 3));
for (u32 i = 0; i < components.size(); i++) { const auto swizzled = ApplySwizzle(ir, values, buffer.DstSelect());
ir.SetVectorReg(dst_reg++, components[i]); for (u32 i = 0; i < 4; i++) {
ir.SetVectorReg(dst_reg++, IR::F32{ir.CompositeExtract(swizzled, i)});
} }
// In case of programmable step rates we need to fallback to instance data pulling in // In case of programmable step rates we need to fallback to instance data pulling in

View File

@ -657,6 +657,86 @@ Value IREmitter::CompositeInsert(const Value& vector, const Value& object, size_
} }
} }
Value IREmitter::CompositeShuffle(const Value& vector1, const Value& vector2, size_t comp0,
size_t comp1) {
if (vector1.Type() != vector2.Type()) {
UNREACHABLE_MSG("Mismatching types {} and {}", vector1.Type(), vector2.Type());
}
if (comp0 >= 4 || comp1 >= 4) {
UNREACHABLE_MSG("One or more out of bounds elements {}, {}", comp0, comp1);
}
const auto shuffle{[&](Opcode opcode) -> Value {
return Inst(opcode, vector1, vector2, Value{static_cast<u32>(comp0)},
Value{static_cast<u32>(comp1)});
}};
switch (vector1.Type()) {
case Type::U32x4:
return shuffle(Opcode::CompositeShuffleU32x2);
case Type::F16x4:
return shuffle(Opcode::CompositeShuffleF16x2);
case Type::F32x4:
return shuffle(Opcode::CompositeShuffleF32x2);
case Type::F64x4:
return shuffle(Opcode::CompositeShuffleF64x2);
default:
ThrowInvalidType(vector1.Type());
}
}
Value IREmitter::CompositeShuffle(const Value& vector1, const Value& vector2, size_t comp0,
size_t comp1, size_t comp2) {
if (vector1.Type() != vector2.Type()) {
UNREACHABLE_MSG("Mismatching types {} and {}", vector1.Type(), vector2.Type());
}
if (comp0 >= 6 || comp1 >= 6 || comp2 >= 6) {
UNREACHABLE_MSG("One or more out of bounds elements {}, {}, {}", comp0, comp1, comp2);
}
const auto shuffle{[&](Opcode opcode) -> Value {
return Inst(opcode, vector1, vector2, Value{static_cast<u32>(comp0)},
Value{static_cast<u32>(comp1)}, Value{static_cast<u32>(comp2)});
}};
switch (vector1.Type()) {
case Type::U32x4:
return shuffle(Opcode::CompositeShuffleU32x3);
case Type::F16x4:
return shuffle(Opcode::CompositeShuffleF16x3);
case Type::F32x4:
return shuffle(Opcode::CompositeShuffleF32x3);
case Type::F64x4:
return shuffle(Opcode::CompositeShuffleF64x3);
default:
ThrowInvalidType(vector1.Type());
}
}
Value IREmitter::CompositeShuffle(const Value& vector1, const Value& vector2, size_t comp0,
size_t comp1, size_t comp2, size_t comp3) {
if (vector1.Type() != vector2.Type()) {
UNREACHABLE_MSG("Mismatching types {} and {}", vector1.Type(), vector2.Type());
}
if (comp0 >= 8 || comp1 >= 8 || comp2 >= 8 || comp3 >= 8) {
UNREACHABLE_MSG("One or more out of bounds elements {}, {}, {}, {}", comp0, comp1, comp2,
comp3);
}
const auto shuffle{[&](Opcode opcode) -> Value {
return Inst(opcode, vector1, vector2, Value{static_cast<u32>(comp0)},
Value{static_cast<u32>(comp1)}, Value{static_cast<u32>(comp2)},
Value{static_cast<u32>(comp3)});
}};
switch (vector1.Type()) {
case Type::U32x4:
return shuffle(Opcode::CompositeShuffleU32x4);
case Type::F16x4:
return shuffle(Opcode::CompositeShuffleF16x4);
case Type::F32x4:
return shuffle(Opcode::CompositeShuffleF32x4);
case Type::F64x4:
return shuffle(Opcode::CompositeShuffleF64x4);
default:
ThrowInvalidType(vector1.Type());
}
}
Value IREmitter::Select(const U1& condition, const Value& true_value, const Value& false_value) { Value IREmitter::Select(const U1& condition, const Value& true_value, const Value& false_value) {
if (true_value.Type() != false_value.Type()) { if (true_value.Type() != false_value.Type()) {
UNREACHABLE_MSG("Mismatching types {} and {}", true_value.Type(), false_value.Type()); UNREACHABLE_MSG("Mismatching types {} and {}", true_value.Type(), false_value.Type());

View File

@ -152,6 +152,13 @@ public:
[[nodiscard]] Value CompositeExtract(const Value& vector, size_t element); [[nodiscard]] Value CompositeExtract(const Value& vector, size_t element);
[[nodiscard]] Value CompositeInsert(const Value& vector, const Value& object, size_t element); [[nodiscard]] Value CompositeInsert(const Value& vector, const Value& object, size_t element);
[[nodiscard]] Value CompositeShuffle(const Value& vector1, const Value& vector2, size_t comp0,
size_t comp1);
[[nodiscard]] Value CompositeShuffle(const Value& vector1, const Value& vector2, size_t comp0,
size_t comp1, size_t comp2);
[[nodiscard]] Value CompositeShuffle(const Value& vector1, const Value& vector2, size_t comp0,
size_t comp1, size_t comp2, size_t comp3);
[[nodiscard]] Value Select(const U1& condition, const Value& true_value, [[nodiscard]] Value Select(const U1& condition, const Value& true_value,
const Value& false_value); const Value& false_value);

View File

@ -122,6 +122,9 @@ OPCODE(CompositeExtractU32x4, U32, U32x
OPCODE(CompositeInsertU32x2, U32x2, U32x2, U32, U32, ) OPCODE(CompositeInsertU32x2, U32x2, U32x2, U32, U32, )
OPCODE(CompositeInsertU32x3, U32x3, U32x3, U32, U32, ) OPCODE(CompositeInsertU32x3, U32x3, U32x3, U32, U32, )
OPCODE(CompositeInsertU32x4, U32x4, U32x4, U32, U32, ) OPCODE(CompositeInsertU32x4, U32x4, U32x4, U32, U32, )
OPCODE(CompositeShuffleU32x2, U32x2, U32x2, U32x2, U32, U32, )
OPCODE(CompositeShuffleU32x3, U32x3, U32x3, U32x3, U32, U32, U32, )
OPCODE(CompositeShuffleU32x4, U32x4, U32x4, U32x4, U32, U32, U32, U32, )
OPCODE(CompositeConstructF16x2, F16x2, F16, F16, ) OPCODE(CompositeConstructF16x2, F16x2, F16, F16, )
OPCODE(CompositeConstructF16x3, F16x3, F16, F16, F16, ) OPCODE(CompositeConstructF16x3, F16x3, F16, F16, F16, )
OPCODE(CompositeConstructF16x4, F16x4, F16, F16, F16, F16, ) OPCODE(CompositeConstructF16x4, F16x4, F16, F16, F16, F16, )
@ -131,6 +134,9 @@ OPCODE(CompositeExtractF16x4, F16, F16x
OPCODE(CompositeInsertF16x2, F16x2, F16x2, F16, U32, ) OPCODE(CompositeInsertF16x2, F16x2, F16x2, F16, U32, )
OPCODE(CompositeInsertF16x3, F16x3, F16x3, F16, U32, ) OPCODE(CompositeInsertF16x3, F16x3, F16x3, F16, U32, )
OPCODE(CompositeInsertF16x4, F16x4, F16x4, F16, U32, ) OPCODE(CompositeInsertF16x4, F16x4, F16x4, F16, U32, )
OPCODE(CompositeShuffleF16x2, F16x2, F16x2, F16x2, U32, U32, )
OPCODE(CompositeShuffleF16x3, F16x3, F16x3, F16x3, U32, U32, U32, )
OPCODE(CompositeShuffleF16x4, F16x4, F16x4, F16x4, U32, U32, U32, U32, )
OPCODE(CompositeConstructF32x2, F32x2, F32, F32, ) OPCODE(CompositeConstructF32x2, F32x2, F32, F32, )
OPCODE(CompositeConstructF32x3, F32x3, F32, F32, F32, ) OPCODE(CompositeConstructF32x3, F32x3, F32, F32, F32, )
OPCODE(CompositeConstructF32x4, F32x4, F32, F32, F32, F32, ) OPCODE(CompositeConstructF32x4, F32x4, F32, F32, F32, F32, )
@ -140,6 +146,9 @@ OPCODE(CompositeExtractF32x4, F32, F32x
OPCODE(CompositeInsertF32x2, F32x2, F32x2, F32, U32, ) OPCODE(CompositeInsertF32x2, F32x2, F32x2, F32, U32, )
OPCODE(CompositeInsertF32x3, F32x3, F32x3, F32, U32, ) OPCODE(CompositeInsertF32x3, F32x3, F32x3, F32, U32, )
OPCODE(CompositeInsertF32x4, F32x4, F32x4, F32, U32, ) OPCODE(CompositeInsertF32x4, F32x4, F32x4, F32, U32, )
OPCODE(CompositeShuffleF32x2, F32x2, F32x2, F32x2, U32, U32, )
OPCODE(CompositeShuffleF32x3, F32x3, F32x3, F32x3, U32, U32, U32, )
OPCODE(CompositeShuffleF32x4, F32x4, F32x4, F32x4, U32, U32, U32, U32, )
OPCODE(CompositeConstructF64x2, F64x2, F64, F64, ) OPCODE(CompositeConstructF64x2, F64x2, F64, F64, )
OPCODE(CompositeConstructF64x3, F64x3, F64, F64, F64, ) OPCODE(CompositeConstructF64x3, F64x3, F64, F64, F64, )
OPCODE(CompositeConstructF64x4, F64x4, F64, F64, F64, F64, ) OPCODE(CompositeConstructF64x4, F64x4, F64, F64, F64, F64, )
@ -149,6 +158,9 @@ OPCODE(CompositeExtractF64x4, F64, F64x
OPCODE(CompositeInsertF64x2, F64x2, F64x2, F64, U32, ) OPCODE(CompositeInsertF64x2, F64x2, F64x2, F64, U32, )
OPCODE(CompositeInsertF64x3, F64x3, F64x3, F64, U32, ) OPCODE(CompositeInsertF64x3, F64x3, F64x3, F64, U32, )
OPCODE(CompositeInsertF64x4, F64x4, F64x4, F64, U32, ) OPCODE(CompositeInsertF64x4, F64x4, F64x4, F64, U32, )
OPCODE(CompositeShuffleF64x2, F64x2, F64x2, F64x2, U32, U32, )
OPCODE(CompositeShuffleF64x3, F64x3, F64x3, F64x3, U32, U32, U32, )
OPCODE(CompositeShuffleF64x4, F64x4, F64x4, F64x4, U32, U32, U32, U32, )
// Select operations // Select operations
OPCODE(SelectU1, U1, U1, U1, U1, ) OPCODE(SelectU1, U1, U1, U1, U1, )

View File

@ -8,6 +8,7 @@
#include "shader_recompiler/ir/breadth_first_search.h" #include "shader_recompiler/ir/breadth_first_search.h"
#include "shader_recompiler/ir/ir_emitter.h" #include "shader_recompiler/ir/ir_emitter.h"
#include "shader_recompiler/ir/program.h" #include "shader_recompiler/ir/program.h"
#include "shader_recompiler/ir/reinterpret.h"
#include "video_core/amdgpu/resource.h" #include "video_core/amdgpu/resource.h"
namespace Shader::Optimization { namespace Shader::Optimization {
@ -128,13 +129,6 @@ bool IsImageInstruction(const IR::Inst& inst) {
} }
} }
IR::Value SwizzleVector(IR::IREmitter& ir, auto sharp, IR::Value texel) {
const std::array components = sharp.DstSelect().template Apply<IR::Value>(
[&](const u32 index) { return ir.CompositeExtract(texel, index); },
[&](const u32 imm) { return ir.Imm32(float(imm)); });
return ir.CompositeConstruct(components[0], components[1], components[2], components[3]);
};
class Descriptors { class Descriptors {
public: public:
explicit Descriptors(Info& info_) explicit Descriptors(Info& info_)
@ -387,15 +381,6 @@ void PatchTextureBufferInstruction(IR::Block& block, IR::Inst& inst, Info& info,
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
inst.SetArg(0, ir.Imm32(binding)); inst.SetArg(0, ir.Imm32(binding));
ASSERT(!buffer.swizzle_enable && !buffer.add_tid_enable); ASSERT(!buffer.swizzle_enable && !buffer.add_tid_enable);
// Apply dst_sel swizzle on formatted buffer instructions
if (inst.GetOpcode() == IR::Opcode::StoreBufferFormatF32) {
inst.SetArg(2, SwizzleVector(ir, buffer, inst.Arg(2)));
} else {
const auto inst_info = inst.Flags<IR::BufferInstInfo>();
const auto texel = ir.LoadBufferFormat(inst.Arg(0), inst.Arg(1), inst_info);
inst.ReplaceUsesWith(SwizzleVector(ir, buffer, texel));
}
} }
IR::Value PatchCubeCoord(IR::IREmitter& ir, const IR::Value& s, const IR::Value& t, IR::Value PatchCubeCoord(IR::IREmitter& ir, const IR::Value& s, const IR::Value& t,
@ -743,10 +728,6 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
}(); }();
inst.SetArg(1, coords); inst.SetArg(1, coords);
if (inst.GetOpcode() == IR::Opcode::ImageWrite) {
inst.SetArg(4, SwizzleVector(ir, image, inst.Arg(4)));
}
if (inst_info.has_lod) { if (inst_info.has_lod) {
ASSERT(inst.GetOpcode() == IR::Opcode::ImageRead || ASSERT(inst.GetOpcode() == IR::Opcode::ImageRead ||
inst.GetOpcode() == IR::Opcode::ImageWrite); inst.GetOpcode() == IR::Opcode::ImageWrite);
@ -761,6 +742,47 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip
} }
} }
void PatchTextureBufferInterpretation(IR::Block& block, IR::Inst& inst, Info& info) {
const auto binding = inst.Arg(0).U32();
const auto buffer_res = info.texture_buffers[binding];
const auto buffer = buffer_res.GetSharp(info);
if (!buffer.Valid()) {
// Don't need to swizzle invalid buffer.
return;
}
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
if (inst.GetOpcode() == IR::Opcode::StoreBufferFormatF32) {
inst.SetArg(2, ApplySwizzle(ir, inst.Arg(2), buffer.DstSelect()));
} else if (inst.GetOpcode() == IR::Opcode::LoadBufferFormatF32) {
const auto inst_info = inst.Flags<IR::BufferInstInfo>();
const auto texel = ir.LoadBufferFormat(inst.Arg(0), inst.Arg(1), inst_info);
const auto swizzled = ApplySwizzle(ir, texel, buffer.DstSelect());
inst.ReplaceUsesWith(swizzled);
}
}
void PatchImageInterpretation(IR::Block& block, IR::Inst& inst, Info& info) {
const auto binding = inst.Arg(0).U32();
const auto image_res = info.images[binding & 0xFFFF];
const auto image = image_res.GetSharp(info);
if (!image.Valid() || !image_res.IsStorage(image)) {
// Don't need to swizzle invalid or non-storage image.
return;
}
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
if (inst.GetOpcode() == IR::Opcode::ImageWrite) {
inst.SetArg(4, ApplySwizzle(ir, inst.Arg(4), image.DstSelect()));
} else if (inst.GetOpcode() == IR::Opcode::ImageRead) {
const auto inst_info = inst.Flags<IR::TextureInstInfo>();
const auto texel = ir.ImageRead(inst.Arg(0), inst.Arg(1), IR::U32{inst.Arg(2)},
IR::U32{inst.Arg(3)}, inst_info);
const auto swizzled = ApplySwizzle(ir, texel, image.DstSelect());
inst.ReplaceUsesWith(swizzled);
}
}
void PatchDataRingInstruction(IR::Block& block, IR::Inst& inst, Info& info, void PatchDataRingInstruction(IR::Block& block, IR::Inst& inst, Info& info,
Descriptors& descriptors) { Descriptors& descriptors) {
// Insert gds binding in the shader if it doesn't exist already. // Insert gds binding in the shader if it doesn't exist already.
@ -830,6 +852,19 @@ void ResourceTrackingPass(IR::Program& program) {
} }
} }
} }
// Second pass to reinterpret format read/write where needed, since we now know
// the bindings and their properties.
for (IR::Block* const block : program.blocks) {
for (IR::Inst& inst : block->Instructions()) {
if (IsTextureBufferInstruction(inst)) {
PatchTextureBufferInterpretation(*block, inst, info);
continue;
}
if (IsImageInstruction(inst)) {
PatchImageInterpretation(*block, inst, info);
}
}
}
} }
} // namespace Shader::Optimization } // namespace Shader::Optimization

View File

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "shader_recompiler/ir/ir_emitter.h"
#include "video_core/amdgpu/resource.h"
namespace Shader::IR {
/// Applies a component swizzle to a vec4.
inline Value ApplySwizzle(IREmitter& ir, const Value& vector, const AmdGpu::CompMapping& swizzle) {
// Constants are indexed as 0 and 1, and components are 4-7. Thus we can apply a swizzle
// using two vectors and a shuffle, using one vector of constants and one of the components.
const auto zero = ir.Imm32(0.f);
const auto one = ir.Imm32(1.f);
const auto constants_vec = ir.CompositeConstruct(zero, one, zero, zero);
const auto swizzled =
ir.CompositeShuffle(constants_vec, vector, size_t(swizzle.r), size_t(swizzle.g),
size_t(swizzle.b), size_t(swizzle.a));
return swizzled;
}
} // namespace Shader::IR

View File

@ -912,24 +912,24 @@ struct Liverpool {
}}, }},
// Alternate // Alternate
std::array<CompMapping, 4>{{ std::array<CompMapping, 4>{{
{.r = CompSwizzle::Zero, .g = CompSwizzle::Red, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero}, {.r = CompSwizzle::Green, .g = CompSwizzle::Zero, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero},
{.r = CompSwizzle::Red, .g = CompSwizzle::Zero, .b = CompSwizzle::Zero, .a = CompSwizzle::Green}, {.r = CompSwizzle::Red, .g = CompSwizzle::Alpha, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero},
{.r = CompSwizzle::Red, .g = CompSwizzle::Green, .b = CompSwizzle::Zero, .a = CompSwizzle::Blue}, {.r = CompSwizzle::Red, .g = CompSwizzle::Green, .b = CompSwizzle::Alpha, .a = CompSwizzle::Zero},
{.r = CompSwizzle::Blue, .g = CompSwizzle::Green, .b = CompSwizzle::Red, .a = CompSwizzle::Alpha}, {.r = CompSwizzle::Blue, .g = CompSwizzle::Green, .b = CompSwizzle::Red, .a = CompSwizzle::Alpha},
}}, }},
// StandardReverse // StandardReverse
std::array<CompMapping, 4>{{ std::array<CompMapping, 4>{{
{CompSwizzle::Zero, CompSwizzle::Zero, CompSwizzle::Red, CompSwizzle::Zero}, {.r = CompSwizzle::Blue, .g = CompSwizzle::Zero, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero},
{CompSwizzle::Green, CompSwizzle::Red, CompSwizzle::Zero, CompSwizzle::Zero}, {.r = CompSwizzle::Green, .g = CompSwizzle::Red, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero},
{CompSwizzle::Blue, CompSwizzle::Green, CompSwizzle::Red, CompSwizzle::Zero}, {.r = CompSwizzle::Blue, .g = CompSwizzle::Green, .b = CompSwizzle::Red, .a = CompSwizzle::Zero},
{CompSwizzle::Alpha, CompSwizzle::Blue, CompSwizzle::Green, CompSwizzle::Red}, {.r = CompSwizzle::Alpha, .g = CompSwizzle::Blue, .b = CompSwizzle::Green, .a = CompSwizzle::Red},
}}, }},
// AlternateReverse // AlternateReverse
std::array<CompMapping, 4>{{ std::array<CompMapping, 4>{{
{CompSwizzle::Zero, CompSwizzle::Zero, CompSwizzle::Zero, CompSwizzle::Red}, {.r = CompSwizzle::Alpha, .g = CompSwizzle::Zero, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero},
{CompSwizzle::Green, CompSwizzle::Zero, CompSwizzle::Zero, CompSwizzle::Red}, {.r = CompSwizzle::Alpha, .g = CompSwizzle::Red, .b = CompSwizzle::Zero, .a = CompSwizzle::Zero},
{CompSwizzle::Blue, CompSwizzle::Green, CompSwizzle::Zero, CompSwizzle::Red}, {.r = CompSwizzle::Alpha, .g = CompSwizzle::Green, .b = CompSwizzle::Red, .a = CompSwizzle::Zero},
{CompSwizzle::Alpha, CompSwizzle::Red, CompSwizzle::Green, CompSwizzle::Blue}, {.r = CompSwizzle::Alpha, .g = CompSwizzle::Red, .b = CompSwizzle::Green, .a = CompSwizzle::Blue},
}}, }},
}}; }};
// clang-format on // clang-format on

View File

@ -3,7 +3,6 @@
#pragma once #pragma once
#include <functional>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_field.h" #include "common/bit_field.h"
@ -31,38 +30,30 @@ struct CompMapping {
template <typename T> template <typename T>
[[nodiscard]] std::array<T, 4> Apply(const std::array<T, 4>& data) const { [[nodiscard]] std::array<T, 4> Apply(const std::array<T, 4>& data) const {
return Apply<T>([&data](const u32 index) { return data[index]; },
[](const u32 imm) { return T(imm); });
}
template <typename T>
[[nodiscard]] std::array<T, 4> Apply(const std::function<T(u32)>& get_value,
const std::function<T(u32)>& get_immediate) const {
return { return {
ApplySingle(get_value, get_immediate, r), ApplySingle(data, r),
ApplySingle(get_value, get_immediate, g), ApplySingle(data, g),
ApplySingle(get_value, get_immediate, b), ApplySingle(data, b),
ApplySingle(get_value, get_immediate, a), ApplySingle(data, a),
}; };
} }
private: private:
template <typename T> template <typename T>
T ApplySingle(const std::function<T(u32)>& get_value, T ApplySingle(const std::array<T, 4>& data, const CompSwizzle swizzle) const {
const std::function<T(u32)>& get_immediate, const CompSwizzle swizzle) const {
switch (swizzle) { switch (swizzle) {
case CompSwizzle::Zero: case CompSwizzle::Zero:
return get_immediate(0); return T(0);
case CompSwizzle::One: case CompSwizzle::One:
return get_immediate(1); return T(1);
case CompSwizzle::Red: case CompSwizzle::Red:
return get_value(0); return data[0];
case CompSwizzle::Green: case CompSwizzle::Green:
return get_value(1); return data[1];
case CompSwizzle::Blue: case CompSwizzle::Blue:
return get_value(2); return data[2];
case CompSwizzle::Alpha: case CompSwizzle::Alpha:
return get_value(3); return data[3];
default: default:
UNREACHABLE(); UNREACHABLE();
} }