diff options
| author | 2019-04-15 19:48:11 -0300 | |
|---|---|---|
| committer | 2019-04-15 21:16:10 -0300 | |
| commit | f43995ec535042d24fa1af637642a2974bfa4773 (patch) | |
| tree | 9b5526da635742d96d7e3d95d6fd2e95dd5b1399 /src | |
| parent | gl_shader_decompiler: Fix MrgH0 decompilation (diff) | |
| download | yuzu-f43995ec535042d24fa1af637642a2974bfa4773.tar.gz yuzu-f43995ec535042d24fa1af637642a2974bfa4773.tar.xz yuzu-f43995ec535042d24fa1af637642a2974bfa4773.zip | |
shader_ir/decode: Fix half float pre-operations and remove MetaHalfArithmetic
Operations done before the main half float operation (like HAdd) were
managing a packed value instead of the unpacked one. Adding an unpacked
operation allows us to drop the per-operand MetaHalfArithmetic entry,
simplifying the code overall.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 51 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/shader/decode/arithmetic_half.cpp | 11 | ||||
| -rw-r--r-- | src/video_core/shader/decode/arithmetic_half_immediate.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/shader/decode/half_set.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/shader/decode/half_set_predicate.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/shader/decode/hfma2.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.cpp | 18 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 26 |
9 files changed, 72 insertions, 85 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 01e9433c8..44ad21b7f 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -121,14 +121,10 @@ std::string GetTopologyName(Tegra::Shader::OutputTopology topology) { | |||
| 121 | 121 | ||
| 122 | /// Returns true if an object has to be treated as precise | 122 | /// Returns true if an object has to be treated as precise |
| 123 | bool IsPrecise(Operation operand) { | 123 | bool IsPrecise(Operation operand) { |
| 124 | const auto& meta = operand.GetMeta(); | 124 | const auto& meta{operand.GetMeta()}; |
| 125 | |||
| 126 | if (const auto arithmetic = std::get_if<MetaArithmetic>(&meta)) { | 125 | if (const auto arithmetic = std::get_if<MetaArithmetic>(&meta)) { |
| 127 | return arithmetic->precise; | 126 | return arithmetic->precise; |
| 128 | } | 127 | } |
| 129 | if (const auto half_arithmetic = std::get_if<MetaHalfArithmetic>(&meta)) { | ||
| 130 | return half_arithmetic->precise; | ||
| 131 | } | ||
| 132 | return false; | 128 | return false; |
| 133 | } | 129 | } |
| 134 | 130 | ||
| @@ -617,26 +613,7 @@ private: | |||
| 617 | } | 613 | } |
| 618 | 614 | ||
| 619 | std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) { | 615 | std::string VisitOperand(Operation operation, std::size_t operand_index, Type type) { |
| 620 | const std::string value = VisitOperand(operation, operand_index); | 616 | return CastOperand(VisitOperand(operation, operand_index), type); |
| 621 | switch (type) { | ||
| 622 | case Type::HalfFloat: { | ||
| 623 | const auto half_meta = std::get_if<MetaHalfArithmetic>(&operation.GetMeta()); | ||
| 624 | ASSERT(half_meta); | ||
| 625 | |||
| 626 | switch (half_meta->types.at(operand_index)) { | ||
| 627 | case Tegra::Shader::HalfType::H0_H1: | ||
| 628 | return "toHalf2(" + value + ')'; | ||
| 629 | case Tegra::Shader::HalfType::F32: | ||
| 630 | return "vec2(" + value + ')'; | ||
| 631 | case Tegra::Shader::HalfType::H0_H0: | ||
| 632 | return "vec2(toHalf2(" + value + ")[0])"; | ||
| 633 | case Tegra::Shader::HalfType::H1_H1: | ||
| 634 | return "vec2(toHalf2(" + value + ")[1])"; | ||
| 635 | } | ||
| 636 | } | ||
| 637 | default: | ||
| 638 | return CastOperand(value, type); | ||
| 639 | } | ||
| 640 | } | 617 | } |
| 641 | 618 | ||
| 642 | std::string CastOperand(const std::string& value, Type type) const { | 619 | std::string CastOperand(const std::string& value, Type type) const { |
| @@ -650,9 +627,7 @@ private: | |||
| 650 | case Type::Uint: | 627 | case Type::Uint: |
| 651 | return "ftou(" + value + ')'; | 628 | return "ftou(" + value + ')'; |
| 652 | case Type::HalfFloat: | 629 | case Type::HalfFloat: |
| 653 | // Can't be handled as a stand-alone value | 630 | return "toHalf2(" + value + ')'; |
| 654 | UNREACHABLE(); | ||
| 655 | return value; | ||
| 656 | } | 631 | } |
| 657 | UNREACHABLE(); | 632 | UNREACHABLE(); |
| 658 | return value; | 633 | return value; |
| @@ -1073,6 +1048,25 @@ private: | |||
| 1073 | return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat)); | 1048 | return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat)); |
| 1074 | } | 1049 | } |
| 1075 | 1050 | ||
| 1051 | std::string HUnpack(Operation operation) { | ||
| 1052 | const std::string operand{VisitOperand(operation, 0, Type::HalfFloat)}; | ||
| 1053 | const auto value = [&]() -> std::string { | ||
| 1054 | switch (std::get<Tegra::Shader::HalfType>(operation.GetMeta())) { | ||
| 1055 | case Tegra::Shader::HalfType::H0_H1: | ||
| 1056 | return operand; | ||
| 1057 | case Tegra::Shader::HalfType::F32: | ||
| 1058 | return "vec2(fromHalf2(" + operand + "))"; | ||
| 1059 | case Tegra::Shader::HalfType::H0_H0: | ||
| 1060 | return "vec2(" + operand + "[0])"; | ||
| 1061 | case Tegra::Shader::HalfType::H1_H1: | ||
| 1062 | return "vec2(" + operand + "[1])"; | ||
| 1063 | } | ||
| 1064 | UNREACHABLE(); | ||
| 1065 | return "0"; | ||
| 1066 | }(); | ||
| 1067 | return "fromHalf2(" + value + ')'; | ||
| 1068 | } | ||
| 1069 | |||
| 1076 | std::string HMergeF32(Operation operation) { | 1070 | std::string HMergeF32(Operation operation) { |
| 1077 | return "float(toHalf2(" + Visit(operation[0]) + ")[0])"; | 1071 | return "float(toHalf2(" + Visit(operation[0]) + ")[0])"; |
| 1078 | } | 1072 | } |
| @@ -1508,6 +1502,7 @@ private: | |||
| 1508 | &GLSLDecompiler::Absolute<Type::HalfFloat>, | 1502 | &GLSLDecompiler::Absolute<Type::HalfFloat>, |
| 1509 | &GLSLDecompiler::HNegate, | 1503 | &GLSLDecompiler::HNegate, |
| 1510 | &GLSLDecompiler::HClamp, | 1504 | &GLSLDecompiler::HClamp, |
| 1505 | &GLSLDecompiler::HUnpack, | ||
| 1511 | &GLSLDecompiler::HMergeF32, | 1506 | &GLSLDecompiler::HMergeF32, |
| 1512 | &GLSLDecompiler::HMergeH0, | 1507 | &GLSLDecompiler::HMergeH0, |
| 1513 | &GLSLDecompiler::HMergeH1, | 1508 | &GLSLDecompiler::HMergeH1, |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 6ecb0bcb0..beff33ba1 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -76,14 +76,10 @@ constexpr u32 GetGenericAttributeLocation(Attribute::Index attribute) { | |||
| 76 | 76 | ||
| 77 | /// Returns true if an object has to be treated as precise | 77 | /// Returns true if an object has to be treated as precise |
| 78 | bool IsPrecise(Operation operand) { | 78 | bool IsPrecise(Operation operand) { |
| 79 | const auto& meta = operand.GetMeta(); | 79 | const auto& meta{operand.GetMeta()}; |
| 80 | |||
| 81 | if (std::holds_alternative<MetaArithmetic>(meta)) { | 80 | if (std::holds_alternative<MetaArithmetic>(meta)) { |
| 82 | return std::get<MetaArithmetic>(meta).precise; | 81 | return std::get<MetaArithmetic>(meta).precise; |
| 83 | } | 82 | } |
| 84 | if (std::holds_alternative<MetaHalfArithmetic>(meta)) { | ||
| 85 | return std::get<MetaHalfArithmetic>(meta).precise; | ||
| 86 | } | ||
| 87 | return false; | 83 | return false; |
| 88 | } | 84 | } |
| 89 | 85 | ||
| @@ -749,6 +745,11 @@ private: | |||
| 749 | return {}; | 745 | return {}; |
| 750 | } | 746 | } |
| 751 | 747 | ||
| 748 | Id HUnpack(Operation operation) { | ||
| 749 | UNIMPLEMENTED(); | ||
| 750 | return {}; | ||
| 751 | } | ||
| 752 | |||
| 752 | Id HMergeF32(Operation operation) { | 753 | Id HMergeF32(Operation operation) { |
| 753 | UNIMPLEMENTED(); | 754 | UNIMPLEMENTED(); |
| 754 | return {}; | 755 | return {}; |
| @@ -1222,6 +1223,7 @@ private: | |||
| 1222 | &SPIRVDecompiler::Unary<&Module::OpFAbs, Type::HalfFloat>, | 1223 | &SPIRVDecompiler::Unary<&Module::OpFAbs, Type::HalfFloat>, |
| 1223 | &SPIRVDecompiler::HNegate, | 1224 | &SPIRVDecompiler::HNegate, |
| 1224 | &SPIRVDecompiler::HClamp, | 1225 | &SPIRVDecompiler::HClamp, |
| 1226 | &SPIRVDecompiler::HUnpack, | ||
| 1225 | &SPIRVDecompiler::HMergeF32, | 1227 | &SPIRVDecompiler::HMergeF32, |
| 1226 | &SPIRVDecompiler::HMergeH0, | 1228 | &SPIRVDecompiler::HMergeH0, |
| 1227 | &SPIRVDecompiler::HMergeH1, | 1229 | &SPIRVDecompiler::HMergeH1, |
diff --git a/src/video_core/shader/decode/arithmetic_half.cpp b/src/video_core/shader/decode/arithmetic_half.cpp index 8cf49314d..9467f9417 100644 --- a/src/video_core/shader/decode/arithmetic_half.cpp +++ b/src/video_core/shader/decode/arithmetic_half.cpp | |||
| @@ -29,9 +29,8 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) { | |||
| 29 | const bool negate_b = | 29 | const bool negate_b = |
| 30 | opcode->get().GetId() != OpCode::Id::HMUL2_C && instr.alu_half.negate_b != 0; | 30 | opcode->get().GetId() != OpCode::Id::HMUL2_C && instr.alu_half.negate_b != 0; |
| 31 | 31 | ||
| 32 | const Node op_a = GetOperandAbsNegHalf(GetRegister(instr.gpr8), instr.alu_half.abs_a, negate_a); | 32 | Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.alu_half.type_a); |
| 33 | 33 | op_a = GetOperandAbsNegHalf(op_a, instr.alu_half.abs_a, negate_a); | |
| 34 | // instr.alu_half.type_a | ||
| 35 | 34 | ||
| 36 | Node op_b = [&]() { | 35 | Node op_b = [&]() { |
| 37 | switch (opcode->get().GetId()) { | 36 | switch (opcode->get().GetId()) { |
| @@ -46,17 +45,17 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) { | |||
| 46 | return Immediate(0); | 45 | return Immediate(0); |
| 47 | } | 46 | } |
| 48 | }(); | 47 | }(); |
| 48 | op_b = UnpackHalfFloat(op_b, instr.alu_half.type_b); | ||
| 49 | op_b = GetOperandAbsNegHalf(op_b, instr.alu_half.abs_b, negate_b); | 49 | op_b = GetOperandAbsNegHalf(op_b, instr.alu_half.abs_b, negate_b); |
| 50 | 50 | ||
| 51 | Node value = [&]() { | 51 | Node value = [&]() { |
| 52 | MetaHalfArithmetic meta{true, {instr.alu_half_imm.type_a, instr.alu_half.type_b}}; | ||
| 53 | switch (opcode->get().GetId()) { | 52 | switch (opcode->get().GetId()) { |
| 54 | case OpCode::Id::HADD2_C: | 53 | case OpCode::Id::HADD2_C: |
| 55 | case OpCode::Id::HADD2_R: | 54 | case OpCode::Id::HADD2_R: |
| 56 | return Operation(OperationCode::HAdd, meta, op_a, op_b); | 55 | return Operation(OperationCode::HAdd, PRECISE, op_a, op_b); |
| 57 | case OpCode::Id::HMUL2_C: | 56 | case OpCode::Id::HMUL2_C: |
| 58 | case OpCode::Id::HMUL2_R: | 57 | case OpCode::Id::HMUL2_R: |
| 59 | return Operation(OperationCode::HMul, meta, op_a, op_b); | 58 | return Operation(OperationCode::HMul, PRECISE, op_a, op_b); |
| 60 | default: | 59 | default: |
| 61 | UNIMPLEMENTED_MSG("Unhandled half float instruction: {}", opcode->get().GetName()); | 60 | UNIMPLEMENTED_MSG("Unhandled half float instruction: {}", opcode->get().GetName()); |
| 62 | return Immediate(0); | 61 | return Immediate(0); |
diff --git a/src/video_core/shader/decode/arithmetic_half_immediate.cpp b/src/video_core/shader/decode/arithmetic_half_immediate.cpp index cf4bc0432..fbcd35b18 100644 --- a/src/video_core/shader/decode/arithmetic_half_immediate.cpp +++ b/src/video_core/shader/decode/arithmetic_half_immediate.cpp | |||
| @@ -24,18 +24,17 @@ u32 ShaderIR::DecodeArithmeticHalfImmediate(NodeBlock& bb, u32 pc) { | |||
| 24 | UNIMPLEMENTED_IF(instr.alu_half_imm.precision != Tegra::Shader::HalfPrecision::None); | 24 | UNIMPLEMENTED_IF(instr.alu_half_imm.precision != Tegra::Shader::HalfPrecision::None); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | Node op_a = GetRegister(instr.gpr8); | 27 | Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.alu_half_imm.type_a); |
| 28 | op_a = GetOperandAbsNegHalf(op_a, instr.alu_half_imm.abs_a, instr.alu_half_imm.negate_a); | 28 | op_a = GetOperandAbsNegHalf(op_a, instr.alu_half_imm.abs_a, instr.alu_half_imm.negate_a); |
| 29 | 29 | ||
| 30 | const Node op_b = UnpackHalfImmediate(instr, true); | 30 | const Node op_b = UnpackHalfImmediate(instr, true); |
| 31 | 31 | ||
| 32 | Node value = [&]() { | 32 | Node value = [&]() { |
| 33 | MetaHalfArithmetic meta{true, {instr.alu_half_imm.type_a}}; | ||
| 34 | switch (opcode->get().GetId()) { | 33 | switch (opcode->get().GetId()) { |
| 35 | case OpCode::Id::HADD2_IMM: | 34 | case OpCode::Id::HADD2_IMM: |
| 36 | return Operation(OperationCode::HAdd, meta, op_a, op_b); | 35 | return Operation(OperationCode::HAdd, PRECISE, op_a, op_b); |
| 37 | case OpCode::Id::HMUL2_IMM: | 36 | case OpCode::Id::HMUL2_IMM: |
| 38 | return Operation(OperationCode::HMul, meta, op_a, op_b); | 37 | return Operation(OperationCode::HMul, PRECISE, op_a, op_b); |
| 39 | default: | 38 | default: |
| 40 | UNREACHABLE(); | 39 | UNREACHABLE(); |
| 41 | return Immediate(0); | 40 | return Immediate(0); |
diff --git a/src/video_core/shader/decode/half_set.cpp b/src/video_core/shader/decode/half_set.cpp index d07625741..1dd94bf9d 100644 --- a/src/video_core/shader/decode/half_set.cpp +++ b/src/video_core/shader/decode/half_set.cpp | |||
| @@ -22,9 +22,9 @@ u32 ShaderIR::DecodeHalfSet(NodeBlock& bb, u32 pc) { | |||
| 22 | LOG_WARNING(HW_GPU, "{} FTZ not implemented", opcode->get().GetName()); | 22 | LOG_WARNING(HW_GPU, "{} FTZ not implemented", opcode->get().GetName()); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | // instr.hset2.type_a | 25 | Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.hset2.type_a); |
| 26 | // instr.hset2.type_b | 26 | op_a = GetOperandAbsNegHalf(op_a, instr.hset2.abs_a, instr.hset2.negate_a); |
| 27 | Node op_a = GetRegister(instr.gpr8); | 27 | |
| 28 | Node op_b = [&]() { | 28 | Node op_b = [&]() { |
| 29 | switch (opcode->get().GetId()) { | 29 | switch (opcode->get().GetId()) { |
| 30 | case OpCode::Id::HSET2_R: | 30 | case OpCode::Id::HSET2_R: |
| @@ -34,14 +34,12 @@ u32 ShaderIR::DecodeHalfSet(NodeBlock& bb, u32 pc) { | |||
| 34 | return Immediate(0); | 34 | return Immediate(0); |
| 35 | } | 35 | } |
| 36 | }(); | 36 | }(); |
| 37 | 37 | op_b = UnpackHalfFloat(op_b, instr.hset2.type_b); | |
| 38 | op_a = GetOperandAbsNegHalf(op_a, instr.hset2.abs_a, instr.hset2.negate_a); | ||
| 39 | op_b = GetOperandAbsNegHalf(op_b, instr.hset2.abs_b, instr.hset2.negate_b); | 38 | op_b = GetOperandAbsNegHalf(op_b, instr.hset2.abs_b, instr.hset2.negate_b); |
| 40 | 39 | ||
| 41 | const Node second_pred = GetPredicate(instr.hset2.pred39, instr.hset2.neg_pred); | 40 | const Node second_pred = GetPredicate(instr.hset2.pred39, instr.hset2.neg_pred); |
| 42 | 41 | ||
| 43 | MetaHalfArithmetic meta{false, {instr.hset2.type_a, instr.hset2.type_b}}; | 42 | const Node comparison_pair = GetPredicateComparisonHalf(instr.hset2.cond, op_a, op_b); |
| 44 | const Node comparison_pair = GetPredicateComparisonHalf(instr.hset2.cond, meta, op_a, op_b); | ||
| 45 | 43 | ||
| 46 | const OperationCode combiner = GetPredicateCombiner(instr.hset2.op); | 44 | const OperationCode combiner = GetPredicateCombiner(instr.hset2.op); |
| 47 | 45 | ||
diff --git a/src/video_core/shader/decode/half_set_predicate.cpp b/src/video_core/shader/decode/half_set_predicate.cpp index e68512692..6e59eb650 100644 --- a/src/video_core/shader/decode/half_set_predicate.cpp +++ b/src/video_core/shader/decode/half_set_predicate.cpp | |||
| @@ -19,10 +19,10 @@ u32 ShaderIR::DecodeHalfSetPredicate(NodeBlock& bb, u32 pc) { | |||
| 19 | 19 | ||
| 20 | UNIMPLEMENTED_IF(instr.hsetp2.ftz != 0); | 20 | UNIMPLEMENTED_IF(instr.hsetp2.ftz != 0); |
| 21 | 21 | ||
| 22 | Node op_a = GetRegister(instr.gpr8); | 22 | Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.hsetp2.type_a); |
| 23 | op_a = GetOperandAbsNegHalf(op_a, instr.hsetp2.abs_a, instr.hsetp2.negate_a); | 23 | op_a = GetOperandAbsNegHalf(op_a, instr.hsetp2.abs_a, instr.hsetp2.negate_a); |
| 24 | 24 | ||
| 25 | const Node op_b = [&]() { | 25 | Node op_b = [&]() { |
| 26 | switch (opcode->get().GetId()) { | 26 | switch (opcode->get().GetId()) { |
| 27 | case OpCode::Id::HSETP2_R: | 27 | case OpCode::Id::HSETP2_R: |
| 28 | return GetOperandAbsNegHalf(GetRegister(instr.gpr20), instr.hsetp2.abs_a, | 28 | return GetOperandAbsNegHalf(GetRegister(instr.gpr20), instr.hsetp2.abs_a, |
| @@ -32,6 +32,7 @@ u32 ShaderIR::DecodeHalfSetPredicate(NodeBlock& bb, u32 pc) { | |||
| 32 | return Immediate(0); | 32 | return Immediate(0); |
| 33 | } | 33 | } |
| 34 | }(); | 34 | }(); |
| 35 | op_b = UnpackHalfFloat(op_b, instr.hsetp2.type_b); | ||
| 35 | 36 | ||
| 36 | // We can't use the constant predicate as destination. | 37 | // We can't use the constant predicate as destination. |
| 37 | ASSERT(instr.hsetp2.pred3 != static_cast<u64>(Pred::UnusedIndex)); | 38 | ASSERT(instr.hsetp2.pred3 != static_cast<u64>(Pred::UnusedIndex)); |
| @@ -42,8 +43,7 @@ u32 ShaderIR::DecodeHalfSetPredicate(NodeBlock& bb, u32 pc) { | |||
| 42 | const OperationCode pair_combiner = | 43 | const OperationCode pair_combiner = |
| 43 | instr.hsetp2.h_and ? OperationCode::LogicalAll2 : OperationCode::LogicalAny2; | 44 | instr.hsetp2.h_and ? OperationCode::LogicalAll2 : OperationCode::LogicalAny2; |
| 44 | 45 | ||
| 45 | MetaHalfArithmetic meta = {false, {instr.hsetp2.type_a, instr.hsetp2.type_b}}; | 46 | const Node comparison = GetPredicateComparisonHalf(instr.hsetp2.cond, op_a, op_b); |
| 46 | const Node comparison = GetPredicateComparisonHalf(instr.hsetp2.cond, meta, op_a, op_b); | ||
| 47 | const Node first_pred = Operation(pair_combiner, comparison); | 47 | const Node first_pred = Operation(pair_combiner, comparison); |
| 48 | 48 | ||
| 49 | // Set the primary predicate to the result of Predicate OP SecondPredicate | 49 | // Set the primary predicate to the result of Predicate OP SecondPredicate |
diff --git a/src/video_core/shader/decode/hfma2.cpp b/src/video_core/shader/decode/hfma2.cpp index 7a07c5ec6..5c1becce5 100644 --- a/src/video_core/shader/decode/hfma2.cpp +++ b/src/video_core/shader/decode/hfma2.cpp | |||
| @@ -27,10 +27,6 @@ u32 ShaderIR::DecodeHfma2(NodeBlock& bb, u32 pc) { | |||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | constexpr auto identity = HalfType::H0_H1; | 29 | constexpr auto identity = HalfType::H0_H1; |
| 30 | |||
| 31 | const HalfType type_a = instr.hfma2.type_a; | ||
| 32 | const Node op_a = GetRegister(instr.gpr8); | ||
| 33 | |||
| 34 | bool neg_b{}, neg_c{}; | 30 | bool neg_b{}, neg_c{}; |
| 35 | auto [saturate, type_b, op_b, type_c, | 31 | auto [saturate, type_b, op_b, type_c, |
| 36 | op_c] = [&]() -> std::tuple<bool, HalfType, Node, HalfType, Node> { | 32 | op_c] = [&]() -> std::tuple<bool, HalfType, Node, HalfType, Node> { |
| @@ -62,11 +58,11 @@ u32 ShaderIR::DecodeHfma2(NodeBlock& bb, u32 pc) { | |||
| 62 | }(); | 58 | }(); |
| 63 | UNIMPLEMENTED_IF_MSG(saturate, "HFMA2 saturation is not implemented"); | 59 | UNIMPLEMENTED_IF_MSG(saturate, "HFMA2 saturation is not implemented"); |
| 64 | 60 | ||
| 65 | op_b = GetOperandAbsNegHalf(op_b, false, neg_b); | 61 | const Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.hfma2.type_a); |
| 66 | op_c = GetOperandAbsNegHalf(op_c, false, neg_c); | 62 | op_b = GetOperandAbsNegHalf(UnpackHalfFloat(op_b, type_b), false, neg_b); |
| 63 | op_c = GetOperandAbsNegHalf(UnpackHalfFloat(op_c, type_c), false, neg_c); | ||
| 67 | 64 | ||
| 68 | MetaHalfArithmetic meta{true, {type_a, type_b, type_c}}; | 65 | Node value = Operation(OperationCode::HFma, PRECISE, op_a, op_b, op_c); |
| 69 | Node value = Operation(OperationCode::HFma, meta, op_a, op_b, op_c); | ||
| 70 | value = HalfMerge(GetRegister(instr.gpr0), value, instr.hfma2.merge); | 66 | value = HalfMerge(GetRegister(instr.gpr0), value, instr.hfma2.merge); |
| 71 | 67 | ||
| 72 | SetRegister(bb, instr.gpr0, value); | 68 | SetRegister(bb, instr.gpr0, value); |
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index d158b4bfd..17f2f711c 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp | |||
| @@ -189,7 +189,11 @@ Node ShaderIR::UnpackHalfImmediate(Instruction instr, bool has_negation) { | |||
| 189 | const Node first_negate = GetPredicate(instr.half_imm.first_negate != 0); | 189 | const Node first_negate = GetPredicate(instr.half_imm.first_negate != 0); |
| 190 | const Node second_negate = GetPredicate(instr.half_imm.second_negate != 0); | 190 | const Node second_negate = GetPredicate(instr.half_imm.second_negate != 0); |
| 191 | 191 | ||
| 192 | return Operation(OperationCode::HNegate, HALF_NO_PRECISE, value, first_negate, second_negate); | 192 | return Operation(OperationCode::HNegate, NO_PRECISE, value, first_negate, second_negate); |
| 193 | } | ||
| 194 | |||
| 195 | Node ShaderIR::UnpackHalfFloat(Node value, Tegra::Shader::HalfType type) { | ||
| 196 | return Operation(OperationCode::HUnpack, type, value); | ||
| 193 | } | 197 | } |
| 194 | 198 | ||
| 195 | Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) { | 199 | Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) { |
| @@ -209,10 +213,10 @@ Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) { | |||
| 209 | 213 | ||
| 210 | Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) { | 214 | Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) { |
| 211 | if (absolute) { | 215 | if (absolute) { |
| 212 | value = Operation(OperationCode::HAbsolute, HALF_NO_PRECISE, value); | 216 | value = Operation(OperationCode::HAbsolute, NO_PRECISE, value); |
| 213 | } | 217 | } |
| 214 | if (negate) { | 218 | if (negate) { |
| 215 | value = Operation(OperationCode::HNegate, HALF_NO_PRECISE, value, GetPredicate(true), | 219 | value = Operation(OperationCode::HNegate, NO_PRECISE, value, GetPredicate(true), |
| 216 | GetPredicate(true)); | 220 | GetPredicate(true)); |
| 217 | } | 221 | } |
| 218 | return value; | 222 | return value; |
| @@ -224,7 +228,7 @@ Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) { | |||
| 224 | } | 228 | } |
| 225 | const Node positive_zero = Immediate(std::copysignf(0, 1)); | 229 | const Node positive_zero = Immediate(std::copysignf(0, 1)); |
| 226 | const Node positive_one = Immediate(1.0f); | 230 | const Node positive_one = Immediate(1.0f); |
| 227 | return Operation(OperationCode::HClamp, HALF_NO_PRECISE, value, positive_zero, positive_one); | 231 | return Operation(OperationCode::HClamp, NO_PRECISE, value, positive_zero, positive_one); |
| 228 | } | 232 | } |
| 229 | 233 | ||
| 230 | Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) { | 234 | Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) { |
| @@ -292,8 +296,8 @@ Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_si | |||
| 292 | return predicate; | 296 | return predicate; |
| 293 | } | 297 | } |
| 294 | 298 | ||
| 295 | Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, | 299 | Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a, |
| 296 | const MetaHalfArithmetic& meta, Node op_a, Node op_b) { | 300 | Node op_b) { |
| 297 | const std::unordered_map<PredCondition, OperationCode> PredicateComparisonTable = { | 301 | const std::unordered_map<PredCondition, OperationCode> PredicateComparisonTable = { |
| 298 | {PredCondition::LessThan, OperationCode::Logical2HLessThan}, | 302 | {PredCondition::LessThan, OperationCode::Logical2HLessThan}, |
| 299 | {PredCondition::Equal, OperationCode::Logical2HEqual}, | 303 | {PredCondition::Equal, OperationCode::Logical2HEqual}, |
| @@ -311,7 +315,7 @@ Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition | |||
| 311 | UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonTable.end(), | 315 | UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonTable.end(), |
| 312 | "Unknown predicate comparison operation"); | 316 | "Unknown predicate comparison operation"); |
| 313 | 317 | ||
| 314 | const Node predicate = Operation(comparison->second, meta, op_a, op_b); | 318 | const Node predicate = Operation(comparison->second, NO_PRECISE, op_a, op_b); |
| 315 | 319 | ||
| 316 | return predicate; | 320 | return predicate; |
| 317 | } | 321 | } |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index d329da58d..88957e970 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -109,12 +109,13 @@ enum class OperationCode { | |||
| 109 | UBitfieldExtract, /// (MetaArithmetic, uint value, int offset, int offset) -> uint | 109 | UBitfieldExtract, /// (MetaArithmetic, uint value, int offset, int offset) -> uint |
| 110 | UBitCount, /// (MetaArithmetic, uint) -> uint | 110 | UBitCount, /// (MetaArithmetic, uint) -> uint |
| 111 | 111 | ||
| 112 | HAdd, /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 | 112 | HAdd, /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 |
| 113 | HMul, /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 | 113 | HMul, /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2 |
| 114 | HFma, /// (MetaHalfArithmetic, f16vec2 a, f16vec2 b, f16vec2 c) -> f16vec2 | 114 | HFma, /// (MetaArithmetic, f16vec2 a, f16vec2 b, f16vec2 c) -> f16vec2 |
| 115 | HAbsolute, /// (f16vec2 a) -> f16vec2 | 115 | HAbsolute, /// (f16vec2 a) -> f16vec2 |
| 116 | HNegate, /// (f16vec2 a, bool first, bool second) -> f16vec2 | 116 | HNegate, /// (f16vec2 a, bool first, bool second) -> f16vec2 |
| 117 | HClamp, /// (f16vec2 src, float min, float max) -> f16vec2 | 117 | HClamp, /// (f16vec2 src, float min, float max) -> f16vec2 |
| 118 | HUnpack, /// (Tegra::Shader::HalfType, T value) -> f16vec2 | ||
| 118 | HMergeF32, /// (f16vec2 src) -> float | 119 | HMergeF32, /// (f16vec2 src) -> float |
| 119 | HMergeH0, /// (f16vec2 dest, f16vec2 src) -> f16vec2 | 120 | HMergeH0, /// (f16vec2 dest, f16vec2 src) -> f16vec2 |
| 120 | HMergeH1, /// (f16vec2 dest, f16vec2 src) -> f16vec2 | 121 | HMergeH1, /// (f16vec2 dest, f16vec2 src) -> f16vec2 |
| @@ -287,13 +288,6 @@ struct MetaArithmetic { | |||
| 287 | bool precise{}; | 288 | bool precise{}; |
| 288 | }; | 289 | }; |
| 289 | 290 | ||
| 290 | struct MetaHalfArithmetic { | ||
| 291 | bool precise{}; | ||
| 292 | std::array<Tegra::Shader::HalfType, 3> types = {Tegra::Shader::HalfType::H0_H1, | ||
| 293 | Tegra::Shader::HalfType::H0_H1, | ||
| 294 | Tegra::Shader::HalfType::H0_H1}; | ||
| 295 | }; | ||
| 296 | |||
| 297 | struct MetaTexture { | 291 | struct MetaTexture { |
| 298 | const Sampler& sampler; | 292 | const Sampler& sampler; |
| 299 | Node array{}; | 293 | Node array{}; |
| @@ -305,11 +299,10 @@ struct MetaTexture { | |||
| 305 | u32 element{}; | 299 | u32 element{}; |
| 306 | }; | 300 | }; |
| 307 | 301 | ||
| 308 | constexpr MetaArithmetic PRECISE = {true}; | 302 | inline constexpr MetaArithmetic PRECISE = {true}; |
| 309 | constexpr MetaArithmetic NO_PRECISE = {false}; | 303 | inline constexpr MetaArithmetic NO_PRECISE = {false}; |
| 310 | constexpr MetaHalfArithmetic HALF_NO_PRECISE = {false}; | ||
| 311 | 304 | ||
| 312 | using Meta = std::variant<MetaArithmetic, MetaHalfArithmetic, MetaTexture>; | 305 | using Meta = std::variant<MetaArithmetic, MetaTexture, Tegra::Shader::HalfType>; |
| 313 | 306 | ||
| 314 | /// Holds any kind of operation that can be done in the IR | 307 | /// Holds any kind of operation that can be done in the IR |
| 315 | class OperationNode final { | 308 | class OperationNode final { |
| @@ -713,6 +706,8 @@ private: | |||
| 713 | 706 | ||
| 714 | /// Unpacks a half immediate from an instruction | 707 | /// Unpacks a half immediate from an instruction |
| 715 | Node UnpackHalfImmediate(Tegra::Shader::Instruction instr, bool has_negation); | 708 | Node UnpackHalfImmediate(Tegra::Shader::Instruction instr, bool has_negation); |
| 709 | /// Unpacks a binary value into a half float pair with a type format | ||
| 710 | Node UnpackHalfFloat(Node value, Tegra::Shader::HalfType type); | ||
| 716 | /// Merges a half pair into another value | 711 | /// Merges a half pair into another value |
| 717 | Node HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge); | 712 | Node HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge); |
| 718 | /// Conditionally absolute/negated half float pair. Absolute is applied first | 713 | /// Conditionally absolute/negated half float pair. Absolute is applied first |
| @@ -726,8 +721,7 @@ private: | |||
| 726 | Node GetPredicateComparisonInteger(Tegra::Shader::PredCondition condition, bool is_signed, | 721 | Node GetPredicateComparisonInteger(Tegra::Shader::PredCondition condition, bool is_signed, |
| 727 | Node op_a, Node op_b); | 722 | Node op_a, Node op_b); |
| 728 | /// Returns a predicate comparing two half floats. meta consumes how both pairs will be compared | 723 | /// Returns a predicate comparing two half floats. meta consumes how both pairs will be compared |
| 729 | Node GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, | 724 | Node GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a, Node op_b); |
| 730 | const MetaHalfArithmetic& meta, Node op_a, Node op_b); | ||
| 731 | 725 | ||
| 732 | /// Returns a predicate combiner operation | 726 | /// Returns a predicate combiner operation |
| 733 | OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); | 727 | OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); |