diff options
| author | 2018-09-18 22:10:48 -0400 | |
|---|---|---|
| committer | 2018-09-18 22:10:48 -0400 | |
| commit | 0284cbe7ecfcff39bb6c7ac0a7c5e01480dafd24 (patch) | |
| tree | fd79df648e4f2bfdbd2cf87e7b904047bbf8630d /src | |
| parent | Merge pull request #1299 from FernandoS27/texture-sanatize (diff) | |
| parent | Implemented Internal Flags (diff) | |
| download | yuzu-0284cbe7ecfcff39bb6c7ac0a7c5e01480dafd24.tar.gz yuzu-0284cbe7ecfcff39bb6c7ac0a7c5e01480dafd24.tar.xz yuzu-0284cbe7ecfcff39bb6c7ac0a7c5e01480dafd24.zip | |
Merge pull request #1279 from FernandoS27/csetp
shader_decompiler: Implemented (Partialy) Control Codes and CSETP
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 47 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 107 |
2 files changed, 133 insertions, 21 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 88b4d0bac..7e1de0fa1 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -240,6 +240,41 @@ enum class FlowCondition : u64 { | |||
| 240 | Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? | 240 | Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? |
| 241 | }; | 241 | }; |
| 242 | 242 | ||
| 243 | enum class ControlCode : u64 { | ||
| 244 | F = 0, | ||
| 245 | LT = 1, | ||
| 246 | EQ = 2, | ||
| 247 | LE = 3, | ||
| 248 | GT = 4, | ||
| 249 | NE = 5, | ||
| 250 | GE = 6, | ||
| 251 | Num = 7, | ||
| 252 | Nan = 8, | ||
| 253 | LTU = 9, | ||
| 254 | EQU = 10, | ||
| 255 | LEU = 11, | ||
| 256 | GTU = 12, | ||
| 257 | NEU = 13, | ||
| 258 | GEU = 14, | ||
| 259 | // | ||
| 260 | OFF = 16, | ||
| 261 | LO = 17, | ||
| 262 | SFF = 18, | ||
| 263 | LS = 19, | ||
| 264 | HI = 20, | ||
| 265 | SFT = 21, | ||
| 266 | HS = 22, | ||
| 267 | OFT = 23, | ||
| 268 | CSM_TA = 24, | ||
| 269 | CSM_TR = 25, | ||
| 270 | CSM_MX = 26, | ||
| 271 | FCSM_TA = 27, | ||
| 272 | FCSM_TR = 28, | ||
| 273 | FCSM_MX = 29, | ||
| 274 | RLE = 30, | ||
| 275 | RGT = 31, | ||
| 276 | }; | ||
| 277 | |||
| 243 | enum class PredicateResultMode : u64 { | 278 | enum class PredicateResultMode : u64 { |
| 244 | None = 0x0, | 279 | None = 0x0, |
| 245 | NotZero = 0x3, | 280 | NotZero = 0x3, |
| @@ -555,6 +590,15 @@ union Instruction { | |||
| 555 | } pset; | 590 | } pset; |
| 556 | 591 | ||
| 557 | union { | 592 | union { |
| 593 | BitField<0, 3, u64> pred0; | ||
| 594 | BitField<3, 3, u64> pred3; | ||
| 595 | BitField<8, 5, ControlCode> cc; // flag in cc | ||
| 596 | BitField<39, 3, u64> pred39; | ||
| 597 | BitField<42, 1, u64> neg_pred39; | ||
| 598 | BitField<45, 4, PredOperation> op; // op with pred39 | ||
| 599 | } csetp; | ||
| 600 | |||
| 601 | union { | ||
| 558 | BitField<39, 3, u64> pred39; | 602 | BitField<39, 3, u64> pred39; |
| 559 | BitField<42, 1, u64> neg_pred; | 603 | BitField<42, 1, u64> neg_pred; |
| 560 | BitField<43, 1, u64> neg_a; | 604 | BitField<43, 1, u64> neg_a; |
| @@ -881,6 +925,7 @@ union Instruction { | |||
| 881 | BitField<36, 5, u64> index; | 925 | BitField<36, 5, u64> index; |
| 882 | } cbuf36; | 926 | } cbuf36; |
| 883 | 927 | ||
| 928 | BitField<47, 1, u64> generates_cc; | ||
| 884 | BitField<61, 1, u64> is_b_imm; | 929 | BitField<61, 1, u64> is_b_imm; |
| 885 | BitField<60, 1, u64> is_b_gpr; | 930 | BitField<60, 1, u64> is_b_gpr; |
| 886 | BitField<59, 1, u64> is_c_gpr; | 931 | BitField<59, 1, u64> is_c_gpr; |
| @@ -1005,6 +1050,7 @@ public: | |||
| 1005 | ISET_IMM, | 1050 | ISET_IMM, |
| 1006 | PSETP, | 1051 | PSETP, |
| 1007 | PSET, | 1052 | PSET, |
| 1053 | CSETP, | ||
| 1008 | XMAD_IMM, | 1054 | XMAD_IMM, |
| 1009 | XMAD_CR, | 1055 | XMAD_CR, |
| 1010 | XMAD_RC, | 1056 | XMAD_RC, |
| @@ -1241,6 +1287,7 @@ private: | |||
| 1241 | INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), | 1287 | INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), |
| 1242 | INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), | 1288 | INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), |
| 1243 | INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), | 1289 | INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), |
| 1290 | INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"), | ||
| 1244 | INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), | 1291 | INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), |
| 1245 | INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), | 1292 | INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), |
| 1246 | INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), | 1293 | INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index cca6cc6ff..393ab5eab 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -236,6 +236,14 @@ private: | |||
| 236 | const std::string& suffix; | 236 | const std::string& suffix; |
| 237 | }; | 237 | }; |
| 238 | 238 | ||
| 239 | enum class InternalFlag : u64 { | ||
| 240 | ZeroFlag = 0, | ||
| 241 | CarryFlag = 1, | ||
| 242 | OverflowFlag = 2, | ||
| 243 | NaNFlag = 3, | ||
| 244 | Amount | ||
| 245 | }; | ||
| 246 | |||
| 239 | /** | 247 | /** |
| 240 | * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state | 248 | * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state |
| 241 | * of all registers (e.g. whether they are currently being used as Floats or Integers), and | 249 | * of all registers (e.g. whether they are currently being used as Floats or Integers), and |
| @@ -329,13 +337,19 @@ public: | |||
| 329 | void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, | 337 | void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, |
| 330 | const std::string& value, u64 dest_num_components, | 338 | const std::string& value, u64 dest_num_components, |
| 331 | u64 value_num_components, bool is_saturated = false, | 339 | u64 value_num_components, bool is_saturated = false, |
| 332 | u64 dest_elem = 0, Register::Size size = Register::Size::Word) { | 340 | u64 dest_elem = 0, Register::Size size = Register::Size::Word, |
| 341 | bool sets_cc = false) { | ||
| 333 | ASSERT_MSG(!is_saturated, "Unimplemented"); | 342 | ASSERT_MSG(!is_saturated, "Unimplemented"); |
| 334 | 343 | ||
| 335 | const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"}; | 344 | const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"}; |
| 336 | 345 | ||
| 337 | SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')', | 346 | SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')', |
| 338 | dest_num_components, value_num_components, dest_elem); | 347 | dest_num_components, value_num_components, dest_elem); |
| 348 | |||
| 349 | if (sets_cc) { | ||
| 350 | const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; | ||
| 351 | SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); | ||
| 352 | } | ||
| 339 | } | 353 | } |
| 340 | 354 | ||
| 341 | /** | 355 | /** |
| @@ -352,6 +366,26 @@ public: | |||
| 352 | shader.AddLine(dest + " = " + src + ';'); | 366 | shader.AddLine(dest + " = " + src + ';'); |
| 353 | } | 367 | } |
| 354 | 368 | ||
| 369 | std::string GetControlCode(const Tegra::Shader::ControlCode cc) const { | ||
| 370 | switch (cc) { | ||
| 371 | case Tegra::Shader::ControlCode::NEU: | ||
| 372 | return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')'; | ||
| 373 | default: | ||
| 374 | LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc)); | ||
| 375 | UNREACHABLE(); | ||
| 376 | return "false"; | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | std::string GetInternalFlag(const InternalFlag ii) const { | ||
| 381 | const u32 code = static_cast<u32>(ii); | ||
| 382 | return "internalFlag_" + std::to_string(code) + suffix; | ||
| 383 | } | ||
| 384 | |||
| 385 | void SetInternalFlag(const InternalFlag ii, const std::string& value) const { | ||
| 386 | shader.AddLine(GetInternalFlag(ii) + " = " + value + ';'); | ||
| 387 | } | ||
| 388 | |||
| 355 | /** | 389 | /** |
| 356 | * Writes code that does a output attribute assignment to register operation. Output attributes | 390 | * Writes code that does a output attribute assignment to register operation. Output attributes |
| 357 | * are stored as floats, so this may require conversion. | 391 | * are stored as floats, so this may require conversion. |
| @@ -415,6 +449,12 @@ public: | |||
| 415 | } | 449 | } |
| 416 | declarations.AddNewLine(); | 450 | declarations.AddNewLine(); |
| 417 | 451 | ||
| 452 | for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) { | ||
| 453 | const InternalFlag code = static_cast<InternalFlag>(ii); | ||
| 454 | declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); | ||
| 455 | } | ||
| 456 | declarations.AddNewLine(); | ||
| 457 | |||
| 418 | for (const auto element : declr_input_attribute) { | 458 | for (const auto element : declr_input_attribute) { |
| 419 | // TODO(bunnei): Use proper number of elements for these | 459 | // TODO(bunnei): Use proper number of elements for these |
| 420 | u32 idx = | 460 | u32 idx = |
| @@ -1620,7 +1660,8 @@ private: | |||
| 1620 | } | 1660 | } |
| 1621 | 1661 | ||
| 1622 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, | 1662 | regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, |
| 1623 | 1, instr.alu.saturate_d, 0, instr.conversion.dest_size); | 1663 | 1, instr.alu.saturate_d, 0, instr.conversion.dest_size, |
| 1664 | instr.generates_cc.Value() != 0); | ||
| 1624 | break; | 1665 | break; |
| 1625 | } | 1666 | } |
| 1626 | case OpCode::Id::I2F_R: | 1667 | case OpCode::Id::I2F_R: |
| @@ -2277,31 +2318,55 @@ private: | |||
| 2277 | break; | 2318 | break; |
| 2278 | } | 2319 | } |
| 2279 | case OpCode::Type::PredicateSetPredicate: { | 2320 | case OpCode::Type::PredicateSetPredicate: { |
| 2280 | const std::string op_a = | 2321 | switch (opcode->GetId()) { |
| 2281 | GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); | 2322 | case OpCode::Id::PSETP: { |
| 2282 | const std::string op_b = | 2323 | const std::string op_a = |
| 2283 | GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); | 2324 | GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); |
| 2325 | const std::string op_b = | ||
| 2326 | GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); | ||
| 2284 | 2327 | ||
| 2285 | // We can't use the constant predicate as destination. | 2328 | // We can't use the constant predicate as destination. |
| 2286 | ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); | 2329 | ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); |
| 2287 | 2330 | ||
| 2288 | const std::string second_pred = | 2331 | const std::string second_pred = |
| 2289 | GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); | 2332 | GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); |
| 2290 | 2333 | ||
| 2291 | const std::string combiner = GetPredicateCombiner(instr.psetp.op); | 2334 | const std::string combiner = GetPredicateCombiner(instr.psetp.op); |
| 2292 | 2335 | ||
| 2293 | const std::string predicate = | 2336 | const std::string predicate = |
| 2294 | '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; | 2337 | '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; |
| 2295 | 2338 | ||
| 2296 | // Set the primary predicate to the result of Predicate OP SecondPredicate | 2339 | // Set the primary predicate to the result of Predicate OP SecondPredicate |
| 2297 | SetPredicate(instr.psetp.pred3, | 2340 | SetPredicate(instr.psetp.pred3, |
| 2298 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); | 2341 | '(' + predicate + ") " + combiner + " (" + second_pred + ')'); |
| 2299 | 2342 | ||
| 2300 | if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | 2343 | if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { |
| 2301 | // Set the secondary predicate to the result of !Predicate OP SecondPredicate, | 2344 | // Set the secondary predicate to the result of !Predicate OP SecondPredicate, |
| 2302 | // if enabled | 2345 | // if enabled |
| 2303 | SetPredicate(instr.psetp.pred0, | 2346 | SetPredicate(instr.psetp.pred0, |
| 2304 | "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); | 2347 | "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); |
| 2348 | } | ||
| 2349 | break; | ||
| 2350 | } | ||
| 2351 | case OpCode::Id::CSETP: { | ||
| 2352 | const std::string pred = | ||
| 2353 | GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0); | ||
| 2354 | const std::string combiner = GetPredicateCombiner(instr.csetp.op); | ||
| 2355 | const std::string controlCode = regs.GetControlCode(instr.csetp.cc); | ||
| 2356 | if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) { | ||
| 2357 | SetPredicate(instr.csetp.pred3, | ||
| 2358 | '(' + controlCode + ") " + combiner + " (" + pred + ')'); | ||
| 2359 | } | ||
| 2360 | if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | ||
| 2361 | SetPredicate(instr.csetp.pred0, | ||
| 2362 | "!(" + controlCode + ") " + combiner + " (" + pred + ')'); | ||
| 2363 | } | ||
| 2364 | break; | ||
| 2365 | } | ||
| 2366 | default: { | ||
| 2367 | LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName()); | ||
| 2368 | UNREACHABLE(); | ||
| 2369 | } | ||
| 2305 | } | 2370 | } |
| 2306 | break; | 2371 | break; |
| 2307 | } | 2372 | } |