Skip to content

Commit 6980a32

Browse files
committed
More efficient Yuy2 decoding
* Rename ColorExtensions to Color * Remove constraints on NumericConversion.GetXXXValue()
1 parent 81e2a38 commit 6980a32

File tree

6 files changed

+252
-49
lines changed

6 files changed

+252
-49
lines changed

AssetRipper.TextureDecoder.ColorGenerator/NumericConversionGenerator.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static void Run()
2020

2121
private static void Write(IndentedTextWriter writer)
2222
{
23-
writer.WriteLine("//This code is source generated. Do not edit manually.");
23+
writer.WriteGeneratedCodeWarning();
2424
writer.WriteLine();
2525
writer.WriteFileScopedNamespace(OutputNamespace);
2626
writer.WriteLine();
@@ -32,6 +32,8 @@ private static void Write(IndentedTextWriter writer)
3232
{
3333
WriteConvertMethod(writer, from);
3434
}
35+
WriteGetValueMethod(writer, "GetMinimumValue");
36+
WriteGetValueMethod(writer, "GetMaximumValue");
3537
WriteChangeSignMethods(writer);
3638
}
3739
}
@@ -226,6 +228,31 @@ private static void WriteConvertMethod(IndentedTextWriter writer, CSharpPrimitiv
226228
writer.WriteLineNoTabs();
227229
}
228230

231+
private static void WriteGetValueMethod(IndentedTextWriter writer, string methodName)
232+
{
233+
writer.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]");
234+
writer.WriteLine($"public static T {methodName}<T>() where T : unmanaged");
235+
using (new CurlyBrackets(writer))
236+
{
237+
foreach (CSharpPrimitives.Data from in CSharpPrimitives.List)
238+
{
239+
string ifOrElseIf = from == CSharpPrimitives.FirstData ? "if" : "else if";
240+
writer.WriteLine($"{ifOrElseIf} (typeof(T) == typeof({from.LangName}))");
241+
using (new CurlyBrackets(writer))
242+
{
243+
writer.WriteLine($"{from.LangName} value = {methodName}Safe<{from.LangName}>();");
244+
writer.WriteLine($"return Unsafe.As<{from.LangName}, T>(ref value);");
245+
}
246+
}
247+
writer.WriteLine("else");
248+
using (new CurlyBrackets(writer))
249+
{
250+
writer.WriteLine("return ThrowOrReturnDefault<T>();");
251+
}
252+
}
253+
writer.WriteLineNoTabs();
254+
}
255+
229256
private static string ConvertMethodName(Type from)
230257
{
231258
return $"Convert{from.Name}";
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
namespace AssetRipper.TextureDecoder.Rgb;
2+
3+
public static class Color
4+
{
5+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
6+
internal static void SetConvertedChannels<TThis, TThisChannel, TSourceChannel>(this ref TThis color, TSourceChannel r, TSourceChannel g, TSourceChannel b)
7+
where TThisChannel : unmanaged
8+
where TSourceChannel : unmanaged
9+
where TThis : unmanaged, IColor<TThisChannel>
10+
{
11+
color.SetChannels(
12+
NumericConversion.Convert<TSourceChannel, TThisChannel>(r),
13+
NumericConversion.Convert<TSourceChannel, TThisChannel>(g),
14+
NumericConversion.Convert<TSourceChannel, TThisChannel>(b),
15+
NumericConversion.GetMaximumValue<TThisChannel>());
16+
}
17+
18+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
19+
internal static void SetConvertedChannels<TThis, TThisChannel, TSourceChannel>(this ref TThis color, TSourceChannel r, TSourceChannel g, TSourceChannel b, TSourceChannel a)
20+
where TThisChannel : unmanaged
21+
where TSourceChannel : unmanaged
22+
where TThis : unmanaged, IColor<TThisChannel>
23+
{
24+
color.SetChannels(
25+
NumericConversion.Convert<TSourceChannel, TThisChannel>(r),
26+
NumericConversion.Convert<TSourceChannel, TThisChannel>(g),
27+
NumericConversion.Convert<TSourceChannel, TThisChannel>(b),
28+
NumericConversion.Convert<TSourceChannel, TThisChannel>(a));
29+
}
30+
31+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
32+
public static TTarget Convert<TThis, TThisChannel, TTarget, TTargetChannel>(this TThis color)
33+
where TThisChannel : unmanaged
34+
where TTargetChannel : unmanaged
35+
where TThis : unmanaged, IColor<TThisChannel>
36+
where TTarget : unmanaged, IColor<TTargetChannel>
37+
{
38+
if (typeof(TThis) == typeof(TTarget))
39+
{
40+
return Unsafe.As<TThis, TTarget>(ref color);
41+
}
42+
else
43+
{
44+
TTarget destination = default;
45+
color.GetChannels(out TThisChannel r, out TThisChannel g, out TThisChannel b, out TThisChannel a);
46+
destination.SetConvertedChannels<TTarget, TTargetChannel, TThisChannel>(r, g, b, a);
47+
return destination;
48+
}
49+
}
50+
}

AssetRipper.TextureDecoder/Rgb/IColor.cs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -48,40 +48,4 @@ public interface IColor<T> : IColorBase where T : unmanaged
4848
void GetChannels(out T r, out T g, out T b, out T a);
4949
void SetChannels(T r, T g, T b, T a);
5050
}
51-
52-
public static class ColorExtensions
53-
{
54-
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
55-
internal static void SetConvertedChannels<TThis, TThisChannel, TSourceChannel>(this ref TThis color, TSourceChannel r, TSourceChannel g, TSourceChannel b, TSourceChannel a)
56-
where TThisChannel : unmanaged
57-
where TSourceChannel : unmanaged
58-
where TThis : unmanaged, IColor<TThisChannel>
59-
{
60-
color.SetChannels(
61-
NumericConversion.Convert<TSourceChannel, TThisChannel>(r),
62-
NumericConversion.Convert<TSourceChannel, TThisChannel>(g),
63-
NumericConversion.Convert<TSourceChannel, TThisChannel>(b),
64-
NumericConversion.Convert<TSourceChannel, TThisChannel>(a));
65-
}
66-
67-
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
68-
public static TTarget Convert<TThis, TThisChannel, TTarget, TTargetChannel>(this TThis color)
69-
where TThisChannel : unmanaged
70-
where TTargetChannel : unmanaged
71-
where TThis : unmanaged, IColor<TThisChannel>
72-
where TTarget : unmanaged, IColor<TTargetChannel>
73-
{
74-
if (typeof(TThis) == typeof(TTarget))
75-
{
76-
return Unsafe.As<TThis, TTarget>(ref color);
77-
}
78-
else
79-
{
80-
TTarget destination = default;
81-
color.GetChannels(out TThisChannel r, out TThisChannel g, out TThisChannel b, out TThisChannel a);
82-
destination.SetConvertedChannels<TTarget, TTargetChannel, TThisChannel>(r, g, b, a);
83-
return destination;
84-
}
85-
}
86-
}
8751
}

