AdvancedBlendManager.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. using Ryujinx.Common;
  2. using Ryujinx.Graphics.GAL;
  3. using System;
  4. using System.Runtime.InteropServices;
  5. namespace Ryujinx.Graphics.Gpu.Engine.Threed.Blender
  6. {
  7. /// <summary>
  8. /// Advanced blend manager.
  9. /// </summary>
  10. class AdvancedBlendManager
  11. {
  12. private const int InstructionRamSize = 128;
  13. private const int InstructionRamSizeMask = InstructionRamSize - 1;
  14. private readonly DeviceStateWithShadow<ThreedClassState> _state;
  15. private readonly uint[] _code;
  16. private int _ip;
  17. /// <summary>
  18. /// Creates a new instance of the advanced blend manager.
  19. /// </summary>
  20. /// <param name="state">GPU state of the channel owning this manager</param>
  21. public AdvancedBlendManager(DeviceStateWithShadow<ThreedClassState> state)
  22. {
  23. _state = state;
  24. _code = new uint[InstructionRamSize];
  25. }
  26. /// <summary>
  27. /// Sets the start offset of the blend microcode in memory.
  28. /// </summary>
  29. /// <param name="argument">Method call argument</param>
  30. public void LoadBlendUcodeStart(int argument)
  31. {
  32. _ip = argument;
  33. }
  34. /// <summary>
  35. /// Pushes one word of blend microcode.
  36. /// </summary>
  37. /// <param name="argument">Method call argument</param>
  38. public void LoadBlendUcodeInstruction(int argument)
  39. {
  40. _code[_ip++ & InstructionRamSizeMask] = (uint)argument;
  41. }
  42. /// <summary>
  43. /// Tries to identify the current advanced blend function being used,
  44. /// given the current state and microcode that was uploaded.
  45. /// </summary>
  46. /// <param name="descriptor">Advanced blend descriptor</param>
  47. /// <returns>True if the function was found, false otherwise</returns>
  48. public bool TryGetAdvancedBlend(out AdvancedBlendDescriptor descriptor)
  49. {
  50. Span<uint> currentCode = new Span<uint>(_code);
  51. byte codeLength = (byte)_state.State.BlendUcodeSize;
  52. if (currentCode.Length > codeLength)
  53. {
  54. currentCode = currentCode.Slice(0, codeLength);
  55. }
  56. Hash128 hash = XXHash128.ComputeHash(MemoryMarshal.Cast<uint, byte>(currentCode));
  57. descriptor = default;
  58. if (!AdvancedBlendPreGenTable.Entries.TryGetValue(hash, out var entry))
  59. {
  60. return false;
  61. }
  62. if (entry.Constants != null)
  63. {
  64. bool constantsMatch = true;
  65. for (int i = 0; i < entry.Constants.Length; i++)
  66. {
  67. RgbFloat constant = entry.Constants[i];
  68. RgbHalf constant2 = _state.State.BlendUcodeConstants[i];
  69. if ((Half)constant.R != constant2.UnpackR() ||
  70. (Half)constant.G != constant2.UnpackG() ||
  71. (Half)constant.B != constant2.UnpackB())
  72. {
  73. constantsMatch = false;
  74. break;
  75. }
  76. }
  77. if (!constantsMatch)
  78. {
  79. return false;
  80. }
  81. }
  82. if (entry.Alpha.Enable != _state.State.BlendUcodeEnable)
  83. {
  84. return false;
  85. }
  86. if (entry.Alpha.Enable == BlendUcodeEnable.EnableRGBA &&
  87. (entry.Alpha.AlphaOp != _state.State.BlendStateCommon.AlphaOp ||
  88. entry.Alpha.AlphaSrcFactor != _state.State.BlendStateCommon.AlphaSrcFactor ||
  89. entry.Alpha.AlphaDstFactor != _state.State.BlendStateCommon.AlphaDstFactor))
  90. {
  91. return false;
  92. }
  93. descriptor = new AdvancedBlendDescriptor(entry.Op, entry.Overlap, entry.SrcPreMultiplied);
  94. return true;
  95. }
  96. }
  97. }