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<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()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user