AssetRipper.TextureDecoder/Rgb/NumericConversion.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
namespace AssetRipper.TextureDecoder.Rgb;
1+
using System.Runtime.InteropServices;
2+
3+
namespace AssetRipper.TextureDecoder.Rgb;
24
public static partial class NumericConversion
35
{
4-
public static T GetMinimumValue<T>() where T : unmanaged, INumberBase<T>, IMinMaxValue<T>
6+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
7+
private static T GetMinimumValueSafe<T>() where T : unmanaged, INumberBase<T>, IMinMaxValue<T>
58
{
6-
return typeof(T) == typeof(Half) || typeof(T) == typeof(float) || typeof(T) == typeof(double) || typeof(T) == typeof(decimal)
9+
return typeof(T) == typeof(Half) || typeof(T) == typeof(float) || typeof(T) == typeof(NFloat) || typeof(T) == typeof(double) || typeof(T) == typeof(decimal)
710
? T.Zero
811
: T.MinValue;
912
}
1013

11-
public static T GetMaximumValue<T>() where T : unmanaged, INumberBase<T>, IMinMaxValue<T>
14+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
15+
private static T GetMaximumValueSafe<T>() where T : unmanaged, INumberBase<T>, IMinMaxValue<T>
1216
{
13-
return typeof(T) == typeof(Half) || typeof(T) == typeof(float) || typeof(T) == typeof(double) || typeof(T) == typeof(decimal)
17+
return typeof(T) == typeof(Half) || typeof(T) == typeof(float) || typeof(T) == typeof(NFloat) || typeof(T) == typeof(double) || typeof(T) == typeof(decimal)
1418
? T.One
1519
: T.MaxValue;
1620
}
@@ -26,8 +30,8 @@ private static T ThrowOrReturnDefault<T>() where T : struct
2630
#else
2731
return default; //exceptions prevent inlining
2832
#endif
29-
}
30-
33+
}
34+
3135
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
3236
private static TTo ToSignedNumber<TFrom, TTo>(TFrom value)
3337
where TFrom : unmanaged, IUnsignedNumber<TFrom>, IShiftOperators<TFrom, int, TFrom>, IBitwiseOperators<TFrom, TFrom, TFrom>
@@ -41,8 +45,8 @@ private static TTo ToSignedNumber<TFrom, TTo>(TFrom value)
4145
TFrom SignBit = TFrom.One << (Unsafe.SizeOf<TFrom>() * 8 - 1);
4246
TFrom converted = (SignBit ^ value);
4347
return Unsafe.As<TFrom, TTo>(ref converted);
44-
}
45-
48+
}
49+
4650
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
4751
private static TTo ToUnsignedNumber<TFrom, TTo>(TFrom value)
4852
where TFrom : unmanaged, ISignedNumber<TFrom>

