summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-04-15 19:04:33 -0400
committerGravatar FernandoS272019-04-15 19:16:27 -0400
commitaa471274d9018fd6f8fb240dd908f1535a99742e (patch)
treea09858230f8c4079c538efb76dcbcb825032b5f6 /src
parentMerge pull request #2378 from lioncash/ro (diff)
downloadyuzu-aa471274d9018fd6f8fb240dd908f1535a99742e.tar.gz
yuzu-aa471274d9018fd6f8fb240dd908f1535a99742e.tar.xz
yuzu-aa471274d9018fd6f8fb240dd908f1535a99742e.zip
Do some corrections in conversion shader instructions.
Corrects encodings for I2F, F2F, I2I and F2I Implements Immediate variants of all four conversion types. Add assertions to unimplemented stuffs.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_bytecode.h27
-rw-r--r--src/video_core/shader/decode/conversion.cpp69
2 files changed, 73 insertions, 23 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 2e1e96c81..d5656271c 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -917,21 +917,34 @@ union Instruction {
917 } iset; 917 } iset;
918 918
919 union { 919 union {
920 BitField<8, 2, Register::Size> dest_size; 920 BitField<41, 2, u64> selector; // i2i and i2f only
921 BitField<10, 2, Register::Size> src_size;
922 BitField<12, 1, u64> is_output_signed;
923 BitField<13, 1, u64> is_input_signed;
924 BitField<41, 2, u64> selector;
925 BitField<45, 1, u64> negate_a; 921 BitField<45, 1, u64> negate_a;
926 BitField<49, 1, u64> abs_a; 922 BitField<49, 1, u64> abs_a;
923 BitField<10, 2, Register::Size> src_size;
924 BitField<13, 1, u64> is_input_signed;
925 BitField<8, 2, Register::Size> dst_size;
926 BitField<12, 1, u64> is_output_signed;
927
928 union {
929 BitField<39, 2, u64> tab5cb8_2;
930 } i2f;
927 931
928 union { 932 union {
929 BitField<39, 2, F2iRoundingOp> rounding; 933 BitField<39, 2, F2iRoundingOp> rounding;
930 } f2i; 934 } f2i;
931 935
932 union { 936 union {
933 BitField<39, 4, F2fRoundingOp> rounding; 937 BitField<8, 2, Register::Size> src_size;
938 BitField<10, 2, Register::Size> dst_size;
939 BitField<39, 4, u64> rounding;
940 // H0, H1 extract for F16 missing
941 BitField<41, 1, u64> selector; // Guessed as some games set it, TODO: reverse this value
942 F2fRoundingOp GetRoundingMode() const {
943 constexpr u64 rounding_mask = 0x0B;
944 return static_cast<F2fRoundingOp>(rounding.Value() & rounding_mask);
945 }
934 } f2f; 946 } f2f;
947
935 } conversion; 948 } conversion;
936 949
937 union { 950 union {
@@ -1678,7 +1691,7 @@ private:
1678 INST("0011100-00101---", Id::SHR_IMM, Type::Shift, "SHR_IMM"), 1691 INST("0011100-00101---", Id::SHR_IMM, Type::Shift, "SHR_IMM"),
1679 INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"), 1692 INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"),
1680 INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"), 1693 INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"),
1681 INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"), 1694 INST("0011101-11100---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"),
1682 INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"), 1695 INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"),
1683 INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"), 1696 INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"),
1684 INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"), 1697 INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"),
diff --git a/src/video_core/shader/decode/conversion.cpp b/src/video_core/shader/decode/conversion.cpp
index 55a6fbbf2..ba15b1115 100644
--- a/src/video_core/shader/decode/conversion.cpp
+++ b/src/video_core/shader/decode/conversion.cpp
@@ -18,13 +18,29 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
18 const auto opcode = OpCode::Decode(instr); 18 const auto opcode = OpCode::Decode(instr);
19 19
20 switch (opcode->get().GetId()) { 20 switch (opcode->get().GetId()) {
21 case OpCode::Id::I2I_R: { 21 case OpCode::Id::I2I_R:
22 case OpCode::Id::I2I_C:
23 case OpCode::Id::I2I_IMM: {
22 UNIMPLEMENTED_IF(instr.conversion.selector); 24 UNIMPLEMENTED_IF(instr.conversion.selector);
25 UNIMPLEMENTED_IF(instr.conversion.dst_size != Register::Size::Word);
26 UNIMPLEMENTED_IF(instr.alu.saturate_d);
23 27
24 const bool input_signed = instr.conversion.is_input_signed; 28 const bool input_signed = instr.conversion.is_input_signed;
25 const bool output_signed = instr.conversion.is_output_signed; 29 const bool output_signed = instr.conversion.is_output_signed;
26 30
27 Node value = GetRegister(instr.gpr20); 31 Node value = [&]() {
32 switch (opcode->get().GetId()) {
33 case OpCode::Id::I2I_R:
34 return GetRegister(instr.gpr20);
35 case OpCode::Id::I2I_C:
36 return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
37 case OpCode::Id::I2I_IMM:
38 return Immediate(instr.alu.GetSignedImm20_20());
39 default:
40 UNREACHABLE();
41 return Immediate(0);
42 }
43 }();
28 value = ConvertIntegerSize(value, instr.conversion.src_size, input_signed); 44 value = ConvertIntegerSize(value, instr.conversion.src_size, input_signed);
29 45
30 value = GetOperandAbsNegInteger(value, instr.conversion.abs_a, instr.conversion.negate_a, 46 value = GetOperandAbsNegInteger(value, instr.conversion.abs_a, instr.conversion.negate_a,
@@ -38,17 +54,24 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
38 break; 54 break;
39 } 55 }
40 case OpCode::Id::I2F_R: 56 case OpCode::Id::I2F_R:
41 case OpCode::Id::I2F_C: { 57 case OpCode::Id::I2F_C:
42 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); 58 case OpCode::Id::I2F_IMM: {
59 UNIMPLEMENTED_IF(instr.conversion.dst_size != Register::Size::Word);
43 UNIMPLEMENTED_IF(instr.conversion.selector); 60 UNIMPLEMENTED_IF(instr.conversion.selector);
44 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 61 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
45 "Condition codes generation in I2F is not implemented"); 62 "Condition codes generation in I2F is not implemented");
46 63
47 Node value = [&]() { 64 Node value = [&]() {
48 if (instr.is_b_gpr) { 65 switch (opcode->get().GetId()) {
66 case OpCode::Id::I2F_R:
49 return GetRegister(instr.gpr20); 67 return GetRegister(instr.gpr20);
50 } else { 68 case OpCode::Id::I2F_C:
51 return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); 69 return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
70 case OpCode::Id::I2F_IMM:
71 return Immediate(instr.alu.GetSignedImm20_20());
72 default:
73 UNREACHABLE();
74 return Immediate(0);
52 } 75 }
53 }(); 76 }();
54 const bool input_signed = instr.conversion.is_input_signed; 77 const bool input_signed = instr.conversion.is_input_signed;
@@ -62,24 +85,31 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
62 break; 85 break;
63 } 86 }
64 case OpCode::Id::F2F_R: 87 case OpCode::Id::F2F_R:
65 case OpCode::Id::F2F_C: { 88 case OpCode::Id::F2F_C:
66 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); 89 case OpCode::Id::F2F_IMM: {
67 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); 90 UNIMPLEMENTED_IF(instr.conversion.f2f.dst_size != Register::Size::Word);
91 UNIMPLEMENTED_IF(instr.conversion.f2f.src_size != Register::Size::Word);
68 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 92 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
69 "Condition codes generation in F2F is not implemented"); 93 "Condition codes generation in F2F is not implemented");
70 94
71 Node value = [&]() { 95 Node value = [&]() {
72 if (instr.is_b_gpr) { 96 switch (opcode->get().GetId()) {
97 case OpCode::Id::F2F_R:
73 return GetRegister(instr.gpr20); 98 return GetRegister(instr.gpr20);
74 } else { 99 case OpCode::Id::F2F_C:
75 return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); 100 return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
101 case OpCode::Id::F2F_IMM:
102 return GetImmediate19(instr);
103 default:
104 UNREACHABLE();
105 return Immediate(0);
76 } 106 }
77 }(); 107 }();
78 108
79 value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a); 109 value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a);
80 110
81 value = [&]() { 111 value = [&]() {
82 switch (instr.conversion.f2f.rounding) { 112 switch (instr.conversion.f2f.GetRoundingMode()) {
83 case Tegra::Shader::F2fRoundingOp::None: 113 case Tegra::Shader::F2fRoundingOp::None:
84 return value; 114 return value;
85 case Tegra::Shader::F2fRoundingOp::Round: 115 case Tegra::Shader::F2fRoundingOp::Round:
@@ -102,15 +132,22 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
102 break; 132 break;
103 } 133 }
104 case OpCode::Id::F2I_R: 134 case OpCode::Id::F2I_R:
105 case OpCode::Id::F2I_C: { 135 case OpCode::Id::F2I_C:
136 case OpCode::Id::F2I_IMM: {
106 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); 137 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
107 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 138 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
108 "Condition codes generation in F2I is not implemented"); 139 "Condition codes generation in F2I is not implemented");
109 Node value = [&]() { 140 Node value = [&]() {
110 if (instr.is_b_gpr) { 141 switch (opcode->get().GetId()) {
142 case OpCode::Id::F2I_R:
111 return GetRegister(instr.gpr20); 143 return GetRegister(instr.gpr20);
112 } else { 144 case OpCode::Id::F2I_C:
113 return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()); 145 return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
146 case OpCode::Id::F2I_IMM:
147 return GetImmediate19(instr);
148 default:
149 UNREACHABLE();
150 return Immediate(0);
114 } 151 }
115 }(); 152 }();
116 153
@@ -134,7 +171,7 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
134 }(); 171 }();
135 const bool is_signed = instr.conversion.is_output_signed; 172 const bool is_signed = instr.conversion.is_output_signed;
136 value = SignedOperation(OperationCode::ICastFloat, is_signed, PRECISE, value); 173 value = SignedOperation(OperationCode::ICastFloat, is_signed, PRECISE, value);
137 value = ConvertIntegerSize(value, instr.conversion.dest_size, is_signed); 174 value = ConvertIntegerSize(value, instr.conversion.dst_size, is_signed);
138 175
139 SetRegister(bb, instr.gpr0, value); 176 SetRegister(bb, instr.gpr0, value);
140 break; 177 break;