Browse Source

Using BulkPixelOperations<T> in PixelAccessor<T>

af/merge-core
Anton Firszov 9 years ago
parent
commit
13ab7a4631
  1. 12
      src/ImageSharp/Image.cs
  2. 2
      src/ImageSharp/Image/ImageBase{TColor}.cs
  3. 155
      src/ImageSharp/Image/PixelAccessor{TColor}.cs
  4. 10
      src/ImageSharp/Image/PixelArea{TColor}.cs
  5. 52
      src/ImageSharp/ImageFrame.cs
  6. 153
      src/ImageSharp/PixelAccessor.cs
  7. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs
  8. 44
      tests/ImageSharp.Tests/Image/PixelAccessorTests.cs

12
src/ImageSharp/Image.cs

@ -223,17 +223,5 @@ namespace ImageSharp
: base(other)
{
}
/// <inheritdoc />
public override PixelAccessor<Color> Lock()
{
return new PixelAccessor(this);
}
/// <inheritdoc />
internal override ImageFrame<Color> ToFrame()
{
return new ImageFrame(this);
}
}
}

2
src/ImageSharp/Image/ImageBase{TColor}.cs

@ -150,7 +150,7 @@ namespace ImageSharp
}
/// <inheritdoc/>
public virtual PixelAccessor<TColor> Lock()
public PixelAccessor<TColor> Lock()
{
return new PixelAccessor<TColor>(this);
}

155
src/ImageSharp/Image/PixelAccessor{TColor}.cs

