diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp index 157e5dfaaf..8b5a103006 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp @@ -271,40 +271,4 @@ void TranslatorVisitor::ResetOFlag() { SetOFlag(ir.Imm1(false)); } -IR::U32 TranslatorVisitor::apply_ISBERD_shift(IR::U32 result, Isberd::Shift shift_value) { - if (shift_value != Isberd::Shift::Default) { - return ir.ShiftLeftLogical(result, ir.Imm32(1)); - } - return result; -} - -IR::U32 TranslatorVisitor::apply_ISBERD_size_read(IR::U32 address, Isberd::SZ sz) { - switch (sz) { - case Isberd::SZ::U8: - return ir.LoadGlobalU8(ir.UConvert(64, address)); - case Isberd::SZ::U16: - return ir.LoadGlobalU16(ir.UConvert(64, address)); - case Isberd::SZ::U32: - case Isberd::SZ::F32: - return ir.LoadGlobal32(ir.UConvert(64, address)); - default: - UNREACHABLE(); - } -} - -IR::U32 TranslatorVisitor::compute_ISBERD_address(IR::Reg src_reg, u32 src_reg_num, u32 imm, u64 skew_value) { - IR::U32 address{}; - if (src_reg_num == 0xFF) { - address = ir.Imm32(imm); - } else { - auto offset = ir.Imm32(imm); - address = ir.IAdd(X(src_reg), offset); - if (skew_value != 0) { - address = ir.IAdd(address, ir.LaneId()); - } - } - - return address; -}; - } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h index 1b2547a1bd..37963dc777 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/impl.h @@ -56,30 +56,6 @@ enum class FPCompareOp : u64 { T, }; -namespace Isberd { -enum class Mode : u64 { - Default, - Patch, - Prim, - Attr, -}; - -enum class Shift : u64 { - Default, - U16, - B32, -}; - -enum class SZ : u64 { - U8, - U16, - U32, - F32, -}; - -} // namespace Isberd - - class TranslatorVisitor { public: explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_}, ir(block) {} @@ -408,12 +384,6 @@ public: void ResetSFlag(); void ResetCFlag(); void ResetOFlag(); - -private: - // Helper functions for various translator visitors - IR::U32 apply_ISBERD_shift(IR::U32 result, Isberd::Shift shift_value); - IR::U32 apply_ISBERD_size_read(IR::U32 address, Isberd::SZ sz_value); - IR::U32 compute_ISBERD_address(IR::Reg src_reg, u32 src_reg_num, u32 imm, u64 skew_value); }; } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/internal_stage_buffer_entry_read.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/internal_stage_buffer_entry_read.cpp index 2aaf85772d..e6345de65e 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/internal_stage_buffer_entry_read.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/internal_stage_buffer_entry_read.cpp @@ -9,9 +9,52 @@ #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" namespace Shader::Maxwell { +namespace { +enum class Mode : u64 { + Default, + Patch, + Prim, + Attr, +}; + +enum class SZ : u64 { + U8, + U16, + U32, + F32 +}; + +enum class Shift : u64 { + Default, + U16, + B32, +}; + +IR::U32 scaleIndex(IR::IREmitter& ir, IR::U32 index, Shift shift) { + switch (shift) { + case Shift::Default: return index; + case Shift::U16: return ir.ShiftLeftLogical(index, ir.Imm32(1)); + case Shift::B32: return ir.ShiftLeftLogical(index, ir.Imm32(2)); + default: UNREACHABLE(); + } +} + +IR::U32 skewBytes(IR::IREmitter& ir, SZ sizeRead) { + const IR::U32 lane = ir.LaneId(); + switch (sizeRead) { + case SZ::U8: return lane; + case SZ::U16: return ir.ShiftLeftLogical(lane, ir.Imm32(1)); + case SZ::U32: + case SZ::F32: return ir.ShiftLeftLogical(lane, ir.Imm32(2)); + default: UNREACHABLE(); + } +} + +} // Anonymous namespace -// Valid only for GS, TI, VS and trap void TranslatorVisitor::ISBERD(u64 insn) { + LOG_DEBUG(Shader, "called with insn={:#X}", insn); + union { u64 raw; BitField<0, 8, IR::Reg> dest_reg; @@ -20,49 +63,66 @@ void TranslatorVisitor::ISBERD(u64 insn) { BitField<24, 8, u32> imm; BitField<31, 1, u64> skew; BitField<32, 1, u64> o; - BitField<33, 2, Isberd::Mode> mode; - BitField<36, 4, Isberd::SZ> sz; - BitField<47, 2, Isberd::Shift> shift; + BitField<33, 2, Mode> mode; + BitField<36, 4, SZ> sz; + BitField<47, 2, Shift> shift; } const isberd{insn}; - auto address = compute_ISBERD_address(isberd.src_reg, isberd.src_reg_num, isberd.imm, isberd.skew); - if (isberd.o != 0) { - auto result = apply_ISBERD_size_read(address, isberd.sz.Value()); - X(isberd.dest_reg, apply_ISBERD_shift(result, isberd.shift.Value())); - - return; + IR::U32 index{}; + if (isberd.src_reg_num.Value() == 0xFF) { + index = ir.Imm32(isberd.imm.Value()); + } else { + const IR::U32 scaledIndex = scaleIndex(ir, X(isberd.src_reg.Value()), isberd.shift.Value()); + index = ir.IAdd(scaledIndex, ir.Imm32(isberd.imm.Value())); } - if (isberd.mode != Isberd::Mode::Default) { - IR::F32 result_f32{}; - switch (isberd.mode.Value()) { - case Isberd::Mode::Patch: - result_f32 = ir.GetPatch(address.Patch()); - break; - case Isberd::Mode::Prim: - result_f32 = ir.GetAttribute(address.Attribute()); - break; - case Isberd::Mode::Attr: - result_f32 = ir.GetAttributeIndexed(address); - break; - default: - UNREACHABLE(); + if (isberd.o.Value()) { + if (isberd.skew.Value()) { + index = ir.IAdd(index, skewBytes(ir, isberd.sz.Value())); } - auto result_u32 = ir.BitCast(result_f32); - X(isberd.dest_reg, apply_ISBERD_shift(result_u32, isberd.shift.Value())); - return; - } - - if (isberd.skew != 0) { - auto result = ir.IAdd(X(isberd.src_reg), ir.LaneId()); - X(isberd.dest_reg, result); + const IR::U64 index64 = ir.UConvert(64, index); + IR::U32 globalLoaded{}; + switch (isberd.sz.Value()) { + case SZ::U8: globalLoaded = ir.LoadGlobalU8 (index64); break; + case SZ::U16: globalLoaded = ir.LoadGlobalU16(index64); break; + case SZ::U32: + case SZ::F32: globalLoaded = ir.LoadGlobal32(index64); break; + default: UNREACHABLE(); + } + X(isberd.dest_reg.Value(), globalLoaded); return; } - // Fallback if nothing else applies - X(isberd.dest_reg, X(isberd.src_reg)); + if (isberd.mode.Value() != Mode::Default) { + if (isberd.skew.Value()) { + index = ir.IAdd(index, skewBytes(ir, SZ::U32)); + } + + IR::F32 float_index{}; + switch (isberd.mode.Value()) { + case Mode::Patch: float_index = ir.GetPatch(index.Patch()); + break; + case Mode::Prim: float_index = ir.GetAttribute(index.Attribute()); + break; + case Mode::Attr: float_index = ir.GetAttributeIndexed(index); + break; + default: UNREACHABLE(); + } + X(isberd.dest_reg.Value(), ir.BitCast(float_index)); + + return; + } + + if (isberd.skew.Value()) { + X(isberd.dest_reg.Value(), ir.IAdd(X(isberd.src_reg.Value()), ir.LaneId())); + + return; + } + + // Fallback copy + X(isberd.dest_reg.Value(), X(isberd.src_reg.Value())); } } // namespace Shader::Maxwell