RgbaColor32.cs
1 using System; 2 using System.Diagnostics.CodeAnalysis; 3 using System.Runtime.CompilerServices; 4 using System.Runtime.Intrinsics; 5 using System.Runtime.Intrinsics.X86; 6 7 namespace Ryujinx.Graphics.Texture.Utils 8 { 9 struct RgbaColor32 : IEquatable<RgbaColor32> 10 { 11 private Vector128<int> _color; 12 13 public int R 14 { 15 readonly get => _color.GetElement(0); 16 set => _color = _color.WithElement(0, value); 17 } 18 19 public int G 20 { 21 readonly get => _color.GetElement(1); 22 set => _color = _color.WithElement(1, value); 23 } 24 25 public int B 26 { 27 readonly get => _color.GetElement(2); 28 set => _color = _color.WithElement(2, value); 29 } 30 31 public int A 32 { 33 readonly get => _color.GetElement(3); 34 set => _color = _color.WithElement(3, value); 35 } 36 37 public RgbaColor32(Vector128<int> color) 38 { 39 _color = color; 40 } 41 42 public RgbaColor32(int r, int g, int b, int a) 43 { 44 _color = Vector128.Create(r, g, b, a); 45 } 46 47 public RgbaColor32(int scalar) 48 { 49 _color = Vector128.Create(scalar); 50 } 51 52 [MethodImpl(MethodImplOptions.AggressiveInlining)] 53 public static RgbaColor32 operator +(RgbaColor32 x, RgbaColor32 y) 54 { 55 if (Sse2.IsSupported) 56 { 57 return new RgbaColor32(Sse2.Add(x._color, y._color)); 58 } 59 else 60 { 61 return new RgbaColor32(x.R + y.R, x.G + y.G, x.B + y.B, x.A + y.A); 62 } 63 } 64 65 [MethodImpl(MethodImplOptions.AggressiveInlining)] 66 public static RgbaColor32 operator -(RgbaColor32 x, RgbaColor32 y) 67 { 68 if (Sse2.IsSupported) 69 { 70 return new RgbaColor32(Sse2.Subtract(x._color, y._color)); 71 } 72 else 73 { 74 return new RgbaColor32(x.R - y.R, x.G - y.G, x.B - y.B, x.A - y.A); 75 } 76 } 77 78 [MethodImpl(MethodImplOptions.AggressiveInlining)] 79 public static RgbaColor32 operator *(RgbaColor32 x, RgbaColor32 y) 80 { 81 if (Sse41.IsSupported) 82 { 83 return new RgbaColor32(Sse41.MultiplyLow(x._color, y._color)); 84 } 85 else 86 { 87 return new RgbaColor32(x.R * y.R, x.G * y.G, x.B * y.B, x.A * y.A); 88 } 89 } 90 91 public static RgbaColor32 operator /(RgbaColor32 x, RgbaColor32 y) 92 { 93 return new RgbaColor32(x.R / y.R, x.G / y.G, x.B / y.B, x.A / y.A); 94 } 95 96 public static RgbaColor32 DivideGuarded(RgbaColor32 x, RgbaColor32 y, int resultIfZero) 97 { 98 return new RgbaColor32( 99 DivideGuarded(x.R, y.R, resultIfZero), 100 DivideGuarded(x.G, y.G, resultIfZero), 101 DivideGuarded(x.B, y.B, resultIfZero), 102 DivideGuarded(x.A, y.A, resultIfZero)); 103 } 104 105 [MethodImpl(MethodImplOptions.AggressiveInlining)] 106 public static RgbaColor32 operator <<(RgbaColor32 x, [ConstantExpected] byte shift) 107 { 108 if (Sse2.IsSupported) 109 { 110 return new RgbaColor32(Sse2.ShiftLeftLogical(x._color, shift)); 111 } 112 else 113 { 114 return new RgbaColor32(x.R << shift, x.G << shift, x.B << shift, x.A << shift); 115 } 116 } 117 118 [MethodImpl(MethodImplOptions.AggressiveInlining)] 119 public static RgbaColor32 operator >>(RgbaColor32 x, [ConstantExpected] byte shift) 120 { 121 if (Sse2.IsSupported) 122 { 123 return new RgbaColor32(Sse2.ShiftRightLogical(x._color, shift)); 124 } 125 else 126 { 127 return new RgbaColor32(x.R >> shift, x.G >> shift, x.B >> shift, x.A >> shift); 128 } 129 } 130 131 public static bool operator ==(RgbaColor32 x, RgbaColor32 y) 132 { 133 return x.Equals(y); 134 } 135 136 public static bool operator !=(RgbaColor32 x, RgbaColor32 y) 137 { 138 return !x.Equals(y); 139 } 140 141 [MethodImpl(MethodImplOptions.AggressiveInlining)] 142 public static int Dot(RgbaColor32 x, RgbaColor32 y) 143 { 144 if (Sse41.IsSupported) 145 { 146 Vector128<int> product = Sse41.MultiplyLow(x._color, y._color); 147 Vector128<int> sum = Ssse3.HorizontalAdd(product, product); 148 sum = Ssse3.HorizontalAdd(sum, sum); 149 return sum.GetElement(0); 150 } 151 else 152 { 153 return x.R * y.R + x.G * y.G + x.B * y.B + x.A * y.A; 154 } 155 } 156 157 [MethodImpl(MethodImplOptions.AggressiveInlining)] 158 public static RgbaColor32 Max(RgbaColor32 x, RgbaColor32 y) 159 { 160 if (Sse41.IsSupported) 161 { 162 return new RgbaColor32(Sse41.Max(x._color, y._color)); 163 } 164 else 165 { 166 return new RgbaColor32(Math.Max(x.R, y.R), Math.Max(x.G, y.G), Math.Max(x.B, y.B), Math.Max(x.A, y.A)); 167 } 168 } 169 170 [MethodImpl(MethodImplOptions.AggressiveInlining)] 171 public static RgbaColor32 Min(RgbaColor32 x, RgbaColor32 y) 172 { 173 if (Sse41.IsSupported) 174 { 175 return new RgbaColor32(Sse41.Min(x._color, y._color)); 176 } 177 else 178 { 179 return new RgbaColor32(Math.Min(x.R, y.R), Math.Min(x.G, y.G), Math.Min(x.B, y.B), Math.Min(x.A, y.A)); 180 } 181 } 182 183 [MethodImpl(MethodImplOptions.AggressiveInlining)] 184 public readonly RgbaColor8 GetColor8() 185 { 186 if (Sse41.IsSupported) 187 { 188 Vector128<int> temp = _color; 189 Vector128<ushort> color16 = Sse41.PackUnsignedSaturate(temp, temp); 190 Vector128<byte> color8 = Sse2.PackUnsignedSaturate(color16.AsInt16(), color16.AsInt16()); 191 uint color = color8.AsUInt32().GetElement(0); 192 return Unsafe.As<uint, RgbaColor8>(ref color); 193 } 194 else 195 { 196 return new RgbaColor8(ClampByte(R), ClampByte(G), ClampByte(B), ClampByte(A)); 197 } 198 } 199 200 private static int DivideGuarded(int dividend, int divisor, int resultIfZero) 201 { 202 if (divisor == 0) 203 { 204 return resultIfZero; 205 } 206 207 return dividend / divisor; 208 } 209 210 private static byte ClampByte(int value) 211 { 212 return (byte)Math.Clamp(value, 0, 255); 213 } 214 215 public readonly override int GetHashCode() 216 { 217 return HashCode.Combine(R, G, B, A); 218 } 219 220 public readonly override bool Equals(object obj) 221 { 222 return obj is RgbaColor32 other && Equals(other); 223 } 224 225 public readonly bool Equals(RgbaColor32 other) 226 { 227 return _color.Equals(other._color); 228 } 229 } 230 }