mirror of
https://github.com/DarthAffe/HPPH.git
synced 2025-12-12 13:28:37 +00:00
Improved performance of Average on Images
This commit is contained in:
parent
f4c1eaddd6
commit
e6b77ecfdb
@ -13,6 +13,8 @@ public class AverageBenchmarks
|
||||
|
||||
private readonly List<ColorRGB[]> _colors3bpp;
|
||||
private readonly List<ColorRGBA[]> _colors4bpp;
|
||||
private readonly List<IImage<ColorRGB>> _images3bpp;
|
||||
private readonly List<IImage<ColorRGBA>> _images4bpp;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -22,6 +24,9 @@ public class AverageBenchmarks
|
||||
{
|
||||
_colors3bpp = BenchmarkHelper.GetSampleData<ColorRGB>();
|
||||
_colors4bpp = BenchmarkHelper.GetSampleData<ColorRGBA>();
|
||||
|
||||
_images3bpp = BenchmarkHelper.GetSampleDataImages<ColorRGB>();
|
||||
_images4bpp = BenchmarkHelper.GetSampleDataImages<ColorRGBA>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -48,6 +53,26 @@ public class AverageBenchmarks
|
||||
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]
|
||||
public ColorRGB[] Reference_3BPP()
|
||||
{
|
||||
|
||||
@ -19,7 +19,6 @@ public class ColorSourceGenerator : IIncrementalGenerator
|
||||
private static readonly IGeneratorFeature[] FEATURES =
|
||||
[
|
||||
new Colors(),
|
||||
new Average(),
|
||||
new MinMax(),
|
||||
new Sum(),
|
||||
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}}() {}
|
||||
|
||||
#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("""
|
||||
IColor CreateColor(byte r, byte g, byte b, byte a);
|
||||
|
||||
#endregion
|
||||
}
|
||||
""");
|
||||
|
||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatABGR : IColorFormat
|
||||
private ColorFormatABGR() {}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorABGR.Create(r, g, b, a);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatARGB : IColorFormat
|
||||
private ColorFormatARGB() {}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorARGB.Create(r, g, b, a);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatBGR : IColorFormat
|
||||
private ColorFormatBGR() {}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorBGR.Create(r, g, b, a);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatBGRA : IColorFormat
|
||||
private ColorFormatBGRA() {}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorBGRA.Create(r, g, b, a);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatRGB : IColorFormat
|
||||
private ColorFormatRGB() {}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public IColor CreateColor(byte r, byte g, byte b, byte a) => ColorRGB.Create(r, g, b, a);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -21,4 +21,10 @@ public sealed partial class ColorFormatRGBA : IColorFormat
|
||||
private ColorFormatRGBA() {}
|
||||
|
||||
#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 ColorFormatBGRA BGRA => ColorFormatBGRA.Instance;
|
||||
|
||||
IColor CreateColor(byte r, byte g, byte b, byte a);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System.Buffers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HPPH;
|
||||
@ -12,29 +11,14 @@ public static partial class PixelHelper
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(image);
|
||||
|
||||
int dataLength = image.SizeInBytes;
|
||||
float count = image.Width * image.Height;
|
||||
|
||||
if (dataLength <= 1024)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[dataLength];
|
||||
ISum sum = Sum(image);
|
||||
|
||||
image.CopyTo(buffer);
|
||||
return image.ColorFormat.Average(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
return image.ColorFormat.CreateColor((byte)MathF.Round(sum.R / count),
|
||||
(byte)MathF.Round(sum.G / count),
|
||||
(byte)MathF.Round(sum.B / count),
|
||||
(byte)MathF.Round(sum.A / count));
|
||||
}
|
||||
|
||||
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)
|
||||
where T : struct, IColor
|
||||
{
|
||||
int dataLength = image.Width * image.Height;
|
||||
int sizeInBytes = dataLength * T.ColorFormat.BytesPerPixel;
|
||||
float count = image.Width * image.Height;
|
||||
|
||||
if (sizeInBytes <= 1024)
|
||||
{
|
||||
Span<T> buffer = MemoryMarshal.Cast<byte, T>(stackalloc byte[sizeInBytes]);
|
||||
|
||||
image.CopyTo(buffer);
|
||||
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);
|
||||
}
|
||||
}
|
||||
ISum sum = Sum(image);
|
||||
return (T)T.Create((byte)MathF.Round(sum.R / count),
|
||||
(byte)MathF.Round(sum.G / count),
|
||||
(byte)MathF.Round(sum.B / count),
|
||||
(byte)MathF.Round(sum.A / count));
|
||||
}
|
||||
|
||||
public static T Average<T>(this Span<T> colors)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user