@ -15,7 +15,7 @@ namespace ImageSharp
/// Provides per-pixel access to generic <see cref="Image{TColor}"/> pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public unsafe class PixelAccessor<TColor> : IDisposable
public sealed unsafe class PixelAccessor<TColor> : IDisposable
where TColor : struct, IPixel<TColor>
{
/// <summary>
@ -91,7 +91,7 @@ namespace ImageSharp
/// <summary>
/// Gets the pixel buffer array.
/// </summary>
public TColor[] PixelBuffer => this.pixelBuffer.Array;
public TColor[] PixelArray => this.pixelBuffer.Array;
/// <summary>
/// Gets the pointer to the pixel buffer.
@ -123,6 +123,8 @@ namespace ImageSharp
/// </summary>
public ParallelOptions ParallelOptions { get; }
private static BulkPixelOperations<TColor> Operations => BulkPixelOperations<TColor>.Instance;
/// <summary>
/// Gets or sets the pixel at the specified position.
/// </summary>
@ -236,6 +238,17 @@ namespace ImageSharp
Unsafe.InitBlock(this.pixelsBase, 0, (uint)(this.RowStride * this.Height));
}
/// <summary>
/// Gets a <see cref="BufferPointer{TColor}"/> to the row 'y' beginning from the pixel at 'x'.
/// </summary>
/// <param name="x">The x coordinate</param>
/// <param name="y">The y coordinate</param>
/// <returns>The <see cref="BufferPointer{TColor}"/></returns>
internal BufferPointer<TColor> GetRowPointer(int x, int y)
{
return this.pixelBuffer.Slice((y * this.Width) + x);
}
/// <summary>
/// Sets the pixel buffer in an unsafe manner. This should not be used unless you know what its doing!!!
/// </summary>
@ -270,24 +283,15 @@ namespace ImageSharp
/// <param name="targetY">The target row index.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected virtual void CopyFromZyx(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyFromZyx(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
{
TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>();
for (int y = 0; y < height; y++)
{
byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++)
{
packed.PackFromBytes(*(source + 2), *(source + 1), *source, 255);
Unsafe.Write(destination, packed);
BufferPointer<byte> source = area.GetRowPointer(y);
BufferPointer<TColor> destination = this.GetRowPointer(targetX, targetY + y);
source += 3;
destination += size;
}
Operations.PackFromZyxBytes(source, destination, width);
}
}
@ -299,24 +303,15 @@ namespace ImageSharp
/// <param name="targetY">The target row index.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected virtual void CopyFromZyxw(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyFromZyxw(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
{
TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>();
for (int y = 0; y < height; y++)
{
byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++)
{
packed.PackFromBytes(*(source + 2), *(source + 1), *source, *(source + 3));
Unsafe.Write(destination, packed);
BufferPointer<byte> source = area.GetRowPointer(y);
BufferPointer<TColor> destination = this.GetRowPointer(targetX, targetY + y);
source += 4;
destination += size;
}
Operations.PackFromZyxwBytes(source, destination, width);
}
}
@ -328,24 +323,15 @@ namespace ImageSharp
/// <param name="targetY">The target row index.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected virtual void CopyFromXyz(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyFromXyz(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
{
TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>();
for (int y = 0; y < height; y++)
{
byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++)
{
packed.PackFromBytes(*source, *(source + 1), *(source + 2), 255);
Unsafe.Write(destination, packed);
BufferPointer<byte> source = area.GetRowPointer(y);
BufferPointer<TColor> destination = this.GetRowPointer(targetX, targetY + y);
source += 3;
destination += size;
}
Operations.PackFromXyzBytes(source, destination, width);
}
}
@ -357,24 +343,14 @@ namespace ImageSharp
/// <param name="targetY">The target row index.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected virtual void CopyFromXyzw(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyFromXyzw(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
{
TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>();
for (int y = 0; y < height; y++)
{
byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++)
{
packed.PackFromBytes(*source, *(source + 1), *(source + 2), *(source + 3));
Unsafe.Write(destination, packed);
source += 4;
destination += size;
}
BufferPointer<byte> source = area.GetRowPointer(y);
BufferPointer<TColor> destination = this.GetRowPointer(targetX, targetY + y);
Operations.PackFromXyzwBytes(source, destination, width);
}
}
@ -386,16 +362,14 @@ namespace ImageSharp
/// <param name="sourceY">The source row index.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected virtual void CopyToZyx(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyToZyx(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
{
for (int y = 0; y < height; y++)
{
int offset = y * area.RowStride;
for (int x = 0; x < width; x++)
{
this[sourceX + x, sourceY + y].ToZyxBytes(area.Bytes, offset);
offset += 3;
}
BufferPointer<TColor> source = this.GetRowPointer(sourceX, sourceY + y);
BufferPointer<byte> destination = area.GetRowPointer(y);
Operations.ToZyxBytes(source, destination, width);
}
}
@ -407,16 +381,14 @@ namespace ImageSharp
/// <param name="sourceY">The source row index.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected virtual void CopyToZyxw(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyToZyxw(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
{
for (int y = 0; y < height; y++)
{
int offset = y * area.RowStride;
for (int x = 0; x < width; x++)
{
this[sourceX + x, sourceY + y].ToZyxwBytes(area.Bytes, offset);
offset += 4;
}
BufferPointer<TColor> source = this.GetRowPointer(sourceX, sourceY + y);
BufferPointer<byte> destination = area.GetRowPointer(y);
Operations.ToZyxwBytes(source, destination, width);
}
}
@ -428,16 +400,14 @@ namespace ImageSharp
/// <param name="sourceY">The source row index.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected virtual void CopyToXyz(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyToXyz(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
{
for (int y = 0; y < height; y++)
{
int offset = y * area.RowStride;
for (int x = 0; x < width; x++)
{
this[sourceX + x, sourceY + y].ToXyzBytes(area.Bytes, offset);
offset += 3;
}
BufferPointer<TColor> source = this.GetRowPointer(sourceX, sourceY + y);
BufferPointer<byte> destination = area.GetRowPointer(y);
Operations.ToXyzBytes(source, destination, width);
}
}
@ -449,32 +419,17 @@ namespace ImageSharp
/// <param name="sourceY">The source row index.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected virtual void CopyToXyzw(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyToXyzw(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
{
for (int y = 0; y < height; y++)
{
int offset = y * area.RowStride;
for (int x = 0; x < width; x++)
{
this[sourceX + x, sourceY + y].ToXyzwBytes(area.Bytes, offset);
offset += 4;
}
BufferPointer<TColor> source = this.GetRowPointer(sourceX, sourceY + y);
BufferPointer<byte> destination = area.GetRowPointer(y);
Operations.ToXyzwBytes(source, destination, width);
}
}
/// <summary>
/// Gets the pointer at the specified row.
/// </summary>
/// <param name="x">The column index.</param>
/// <param name="y">The row index.</param>
/// <returns>
/// The <see cref="T:byte*"/>.
/// </returns>
protected byte* GetRowPointer(int x, int y)
{
return this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf<TColor>());
}
private void SetPixelBufferUnsafe(int width, int height, TColor[] pixels)
{
this.SetPixelBufferUnsafe(width, height, new PinnedBuffer<TColor>(width * height, pixels));

10
src/ImageSharp/Image/PixelArea{TColor}.cs

@ -203,6 +203,16 @@ namespace ImageSharp
Unsafe.InitBlock(this.PixelBase, 0, (uint)(this.RowStride * this.Height));
}
/// <summary>
/// Gets a <see cref="BufferPointer{Byte}"/> to the row y.
/// </summary>
/// <param name="y">The y coordinate</param>
/// <returns>The <see cref="BufferPointer{Byte}"/></returns>
internal BufferPointer<byte> GetRowPointer(int y)
{
return this.byteBuffer.Slice(y * this.RowStride);
}
/// <summary>
/// Gets component count for the given order.
/// </summary>

52
src/ImageSharp/ImageFrame.cs

@ -1,52 +0,0 @@
// <copyright file="ImageFrame.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Diagnostics;
/// <summary>
/// An optimized frame for the <see cref="Image"/> class.
/// </summary>
[DebuggerDisplay("ImageFrame: {Width}x{Height}")]
public sealed class ImageFrame : ImageFrame<Color>
{
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame"/> class.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
public ImageFrame(int width, int height, Configuration configuration = null)
: base(width, height, configuration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame"/> class.
/// </summary>
/// <param name="image">
/// The image to create the frame from.
/// </param>
public ImageFrame(ImageBase<Color> image)
: base(image)
{
}
/// <inheritdoc />
public override PixelAccessor<Color> Lock()
{
return new PixelAccessor(this);
}
/// <inheritdoc />
internal override ImageFrame<Color> Clone()
{
return new ImageFrame(this);
}
}
}

