summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_bytecode.h16
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp141
2 files changed, 82 insertions, 75 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index d3095089c..bc61f953f 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -214,7 +214,7 @@ enum class IMinMaxExchange : u64 {
214 XHi = 3, 214 XHi = 3,
215}; 215};
216 216
217enum class VmadType : u64 { 217enum class VideoType : u64 {
218 Size16_Low = 0, 218 Size16_Low = 0,
219 Size16_High = 1, 219 Size16_High = 1,
220 Size32 = 2, 220 Size32 = 2,
@@ -783,6 +783,14 @@ union Instruction {
783 } psetp; 783 } psetp;
784 784
785 union { 785 union {
786 BitField<43, 4, PredCondition> cond;
787 BitField<45, 2, PredOperation> op;
788 BitField<3, 3, u64> pred3;
789 BitField<0, 3, u64> pred0;
790 BitField<39, 3, u64> pred39;
791 } vsetp;
792
793 union {
786 BitField<12, 3, u64> pred12; 794 BitField<12, 3, u64> pred12;
787 BitField<15, 1, u64> neg_pred12; 795 BitField<15, 1, u64> neg_pred12;
788 BitField<24, 2, PredOperation> cond; 796 BitField<24, 2, PredOperation> cond;
@@ -1154,15 +1162,17 @@ union Instruction {
1154 union { 1162 union {
1155 BitField<48, 1, u64> signed_a; 1163 BitField<48, 1, u64> signed_a;
1156 BitField<38, 1, u64> is_byte_chunk_a; 1164 BitField<38, 1, u64> is_byte_chunk_a;
1157 BitField<36, 2, VmadType> type_a; 1165 BitField<36, 2, VideoType> type_a;
1158 BitField<36, 2, u64> byte_height_a; 1166 BitField<36, 2, u64> byte_height_a;
1159 1167
1160 BitField<49, 1, u64> signed_b; 1168 BitField<49, 1, u64> signed_b;
1161 BitField<50, 1, u64> use_register_b; 1169 BitField<50, 1, u64> use_register_b;
1162 BitField<30, 1, u64> is_byte_chunk_b; 1170 BitField<30, 1, u64> is_byte_chunk_b;
1163 BitField<28, 2, VmadType> type_b; 1171 BitField<28, 2, VideoType> type_b;
1164 BitField<28, 2, u64> byte_height_b; 1172 BitField<28, 2, u64> byte_height_b;
1173 } video;
1165 1174
1175 union {
1166 BitField<51, 2, VmadShr> shr; 1176 BitField<51, 2, VmadShr> shr;
1167 BitField<55, 1, u64> saturate; // Saturates the result (a * b + c) 1177 BitField<55, 1, u64> saturate; // Saturates the result (a * b + c)
1168 BitField<47, 1, u64> cc; 1178 BitField<47, 1, u64> cc;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index a3daef014..ad4d5a72f 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1291,6 +1291,63 @@ private:
1291 } 1291 }
1292 } 1292 }
1293 1293
1294 /// Unpacks a video instruction operand (e.g. VMAD).
1295 std::string GetVideoOperand(const std::string& op, bool is_chunk, bool is_signed,
1296 Tegra::Shader::VideoType type, u64 byte_height) {
1297 const std::string value = [&]() {
1298 if (!is_chunk) {
1299 const auto offset = static_cast<u32>(byte_height * 8);
1300 return "((" + op + " >> " + std::to_string(offset) + ") & 0xff)";
1301 }
1302 const std::string zero = "0";
1303
1304 switch (type) {
1305 case Tegra::Shader::VideoType::Size16_Low:
1306 return '(' + op + " & 0xffff)";
1307 case Tegra::Shader::VideoType::Size16_High:
1308 return '(' + op + " >> 16)";
1309 case Tegra::Shader::VideoType::Size32:
1310 // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when
1311 // this type is used (1 * 1 + 0 == 0x5b800000). Until a better
1312 // explanation is found: assert.
1313 UNIMPLEMENTED();
1314 return zero;
1315 case Tegra::Shader::VideoType::Invalid:
1316 UNREACHABLE_MSG("Invalid instruction encoding");
1317 return zero;
1318 default:
1319 UNREACHABLE();
1320 return zero;
1321 }
1322 }();
1323
1324 if (is_signed) {
1325 return "int(" + value + ')';
1326 }
1327 return value;
1328 };
1329
1330 /// Gets the A operand for a video instruction.
1331 std::string GetVideoOperandA(Instruction instr) {
1332 return GetVideoOperand(regs.GetRegisterAsInteger(instr.gpr8, 0, false),
1333 instr.video.is_byte_chunk_a != 0, instr.video.signed_a,
1334 instr.video.type_a, instr.video.byte_height_a);
1335 }
1336
1337 /// Gets the B operand for a video instruction.
1338 std::string GetVideoOperandB(Instruction instr) {
1339 if (instr.video.use_register_b) {
1340 return GetVideoOperand(regs.GetRegisterAsInteger(instr.gpr20, 0, false),
1341 instr.video.is_byte_chunk_b != 0, instr.video.signed_b,
1342 instr.video.type_b, instr.video.byte_height_b);
1343 } else {
1344 return '(' +
1345 std::to_string(instr.video.signed_b ? static_cast<s16>(instr.alu.GetImm20_16())
1346 : instr.alu.GetImm20_16()) +
1347 ')';
1348 }
1349 }
1350
1294 /** 1351 /**
1295 * Compiles a single instruction from Tegra to GLSL. 1352 * Compiles a single instruction from Tegra to GLSL.
1296 * @param offset the offset of the Tegra shader instruction. 1353 * @param offset the offset of the Tegra shader instruction.
@@ -3284,82 +3341,22 @@ private:
3284 break; 3341 break;
3285 } 3342 }
3286 case OpCode::Id::VMAD: { 3343 case OpCode::Id::VMAD: {
3287 const bool signed_a = instr.vmad.signed_a == 1; 3344 const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1;
3288 const bool signed_b = instr.vmad.signed_b == 1; 3345 const std::string op_a = GetVideoOperandA(instr);
3289 const bool result_signed = signed_a || signed_b; 3346 const std::string op_b = GetVideoOperandB(instr);
3290 boost::optional<std::string> forced_result;
3291
3292 auto Unpack = [&](const std::string& op, bool is_chunk, bool is_signed,
3293 Tegra::Shader::VmadType type, u64 byte_height) {
3294 const std::string value = [&]() {
3295 if (!is_chunk) {
3296 const auto shift = static_cast<u32>(byte_height * 8);
3297 return "((" + op + " >> " + std::to_string(shift) + ") & 0xff)";
3298 }
3299 const std::string zero = "0";
3300
3301 switch (type) {
3302 case Tegra::Shader::VmadType::Size16_Low:
3303 return '(' + op + " & 0xffff)";
3304 case Tegra::Shader::VmadType::Size16_High:
3305 return '(' + op + " >> 16)";
3306 case Tegra::Shader::VmadType::Size32:
3307 // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when
3308 // this type is used (1 * 1 + 0 == 0x5b800000). Until a better
3309 // explanation is found: assert.
3310 UNREACHABLE_MSG("Unimplemented");
3311 return zero;
3312 case Tegra::Shader::VmadType::Invalid:
3313 // Note(Rodrigo): This flag is invalid according to nvdisasm. From my
3314 // testing (even though it's invalid) this makes the whole instruction
3315 // assign zero to target register.
3316 forced_result = boost::make_optional(zero);
3317 return zero;
3318 default:
3319 UNREACHABLE();
3320 return zero;
3321 }
3322 }();
3323
3324 if (is_signed) {
3325 return "int(" + value + ')';
3326 }
3327 return value;
3328 };
3329
3330 const std::string op_a = Unpack(regs.GetRegisterAsInteger(instr.gpr8, 0, false),
3331 instr.vmad.is_byte_chunk_a != 0, signed_a,
3332 instr.vmad.type_a, instr.vmad.byte_height_a);
3333
3334 std::string op_b;
3335 if (instr.vmad.use_register_b) {
3336 op_b = Unpack(regs.GetRegisterAsInteger(instr.gpr20, 0, false),
3337 instr.vmad.is_byte_chunk_b != 0, signed_b, instr.vmad.type_b,
3338 instr.vmad.byte_height_b);
3339 } else {
3340 op_b = '(' +
3341 std::to_string(signed_b ? static_cast<s16>(instr.alu.GetImm20_16())
3342 : instr.alu.GetImm20_16()) +
3343 ')';
3344 }
3345
3346 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39, 0, result_signed); 3347 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39, 0, result_signed);
3347 3348
3348 std::string result; 3349 std::string result = '(' + op_a + " * " + op_b + " + " + op_c + ')';
3349 if (forced_result) {
3350 result = *forced_result;
3351 } else {
3352 result = '(' + op_a + " * " + op_b + " + " + op_c + ')';
3353 3350
3354 switch (instr.vmad.shr) { 3351 switch (instr.vmad.shr) {
3355 case Tegra::Shader::VmadShr::Shr7: 3352 case Tegra::Shader::VmadShr::Shr7:
3356 result = '(' + result + " >> 7)"; 3353 result = '(' + result + " >> 7)";
3357 break; 3354 break;
3358 case Tegra::Shader::VmadShr::Shr15: 3355 case Tegra::Shader::VmadShr::Shr15:
3359 result = '(' + result + " >> 15)"; 3356 result = '(' + result + " >> 15)";
3360 break; 3357 break;
3361 }
3362 } 3358 }
3359
3363 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, 3360 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
3364 instr.vmad.saturate == 1, 0, Register::Size::Word, 3361 instr.vmad.saturate == 1, 0, Register::Size::Word,
3365 instr.vmad.cc); 3362 instr.vmad.cc);