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 }