153
src/ImageSharp/PixelAccessor.cs

@ -1,153 +0,0 @@
// <copyright file="PixelAccessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Runtime.CompilerServices;
/// <summary>
/// An optimized pixel accessor for the <see cref="Image"/> class.
/// </summary>
public sealed unsafe class PixelAccessor : PixelAccessor<Color>
{
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor"/> class.
/// </summary>
/// <param name="image">The image to provide pixel access for.</param>
public PixelAccessor(ImageBase<Color> image)
: base(image)
{
}
/// <inheritdoc />
protected override void CopyFromXyzw(PixelArea<Color> area, int targetX, int targetY, int width, int height)
{
uint byteCount = (uint)width * 4;
for (int y = 0; y < height; y++)
{
byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y);
Unsafe.CopyBlock(destination, source, byteCount);
}
}
/// <inheritdoc />
protected override void CopyFromXyz(PixelArea<Color> area, int targetX, int targetY, int width, int height)
{
for (int y = 0; y < height; y++)
{
byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++)
{
Unsafe.Write(destination, (uint)(*source << 0 | *(source + 1) << 8 | *(source + 2) << 16 | 255 << 24));
source += 3;
destination += 4;
}
}
}
/// <inheritdoc />
protected override void CopyFromZyx(PixelArea<Color> area, int targetX, int targetY, int width, int height)
{
for (int y = 0; y < height; y++)
{
byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | 255 << 24));
source += 3;
destination += 4;
}
}
}
/// <inheritdoc />
protected override void CopyFromZyxw(PixelArea<Color> area, int targetX, int targetY, int width, int height)
{
for (int y = 0; y < height; y++)
{
byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | *(source + 3) << 24));
source += 4;
destination += 4;
}
}
}
/// <inheritdoc />
protected override void CopyToZyx(PixelArea<Color> area, int sourceX, int sourceY, int width, int height)
{
for (int y = 0; y < height; y++)
{
byte* source = this.GetRowPointer(sourceX, sourceY + y);
byte* destination = area.PixelBase + (y * area.RowStride);
for (int x = 0; x < width; x++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
source += 4;
destination += 3;
}
}
}
/// <inheritdoc />
protected override void CopyToXyz(PixelArea<Color> area, int sourceX, int sourceY, int width, int height)
{
for (int y = 0; y < height; y++)
{
byte* source = this.GetRowPointer(sourceX, sourceY + y);
byte* destination = area.PixelBase + (y * area.RowStride);
for (int x = 0; x < width; x++)
{
*destination = *(source + 0);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 2);
source += 4;
destination += 3;
}
}
}
/// <inheritdoc />
protected override void CopyToZyxw(PixelArea<Color> area, int sourceX, int sourceY, int width, int height)
{
for (int y = 0; y < height; y++)
{
byte* source = this.GetRowPointer(sourceX, sourceY + y);
byte* destination = area.PixelBase + (y * area.RowStride);
for (int x = 0; x < width; x++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
*(destination + 3) = *(source + 3);
source += 4;
destination += 4;
}
}
}
}
}

2
tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs

@ -114,7 +114,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk
private BufferPointer<Color> GetPixelAccessorRow(int x, int y)
{
return new BufferPointer<ImageSharp.Color>(
this.pixelAccessor.PixelBuffer,
this.pixelAccessor.PixelArray,
(void*)this.pixelAccessor.DataPointer,
(y * this.pixelAccessor.Width) + x
);

44
tests/ImageSharp.Tests/Image/PixelAccessorTests.cs

@ -130,16 +130,7 @@ namespace ImageSharp.Tests
CopyFromZYX(image);
}
}
[Fact]
public void CopyFromZYXOptimized()
{
using (Image image = new Image(1, 1))
{
CopyFromZYX(image);
}
}
[Fact]
public void CopyFromZYXW()
{
@ -148,16 +139,7 @@ namespace ImageSharp.Tests
CopyFromZYXW(image);
}
}
[Fact]
public void CopyFromZYXWOptimized()
{
using (Image image = new Image(1, 1))
{
CopyFromZYXW(image);
}
}
[Fact]
public void CopyToZYX()
{
@ -166,16 +148,7 @@ namespace ImageSharp.Tests
CopyToZYX(image);
}
}
[Fact]
public void CopyToZYXOptimized()
{
using (Image image = new Image(1, 1))
{
CopyToZYX(image);
}
}
[Fact]
public void CopyToZYXW()
{
@ -184,16 +157,7 @@ namespace ImageSharp.Tests
CopyToZYXW(image);
}
}
[Fact]
public void CopyToZYXWOptimized()
{
using (Image image = new Image(1, 1))
{
CopyToZYXW(image);
}
}
private static void CopyFromZYX<TColor>(Image<TColor> image)
where TColor : struct, IPixel<TColor>
{

Loading…
Cancel
Save