From b443026cb31f6dfb509228b981a3b0e889fabe36 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 14 Apr 2017 03:14:00 +0200 Subject: [PATCH] more pointers got removed --- src/ImageSharp/Colors/Color.BulkOperations.cs | 9 ++-- src/ImageSharp/Common/Memory/BufferSpan.cs | 18 +++++++- .../Formats/Jpeg/JpegEncoderCore.cs | 11 ++--- .../Formats/Jpeg/Utils/JpegUtils.cs | 45 +++++++++---------- src/ImageSharp/Image/PixelAccessor{TColor}.cs | 25 +++-------- src/ImageSharp/Image/PixelArea{TColor}.cs | 16 +------ 6 files changed, 55 insertions(+), 69 deletions(-) diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index d809416159..462d0c0529 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -67,17 +67,18 @@ namespace ImageSharp using (PinnedBuffer tempBuf = new PinnedBuffer( unpackedRawCount + Vector.Count)) { - uint* tPtr = (uint*)tempBuf.Pointer; uint[] temp = tempBuf.Array; float[] fTemp = Unsafe.As(temp); - UnpackedRGBA* dst = (UnpackedRGBA*)tPtr; - for (int i = 0; i < count; i++, dst++) + ref UnpackedRGBA tempBase = ref Unsafe.As(ref tempBuf[0]); + + for (int i = 0; i < count; i++) { uint sVal = Unsafe.Add(ref src, i); + ref UnpackedRGBA dst = ref Unsafe.Add(ref tempBase, i); // This call is the bottleneck now: - dst->Load(sVal); + dst.Load(sVal); } for (int i = 0; i < unpackedRawCount; i += vecSize) diff --git a/src/ImageSharp/Common/Memory/BufferSpan.cs b/src/ImageSharp/Common/Memory/BufferSpan.cs index 3675084f29..c51c110be4 100644 --- a/src/ImageSharp/Common/Memory/BufferSpan.cs +++ b/src/ImageSharp/Common/Memory/BufferSpan.cs @@ -18,13 +18,16 @@ namespace ImageSharp /// Copy 'count' number of elements of the same type from 'source' to 'dest' /// /// The element type. - /// The input + /// The to copy elements from. /// The destination . /// The number of elements to copy [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void Copy(BufferSpan source, BufferSpan destination, int count) where T : struct { + DebugGuard.MustBeLessThanOrEqualTo(count, source.Length, nameof(count)); + DebugGuard.MustBeLessThanOrEqualTo(count, destination.Length, nameof(count)); + ref byte srcRef = ref Unsafe.As(ref source.DangerousGetPinnableReference()); ref byte destRef = ref Unsafe.As(ref destination.DangerousGetPinnableReference()); @@ -43,6 +46,19 @@ namespace ImageSharp } } + /// + /// Copy all elements of 'source' into 'destination'. + /// + /// The element type. + /// The to copy elements from. + /// The destination . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Copy(BufferSpan source, BufferSpan destination) + where T : struct + { + Copy(source, destination, source.Length); + } + /// /// Gets the size of `count` elements in bytes. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 66f400c017..c3cf75a0f6 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -307,7 +307,8 @@ namespace ImageSharp.Formats rgbBytes.Reset(); pixels.CopyRGBBytesStretchedTo(rgbBytes, y, x); - byte* data = (byte*)rgbBytes.DataPointer; + ref byte data0 = ref rgbBytes.Bytes[0]; + int dataIdx = 0; for (int j = 0; j < 8; j++) { @@ -315,9 +316,9 @@ namespace ImageSharp.Formats for (int i = 0; i < 8; i++) { // Convert returned bytes into the YCbCr color space. Assume RGBA - int r = data[0]; - int g = data[1]; - int b = data[2]; + int r = Unsafe.Add(ref data0, dataIdx); + int g = Unsafe.Add(ref data0, dataIdx + 1); + int b = Unsafe.Add(ref data0, dataIdx + 2); // Speed up the algorithm by removing floating point calculation // Scale by 65536, add .5F and truncate value. We use bit shifting to divide the result @@ -343,7 +344,7 @@ namespace ImageSharp.Formats cbBlockRaw[index] = cb; crBlockRaw[index] = cr; - data += 3; + dataIdx += 3; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Utils/JpegUtils.cs b/src/ImageSharp/Formats/Jpeg/Utils/JpegUtils.cs index dd96985d9a..ace309812a 100644 --- a/src/ImageSharp/Formats/Jpeg/Utils/JpegUtils.cs +++ b/src/ImageSharp/Formats/Jpeg/Utils/JpegUtils.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats.Jpg { using System; using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; /// /// Jpeg specific utilities and extension methods @@ -33,19 +34,6 @@ namespace ImageSharp.Formats.Jpg StretchPixels(dest, stretchFromX, stretchFromY); } - /// - /// Copy an RGB value - /// - /// Source pointer - /// Destination pointer - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void CopyRgb(byte* source, byte* dest) - { - *dest++ = *source++; // R - *dest++ = *source++; // G - *dest = *source; // B - } - // Nothing to stretch if (fromX, fromY) is outside the area, or is at (0,0) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsInvalidStretchStartingPosition(PixelArea area, int fromX, int fromY) @@ -64,31 +52,38 @@ namespace ImageSharp.Formats.Jpg for (int y = 0; y < fromY; y++) { - byte* ptrBase = (byte*)area.DataPointer + (y * area.RowStride); + ref RGB24 ptrBase = ref GetRowStart(area, y); for (int x = fromX; x < area.Width; x++) { - byte* prevPtr = ptrBase + ((x - 1) * 3); - byte* currPtr = ptrBase + (x * 3); - - CopyRgb(prevPtr, currPtr); + // Copy the left neighbour pixel to the current one + Unsafe.Add(ref ptrBase, x) = Unsafe.Add(ref ptrBase, x - 1); } } for (int y = fromY; y < area.Height; y++) { - byte* currBase = (byte*)area.DataPointer + (y * area.RowStride); - byte* prevBase = (byte*)area.DataPointer + ((y - 1) * area.RowStride); + ref RGB24 currBase = ref GetRowStart(area, y); + ref RGB24 prevBase = ref GetRowStart(area, y - 1); for (int x = 0; x < area.Width; x++) { - int x3 = 3 * x; - byte* currPtr = currBase + x3; - byte* prevPtr = prevBase + x3; - - CopyRgb(prevPtr, currPtr); + // Copy the top neighbour pixel to the current one + Unsafe.Add(ref currBase, x) = Unsafe.Add(ref prevBase, x); } } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref RGB24 GetRowStart(PixelArea area, int y) + where TColor : struct, IPixel + { + return ref Unsafe.As(ref area.GetRowSpan(y).DangerousGetPinnableReference()); + } + + [StructLayout(LayoutKind.Sequential, Size = 3)] + private struct RGB24 + { + } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index f5393cfb38..5ff2911d4e 100644 --- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs @@ -15,14 +15,9 @@ namespace ImageSharp /// Provides per-pixel access to generic pixels. /// /// The pixel format. - public sealed unsafe class PixelAccessor : IDisposable, IPinnedImageBuffer + public sealed class PixelAccessor : IDisposable, IPinnedImageBuffer where TColor : struct, IPixel { - /// - /// The position of the first pixel in the image. - /// - private byte* pixelsBase; - /// /// A value indicating whether this instance of the given entity has been disposed. /// @@ -93,11 +88,6 @@ namespace ImageSharp /// public TColor[] PixelArray => this.pixelBuffer.Array; - /// - /// Gets the pointer to the pixel buffer. - /// - public IntPtr DataPointer => this.pixelBuffer.Pointer; - /// /// Gets the size of a single pixel in the number of bytes. /// @@ -139,15 +129,13 @@ namespace ImageSharp get { this.CheckCoordinates(x, y); - - return Unsafe.Read(this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf())); + return this.PixelArray[(y * this.Width) + x]; } set { this.CheckCoordinates(x, y); - - Unsafe.Write(this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf()), value); + this.PixelArray[(y * this.Width) + x] = value; } } @@ -179,7 +167,7 @@ namespace ImageSharp /// public void Reset() { - Unsafe.InitBlock(this.pixelsBase, 0, (uint)(this.RowStride * this.Height)); + this.pixelBuffer.Clear(); } /// @@ -262,9 +250,7 @@ namespace ImageSharp /// The target pixel buffer accessor. internal void CopyTo(PixelAccessor target) { - uint byteCount = (uint)(this.Width * this.Height * Unsafe.SizeOf()); - - Unsafe.CopyBlock(target.pixelsBase, this.pixelsBase, byteCount); + BufferSpan.Copy(this.pixelBuffer.Span, target.pixelBuffer.Span); } /// @@ -436,7 +422,6 @@ namespace ImageSharp private void SetPixelBufferUnsafe(int width, int height, PinnedImageBuffer pixels) { this.pixelBuffer = pixels; - this.pixelsBase = (byte*)pixels.Pointer; this.Width = width; this.Height = height; diff --git a/src/ImageSharp/Image/PixelArea{TColor}.cs b/src/ImageSharp/Image/PixelArea{TColor}.cs index bd10c9b6b0..87e6792058 100644 --- a/src/ImageSharp/Image/PixelArea{TColor}.cs +++ b/src/ImageSharp/Image/PixelArea{TColor}.cs @@ -13,7 +13,7 @@ namespace ImageSharp /// Represents an area of generic pixels. /// /// The pixel format. - internal sealed unsafe class PixelArea : IDisposable + internal sealed class PixelArea : IDisposable where TColor : struct, IPixel { /// @@ -67,7 +67,6 @@ namespace ImageSharp this.Length = bytes.Length; // TODO: Is this the right value for Length? this.byteBuffer = new PinnedBuffer(bytes); - this.PixelBase = (byte*)this.byteBuffer.Pointer; } /// @@ -118,7 +117,6 @@ namespace ImageSharp this.Length = this.RowStride * height; this.byteBuffer = new PinnedBuffer(this.Length); - this.PixelBase = (byte*)this.byteBuffer.Pointer; } /// @@ -136,21 +134,11 @@ namespace ImageSharp /// public ComponentOrder ComponentOrder { get; } - /// - /// Gets the pointer to the pixel buffer. - /// - public IntPtr DataPointer => this.byteBuffer.Pointer; - /// /// Gets the height. /// public int Height { get; } - /// - /// Gets the data pointer. - /// - public byte* PixelBase { get; private set; } - /// /// Gets the width of one row in the number of bytes. /// @@ -198,7 +186,7 @@ namespace ImageSharp /// public void Reset() { - Unsafe.InitBlock(this.PixelBase, 0, (uint)(this.RowStride * this.Height)); + this.byteBuffer.Clear(); } ///