BindlessElimination.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2. using System.Collections.Generic;
  3. namespace Ryujinx.Graphics.Shader.Translation.Optimizations
  4. {
  5. class BindlessElimination
  6. {
  7. private static Operation FindBranchSource(BasicBlock block)
  8. {
  9. foreach (BasicBlock sourceBlock in block.Predecessors)
  10. {
  11. if (sourceBlock.Operations.Count > 0)
  12. {
  13. Operation lastOp = sourceBlock.Operations.Last.Value as Operation;
  14. if (lastOp != null &&
  15. ((sourceBlock.Next == block && lastOp.Inst == Instruction.BranchIfFalse) ||
  16. (sourceBlock.Branch == block && lastOp.Inst == Instruction.BranchIfTrue)))
  17. {
  18. return lastOp;
  19. }
  20. }
  21. }
  22. return null;
  23. }
  24. private static bool BlockConditionsMatch(BasicBlock currentBlock, BasicBlock queryBlock)
  25. {
  26. // Check if all the conditions for the query block are satisfied by the current block.
  27. // Just checks the top-most conditional for now.
  28. Operation currentBranch = FindBranchSource(currentBlock);
  29. Operation queryBranch = FindBranchSource(queryBlock);
  30. Operand currentCondition = currentBranch?.GetSource(0);
  31. Operand queryCondition = queryBranch?.GetSource(0);
  32. // The condition should be the same operand instance.
  33. return currentBranch != null && queryBranch != null &&
  34. currentBranch.Inst == queryBranch.Inst &&
  35. currentCondition == queryCondition;
  36. }
  37. private static Operand FindLastOperation(Operand source, BasicBlock block)
  38. {
  39. if (source.AsgOp is PhiNode phiNode)
  40. {
  41. // This source can have a different value depending on a previous branch.
  42. // Ensure that conditions met for that branch are also met for the current one.
  43. // Prefer the latest sources for the phi node.
  44. for (int i = phiNode.SourcesCount - 1; i >= 0; i--)
  45. {
  46. BasicBlock phiBlock = phiNode.GetBlock(i);
  47. if (BlockConditionsMatch(block, phiBlock))
  48. {
  49. return phiNode.GetSource(i);
  50. }
  51. }
  52. }
  53. return source;
  54. }
  55. public static void RunPass(BasicBlock block, ShaderConfig config)
  56. {
  57. // We can turn a bindless into regular access by recognizing the pattern
  58. // produced by the compiler for separate texture and sampler.
  59. // We check for the following conditions:
  60. // - The handle is a constant buffer value.
  61. // - The handle is the result of a bitwise OR logical operation.
  62. // - Both sources of the OR operation comes from a constant buffer.
  63. for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
  64. {
  65. if (!(node.Value is TextureOperation texOp))
  66. {
  67. continue;
  68. }
  69. if ((texOp.Flags & TextureFlags.Bindless) == 0)
  70. {
  71. continue;
  72. }
  73. if (texOp.Inst == Instruction.Lod ||
  74. texOp.Inst == Instruction.TextureSample ||
  75. texOp.Inst == Instruction.TextureSize)
  76. {
  77. Operand bindlessHandle = FindLastOperation(texOp.GetSource(0), block);
  78. if (bindlessHandle.Type == OperandType.ConstantBuffer)
  79. {
  80. texOp.SetHandle(bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot());
  81. continue;
  82. }
  83. if (!(bindlessHandle.AsgOp is Operation handleCombineOp))
  84. {
  85. continue;
  86. }
  87. if (handleCombineOp.Inst != Instruction.BitwiseOr)
  88. {
  89. continue;
  90. }
  91. Operand src0 = FindLastOperation(handleCombineOp.GetSource(0), block);
  92. Operand src1 = FindLastOperation(handleCombineOp.GetSource(1), block);
  93. if (src0.Type != OperandType.ConstantBuffer ||
  94. src1.Type != OperandType.ConstantBuffer || src0.GetCbufSlot() != src1.GetCbufSlot())
  95. {
  96. continue;
  97. }
  98. texOp.SetHandle(src0.GetCbufOffset() | (src1.GetCbufOffset() << 16), src0.GetCbufSlot());
  99. }
  100. else if (texOp.Inst == Instruction.ImageLoad || texOp.Inst == Instruction.ImageStore)
  101. {
  102. Operand src0 = FindLastOperation(texOp.GetSource(0), block);
  103. if (src0.Type == OperandType.ConstantBuffer)
  104. {
  105. texOp.SetHandle(src0.GetCbufOffset(), src0.GetCbufSlot());
  106. texOp.Format = config.GetTextureFormat(texOp.Handle);
  107. }
  108. }
  109. }
  110. }
  111. }
  112. }