BindlessElimination.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2. using System.Collections.Generic;
  3. namespace Ryujinx.Graphics.Shader.Translation.Optimizations
  4. {
  5. class BindlessElimination
  6. {
  7. public static void RunPass(BasicBlock block, ShaderConfig config)
  8. {
  9. // We can turn a bindless into regular access by recognizing the pattern
  10. // produced by the compiler for separate texture and sampler.
  11. // We check for the following conditions:
  12. // - The handle is a constant buffer value.
  13. // - The handle is the result of a bitwise OR logical operation.
  14. // - Both sources of the OR operation comes from a constant buffer.
  15. for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
  16. {
  17. if (!(node.Value is TextureOperation texOp))
  18. {
  19. continue;
  20. }
  21. if ((texOp.Flags & TextureFlags.Bindless) == 0)
  22. {
  23. continue;
  24. }
  25. if (texOp.Inst == Instruction.Lod ||
  26. texOp.Inst == Instruction.TextureSample ||
  27. texOp.Inst == Instruction.TextureSize)
  28. {
  29. Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block);
  30. bool rewriteSamplerType = texOp.Inst == Instruction.TextureSize;
  31. if (bindlessHandle.Type == OperandType.ConstantBuffer)
  32. {
  33. SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType);
  34. continue;
  35. }
  36. if (!(bindlessHandle.AsgOp is Operation handleCombineOp))
  37. {
  38. continue;
  39. }
  40. if (handleCombineOp.Inst != Instruction.BitwiseOr)
  41. {
  42. continue;
  43. }
  44. Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block);
  45. Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block);
  46. if (src0.Type != OperandType.ConstantBuffer || src1.Type != OperandType.ConstantBuffer)
  47. {
  48. continue;
  49. }
  50. SetHandle(
  51. config,
  52. texOp,
  53. src0.GetCbufOffset() | ((src1.GetCbufOffset() + 1) << 16),
  54. src0.GetCbufSlot() | ((src1.GetCbufSlot() + 1) << 16),
  55. rewriteSamplerType);
  56. }
  57. else if (texOp.Inst == Instruction.ImageLoad ||
  58. texOp.Inst == Instruction.ImageStore ||
  59. texOp.Inst == Instruction.ImageAtomic)
  60. {
  61. Operand src0 = Utils.FindLastOperation(texOp.GetSource(0), block);
  62. if (src0.Type == OperandType.ConstantBuffer)
  63. {
  64. int cbufOffset = src0.GetCbufOffset();
  65. int cbufSlot = src0.GetCbufSlot();
  66. if (texOp.Inst == Instruction.ImageAtomic)
  67. {
  68. texOp.Format = config.GetTextureFormatAtomic(cbufOffset, cbufSlot);
  69. }
  70. else
  71. {
  72. texOp.Format = config.GetTextureFormat(cbufOffset, cbufSlot);
  73. }
  74. SetHandle(config, texOp, cbufOffset, cbufSlot, false);
  75. }
  76. }
  77. }
  78. }
  79. private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType)
  80. {
  81. texOp.SetHandle(cbufOffset, cbufSlot);
  82. if (rewriteSamplerType)
  83. {
  84. texOp.Type = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot);
  85. }
  86. config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, cbufSlot, cbufOffset);
  87. }
  88. }
  89. }