AssetRipper.TextureDecoder/Rgb/NumericConversion.g.cs

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//This code is source generated. Do not edit manually.
1+
// Auto-generated code. Do not modify manually.
22

33
namespace AssetRipper.TextureDecoder.Rgb;
44

@@ -938,6 +938,164 @@ private static TTo ConvertDecimal<TTo>(decimal value) where TTo : unmanaged
938938
}
939939
}
940940

941+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
942+
public static T GetMinimumValue<T>() where T : unmanaged
943+
{
944+
if (typeof(T) == typeof(sbyte))
945+
{
946+
sbyte value = GetMinimumValueSafe<sbyte>();
947+
return Unsafe.As<sbyte, T>(ref value);
948+
}
949+
else if (typeof(T) == typeof(byte))
950+
{
951+
byte value = GetMinimumValueSafe<byte>();
952+
return Unsafe.As<byte, T>(ref value);
953+
}
954+
else if (typeof(T) == typeof(short))
955+
{
956+
short value = GetMinimumValueSafe<short>();
957+
return Unsafe.As<short, T>(ref value);
958+
}
959+
else if (typeof(T) == typeof(ushort))
960+
{
961+
ushort value = GetMinimumValueSafe<ushort>();
962+
return Unsafe.As<ushort, T>(ref value);
963+
}
964+
else if (typeof(T) == typeof(int))
965+
{
966+
int value = GetMinimumValueSafe<int>();
967+
return Unsafe.As<int, T>(ref value);
968+
}
969+
else if (typeof(T) == typeof(uint))
970+
{
971+
uint value = GetMinimumValueSafe<uint>();
972+
return Unsafe.As<uint, T>(ref value);
973+
}
974+
else if (typeof(T) == typeof(long))
975+
{
976+
long value = GetMinimumValueSafe<long>();
977+
return Unsafe.As<long, T>(ref value);
978+
}
979+
else if (typeof(T) == typeof(ulong))
980+
{
981+
ulong value = GetMinimumValueSafe<ulong>();
982+
return Unsafe.As<ulong, T>(ref value);
983+
}
984+
else if (typeof(T) == typeof(Int128))
985+
{
986+
Int128 value = GetMinimumValueSafe<Int128>();
987+
return Unsafe.As<Int128, T>(ref value);
988+
}
989+
else if (typeof(T) == typeof(UInt128))
990+
{
991+
UInt128 value = GetMinimumValueSafe<UInt128>();
992+
return Unsafe.As<UInt128, T>(ref value);
993+
}
994+
else if (typeof(T) == typeof(Half))
995+
{
996+
Half value = GetMinimumValueSafe<Half>();
997+
return Unsafe.As<Half, T>(ref value);
998+
}
999+
else if (typeof(T) == typeof(float))
1000+
{
1001+
float value = GetMinimumValueSafe<float>();
1002+
return Unsafe.As<float, T>(ref value);
1003+
}
1004+
else if (typeof(T) == typeof(double))
1005+
{
1006+
double value = GetMinimumValueSafe<double>();
1007+
return Unsafe.As<double, T>(ref value);
1008+
}
1009+
else if (typeof(T) == typeof(decimal))
1010+
{
1011+
decimal value = GetMinimumValueSafe<decimal>();
1012+
return Unsafe.As<decimal, T>(ref value);
1013+
}
1014+
else
1015+
{
1016+
return ThrowOrReturnDefault<T>();
1017+
}
1018+
}
1019+
1020+
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
1021+
public static T GetMaximumValue<T>() where T : unmanaged
1022+
{
1023+
if (typeof(T) == typeof(sbyte))
1024+
{
1025+
sbyte value = GetMaximumValueSafe<sbyte>();
1026+
return Unsafe.As<sbyte, T>(ref value);
1027+
}
1028+
else if (typeof(T) == typeof(byte))
1029+
{
1030+
byte value = GetMaximumValueSafe<byte>();
1031+
return Unsafe.As<byte, T>(ref value);
1032+
}
1033+
else if (typeof(T) == typeof(short))
1034+
{
1035+
short value = GetMaximumValueSafe<short>();
1036+
return Unsafe.As<short, T>(ref value);
1037+
}
1038+
else if (typeof(T) == typeof(ushort))
1039+
{
1040+
ushort value = GetMaximumValueSafe<ushort>();
1041+
return Unsafe.As<ushort, T>(ref value);
1042+
}
1043+
else if (typeof(T) == typeof(int))
1044+
{
1045+
int value = GetMaximumValueSafe<int>();
1046+
return Unsafe.As<int, T>(ref value);
1047+
}
1048+
else if (typeof(T) == typeof(uint))
1049+
{
1050+
uint value = GetMaximumValueSafe<uint>();
1051+
return Unsafe.As<uint, T>(ref value);
1052+
}
1053+
else if (typeof(T) == typeof(long))
1054+
{
1055+
long value = GetMaximumValueSafe<long>();
1056+
return Unsafe.As<long, T>(ref value);
1057+
}
1058+
else if (typeof(T) == typeof(ulong))
1059+
{
1060+
ulong value = GetMaximumValueSafe<ulong>();
1061+
return Unsafe.As<ulong, T>(ref value);
1062+
}
1063+
else if (typeof(T) == typeof(Int128))
1064+
{
1065+
Int128 value = GetMaximumValueSafe<Int128>();
1066+
return Unsafe.As<Int128, T>(ref value);
1067+
}
1068+
else if (typeof(T) == typeof(UInt128))
1069+
{
1070+
UInt128 value = GetMaximumValueSafe<UInt128>();
1071+
return Unsafe.As<UInt128, T>(ref value);
1072+
}
1073+
else if (typeof(T) == typeof(Half))
1074+
{
1075+
Half value = GetMaximumValueSafe<Half>();
1076+
return Unsafe.As<Half, T>(ref value);
1077+
}
1078+
else if (typeof(T) == typeof(float))
1079+
{
1080+
float value = GetMaximumValueSafe<float>();
1081+
return Unsafe.As<float, T>(ref value);
1082+
}
1083+
else if (typeof(T) == typeof(double))
1084+
{
1085+
double value = GetMaximumValueSafe<double>();
1086+
return Unsafe.As<double, T>(ref value);
1087+
}
1088+
else if (typeof(T) == typeof(decimal))
1089+
{
1090+
decimal value = GetMaximumValueSafe<decimal>();
1091+
return Unsafe.As<decimal, T>(ref value);
1092+
}
1093+
else
1094+
{
1095+
return ThrowOrReturnDefault<T>();
1096+
}
1097+
}
1098+
9411099
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
9421100
private static sbyte ChangeSign(byte value)
9431101
{

AssetRipper.TextureDecoder/Yuy2/Yuy2Decoder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ public static int DecompressYUY2<TOutputColor, TOutputChannel>(ReadOnlySpan<byte
133133
byte b0 = ClampByte((298 * c + 516 * d + 128) >> 8); // blue
134134
byte g0 = ClampByte((298 * c - 100 * d - 208 * e + 128) >> 8); // green
135135
byte r0 = ClampByte((298 * c + 409 * e + 128) >> 8); // red
136-
output[o++].SetConvertedChannels<TOutputColor, TOutputChannel, byte>(r0, g0, b0, byte.MaxValue);
136+
output[o++].SetConvertedChannels<TOutputColor, TOutputChannel, byte>(r0, g0, b0);
137137
c = y1 - 16;
138138
byte b1 = ClampByte((298 * c + 516 * d + 128) >> 8); // blue
139139
byte g1 = ClampByte((298 * c - 100 * d - 208 * e + 128) >> 8); // green
140140
byte r1 = ClampByte((298 * c + 409 * e + 128) >> 8); // red
141-
output[o++].SetConvertedChannels<TOutputColor, TOutputChannel, byte>(r1, g1, b1, byte.MaxValue);
141+
output[o++].SetConvertedChannels<TOutputColor, TOutputChannel, byte>(r1, g1, b1);
142142
}
143143
}
144144

0 commit comments

Comments
 (0)