mirror of https://github.com/SixLabors/ImageSharp
9 changed files with 226 additions and 137 deletions
@ -0,0 +1,63 @@ |
|||
// ReSharper disable InconsistentNaming
|
|||
namespace ImageSharp.Benchmarks.Color.Bulk |
|||
{ |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
using Color = ImageSharp.Color; |
|||
|
|||
public abstract class PackFromXyzw<TColor> |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
private PinnedBuffer<TColor> destination; |
|||
|
|||
private PinnedBuffer<byte> source; |
|||
|
|||
[Params(16, 128, 1024)] |
|||
public int Count { get; set; } |
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
this.destination = new PinnedBuffer<TColor>(this.Count); |
|||
this.source = new PinnedBuffer<byte>(this.Count * 4); |
|||
} |
|||
|
|||
[Cleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.destination.Dispose(); |
|||
this.source.Dispose(); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void PerElement() |
|||
{ |
|||
byte[] s = this.source.Array; |
|||
TColor[] d = this.destination.Array; |
|||
|
|||
for (int i = 0; i < this.Count; i++) |
|||
{ |
|||
int i4 = i * 4; |
|||
TColor c = default(TColor); |
|||
c.PackFromBytes(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3]); |
|||
d[i] = c; |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void CommonBulk() |
|||
{ |
|||
new BulkPixelOperations<TColor>().PackFromXyzwBytes(this.source, this.destination, this.Count); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void OptimizedBulk() |
|||
{ |
|||
BulkPixelOperations<TColor>.Instance.PackFromXyzwBytes(this.source, this.destination, this.Count); |
|||
} |
|||
} |
|||
|
|||
public class PackFromXyzw_Color : PackFromXyzw<Color> |
|||
{ |
|||
} |
|||
} |
|||
@ -1,129 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace ImageSharp.Benchmarks.Color.Bulk |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
using Color = ImageSharp.Color; |
|||
|
|||
/// <summary>
|
|||
/// Benchmark to measure the effect of using virtual bulk-copy calls inside PixelAccessor methods
|
|||
/// </summary>
|
|||
public unsafe class PixelAccessorVirtualCopy |
|||
{ |
|||
abstract class CopyExecutor |
|||
{ |
|||
internal abstract void VirtualCopy(BufferPointer<Color> destination, BufferPointer<byte> source, int count); |
|||
} |
|||
|
|||
class UnsafeCopyExecutor : CopyExecutor |
|||
{ |
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
internal override unsafe void VirtualCopy(BufferPointer<Color> destination, BufferPointer<byte> source, int count) |
|||
{ |
|||
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)count*4); |
|||
} |
|||
} |
|||
|
|||
private PixelAccessor<Color> pixelAccessor; |
|||
|
|||
private PixelArea<Color> area; |
|||
|
|||
private CopyExecutor executor; |
|||
|
|||
[Params(64, 256, 512)] |
|||
public int Width { get; set; } |
|||
|
|||
public int Height { get; set; } = 256; |
|||
|
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
this.pixelAccessor = new PixelAccessor<ImageSharp.Color>(this.Width, this.Height); |
|||
this.area = new PixelArea<Color>(this.Width / 2, this.Height, ComponentOrder.Xyzw); |
|||
this.executor = new UnsafeCopyExecutor(); |
|||
} |
|||
|
|||
[Cleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.pixelAccessor.Dispose(); |
|||
this.area.Dispose(); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void CopyRawUnsafeInlined() |
|||
{ |
|||
uint byteCount = (uint)this.area.Width * 4; |
|||
|
|||
int targetX = this.Width / 4; |
|||
int targetY = 0; |
|||
|
|||
for (int y = 0; y < this.Height; y++) |
|||
{ |
|||
byte* source = this.area.PixelBase + (y * this.area.RowStride); |
|||
byte* destination = this.GetRowPointer(targetX, targetY + y); |
|||
|
|||
Unsafe.CopyBlock(destination, source, byteCount); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void CopyBufferPointerUnsafeInlined() |
|||
{ |
|||
uint byteCount = (uint)this.area.Width * 4; |
|||
|
|||
int targetX = this.Width / 4; |
|||
int targetY = 0; |
|||
|
|||
for (int y = 0; y < this.Height; y++) |
|||
{ |
|||
BufferPointer<byte> source = this.GetAreaRow(y); |
|||
BufferPointer<Color> destination = this.GetPixelAccessorRow(targetX, targetY + y); |
|||
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void CopyBufferPointerUnsafeVirtual() |
|||
{ |
|||
int targetX = this.Width / 4; |
|||
int targetY = 0; |
|||
|
|||
for (int y = 0; y < this.Height; y++) |
|||
{ |
|||
BufferPointer<byte> source = this.GetAreaRow(y); |
|||
BufferPointer<Color> destination = this.GetPixelAccessorRow(targetX, targetY + y); |
|||
this.executor.VirtualCopy(destination, source, this.area.Width); |
|||
} |
|||
} |
|||
|
|||
private byte* GetRowPointer(int x, int y) |
|||
{ |
|||
return (byte*)this.pixelAccessor.DataPointer + (((y * this.pixelAccessor.Width) + x) * Unsafe.SizeOf<Color>()); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private BufferPointer<Color> GetPixelAccessorRow(int x, int y) |
|||
{ |
|||
return new BufferPointer<ImageSharp.Color>( |
|||
this.pixelAccessor.PixelArray, |
|||
(void*)this.pixelAccessor.DataPointer, |
|||
(y * this.pixelAccessor.Width) + x |
|||
); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private BufferPointer<byte> GetAreaRow(int y) |
|||
{ |
|||
return new BufferPointer<byte>(this.area.Bytes, this.area.PixelBase, y * this.area.RowStride); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
// ReSharper disable InconsistentNaming
|
|||
namespace ImageSharp.Benchmarks.Color.Bulk |
|||
{ |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
using Color = ImageSharp.Color; |
|||
|
|||
public abstract class ToXyz<TColor> |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
private PinnedBuffer<TColor> source; |
|||
|
|||
private PinnedBuffer<byte> destination; |
|||
|
|||
[Params(16, 128, 1024)] |
|||
public int Count { get; set; } |
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new PinnedBuffer<TColor>(this.Count); |
|||
this.destination = new PinnedBuffer<byte>(this.Count * 3); |
|||
} |
|||
|
|||
[Cleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.source.Dispose(); |
|||
this.destination.Dispose(); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void PerElement() |
|||
{ |
|||
TColor[] s = this.source.Array; |
|||
byte[] d = this.destination.Array; |
|||
|
|||
for (int i = 0; i < this.Count; i++) |
|||
{ |
|||
TColor c = s[i]; |
|||
c.ToXyzBytes(d, i * 4); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void CommonBulk() |
|||
{ |
|||
new BulkPixelOperations<TColor>().ToXyzBytes(this.source, this.destination, this.Count); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void OptimizedBulk() |
|||
{ |
|||
BulkPixelOperations<TColor>.Instance.ToXyzBytes(this.source, this.destination, this.Count); |
|||
} |
|||
} |
|||
|
|||
public class ToXyz_Color : ToXyz<Color> |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
// ReSharper disable InconsistentNaming
|
|||
|
|||
namespace ImageSharp.Benchmarks.Color.Bulk |
|||
{ |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
using Color = ImageSharp.Color; |
|||
|
|||
public abstract class ToXyzw<TColor> |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
private PinnedBuffer<TColor> source; |
|||
|
|||
private PinnedBuffer<byte> destination; |
|||
|
|||
[Params(16, 128, 1024)] |
|||
public int Count { get; set; } |
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new PinnedBuffer<TColor>(this.Count); |
|||
this.destination = new PinnedBuffer<byte>(this.Count * 4); |
|||
} |
|||
|
|||
[Cleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.source.Dispose(); |
|||
this.destination.Dispose(); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void PerElement() |
|||
{ |
|||
TColor[] s = this.source.Array; |
|||
byte[] d = this.destination.Array; |
|||
|
|||
for (int i = 0; i < this.Count; i++) |
|||
{ |
|||
TColor c = s[i]; |
|||
c.ToXyzwBytes(d, i * 4); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void CommonBulk() |
|||
{ |
|||
new BulkPixelOperations<TColor>().ToXyzwBytes(this.source, this.destination, this.Count); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void OptimizedBulk() |
|||
{ |
|||
BulkPixelOperations<TColor>.Instance.ToXyzwBytes(this.source, this.destination, this.Count); |
|||
} |
|||
} |
|||
|
|||
public class ToXyzw_Color : ToXyzw<Color> |
|||
{ |
|||
} |
|||
|
|||
public class ToXyzw_Argb : ToXyzw<Argb> |
|||
{ |
|||
} |
|||
} |
|||
Loading…
Reference in new issue