shader_ir/decode: Implement half float saturation
This commit is contained in:
		| @@ -617,13 +617,11 @@ private: | ||||
|     } | ||||
|  | ||||
|     std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) { | ||||
|         std::string value = VisitOperand(operation, operand_index); | ||||
|         const std::string value = VisitOperand(operation, operand_index); | ||||
|         switch (type) { | ||||
|         case Type::HalfFloat: { | ||||
|             const auto half_meta = std::get_if<MetaHalfArithmetic>(&operation.GetMeta()); | ||||
|             if (!half_meta) { | ||||
|                 value = "toHalf2(" + value + ')'; | ||||
|             } | ||||
|             ASSERT(half_meta); | ||||
|  | ||||
|             switch (half_meta->types.at(operand_index)) { | ||||
|             case Tegra::Shader::HalfType::H0_H1: | ||||
| @@ -1067,6 +1065,14 @@ private: | ||||
|         return BitwiseCastResult(value, Type::HalfFloat); | ||||
|     } | ||||
|  | ||||
|     std::string HClamp(Operation operation) { | ||||
|         const std::string value = VisitOperand(operation, 0, Type::HalfFloat); | ||||
|         const std::string min = VisitOperand(operation, 1, Type::Float); | ||||
|         const std::string max = VisitOperand(operation, 2, Type::Float); | ||||
|         const std::string clamped = "clamp(" + value + ", vec2(" + min + "), vec2(" + max + "))"; | ||||
|         return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat)); | ||||
|     } | ||||
|  | ||||
|     std::string HMergeF32(Operation operation) { | ||||
|         return "float(toHalf2(" + Visit(operation[0]) + ")[0])"; | ||||
|     } | ||||
| @@ -1501,6 +1507,7 @@ private: | ||||
|         &GLSLDecompiler::Fma<Type::HalfFloat>, | ||||
|         &GLSLDecompiler::Absolute<Type::HalfFloat>, | ||||
|         &GLSLDecompiler::HNegate, | ||||
|         &GLSLDecompiler::HClamp, | ||||
|         &GLSLDecompiler::HMergeF32, | ||||
|         &GLSLDecompiler::HMergeH0, | ||||
|         &GLSLDecompiler::HMergeH1, | ||||
|   | ||||
| @@ -744,6 +744,11 @@ private: | ||||
|         return {}; | ||||
|     } | ||||
|  | ||||
|     Id HClamp(Operation operation) { | ||||
|         UNIMPLEMENTED(); | ||||
|         return {}; | ||||
|     } | ||||
|  | ||||
|     Id HMergeF32(Operation operation) { | ||||
|         UNIMPLEMENTED(); | ||||
|         return {}; | ||||
| @@ -1216,6 +1221,7 @@ private: | ||||
|         &SPIRVDecompiler::Ternary<&Module::OpFma, Type::HalfFloat>, | ||||
|         &SPIRVDecompiler::Unary<&Module::OpFAbs, Type::HalfFloat>, | ||||
|         &SPIRVDecompiler::HNegate, | ||||
|         &SPIRVDecompiler::HClamp, | ||||
|         &SPIRVDecompiler::HMergeF32, | ||||
|         &SPIRVDecompiler::HMergeH0, | ||||
|         &SPIRVDecompiler::HMergeH1, | ||||
|   | ||||
| @@ -23,8 +23,6 @@ u32 ShaderIR::DecodeArithmeticHalfImmediate(NodeBlock& bb, u32 pc) { | ||||
|     } else { | ||||
|         UNIMPLEMENTED_IF(instr.alu_half_imm.precision != Tegra::Shader::HalfPrecision::None); | ||||
|     } | ||||
|     UNIMPLEMENTED_IF_MSG(instr.alu_half_imm.saturate != 0, | ||||
|                          "Half float immediate saturation not implemented"); | ||||
|  | ||||
|     Node op_a = GetRegister(instr.gpr8); | ||||
|     op_a = GetOperandAbsNegHalf(op_a, instr.alu_half_imm.abs_a, instr.alu_half_imm.negate_a); | ||||
| @@ -43,10 +41,10 @@ u32 ShaderIR::DecodeArithmeticHalfImmediate(NodeBlock& bb, u32 pc) { | ||||
|             return Immediate(0); | ||||
|         } | ||||
|     }(); | ||||
|  | ||||
|     value = GetSaturatedHalfFloat(value, instr.alu_half_imm.saturate); | ||||
|     value = HalfMerge(GetRegister(instr.gpr0), value, instr.alu_half_imm.merge); | ||||
|  | ||||
|     SetRegister(bb, instr.gpr0, value); | ||||
|  | ||||
|     return pc; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -218,6 +218,15 @@ Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) { | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) { | ||||
|     if (!saturate) { | ||||
|         return value; | ||||
|     } | ||||
|     const Node positive_zero = Immediate(std::copysignf(0, 1)); | ||||
|     const Node positive_one = Immediate(1.0f); | ||||
|     return Operation(OperationCode::HClamp, HALF_NO_PRECISE, value, positive_zero, positive_one); | ||||
| } | ||||
|  | ||||
| Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) { | ||||
|     const std::unordered_map<PredCondition, OperationCode> PredicateComparisonTable = { | ||||
|         {PredCondition::LessThan, OperationCode::LogicalFLessThan}, | ||||
|   | ||||
| @@ -114,6 +114,7 @@ enum class OperationCode { | ||||
|     HFma,      /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b, f16vec2 c) -> f16vec2 | ||||
|     HAbsolute, /// (f16vec2 a) -> f16vec2 | ||||
|     HNegate,   /// (f16vec2 a, bool first, bool second) -> f16vec2 | ||||
|     HClamp,    /// (f16vec2 src, float min, float max) -> f16vec2 | ||||
|     HMergeF32, /// (f16vec2 src) -> float | ||||
|     HMergeH0,  /// (f16vec2 dest, f16vec2 src) -> f16vec2 | ||||
|     HMergeH1,  /// (f16vec2 dest, f16vec2 src) -> f16vec2 | ||||
| @@ -716,6 +717,8 @@ private: | ||||
|     Node HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge); | ||||
|     /// Conditionally absolute/negated half float pair. Absolute is applied first | ||||
|     Node GetOperandAbsNegHalf(Node value, bool absolute, bool negate); | ||||
|     /// Conditionally saturates a half float pair | ||||
|     Node GetSaturatedHalfFloat(Node value, bool saturate = true); | ||||
|  | ||||
|     /// Returns a predicate comparing two floats | ||||
|     Node GetPredicateComparisonFloat(Tegra::Shader::PredCondition condition, Node op_a, Node op_b); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ReinUsesLisp
					ReinUsesLisp