warp.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/assert.h"
  5. #include "common/common_types.h"
  6. #include "video_core/engines/shader_bytecode.h"
  7. #include "video_core/shader/node_helper.h"
  8. #include "video_core/shader/shader_ir.h"
  9. namespace VideoCommon::Shader {
  10. using Tegra::Shader::Instruction;
  11. using Tegra::Shader::OpCode;
  12. using Tegra::Shader::Pred;
  13. using Tegra::Shader::ShuffleOperation;
  14. using Tegra::Shader::VoteOperation;
  15. namespace {
  16. OperationCode GetOperationCode(VoteOperation vote_op) {
  17. switch (vote_op) {
  18. case VoteOperation::All:
  19. return OperationCode::VoteAll;
  20. case VoteOperation::Any:
  21. return OperationCode::VoteAny;
  22. case VoteOperation::Eq:
  23. return OperationCode::VoteEqual;
  24. default:
  25. UNREACHABLE_MSG("Invalid vote operation={}", static_cast<u64>(vote_op));
  26. return OperationCode::VoteAll;
  27. }
  28. }
  29. } // Anonymous namespace
  30. u32 ShaderIR::DecodeWarp(NodeBlock& bb, u32 pc) {
  31. const Instruction instr = {program_code[pc]};
  32. const auto opcode = OpCode::Decode(instr);
  33. // Signal the backend that this shader uses warp instructions.
  34. uses_warps = true;
  35. switch (opcode->get().GetId()) {
  36. case OpCode::Id::VOTE: {
  37. const Node value = GetPredicate(instr.vote.value, instr.vote.negate_value != 0);
  38. const Node active = Operation(OperationCode::BallotThread, value);
  39. const Node vote = Operation(GetOperationCode(instr.vote.operation), value);
  40. SetRegister(bb, instr.gpr0, active);
  41. SetPredicate(bb, instr.vote.dest_pred, vote);
  42. break;
  43. }
  44. case OpCode::Id::SHFL: {
  45. Node mask = instr.shfl.is_mask_imm ? Immediate(static_cast<u32>(instr.shfl.mask_imm))
  46. : GetRegister(instr.gpr39);
  47. Node index = instr.shfl.is_index_imm ? Immediate(static_cast<u32>(instr.shfl.index_imm))
  48. : GetRegister(instr.gpr20);
  49. Node thread_id = Operation(OperationCode::ThreadId);
  50. Node clamp = Operation(OperationCode::IBitwiseAnd, mask, Immediate(0x1FU));
  51. Node seg_mask = BitfieldExtract(mask, 8, 16);
  52. Node neg_seg_mask = Operation(OperationCode::IBitwiseNot, seg_mask);
  53. Node min_thread_id = Operation(OperationCode::IBitwiseAnd, thread_id, seg_mask);
  54. Node max_thread_id = Operation(OperationCode::IBitwiseOr, min_thread_id,
  55. Operation(OperationCode::IBitwiseAnd, clamp, neg_seg_mask));
  56. Node src_thread_id = [instr, index, neg_seg_mask, min_thread_id, thread_id] {
  57. switch (instr.shfl.operation) {
  58. case ShuffleOperation::Idx:
  59. return Operation(OperationCode::IBitwiseOr,
  60. Operation(OperationCode::IBitwiseAnd, index, neg_seg_mask),
  61. min_thread_id);
  62. case ShuffleOperation::Down:
  63. return Operation(OperationCode::IAdd, thread_id, index);
  64. case ShuffleOperation::Up:
  65. return Operation(OperationCode::IAdd, thread_id,
  66. Operation(OperationCode::INegate, index));
  67. case ShuffleOperation::Bfly:
  68. return Operation(OperationCode::IBitwiseXor, thread_id, index);
  69. }
  70. UNREACHABLE();
  71. return Immediate(0U);
  72. }();
  73. Node in_bounds = [instr, src_thread_id, min_thread_id, max_thread_id] {
  74. if (instr.shfl.operation == ShuffleOperation::Up) {
  75. return Operation(OperationCode::LogicalIGreaterEqual, src_thread_id, min_thread_id);
  76. } else {
  77. return Operation(OperationCode::LogicalILessEqual, src_thread_id, max_thread_id);
  78. }
  79. }();
  80. SetPredicate(bb, instr.shfl.pred48, in_bounds);
  81. SetRegister(
  82. bb, instr.gpr0,
  83. Operation(OperationCode::ShuffleIndexed, GetRegister(instr.gpr8), src_thread_id));
  84. break;
  85. }
  86. case OpCode::Id::FSWZADD: {
  87. UNIMPLEMENTED_IF(instr.fswzadd.ndv);
  88. Node op_a = GetRegister(instr.gpr8);
  89. Node op_b = GetRegister(instr.gpr20);
  90. Node mask = Immediate(static_cast<u32>(instr.fswzadd.swizzle));
  91. SetRegister(bb, instr.gpr0, Operation(OperationCode::FSwizzleAdd, op_a, op_b, mask));
  92. break;
  93. }
  94. default:
  95. UNIMPLEMENTED_MSG("Unhandled warp instruction: {}", opcode->get().GetName());
  96. break;
  97. }
  98. return pc;
  99. }
  100. } // namespace VideoCommon::Shader