Browse Source

Optimized Rgba32 constructors. Created PixelConversion benchmarks.

pull/242/head
Anton Firszov 9 years ago
parent
commit
bcf58cd5a2
  1. 15
      src/ImageSharp/PixelFormats/Argb32.cs
  2. 42
      src/ImageSharp/PixelFormats/Rgba32.cs
  3. 156
      tests/ImageSharp.Benchmarks/General/PixelConversion.cs

15
src/ImageSharp/PixelFormats/Argb32.cs

@ -58,11 +58,24 @@ namespace ImageSharp.PixelFormats
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
public Argb32(byte r, byte g, byte b, byte a = 255)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32(byte r, byte g, byte b, byte a)
{
this.PackedValue = Pack(r, g, b, a);
}
/// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32(byte r, byte g, byte b)
{
this.PackedValue = Pack(r, g, b, 255);
}
/// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary>

42
src/ImageSharp/PixelFormats/Rgba32.cs

@ -49,12 +49,6 @@ namespace ImageSharp
[FieldOffset(3)]
public byte A;
/// <summary>
/// The packed representation of the value.
/// </summary>
[FieldOffset(0)]
public uint Rgba;
/// <summary>
/// The shift count for the red component
/// </summary>
@ -85,6 +79,21 @@ namespace ImageSharp
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// Initializes a new instance of the <see cref="Rgba32"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32(byte r, byte g, byte b)
{
this.R = r;
this.G = g;
this.B = b;
this.A = 255;
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba32"/> struct.
/// </summary>
@ -93,8 +102,7 @@ namespace ImageSharp
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32(byte r, byte g, byte b, byte a = 255)
: this()
public Rgba32(byte r, byte g, byte b, byte a)
{
this.R = r;
this.G = g;
@ -155,6 +163,24 @@ namespace ImageSharp
this.Rgba = packed;
}
/// <summary>
/// Gets or sets the packed representation of the Rgba32 struct.
/// </summary>
public uint Rgba
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return Unsafe.As<Rgba32, uint>(ref this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
Unsafe.As<Rgba32, uint>(ref this) = value;
}
}
/// <inheritdoc/>
public uint PackedValue { get => this.Rgba; set => this.Rgba = value; }

156
tests/ImageSharp.Benchmarks/General/PixelConversion.cs

@ -0,0 +1,156 @@
namespace ImageSharp.Benchmarks.General
{
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
/// <summary>
/// When implementing TPixel --> Rgba32 style conversions on IPixel, should which API should we prefer?
/// 1. Rgba32 ToRgba32();
/// OR
/// 2. void CopyToRgba32(ref Rgba32 dest);
/// ?
/// </summary>
public class PixelConversion
{
interface ITestPixel<T>
where T : struct, ITestPixel<T>
{
Rgba32 ToRgba32();
void CopyToRgba32(ref Rgba32 dest);
}
[StructLayout(LayoutKind.Sequential)]
struct TestArgb : ITestPixel<TestArgb>
{
private byte a, r, g, b;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32()
{
return new Rgba32(this.r, this.g, this.b, this.a);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToRgba32(ref Rgba32 dest)
{
dest.R = this.r;
dest.G = this.g;
dest.B = this.b;
dest.A = this.a;
}
}
[StructLayout(LayoutKind.Sequential)]
struct TestRgba : ITestPixel<TestRgba>
{
private byte r, g, b, a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32()
{
return Unsafe.As<TestRgba, Rgba32>(ref this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToRgba32(ref Rgba32 dest)
{
dest = Unsafe.As<TestRgba, Rgba32>(ref this);
}
}
struct ConversionRunner<T>
where T : struct, ITestPixel<T>
{
private T[] source;
private Rgba32[] dest;
public ConversionRunner(int count)
{
this.source = new T[count];
this.dest = new Rgba32[count];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RunRetvalConversion()
{
int count = this.source.Length;
ref T sourceBaseRef = ref this.source[0];
ref Rgba32 destBaseRef = ref this.dest[0];
for (int i = 0; i < count; i++)
{
Unsafe.Add(ref destBaseRef, i) = Unsafe.Add(ref sourceBaseRef, i).ToRgba32();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RunCopyToConversion()
{
int count = this.source.Length;
ref T sourceBaseRef = ref this.source[0];
ref Rgba32 destBaseRef = ref this.dest[0];
for (int i = 0; i < count; i++)
{
Unsafe.Add(ref sourceBaseRef, i).CopyToRgba32(ref Unsafe.Add(ref destBaseRef, i));
}
}
}
private ConversionRunner<TestRgba> inOrderRunner;
private ConversionRunner<TestArgb> permutedRunner;
[Params(128)]
public int Count { get; set; }
[Setup]
public void Setup()
{
this.inOrderRunner = new ConversionRunner<TestRgba>(this.Count);
this.permutedRunner = new ConversionRunner<TestArgb>(this.Count);
}
[Benchmark(Baseline = true)]
public void InOrderRetval()
{
this.inOrderRunner.RunRetvalConversion();
}
[Benchmark]
public void InOrderCopyTo()
{
this.inOrderRunner.RunCopyToConversion();
}
[Benchmark]
public void PermutedRetval()
{
this.permutedRunner.RunRetvalConversion();
}
[Benchmark]
public void PermutedCopyTo()
{
this.permutedRunner.RunCopyToConversion();
}
}
/*
* Results:
*
* Method | Count | Mean | StdDev | Scaled | Scaled-StdDev |
* --------------- |------ |------------ |---------- |------- |-------------- |
* InOrderRetval | 128 | 89.7358 ns | 2.2389 ns | 1.00 | 0.00 |
* InOrderCopyTo | 128 | 89.4112 ns | 2.2901 ns | 1.00 | 0.03 |
* PermutedRetval | 128 | 845.4038 ns | 5.6154 ns | 9.43 | 0.23 |
* PermutedCopyTo | 128 | 155.6004 ns | 3.8870 ns | 1.73 | 0.06 |
*
*/
}
Loading…
Cancel
Save