mirror of
https://github.com/DarthAffe/HPPH.git
synced 2025-12-12 13:28:37 +00:00
Merge pull request #7 from DarthAffe/PerformanceImprovements
Performance improvements
This commit is contained in:
commit
94695ab9cb
@ -13,6 +13,8 @@ public class AverageBenchmarks
|
|||||||
|
|
||||||
private readonly List<ColorRGB[]> _colors3bpp;
|
private readonly List<ColorRGB[]> _colors3bpp;
|
||||||
private readonly List<ColorRGBA[]> _colors4bpp;
|
private readonly List<ColorRGBA[]> _colors4bpp;
|
||||||
|
private readonly List<IImage<ColorRGB>> _images3bpp;
|
||||||
|
private readonly List<IImage<ColorRGBA>> _images4bpp;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -22,6 +24,9 @@ public class AverageBenchmarks
|
|||||||
{
|
{
|
||||||
_colors3bpp = BenchmarkHelper.GetSampleData<ColorRGB>();
|
_colors3bpp = BenchmarkHelper.GetSampleData<ColorRGB>();
|
||||||
_colors4bpp = BenchmarkHelper.GetSampleData<ColorRGBA>();
|
_colors4bpp = BenchmarkHelper.GetSampleData<ColorRGBA>();
|
||||||
|
|
||||||
|
_images3bpp = BenchmarkHelper.GetSampleDataImages<ColorRGB>();
|
||||||
|
_images4bpp = BenchmarkHelper.GetSampleDataImages<ColorRGBA>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -48,6 +53,26 @@ public class AverageBenchmarks
|
|||||||
return averages;
|
return averages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ColorRGB[] PixelHelper_3BPP_Image()
|
||||||
|
{
|
||||||
|
ColorRGB[] averages = new ColorRGB[_images3bpp.Count];
|
||||||
|
for (int i = 0; i < _images3bpp.Count; i++)
|
||||||
|
averages[i] = _images3bpp[i].Average();
|
||||||
|
|
||||||
|
return averages;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ColorRGBA[] PixelHelper_4BPP_Image()
|
||||||
|
{
|
||||||
|
ColorRGBA[] averages = new ColorRGBA[_images4bpp.Count];
|
||||||
|
for (int i = 0; i < _images4bpp.Count; i++)
|
||||||
|
averages[i] = _images4bpp[i].Average();
|
||||||
|
|
||||||
|
return averages;
|
||||||
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public ColorRGB[] Reference_3BPP()
|
public ColorRGB[] Reference_3BPP()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -21,4 +21,18 @@ internal static class BenchmarkHelper
|
|||||||
|
|
||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<IImage<T>> GetSampleDataImages<T>()
|
||||||
|
where T : struct, IColor
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(SAMPLE_DATA_DIR)) throw new Exception("sample data not found!");
|
||||||
|
|
||||||
|
List<IImage<T>> colors = [];
|
||||||
|
|
||||||
|
IEnumerable<string> files = Directory.EnumerateFiles(SAMPLE_DATA_DIR, "*.png", SearchOption.AllDirectories);
|
||||||
|
foreach (string file in files)
|
||||||
|
colors.Add(ImageHelper.LoadImage(file).ConvertTo<T>());
|
||||||
|
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -13,6 +13,8 @@ public class MinMaxBenchmarks
|
|||||||
|
|
||||||
private readonly List<ColorRGB[]> _colors3bpp;
|
private readonly List<ColorRGB[]> _colors3bpp;
|
||||||
private readonly List<ColorRGBA[]> _colors4bpp;
|
private readonly List<ColorRGBA[]> _colors4bpp;
|
||||||
|
private readonly List<IImage<ColorRGB>> _images3bpp;
|
||||||
|
private readonly List<IImage<ColorRGBA>> _images4bpp;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -22,6 +24,9 @@ public class MinMaxBenchmarks
|
|||||||
{
|
{
|
||||||
_colors3bpp = BenchmarkHelper.GetSampleData<ColorRGB>();
|
_colors3bpp = BenchmarkHelper.GetSampleData<ColorRGB>();
|
||||||
_colors4bpp = BenchmarkHelper.GetSampleData<ColorRGBA>();
|
_colors4bpp = BenchmarkHelper.GetSampleData<ColorRGBA>();
|
||||||
|
|
||||||
|
_images3bpp = BenchmarkHelper.GetSampleDataImages<ColorRGB>();
|
||||||
|
_images4bpp = BenchmarkHelper.GetSampleDataImages<ColorRGBA>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -48,6 +53,26 @@ public class MinMaxBenchmarks
|
|||||||
return minMax;
|
return minMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IMinMax[] PixelHelper_3BPP_Image()
|
||||||
|
{
|
||||||
|
IMinMax[] minMax = new IMinMax[_images3bpp.Count];
|
||||||
|
for (int i = 0; i < _images3bpp.Count; i++)
|
||||||
|
minMax[i] = _images3bpp[i].MinMax();
|
||||||
|
|
||||||
|
return minMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IMinMax[] PixelHelper_4BPP_Image()
|
||||||
|
{
|
||||||
|
IMinMax[] minMax = new IMinMax[_images4bpp.Count];
|
||||||
|
for (int i = 0; i < _images4bpp.Count; i++)
|
||||||
|
minMax[i] = _images4bpp[i].MinMax();
|
||||||
|
|
||||||
|
return minMax;
|
||||||
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public IMinMax[] Reference_3BPP()
|
public IMinMax[] Reference_3BPP()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -13,6 +13,8 @@ public class SumBenchmarks
|
|||||||
|
|
||||||
private readonly List<ColorRGB[]> _colors3bpp;
|
private readonly List<ColorRGB[]> _colors3bpp;
|
||||||
private readonly List<ColorRGBA[]> _colors4bpp;
|
private readonly List<ColorRGBA[]> _colors4bpp;
|
||||||
|
private readonly List<IImage<ColorRGB>> _images3bpp;
|
||||||
|
private readonly List<IImage<ColorRGBA>> _images4bpp;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -22,6 +24,9 @@ public class SumBenchmarks
|
|||||||
{
|
{
|
||||||
_colors3bpp = BenchmarkHelper.GetSampleData<ColorRGB>();
|
_colors3bpp = BenchmarkHelper.GetSampleData<ColorRGB>();
|
||||||
_colors4bpp = BenchmarkHelper.GetSampleData<ColorRGBA>();
|
_colors4bpp = BenchmarkHelper.GetSampleData<ColorRGBA>();
|
||||||
|
|
||||||
|
_images3bpp = BenchmarkHelper.GetSampleDataImages<ColorRGB>();
|
||||||
|
_images4bpp = BenchmarkHelper.GetSampleDataImages<ColorRGBA>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -48,6 +53,26 @@ public class SumBenchmarks
|
|||||||
return sums;
|
return sums;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ISum[] PixelHelper_3BPP_Image()
|
||||||
|
{
|
||||||
|
ISum[] sums = new ISum[_colors3bpp.Count];
|
||||||
|
for (int i = 0; i < _images3bpp.Count; i++)
|
||||||
|
sums[i] = _images3bpp[i].Sum();
|
||||||
|
|
||||||
|
return sums;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ISum[] PixelHelper_4BPP_Image()
|
||||||
|
{
|
||||||
|
ISum[] sums = new ISum[_images4bpp.Count];
|
||||||
|
for (int i = 0; i < _images4bpp.Count; i++)
|
||||||
|
sums[i] = _images4bpp[i].Sum();
|
||||||
|
|
||||||
|
return sums;
|
||||||
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public ISum[] Reference_3BPP()
|
public ISum[] Reference_3BPP()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -19,7 +19,6 @@ public class ColorSourceGenerator : IIncrementalGenerator
|
|||||||
private static readonly IGeneratorFeature[] FEATURES =
|
private static readonly IGeneratorFeature[] FEATURES =
|
||||||
[
|
[
|
||||||
new Colors(),
|
new Colors(),
|
||||||
new Average(),
|
|
||||||
new MinMax(),
|
new MinMax(),
|
||||||
new Sum(),
|
new Sum(),
|
||||||
new Quantize()
|
new Quantize()
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Immutable;
|
|
||||||
|
|
||||||
namespace HPPH.Generators;
|
|
||||||
|
|
||||||
internal class Average : IGeneratorFeature
|
|
||||||
{
|
|
||||||
public IEnumerable<(string name, string source)> GenerateFor(ColorFormatData colorFormat)
|
|
||||||
{
|
|
||||||
yield return ($"ColorFormat{colorFormat.Format}.Average", GenerateColorFormatAverage(colorFormat));
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<(string name, string source)> GenerateFor(ImmutableArray<ColorFormatData> colorFormats)
|
|
||||||
{
|
|
||||||
yield return ("IColorFormat.Average", GenerateColorFormatInterfaceAverage());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GenerateColorFormatAverage(ColorFormatData colorFormat)
|
|
||||||
{
|
|
||||||
return $$"""
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace HPPH;
|
|
||||||
|
|
||||||
public sealed partial class ColorFormat{{colorFormat.Format}}
|
|
||||||
{
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
unsafe IColor IColorFormat.Average(ReadOnlySpan<byte> data) => PixelHelper.Average(MemoryMarshal.Cast<byte, Color{{colorFormat.Format}}>(data));
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GenerateColorFormatInterfaceAverage()
|
|
||||||
{
|
|
||||||
return """
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
namespace HPPH;
|
|
||||||
|
|
||||||
public partial interface IColorFormat
|
|
||||||
{
|
|
||||||
internal IColor Average(ReadOnlySpan<byte> data);
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -218,6 +218,12 @@ internal class Colors : IGeneratorFeature
|
|||||||
private ColorFormat{{colorFormat.Format}}() {}
|
private ColorFormat{{colorFormat.Format}}() {}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public IColor CreateColor(byte r, byte g, byte b, byte a) => Color{{colorFormat.Format}}.Create(r, g, b, a);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
@ -243,6 +249,8 @@ internal class Colors : IGeneratorFeature
|
|||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
sb.AppendLine("""
|
sb.AppendLine("""
|
||||||
|
IColor CreateColor(byte r, byte g, byte b, byte a);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
|
|||||||
@ -139,6 +139,7 @@ internal class MinMax : IGeneratorFeature
|
|||||||
return $$"""
|
return $$"""
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -147,7 +148,8 @@ internal class MinMax : IGeneratorFeature
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<Color{{colorFormat.Format}}, MinMax{{colorFormat.Format}}>(MemoryMarshal.Cast<byte, Color{{colorFormat.Format}}>(data));
|
unsafe IMinMax IColorFormat.ToMinMax(Generic3ByteMinMax data) => {{(colorFormat.Bpp == 3 ? $"Unsafe.BitCast<Generic3ByteMinMax, MinMax{colorFormat.Format}>(data);" : "throw new NotSupportedException();")}}
|
||||||
|
unsafe IMinMax IColorFormat.ToMinMax(Generic4ByteMinMax data) => {{(colorFormat.Bpp == 4 ? $"Unsafe.BitCast<Generic4ByteMinMax, MinMax{colorFormat.Format}>(data);" : "throw new NotSupportedException();")}}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -163,7 +165,8 @@ internal class MinMax : IGeneratorFeature
|
|||||||
|
|
||||||
public partial interface IColorFormat
|
public partial interface IColorFormat
|
||||||
{
|
{
|
||||||
internal IMinMax MinMax(ReadOnlySpan<byte> data);
|
internal IMinMax ToMinMax(Generic3ByteMinMax data);
|
||||||
|
internal IMinMax ToMinMax(Generic4ByteMinMax data);
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -106,6 +106,7 @@ internal class Sum : IGeneratorFeature
|
|||||||
return $$"""
|
return $$"""
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -114,7 +115,8 @@ internal class Sum : IGeneratorFeature
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<Color{{colorFormat.Format}}, Sum{{colorFormat.Format}}>(MemoryMarshal.Cast<byte, Color{{colorFormat.Format}}>(data));
|
unsafe Generic4LongData IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum(MemoryMarshal.Cast<byte, Generic{{colorFormat.Bpp}}ByteData>(data));
|
||||||
|
unsafe ISum IColorFormat.ToSum(Generic4LongData data) => Unsafe.BitCast<Generic4LongData, Sum{{colorFormat.Format}}>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -130,7 +132,8 @@ internal class Sum : IGeneratorFeature
|
|||||||
|
|
||||||
public partial interface IColorFormat
|
public partial interface IColorFormat
|
||||||
{
|
{
|
||||||
internal ISum Sum(ReadOnlySpan<byte> data);
|
internal Generic4LongData Sum(ReadOnlySpan<byte> data);
|
||||||
|
internal ISum ToSum(Generic4LongData data);
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatABGR
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorABGR, MinMaxABGR>(MemoryMarshal.Cast<byte, ColorABGR>(data));
|
unsafe IMinMax IColorFormat.ToMinMax(Generic3ByteMinMax data) => throw new NotSupportedException();
|
||||||
|
unsafe IMinMax IColorFormat.ToMinMax(Generic4ByteMinMax data) => Unsafe.BitCast<Generic4ByteMinMax, MinMaxABGR>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatABGR
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorABGR, SumABGR>(MemoryMarshal.Cast<byte, ColorABGR>(data));
|
unsafe Generic4LongData IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum(MemoryMarshal.Cast<byte, Generic4ByteData>(data));
|
||||||
|
unsafe ISum IColorFormat.ToSum(Generic4LongData data) => Unsafe.BitCast<Generic4LongData, SumABGR>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatABGR : IColorFormat
|
|||||||
private ColorFormatABGR() {}
|
private ColorFormatABGR() {}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorABGR.Create(r, g, b, a);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatARGB
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorARGB, MinMaxARGB>(MemoryMarshal.Cast<byte, ColorARGB>(data));
|
unsafe IMinMax IColorFormat.ToMinMax(Generic3ByteMinMax data) => throw new NotSupportedException();
|
||||||
|
unsafe IMinMax IColorFormat.ToMinMax(Generic4ByteMinMax data) => Unsafe.BitCast<Generic4ByteMinMax, MinMaxARGB>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatARGB
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorARGB, SumARGB>(MemoryMarshal.Cast<byte, ColorARGB>(data));
|
unsafe Generic4LongData IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum(MemoryMarshal.Cast<byte, Generic4ByteData>(data));
|
||||||
|
unsafe ISum IColorFormat.ToSum(Generic4LongData data) => Unsafe.BitCast<Generic4LongData, SumARGB>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatARGB : IColorFormat
|
|||||||
private ColorFormatARGB() {}
|
private ColorFormatARGB() {}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorARGB.Create(r, g, b, a);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatBGR
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorBGR, MinMaxBGR>(MemoryMarshal.Cast<byte, ColorBGR>(data));
|
unsafe IMinMax IColorFormat.ToMinMax(Generic3ByteMinMax data) => Unsafe.BitCast<Generic3ByteMinMax, MinMaxBGR>(data);
|
||||||
|
unsafe IMinMax IColorFormat.ToMinMax(Generic4ByteMinMax data) => throw new NotSupportedException();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatBGR
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorBGR, SumBGR>(MemoryMarshal.Cast<byte, ColorBGR>(data));
|
unsafe Generic4LongData IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum(MemoryMarshal.Cast<byte, Generic3ByteData>(data));
|
||||||
|
unsafe ISum IColorFormat.ToSum(Generic4LongData data) => Unsafe.BitCast<Generic4LongData, SumBGR>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatBGR : IColorFormat
|
|||||||
private ColorFormatBGR() {}
|
private ColorFormatBGR() {}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorBGR.Create(r, g, b, a);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatBGRA
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorBGRA, MinMaxBGRA>(MemoryMarshal.Cast<byte, ColorBGRA>(data));
|
unsafe IMinMax IColorFormat.ToMinMax(Generic3ByteMinMax data) => throw new NotSupportedException();
|
||||||
|
unsafe IMinMax IColorFormat.ToMinMax(Generic4ByteMinMax data) => Unsafe.BitCast<Generic4ByteMinMax, MinMaxBGRA>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatBGRA
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorBGRA, SumBGRA>(MemoryMarshal.Cast<byte, ColorBGRA>(data));
|
unsafe Generic4LongData IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum(MemoryMarshal.Cast<byte, Generic4ByteData>(data));
|
||||||
|
unsafe ISum IColorFormat.ToSum(Generic4LongData data) => Unsafe.BitCast<Generic4LongData, SumBGRA>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatBGRA : IColorFormat
|
|||||||
private ColorFormatBGRA() {}
|
private ColorFormatBGRA() {}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorBGRA.Create(r, g, b, a);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatRGB
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorRGB, MinMaxRGB>(MemoryMarshal.Cast<byte, ColorRGB>(data));
|
unsafe IMinMax IColorFormat.ToMinMax(Generic3ByteMinMax data) => Unsafe.BitCast<Generic3ByteMinMax, MinMaxRGB>(data);
|
||||||
|
unsafe IMinMax IColorFormat.ToMinMax(Generic4ByteMinMax data) => throw new NotSupportedException();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatRGB
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorRGB, SumRGB>(MemoryMarshal.Cast<byte, ColorRGB>(data));
|
unsafe Generic4LongData IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum(MemoryMarshal.Cast<byte, Generic3ByteData>(data));
|
||||||
|
unsafe ISum IColorFormat.ToSum(Generic4LongData data) => Unsafe.BitCast<Generic4LongData, SumRGB>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatRGB : IColorFormat
|
|||||||
private ColorFormatRGB() {}
|
private ColorFormatRGB() {}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorRGB.Create(r, g, b, a);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatRGBA
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe IMinMax IColorFormat.MinMax(ReadOnlySpan<byte> data) => PixelHelper.MinMax<ColorRGBA, MinMaxRGBA>(MemoryMarshal.Cast<byte, ColorRGBA>(data));
|
unsafe IMinMax IColorFormat.ToMinMax(Generic3ByteMinMax data) => throw new NotSupportedException();
|
||||||
|
unsafe IMinMax IColorFormat.ToMinMax(Generic4ByteMinMax data) => Unsafe.BitCast<Generic4ByteMinMax, MinMaxRGBA>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -8,7 +9,8 @@ public sealed partial class ColorFormatRGBA
|
|||||||
{
|
{
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
unsafe ISum IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum<ColorRGBA, SumRGBA>(MemoryMarshal.Cast<byte, ColorRGBA>(data));
|
unsafe Generic4LongData IColorFormat.Sum(ReadOnlySpan<byte> data) => PixelHelper.Sum(MemoryMarshal.Cast<byte, Generic4ByteData>(data));
|
||||||
|
unsafe ISum IColorFormat.ToSum(Generic4LongData data) => Unsafe.BitCast<Generic4LongData, SumRGBA>(data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatRGBA : IColorFormat
|
|||||||
private ColorFormatRGBA() {}
|
private ColorFormatRGBA() {}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorRGBA.Create(r, g, b, a);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@ -13,5 +13,7 @@ public partial interface IColorFormat
|
|||||||
public static ColorFormatRGBA RGBA => ColorFormatRGBA.Instance;
|
public static ColorFormatRGBA RGBA => ColorFormatRGBA.Instance;
|
||||||
public static ColorFormatBGRA BGRA => ColorFormatBGRA.Instance;
|
public static ColorFormatBGRA BGRA => ColorFormatBGRA.Instance;
|
||||||
|
|
||||||
|
IColor CreateColor(byte r, byte g, byte b, byte a);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,5 +4,6 @@ namespace HPPH;
|
|||||||
|
|
||||||
public partial interface IColorFormat
|
public partial interface IColorFormat
|
||||||
{
|
{
|
||||||
internal IMinMax MinMax(ReadOnlySpan<byte> data);
|
internal IMinMax ToMinMax(Generic3ByteMinMax data);
|
||||||
|
internal IMinMax ToMinMax(Generic4ByteMinMax data);
|
||||||
}
|
}
|
||||||
@ -4,5 +4,6 @@ namespace HPPH;
|
|||||||
|
|
||||||
public partial interface IColorFormat
|
public partial interface IColorFormat
|
||||||
{
|
{
|
||||||
internal ISum Sum(ReadOnlySpan<byte> data);
|
internal Generic4LongData Sum(ReadOnlySpan<byte> data);
|
||||||
|
internal ISum ToSum(Generic4LongData data);
|
||||||
}
|
}
|
||||||
@ -156,6 +156,9 @@ internal sealed class IColorImageRow<T> : IImageRow
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ReadOnlySpan<byte> AsByteSpan() => _buffer.AsSpan().Slice(_start, SizeInBytes);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void CopyTo(Span<IColor> destination)
|
public void CopyTo(Span<IColor> destination)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -22,6 +22,8 @@ public interface IImageRow : IEnumerable<IColor>
|
|||||||
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
|
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
|
||||||
IColor this[int x] { get; }
|
IColor this[int x] { get; }
|
||||||
|
|
||||||
|
ReadOnlySpan<byte> AsByteSpan();
|
||||||
|
|
||||||
void CopyTo(Span<IColor> destination);
|
void CopyTo(Span<IColor> destination);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using System.Buffers;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -12,29 +11,14 @@ public static partial class PixelHelper
|
|||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(image);
|
ArgumentNullException.ThrowIfNull(image);
|
||||||
|
|
||||||
int dataLength = image.SizeInBytes;
|
float count = image.Width * image.Height;
|
||||||
|
|
||||||
if (dataLength <= 1024)
|
ISum sum = Sum(image);
|
||||||
{
|
|
||||||
Span<byte> buffer = stackalloc byte[dataLength];
|
|
||||||
|
|
||||||
image.CopyTo(buffer);
|
return image.ColorFormat.CreateColor((byte)MathF.Round(sum.R / count),
|
||||||
return image.ColorFormat.Average(buffer);
|
(byte)MathF.Round(sum.G / count),
|
||||||
}
|
(byte)MathF.Round(sum.B / count),
|
||||||
else
|
(byte)MathF.Round(sum.A / count));
|
||||||
{
|
|
||||||
byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
|
|
||||||
Span<byte> buffer = array.AsSpan()[..dataLength];
|
|
||||||
try
|
|
||||||
{
|
|
||||||
image.CopyTo(buffer);
|
|
||||||
return image.ColorFormat.Average(buffer);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<byte>.Shared.Return(array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T Average<T>(this IImage<T> image)
|
public static T Average<T>(this IImage<T> image)
|
||||||
@ -48,30 +32,13 @@ public static partial class PixelHelper
|
|||||||
public static T Average<T>(this RefImage<T> image)
|
public static T Average<T>(this RefImage<T> image)
|
||||||
where T : struct, IColor
|
where T : struct, IColor
|
||||||
{
|
{
|
||||||
int dataLength = image.Width * image.Height;
|
float count = image.Width * image.Height;
|
||||||
int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel;
|
|
||||||
|
|
||||||
if (sizeInBytes <= 1024)
|
ISum sum = Sum(image);
|
||||||
{
|
return (T)T.Create((byte)MathF.Round(sum.R / count),
|
||||||
Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
|
(byte)MathF.Round(sum.G / count),
|
||||||
|
(byte)MathF.Round(sum.B / count),
|
||||||
image.CopyTo(buffer);
|
(byte)MathF.Round(sum.A / count));
|
||||||
return Average(buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
T[] array = ArrayPool<T>.Shared.Rent(dataLength);
|
|
||||||
Span<T> buffer = array.AsSpan()[..dataLength];
|
|
||||||
try
|
|
||||||
{
|
|
||||||
image.CopyTo(buffer);
|
|
||||||
return Average(buffer);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T Average<T>(this Span<T> colors)
|
public static T Average<T>(this Span<T> colors)
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using System.Buffers;
|
using System.Numerics;
|
||||||
using System.Numerics;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@ -13,29 +12,40 @@ public static unsafe partial class PixelHelper
|
|||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(image);
|
ArgumentNullException.ThrowIfNull(image);
|
||||||
|
|
||||||
int dataLength = image.SizeInBytes;
|
IColorFormat colorFormat = image.ColorFormat;
|
||||||
|
|
||||||
if (dataLength <= 1024)
|
if (colorFormat.BytesPerPixel == 3)
|
||||||
{
|
{
|
||||||
Span<byte> buffer = stackalloc byte[dataLength];
|
if (image.Height == 0) return colorFormat.ToMinMax(new Generic3ByteMinMax(byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue));
|
||||||
|
if (image.Height == 1) return colorFormat.ToMinMax(MinMax(MemoryMarshal.Cast<byte, Generic3ByteData>(image.Rows[0].AsByteSpan())));
|
||||||
|
|
||||||
image.CopyTo(buffer);
|
Generic3ByteMinMax result = new(byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue);
|
||||||
return image.ColorFormat.MinMax(buffer);
|
for (int y = 0; y < image.Height; y++)
|
||||||
|
result = MinMax(MemoryMarshal.Cast<byte, Generic3ByteData>(image.Rows[y].AsByteSpan()),
|
||||||
|
result.B1Min, result.B1Max,
|
||||||
|
result.B2Min, result.B2Max,
|
||||||
|
result.B3Min, result.B3Max);
|
||||||
|
|
||||||
|
return colorFormat.ToMinMax(result);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (colorFormat.BytesPerPixel == 4)
|
||||||
{
|
{
|
||||||
byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
|
if (image.Height == 0) return colorFormat.ToMinMax(new Generic4ByteMinMax(byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue));
|
||||||
Span<byte> buffer = array.AsSpan()[..dataLength];
|
if (image.Height == 1) return colorFormat.ToMinMax(MinMax(MemoryMarshal.Cast<byte, Generic4ByteData>(image.Rows[0].AsByteSpan())));
|
||||||
try
|
|
||||||
{
|
Generic4ByteMinMax result = new(byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue);
|
||||||
image.CopyTo(buffer);
|
for (int y = 0; y < image.Height; y++)
|
||||||
return image.ColorFormat.MinMax(buffer);
|
result = MinMax(MemoryMarshal.Cast<byte, Generic4ByteData>(image.Rows[y].AsByteSpan()),
|
||||||
}
|
result.B1Min, result.B1Max,
|
||||||
finally
|
result.B2Min, result.B2Max,
|
||||||
{
|
result.B3Min, result.B3Max,
|
||||||
ArrayPool<byte>.Shared.Return(array);
|
result.B4Min, result.B4Max);
|
||||||
}
|
|
||||||
|
return colorFormat.ToMinMax(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException("Data is not of a supported valid color-type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IMinMax MinMax<T>(this IImage<T> image)
|
public static IMinMax MinMax<T>(this IImage<T> image)
|
||||||
@ -49,58 +59,75 @@ public static unsafe partial class PixelHelper
|
|||||||
public static IMinMax MinMax<T>(this RefImage<T> image)
|
public static IMinMax MinMax<T>(this RefImage<T> image)
|
||||||
where T : struct, IColor
|
where T : struct, IColor
|
||||||
{
|
{
|
||||||
int dataLength = image.Width * image.Height;
|
IColorFormat colorFormat = T.ColorFormat;
|
||||||
int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel;
|
|
||||||
|
|
||||||
if (sizeInBytes <= 1024)
|
if (colorFormat.BytesPerPixel == 3)
|
||||||
{
|
{
|
||||||
Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
|
if (image.Height == 0) return colorFormat.ToMinMax(new Generic3ByteMinMax(byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue));
|
||||||
|
if (image.Height == 1) return colorFormat.ToMinMax(MinMax(MemoryMarshal.Cast<byte, Generic3ByteData>(image.Rows[0].AsByteSpan())));
|
||||||
|
|
||||||
image.CopyTo(buffer);
|
Generic3ByteMinMax result = new(byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue);
|
||||||
return MinMax(buffer);
|
for (int y = 0; y < image.Height; y++)
|
||||||
|
result = MinMax(MemoryMarshal.Cast<byte, Generic3ByteData>(image.Rows[y].AsByteSpan()),
|
||||||
|
result.B1Min, result.B1Max,
|
||||||
|
result.B2Min, result.B2Max,
|
||||||
|
result.B3Min, result.B3Max);
|
||||||
|
|
||||||
|
return colorFormat.ToMinMax(result);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (colorFormat.BytesPerPixel == 4)
|
||||||
{
|
{
|
||||||
T[] array = ArrayPool<T>.Shared.Rent(dataLength);
|
if (image.Height == 0) return colorFormat.ToMinMax(new Generic4ByteMinMax(byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue));
|
||||||
Span<T> buffer = array.AsSpan()[..(dataLength)];
|
if (image.Height == 1) return colorFormat.ToMinMax(MinMax(MemoryMarshal.Cast<byte, Generic4ByteData>(image.Rows[0].AsByteSpan())));
|
||||||
try
|
|
||||||
{
|
Generic4ByteMinMax result = new(byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue);
|
||||||
image.CopyTo(buffer);
|
for (int y = 0; y < image.Height; y++)
|
||||||
return MinMax(buffer);
|
result = MinMax(MemoryMarshal.Cast<byte, Generic4ByteData>(image.Rows[y].AsByteSpan()),
|
||||||
}
|
result.B1Min, result.B1Max,
|
||||||
finally
|
result.B2Min, result.B2Max,
|
||||||
{
|
result.B3Min, result.B3Max,
|
||||||
ArrayPool<T>.Shared.Return(array);
|
result.B4Min, result.B4Max);
|
||||||
}
|
|
||||||
|
return colorFormat.ToMinMax(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException("Data is not of a supported valid color-type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IMinMax MinMax<T>(this Span<T> colors)
|
public static IMinMax MinMax<T>(this Span<T> colors)
|
||||||
where T : struct, IColor
|
where T : struct, IColor
|
||||||
=> T.ColorFormat.MinMax(MemoryMarshal.AsBytes(colors));
|
|
||||||
|
|
||||||
public static IMinMax MinMax<T>(this ReadOnlySpan<T> colors)
|
|
||||||
where T : struct, IColor
|
|
||||||
=> T.ColorFormat.MinMax(MemoryMarshal.AsBytes(colors));
|
|
||||||
|
|
||||||
internal static IMinMax MinMax<T, TMinMax>(ReadOnlySpan<T> colors)
|
|
||||||
where T : struct, IColor
|
|
||||||
where TMinMax : struct, IMinMax
|
|
||||||
{
|
{
|
||||||
if (colors == null) throw new ArgumentNullException(nameof(colors));
|
if (colors == null) throw new ArgumentNullException(nameof(colors));
|
||||||
|
|
||||||
return T.ColorFormat.BytesPerPixel switch
|
IColorFormat colorFormat = T.ColorFormat;
|
||||||
|
return colorFormat.BytesPerPixel switch
|
||||||
{
|
{
|
||||||
3 => Unsafe.BitCast<Generic3ByteMinMax, TMinMax>(MinMax(MemoryMarshal.Cast<T, Generic3ByteData>(colors))),
|
3 => colorFormat.ToMinMax(MinMax(MemoryMarshal.Cast<T, Generic3ByteData>(colors))),
|
||||||
4 => Unsafe.BitCast<Generic4ByteMinMax, TMinMax>(MinMax(MemoryMarshal.Cast<T, Generic4ByteData>(colors))),
|
4 => colorFormat.ToMinMax(MinMax(MemoryMarshal.Cast<T, Generic4ByteData>(colors))),
|
||||||
_ => throw new NotSupportedException("Data is not of a supported valid color-type.")
|
_ => throw new NotSupportedException("Data is not of a supported valid color-type.")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Generic3ByteMinMax MinMax(ReadOnlySpan<Generic3ByteData> data)
|
public static IMinMax MinMax<T>(this ReadOnlySpan<T> colors)
|
||||||
|
where T : struct, IColor
|
||||||
{
|
{
|
||||||
byte minB1 = byte.MaxValue, minB2 = byte.MaxValue, minB3 = byte.MaxValue;
|
if (colors == null) throw new ArgumentNullException(nameof(colors));
|
||||||
byte maxB1 = byte.MinValue, maxB2 = byte.MinValue, maxB3 = byte.MinValue;
|
|
||||||
|
|
||||||
|
IColorFormat colorFormat = T.ColorFormat;
|
||||||
|
return colorFormat.BytesPerPixel switch
|
||||||
|
{
|
||||||
|
3 => colorFormat.ToMinMax(MinMax(MemoryMarshal.Cast<T, Generic3ByteData>(colors))),
|
||||||
|
4 => colorFormat.ToMinMax(MinMax(MemoryMarshal.Cast<T, Generic4ByteData>(colors))),
|
||||||
|
_ => throw new NotSupportedException("Data is not of a supported valid color-type.")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Generic3ByteMinMax MinMax(ReadOnlySpan<Generic3ByteData> data) => MinMax(data, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static Generic3ByteMinMax MinMax(ReadOnlySpan<Generic3ByteData> data, byte minB1, byte maxB1, byte minB2, byte maxB2, byte minB3, byte maxB3)
|
||||||
|
{
|
||||||
const int BYTES_PER_COLOR = 3;
|
const int BYTES_PER_COLOR = 3;
|
||||||
int elementsPerVector = Vector<byte>.Count / BYTES_PER_COLOR;
|
int elementsPerVector = Vector<byte>.Count / BYTES_PER_COLOR;
|
||||||
|
|
||||||
@ -166,11 +193,12 @@ public static unsafe partial class PixelHelper
|
|||||||
return new Generic3ByteMinMax(minB1, maxB1, minB2, maxB2, minB3, maxB3);
|
return new Generic3ByteMinMax(minB1, maxB1, minB2, maxB2, minB3, maxB3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Generic4ByteMinMax MinMax(ReadOnlySpan<Generic4ByteData> data)
|
|
||||||
{
|
|
||||||
byte minB1 = byte.MaxValue, minB2 = byte.MaxValue, minB3 = byte.MaxValue, minB4 = byte.MaxValue;
|
|
||||||
byte maxB1 = byte.MinValue, maxB2 = byte.MinValue, maxB3 = byte.MinValue, maxB4 = byte.MinValue;
|
|
||||||
|
|
||||||
|
private static Generic4ByteMinMax MinMax(ReadOnlySpan<Generic4ByteData> data) => MinMax(data, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue, byte.MaxValue, byte.MinValue);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static Generic4ByteMinMax MinMax(ReadOnlySpan<Generic4ByteData> data, byte minB1, byte maxB1, byte minB2, byte maxB2, byte minB3, byte maxB3, byte minB4, byte maxB4)
|
||||||
|
{
|
||||||
const int BYTES_PER_COLOR = 4;
|
const int BYTES_PER_COLOR = 4;
|
||||||
int elementsPerVector = Vector<byte>.Count / BYTES_PER_COLOR;
|
int elementsPerVector = Vector<byte>.Count / BYTES_PER_COLOR;
|
||||||
|
|
||||||
|
|||||||
@ -245,8 +245,6 @@ public static partial class PixelHelper
|
|||||||
ColorCube<T>[] cubes = new ColorCube<T>[1 << splits];
|
ColorCube<T>[] cubes = new ColorCube<T>[1 << splits];
|
||||||
cubes[0] = new ColorCube<T>(0, colors.Length, SortTarget.None);
|
cubes[0] = new ColorCube<T>(0, colors.Length, SortTarget.None);
|
||||||
|
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Environment.ProcessorCount };
|
|
||||||
|
|
||||||
int colorsLength = colors.Length;
|
int colorsLength = colors.Length;
|
||||||
fixed (T* colorsPtr = colors)
|
fixed (T* colorsPtr = colors)
|
||||||
{
|
{
|
||||||
@ -257,7 +255,7 @@ public static partial class PixelHelper
|
|||||||
{
|
{
|
||||||
int currentCubeCount = 1 << i;
|
int currentCubeCount = 1 << i;
|
||||||
|
|
||||||
Parallel.For(0, currentCubeCount, parallelOptions, CreateCubes);
|
Parallel.For(0, currentCubeCount, PARALLEL_OPTIONS, CreateCubes);
|
||||||
|
|
||||||
void CreateCubes(int index)
|
void CreateCubes(int index)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Intrinsics.X86;
|
using System.Runtime.Intrinsics.X86;
|
||||||
using System.Runtime.Intrinsics;
|
using System.Runtime.Intrinsics;
|
||||||
using System.Buffers;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
@ -14,29 +13,20 @@ public static unsafe partial class PixelHelper
|
|||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(image);
|
ArgumentNullException.ThrowIfNull(image);
|
||||||
|
|
||||||
int dataLength = image.SizeInBytes;
|
IColorFormat colorFormat = image.ColorFormat;
|
||||||
|
|
||||||
if (dataLength <= 1024)
|
if (image.Height == 0) return colorFormat.ToSum(new Generic4LongData(0, 0, 0, 0));
|
||||||
{
|
if (image.Height == 1) return colorFormat.ToSum(colorFormat.Sum(image.Rows[0].AsByteSpan()));
|
||||||
Span<byte> buffer = stackalloc byte[dataLength];
|
|
||||||
|
|
||||||
image.CopyTo(buffer);
|
Vector256<long> result = Vector256<long>.Zero;
|
||||||
return image.ColorFormat.Sum(buffer);
|
for (int y = 0; y < image.Height; y++)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
byte[] array = ArrayPool<byte>.Shared.Rent(dataLength);
|
Generic4LongData rowSum = colorFormat.Sum(image.Rows[y].AsByteSpan());
|
||||||
Span<byte> buffer = array.AsSpan()[..dataLength];
|
Vector256<long> rowSumVector = Vector256.LoadUnsafe(ref Unsafe.As<Generic4LongData, long>(ref rowSum));
|
||||||
try
|
result = Vector256.Add(result, rowSumVector);
|
||||||
{
|
|
||||||
image.CopyTo(buffer);
|
|
||||||
return image.ColorFormat.Sum(buffer);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<byte>.Shared.Return(array);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return colorFormat.ToSum(Unsafe.BitCast<Vector256<long>, Generic4LongData>(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ISum Sum<T>(this IImage<T> image)
|
public static ISum Sum<T>(this IImage<T> image)
|
||||||
@ -50,56 +40,37 @@ public static unsafe partial class PixelHelper
|
|||||||
public static ISum Sum<T>(this RefImage<T> image)
|
public static ISum Sum<T>(this RefImage<T> image)
|
||||||
where T : struct, IColor
|
where T : struct, IColor
|
||||||
{
|
{
|
||||||
int dataLength = image.Width * image.Height;
|
IColorFormat colorFormat = T.ColorFormat;
|
||||||
int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel;
|
|
||||||
|
|
||||||
if (sizeInBytes <= 1024)
|
if (image.Height == 0) return colorFormat.ToSum(new Generic4LongData(0, 0, 0, 0));
|
||||||
{
|
if (image.Height == 1) return colorFormat.ToSum(colorFormat.Sum(image.Rows[0].AsByteSpan()));
|
||||||
Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
|
|
||||||
|
|
||||||
image.CopyTo(buffer);
|
Vector256<long> result = Vector256<long>.Zero;
|
||||||
return Sum(buffer);
|
for (int y = 0; y < image.Height; y++)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
T[] array = ArrayPool<T>.Shared.Rent(dataLength);
|
Generic4LongData rowSum = colorFormat.Sum(image.Rows[y].AsByteSpan());
|
||||||
Span<T> buffer = array.AsSpan()[..(dataLength)];
|
Vector256<long> rowSumVector = Vector256.LoadUnsafe(ref Unsafe.As<Generic4LongData, long>(ref rowSum));
|
||||||
try
|
result = Vector256.Add(result, rowSumVector);
|
||||||
{
|
|
||||||
image.CopyTo(buffer);
|
|
||||||
return Sum(buffer);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(array);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return colorFormat.ToSum(Unsafe.BitCast<Vector256<long>, Generic4LongData>(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ISum Sum<T>(this ReadOnlySpan<T> colors)
|
public static ISum Sum<T>(this ReadOnlySpan<T> colors)
|
||||||
where T : struct, IColor
|
where T : struct, IColor
|
||||||
=> T.ColorFormat.Sum(MemoryMarshal.AsBytes(colors));
|
{
|
||||||
|
IColorFormat colorFormat = T.ColorFormat;
|
||||||
|
return colorFormat.ToSum(colorFormat.Sum(MemoryMarshal.AsBytes(colors)));
|
||||||
|
}
|
||||||
|
|
||||||
public static ISum Sum<T>(this Span<T> colors)
|
public static ISum Sum<T>(this Span<T> colors)
|
||||||
where T : struct, IColor
|
where T : struct, IColor
|
||||||
=> T.ColorFormat.Sum(MemoryMarshal.AsBytes(colors));
|
|
||||||
|
|
||||||
internal static ISum Sum<T, TSum>(ReadOnlySpan<T> colors)
|
|
||||||
where T : struct, IColor
|
|
||||||
where TSum : struct, ISum
|
|
||||||
{
|
{
|
||||||
if (colors == null) throw new ArgumentNullException(nameof(colors));
|
IColorFormat colorFormat = T.ColorFormat;
|
||||||
|
return colorFormat.ToSum(colorFormat.Sum(MemoryMarshal.AsBytes(colors)));
|
||||||
return T.ColorFormat.BytesPerPixel switch
|
|
||||||
{
|
|
||||||
// DarthAffe 05.07.2024: Important: The sum of 3-byte colors result in 4 byte data!
|
|
||||||
3 => Unsafe.BitCast<Generic4LongData, TSum>(Sum(MemoryMarshal.Cast<T, Generic3ByteData>(colors))),
|
|
||||||
4 => Unsafe.BitCast<Generic4LongData, TSum>(Sum(MemoryMarshal.Cast<T, Generic4ByteData>(colors))),
|
|
||||||
_ => throw new NotSupportedException("Data is not of a supported valid color-type.")
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Generic4LongData Sum(ReadOnlySpan<Generic3ByteData> data)
|
internal static Generic4LongData Sum(ReadOnlySpan<Generic3ByteData> data)
|
||||||
{
|
{
|
||||||
long b1Sum = 0, b2Sum = 0, b3Sum = 0;
|
long b1Sum = 0, b2Sum = 0, b3Sum = 0;
|
||||||
|
|
||||||
@ -215,7 +186,7 @@ public static unsafe partial class PixelHelper
|
|||||||
return new Generic4LongData(b1Sum, b2Sum, b3Sum, data.Length * 255);
|
return new Generic4LongData(b1Sum, b2Sum, b3Sum, data.Length * 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Generic4LongData Sum(ReadOnlySpan<Generic4ByteData> data)
|
internal static Generic4LongData Sum(ReadOnlySpan<Generic4ByteData> data)
|
||||||
{
|
{
|
||||||
long b1Sum, b2Sum, b3Sum, b4Sum;
|
long b1Sum, b2Sum, b3Sum, b4Sum;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|||||||
@ -3,4 +3,7 @@
|
|||||||
namespace HPPH;
|
namespace HPPH;
|
||||||
|
|
||||||
[SkipLocalsInit]
|
[SkipLocalsInit]
|
||||||
public static partial class PixelHelper;
|
public static partial class PixelHelper
|
||||||
|
{
|
||||||
|
private static readonly ParallelOptions PARALLEL_OPTIONS = new() { MaxDegreeOfParallelism = Environment.ProcessorCount };
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user