forked from eden-emu/eden
		
	shader: Implement F2F
This commit is contained in:
		
							parent
							
								
									8b3b9c3371
								
							
						
					
					
						commit
						a62f04efab
					
				
					 6 changed files with 192 additions and 20 deletions
				
			
		|  | @ -72,6 +72,7 @@ add_library(shader_recompiler STATIC | |||
|     frontend/maxwell/translate/impl/floating_point_add.cpp | ||||
|     frontend/maxwell/translate/impl/floating_point_compare.cpp | ||||
|     frontend/maxwell/translate/impl/floating_point_compare_and_set.cpp | ||||
|     frontend/maxwell/translate/impl/floating_point_conversion_floating_point.cpp | ||||
|     frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp | ||||
|     frontend/maxwell/translate/impl/floating_point_fused_multiply_add.cpp | ||||
|     frontend/maxwell/translate/impl/floating_point_min_max.cpp | ||||
|  |  | |||
|  | @ -1361,7 +1361,7 @@ U32U64 IREmitter::UConvert(size_t result_bitsize, const U32U64& value) { | |||
|     throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize); | ||||
| } | ||||
| 
 | ||||
| F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) { | ||||
| F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value, FpControl control) { | ||||
|     switch (result_bitsize) { | ||||
|     case 16: | ||||
|         switch (value.Type()) { | ||||
|  | @ -1369,7 +1369,7 @@ F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) { | |||
|             // Nothing to do
 | ||||
|             return value; | ||||
|         case Type::F32: | ||||
|             return Inst<F16>(Opcode::ConvertF16F32, value); | ||||
|             return Inst<F16>(Opcode::ConvertF16F32, Flags{control}, value); | ||||
|         case Type::F64: | ||||
|             throw LogicError("Illegal conversion from F64 to F16"); | ||||
|         default: | ||||
|  | @ -1379,12 +1379,12 @@ F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) { | |||
|     case 32: | ||||
|         switch (value.Type()) { | ||||
|         case Type::F16: | ||||
|             return Inst<F32>(Opcode::ConvertF32F16, value); | ||||
|             return Inst<F32>(Opcode::ConvertF32F16, Flags{control}, value); | ||||
|         case Type::F32: | ||||
|             // Nothing to do
 | ||||
|             return value; | ||||
|         case Type::F64: | ||||
|             return Inst<F64>(Opcode::ConvertF32F64, value); | ||||
|             return Inst<F32>(Opcode::ConvertF32F64, Flags{control}, value); | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|  | @ -1394,10 +1394,10 @@ F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) { | |||
|         case Type::F16: | ||||
|             throw LogicError("Illegal conversion from F16 to F64"); | ||||
|         case Type::F32: | ||||
|             return Inst<F64>(Opcode::ConvertF64F32, Flags{control}, value); | ||||
|         case Type::F64: | ||||
|             // Nothing to do
 | ||||
|             return value; | ||||
|         case Type::F64: | ||||
|             return Inst<F64>(Opcode::ConvertF32F64, value); | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|  |  | |||
|  | @ -216,7 +216,8 @@ public: | |||
|                                         const Value& value); | ||||
| 
 | ||||
|     [[nodiscard]] U32U64 UConvert(size_t result_bitsize, const U32U64& value); | ||||
|     [[nodiscard]] F16F32F64 FPConvert(size_t result_bitsize, const F16F32F64& value); | ||||
|     [[nodiscard]] F16F32F64 FPConvert(size_t result_bitsize, const F16F32F64& value, | ||||
|                                       FpControl control = {}); | ||||
| 
 | ||||
|     [[nodiscard]] Value ImageSampleImplicitLod(const Value& handle, const Value& coords, | ||||
|                                                const F32& bias, const Value& offset, | ||||
|  |  | |||
|  | @ -0,0 +1,180 @@ | |||
| // Copyright 2021 yuzu Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "shader_recompiler/frontend/maxwell/translate/impl/common_encoding.h" | ||||
| #include "shader_recompiler/frontend/maxwell/translate/impl/half_floating_point_helper.h" | ||||
| 
 | ||||
| namespace Shader::Maxwell { | ||||
| namespace { | ||||
| enum class FloatFormat : u64 { | ||||
|     F16 = 1, | ||||
|     F32 = 2, | ||||
|     F64 = 3, | ||||
| }; | ||||
| 
 | ||||
| enum class RoundingOp : u64 { | ||||
|     None = 0, | ||||
|     Pass = 3, | ||||
|     Round = 8, | ||||
|     Floor = 9, | ||||
|     Ceil = 10, | ||||
|     Trunc = 11, | ||||
| }; | ||||
| 
 | ||||
| [[nodiscard]] u32 WidthSize(FloatFormat width) { | ||||
|     switch (width) { | ||||
|     case FloatFormat::F16: | ||||
|         return 16; | ||||
|     case FloatFormat::F32: | ||||
|         return 32; | ||||
|     case FloatFormat::F64: | ||||
|         return 64; | ||||
|     default: | ||||
|         throw NotImplementedException("Invalid width {}", width); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void F2F(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a, bool abs) { | ||||
|     union { | ||||
|         u64 insn; | ||||
|         BitField<0, 8, IR::Reg> dest_reg; | ||||
|         BitField<44, 1, u64> ftz; | ||||
|         BitField<45, 1, u64> neg; | ||||
|         BitField<50, 1, u64> sat; | ||||
|         BitField<39, 4, u64> rounding_op; | ||||
|         BitField<39, 2, FpRounding> rounding; | ||||
|         BitField<10, 2, FloatFormat> src_size; | ||||
|         BitField<8, 2, FloatFormat> dst_size; | ||||
| 
 | ||||
|         [[nodiscard]] RoundingOp RoundingOperation() const { | ||||
|             constexpr u64 rounding_mask = 0x0B; | ||||
|             return static_cast<RoundingOp>(rounding_op.Value() & rounding_mask); | ||||
|         } | ||||
|     } const f2f{insn}; | ||||
| 
 | ||||
|     IR::F16F32F64 input{v.ir.FPAbsNeg(src_a, abs, f2f.neg != 0)}; | ||||
| 
 | ||||
|     const bool any_fp64{f2f.src_size == FloatFormat::F64 || f2f.dst_size == FloatFormat::F64}; | ||||
|     IR::FpControl fp_control{ | ||||
|         .no_contraction{false}, | ||||
|         .rounding{IR::FpRounding::DontCare}, | ||||
|         .fmz_mode{f2f.ftz != 0 && !any_fp64 ? IR::FmzMode::FTZ : IR::FmzMode::None}, | ||||
|     }; | ||||
|     if (f2f.src_size != f2f.dst_size) { | ||||
|         fp_control.rounding = CastFpRounding(f2f.rounding); | ||||
|         input = v.ir.FPConvert(WidthSize(f2f.dst_size), input, fp_control); | ||||
|     } else { | ||||
|         switch (f2f.RoundingOperation()) { | ||||
|         case RoundingOp::None: | ||||
|         case RoundingOp::Pass: | ||||
|             // Make sure NANs are handled properly
 | ||||
|             switch (f2f.src_size) { | ||||
|             case FloatFormat::F16: | ||||
|                 input = v.ir.FPAdd(input, v.ir.FPConvert(16, v.ir.Imm32(0.0f)), fp_control); | ||||
|                 break; | ||||
|             case FloatFormat::F32: | ||||
|                 input = v.ir.FPAdd(input, v.ir.Imm32(0.0f), fp_control); | ||||
|                 break; | ||||
|             case FloatFormat::F64: | ||||
|                 input = v.ir.FPAdd(input, v.ir.Imm64(0.0), fp_control); | ||||
|                 break; | ||||
|             } | ||||
|             break; | ||||
|         case RoundingOp::Round: | ||||
|             input = v.ir.FPRoundEven(input, fp_control); | ||||
|             break; | ||||
|         case RoundingOp::Floor: | ||||
|             input = v.ir.FPFloor(input, fp_control); | ||||
|             break; | ||||
|         case RoundingOp::Ceil: | ||||
|             input = v.ir.FPCeil(input, fp_control); | ||||
|             break; | ||||
|         case RoundingOp::Trunc: | ||||
|             input = v.ir.FPTrunc(input, fp_control); | ||||
|             break; | ||||
|         default: | ||||
|             throw NotImplementedException("Unimplemented rounding mode {}", f2f.rounding.Value()); | ||||
|         } | ||||
|     } | ||||
|     if (f2f.sat != 0 && !any_fp64) { | ||||
|         input = v.ir.FPSaturate(input); | ||||
|     } | ||||
| 
 | ||||
|     switch (f2f.dst_size) { | ||||
|     case FloatFormat::F16: { | ||||
|         const IR::F16 imm{v.ir.FPConvert(16, v.ir.Imm32(0.0f))}; | ||||
|         v.X(f2f.dest_reg, v.ir.PackFloat2x16(v.ir.CompositeConstruct(input, imm))); | ||||
|         break; | ||||
|     } | ||||
|     case FloatFormat::F32: | ||||
|         v.F(f2f.dest_reg, input); | ||||
|         break; | ||||
|     case FloatFormat::F64: | ||||
|         v.D(f2f.dest_reg, input); | ||||
|         break; | ||||
|     default: | ||||
|         throw NotImplementedException("Invalid dest format {}", f2f.dst_size.Value()); | ||||
|     } | ||||
| } | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| void TranslatorVisitor::F2F_reg(u64 insn) { | ||||
|     union { | ||||
|         u64 insn; | ||||
|         BitField<49, 1, u64> abs; | ||||
|         BitField<10, 2, FloatFormat> src_size; | ||||
|         BitField<41, 1, u64> selector; | ||||
|     } const f2f{insn}; | ||||
| 
 | ||||
|     IR::F16F32F64 src_a; | ||||
|     switch (f2f.src_size) { | ||||
|     case FloatFormat::F16: { | ||||
|         auto [lhs_a, rhs_a]{Extract(ir, GetReg20(insn), Swizzle::H1_H0)}; | ||||
|         src_a = f2f.selector != 0 ? rhs_a : lhs_a; | ||||
|         break; | ||||
|     } | ||||
|     case FloatFormat::F32: | ||||
|         src_a = GetFloatReg20(insn); | ||||
|         break; | ||||
|     case FloatFormat::F64: | ||||
|         src_a = GetDoubleReg20(insn); | ||||
|         break; | ||||
|     default: | ||||
|         throw NotImplementedException("Invalid dest format {}", f2f.src_size.Value()); | ||||
|     } | ||||
|     F2F(*this, insn, src_a, f2f.abs != 0); | ||||
| } | ||||
| 
 | ||||
| void TranslatorVisitor::F2F_cbuf(u64 insn) { | ||||
|     union { | ||||
|         u64 insn; | ||||
|         BitField<49, 1, u64> abs; | ||||
|         BitField<10, 2, FloatFormat> src_size; | ||||
|         BitField<41, 1, u64> selector; | ||||
|     } const f2f{insn}; | ||||
| 
 | ||||
|     IR::F16F32F64 src_a; | ||||
|     switch (f2f.src_size) { | ||||
|     case FloatFormat::F16: { | ||||
|         auto [lhs_a, rhs_a]{Extract(ir, GetCbuf(insn), Swizzle::H1_H0)}; | ||||
|         src_a = f2f.selector != 0 ? rhs_a : lhs_a; | ||||
|         break; | ||||
|     } | ||||
|     case FloatFormat::F32: | ||||
|         src_a = GetFloatCbuf(insn); | ||||
|         break; | ||||
|     case FloatFormat::F64: | ||||
|         src_a = GetDoubleCbuf(insn); | ||||
|         break; | ||||
|     default: | ||||
|         throw NotImplementedException("Invalid dest format {}", f2f.src_size.Value()); | ||||
|     } | ||||
|     F2F(*this, insn, src_a, f2f.abs != 0); | ||||
| } | ||||
| 
 | ||||
| void TranslatorVisitor::F2F_imm([[maybe_unused]] u64 insn) { | ||||
|     throw NotImplementedException("Instruction"); | ||||
| } | ||||
| 
 | ||||
| } // namespace Shader::Maxwell
 | ||||
|  | @ -117,18 +117,6 @@ void TranslatorVisitor::DSETP_imm(u64) { | |||
|     ThrowNotImplemented(Opcode::DSETP_imm); | ||||
| } | ||||
| 
 | ||||
| void TranslatorVisitor::F2F_reg(u64) { | ||||
|     ThrowNotImplemented(Opcode::F2F_reg); | ||||
| } | ||||
| 
 | ||||
| void TranslatorVisitor::F2F_cbuf(u64) { | ||||
|     ThrowNotImplemented(Opcode::F2F_cbuf); | ||||
| } | ||||
| 
 | ||||
| void TranslatorVisitor::F2F_imm(u64) { | ||||
|     ThrowNotImplemented(Opcode::F2F_imm); | ||||
| } | ||||
| 
 | ||||
| void TranslatorVisitor::FCHK_reg(u64) { | ||||
|     ThrowNotImplemented(Opcode::FCHK_reg); | ||||
| } | ||||
|  |  | |||
|  | @ -404,7 +404,9 @@ void VisitFpModifiers(Info& info, IR::Inst& inst) { | |||
|     case IR::Opcode::FPOrdLessThanEqual32: | ||||
|     case IR::Opcode::FPUnordLessThanEqual32: | ||||
|     case IR::Opcode::FPOrdGreaterThanEqual32: | ||||
|     case IR::Opcode::FPUnordGreaterThanEqual32: { | ||||
|     case IR::Opcode::FPUnordGreaterThanEqual32: | ||||
|     case IR::Opcode::ConvertF16F32: | ||||
|     case IR::Opcode::ConvertF64F32: { | ||||
|         const auto control{inst.Flags<IR::FpControl>()}; | ||||
|         switch (control.fmz_mode) { | ||||
|         case IR::FmzMode::DontCare: | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 FernandoS27
						FernandoS27