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