diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp index c75f43393..d4ff3ff69 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_convert.cpp @@ -271,4 +271,16 @@ Id EmitConvertU32U8(EmitContext& ctx, Id value) { return ctx.OpUConvert(ctx.U32[1], value); } +Id EmitConvertS32S8(EmitContext& ctx, Id value) { + const Id as_s8 = ctx.OpBitcast(ctx.S8, value); + const Id as_s32 = ctx.OpSConvert(ctx.S32[1], as_s8); + return ctx.OpBitcast(ctx.U32[1], as_s32); +} + +Id EmitConvertS32S16(EmitContext& ctx, Id value) { + const Id as_s16 = ctx.OpBitcast(ctx.S16, value); + const Id as_s32 = ctx.OpSConvert(ctx.S32[1], as_s16); + return ctx.OpBitcast(ctx.U32[1], as_s32); +} + } // namespace Shader::Backend::SPIRV diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 74c94754d..0ef3e72e3 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -488,6 +488,8 @@ Id EmitConvertU16U32(EmitContext& ctx, Id value); Id EmitConvertU32U16(EmitContext& ctx, Id value); Id EmitConvertU8U32(EmitContext& ctx, Id value); Id EmitConvertU32U8(EmitContext& ctx, Id value); +Id EmitConvertS32S8(EmitContext& ctx, Id value); +Id EmitConvertS32S16(EmitContext& ctx, Id value); Id EmitImageSampleRaw(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address1, Id address2, Id address3, Id address4); diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index 4b5ff827b..637863530 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -280,9 +280,10 @@ public: // Buffer Memory // MUBUF / MTBUF - void BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst); - void BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, - const GcnInst& inst); + void BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst, + u32 scalar_width = 32, bool is_signed = false); + void BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst, + u32 scalar_width = 32); template void BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst); diff --git a/src/shader_recompiler/frontend/translate/vector_memory.cpp b/src/shader_recompiler/frontend/translate/vector_memory.cpp index df20f7f73..f4f0b994e 100644 --- a/src/shader_recompiler/frontend/translate/vector_memory.cpp +++ b/src/shader_recompiler/frontend/translate/vector_memory.cpp @@ -28,6 +28,15 @@ void Translator::EmitVectorMemory(const GcnInst& inst) { case Opcode::BUFFER_LOAD_FORMAT_XYZW: return BUFFER_LOAD(4, false, true, inst); + case Opcode::BUFFER_LOAD_UBYTE: + return BUFFER_LOAD(1, false, false, inst, 8, false); + case Opcode::BUFFER_LOAD_SBYTE: + return BUFFER_LOAD(1, false, false, inst, 8, true); + case Opcode::BUFFER_LOAD_USHORT: + return BUFFER_LOAD(1, false, false, inst, 16, false); + case Opcode::BUFFER_LOAD_SSHORT: + return BUFFER_LOAD(1, false, false, inst, 16, true); + case Opcode::BUFFER_LOAD_DWORD: return BUFFER_LOAD(1, false, false, inst); case Opcode::BUFFER_LOAD_DWORDX2: @@ -56,6 +65,11 @@ void Translator::EmitVectorMemory(const GcnInst& inst) { case Opcode::TBUFFER_STORE_FORMAT_XYZW: return BUFFER_STORE(4, true, false, inst); + case Opcode::BUFFER_STORE_BYTE: + return BUFFER_STORE(1, false, false, inst, 8); + case Opcode::BUFFER_STORE_SHORT: + return BUFFER_STORE(1, false, false, inst, 16); + case Opcode::BUFFER_STORE_DWORD: return BUFFER_STORE(1, false, false, inst); case Opcode::BUFFER_STORE_DWORDX2: @@ -186,7 +200,7 @@ void Translator::EmitVectorMemory(const GcnInst& inst) { } void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, - const GcnInst& inst) { + const GcnInst& inst, u32 scalar_width, bool is_signed) { const auto& mubuf = inst.control.mubuf; const bool is_ring = mubuf.glc && mubuf.slc; const IR::VectorReg vaddr{inst.src[0].code}; @@ -242,7 +256,28 @@ void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_ ir.SetVectorReg(dst_reg + i, IR::F32{ir.CompositeExtract(value, i)}); } } else { - const IR::Value value = ir.LoadBufferU32(num_dwords, handle, address, buffer_info); + IR::Value value; + switch (scalar_width) { + case 8: + value = ir.LoadBufferU8(handle, address, buffer_info); + if (is_signed) { + value = ir.SConvert(32, IR::U8{value}); + } + break; + case 16: + value = ir.LoadBufferU16(handle, address, buffer_info); + if (is_signed) { + value = ir.SConvert(32, IR::U16{value}); + } + break; + case 32: + value = ir.LoadBufferU32(num_dwords, handle, address, buffer_info); + break; + + default: + UNREACHABLE(); + } + if (num_dwords == 1) { ir.SetVectorReg(dst_reg, IR::U32{value}); return; @@ -254,7 +289,7 @@ void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_ } void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, - const GcnInst& inst) { + const GcnInst& inst, u32 scalar_width) { const auto& mubuf = inst.control.mubuf; const bool is_ring = mubuf.glc && mubuf.slc; const IR::VectorReg vaddr{inst.src[0].code}; @@ -314,8 +349,23 @@ void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer } ir.StoreBufferFormat(handle, address, ir.CompositeConstruct(comps), buffer_info); } else { - const auto value = num_dwords == 1 ? comps[0] : ir.CompositeConstruct(comps); - ir.StoreBufferU32(num_dwords, handle, address, value, buffer_info); + IR::Value value = num_dwords == 1 ? comps[0] : ir.CompositeConstruct(comps); + if (scalar_width != 32) { + value = ir.UConvert(scalar_width, IR::U32{value}); + } + switch (scalar_width) { + case 8: + ir.StoreBufferU8(handle, address, IR::U8{value}, buffer_info); + break; + case 16: + ir.StoreBufferU16(handle, address, IR::U16{value}, buffer_info); + break; + case 32: + ir.StoreBufferU32(num_dwords, handle, address, value, buffer_info); + break; + default: + UNREACHABLE(); + } } } diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index 4997145d7..51de9633d 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -1979,6 +1979,24 @@ U8U16U32U64 IREmitter::UConvert(size_t result_bitsize, const U8U16U32U64& value) throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize); } +U8U16U32U64 IR::IREmitter::SConvert(size_t result_bitsize, const U8U16U32U64& value) { + switch (result_bitsize) { + case 32: + switch (value.Type()) { + case Type::U8: + return Inst(Opcode::ConvertS32S8, value); + case Type::U16: + return Inst(Opcode::ConvertS32S16, value); + default: + break; + } + default: + break; + } + throw NotImplementedException("Signed Conversion from {} to {} bits", value.Type(), + result_bitsize); +} + F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) { switch (result_bitsize) { case 16: diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 6055df565..84599e038 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -326,6 +326,7 @@ public: const Value& value); [[nodiscard]] U8U16U32U64 UConvert(size_t result_bitsize, const U8U16U32U64& value); + [[nodiscard]] U8U16U32U64 SConvert(size_t result_bitsize, const U8U16U32U64& value); [[nodiscard]] F16F32F64 FPConvert(size_t result_bitsize, const F16F32F64& value); [[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords, diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 747a27e35..280cd47ec 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -432,6 +432,8 @@ OPCODE(ConvertU16U32, U16, U32, OPCODE(ConvertU32U16, U32, U16, ) OPCODE(ConvertU8U32, U8, U32, ) OPCODE(ConvertU32U8, U32, U8, ) +OPCODE(ConvertS32S8, U32, U8, ) +OPCODE(ConvertS32S16, U32, U16, ) // Image operations OPCODE(ImageSampleRaw, F32x4, Opaque, F32x4, F32x4, F32x4, F32, Opaque, )