diff options
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/Threed/Blender/AdvancedBlendManager.cs')
-rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/Threed/Blender/AdvancedBlendManager.cs | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/Blender/AdvancedBlendManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/Blender/AdvancedBlendManager.cs new file mode 100644 index 00000000..8072c6af --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/Blender/AdvancedBlendManager.cs @@ -0,0 +1,115 @@ +using Ryujinx.Common; +using Ryujinx.Graphics.GAL; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Engine.Threed.Blender +{ + /// <summary> + /// Advanced blend manager. + /// </summary> + class AdvancedBlendManager + { + private const int InstructionRamSize = 128; + private const int InstructionRamSizeMask = InstructionRamSize - 1; + + private readonly DeviceStateWithShadow<ThreedClassState> _state; + + private readonly uint[] _code; + private int _ip; + + /// <summary> + /// Creates a new instance of the advanced blend manager. + /// </summary> + /// <param name="state">GPU state of the channel owning this manager</param> + public AdvancedBlendManager(DeviceStateWithShadow<ThreedClassState> state) + { + _state = state; + _code = new uint[InstructionRamSize]; + } + + /// <summary> + /// Sets the start offset of the blend microcode in memory. + /// </summary> + /// <param name="argument">Method call argument</param> + public void LoadBlendUcodeStart(int argument) + { + _ip = argument; + } + + /// <summary> + /// Pushes one word of blend microcode. + /// </summary> + /// <param name="argument">Method call argument</param> + public void LoadBlendUcodeInstruction(int argument) + { + _code[_ip++ & InstructionRamSizeMask] = (uint)argument; + } + + /// <summary> + /// Tries to identify the current advanced blend function being used, + /// given the current state and microcode that was uploaded. + /// </summary> + /// <param name="descriptor">Advanced blend descriptor</param> + /// <returns>True if the function was found, false otherwise</returns> + public bool TryGetAdvancedBlend(out AdvancedBlendDescriptor descriptor) + { + Span<uint> currentCode = new Span<uint>(_code); + byte codeLength = (byte)_state.State.BlendUcodeSize; + + if (currentCode.Length > codeLength) + { + currentCode = currentCode.Slice(0, codeLength); + } + + Hash128 hash = XXHash128.ComputeHash(MemoryMarshal.Cast<uint, byte>(currentCode)); + + descriptor = default; + + if (!AdvancedBlendPreGenTable.Entries.TryGetValue(hash, out var entry)) + { + return false; + } + + if (entry.Constants != null) + { + bool constantsMatch = true; + + for (int i = 0; i < entry.Constants.Length; i++) + { + RgbFloat constant = entry.Constants[i]; + RgbHalf constant2 = _state.State.BlendUcodeConstants[i]; + + if ((Half)constant.R != constant2.UnpackR() || + (Half)constant.G != constant2.UnpackG() || + (Half)constant.B != constant2.UnpackB()) + { + constantsMatch = false; + break; + } + } + + if (!constantsMatch) + { + return false; + } + } + + if (entry.Alpha.Enable != _state.State.BlendUcodeEnable) + { + return false; + } + + if (entry.Alpha.Enable == BlendUcodeEnable.EnableRGBA && + (entry.Alpha.AlphaOp != _state.State.BlendStateCommon.AlphaOp || + entry.Alpha.AlphaSrcFactor != _state.State.BlendStateCommon.AlphaSrcFactor || + entry.Alpha.AlphaDstFactor != _state.State.BlendStateCommon.AlphaDstFactor)) + { + return false; + } + + descriptor = new AdvancedBlendDescriptor(entry.Op, entry.Overlap, entry.SrcPreMultiplied); + return true; + } + } +}
\ No newline at end of file |