From 969d8f004df8442dccaf7d4989bab928d68f0f4e Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 20 Mar 2019 10:38:42 +0100 Subject: [PATCH] Reduced UnmanagedBitmap fields, and changed the Scale2x_Unmanaged performance test to use refs (shows as a 20% performance increase vs. the Scale2x_Unmanaged_Reference on net472) --- src/Greenshot.Gfx/ScaleXUnmanaged.cs | 125 +++++++++++++-------------- src/Greenshot.Gfx/UnmanagedBitmap.cs | 30 +++---- 2 files changed, 72 insertions(+), 83 deletions(-) diff --git a/src/Greenshot.Gfx/ScaleXUnmanaged.cs b/src/Greenshot.Gfx/ScaleXUnmanaged.cs index 02c9714ff..1f029b06b 100644 --- a/src/Greenshot.Gfx/ScaleXUnmanaged.cs +++ b/src/Greenshot.Gfx/ScaleXUnmanaged.cs @@ -60,76 +60,67 @@ namespace Greenshot.Gfx var destinationWidth = destinationBitmap.Width; ReadOnlySpan sourceSpan = MemoryMarshal.Cast(sourceBitmap.Span); var destinationSpan = MemoryMarshal.Cast(destinationBitmap.Span); - unsafe + for (var y = 0; y < sourceBitmap.Height; y++) { - var colors = stackalloc uint[5]; - var colorsE = stackalloc uint[4]; - for (var y = 0; y < sourceBitmap.Height; y++) + var sourceYOffset = y * sourceWidth; + var destinationYOffset = (y << 1) * destinationWidth; + for (var x = 0; x < sourceWidth; x++) { - var sourceYOffset = y * sourceWidth; - var destinationYOffset = (y << 1) * destinationWidth; - for (var x = 0; x < sourceWidth; x++) + var sourceOffset = sourceYOffset + x; + ref readonly uint colorE = ref sourceSpan[sourceOffset]; + + ref readonly uint colorB = ref colorE; + if (y != 0) { - var sourceOffset = sourceYOffset + x; - colors[ColorE] = sourceSpan[sourceOffset]; - - if (y != 0) - { - colors[ColorB] = sourceSpan[sourceOffset - sourceWidth]; - } - else - { - colors[ColorB] = colors[ColorE]; - } - - if (y != sourceBitmap.Height - 1) - { - colors[ColorH] = sourceSpan[sourceOffset + sourceWidth]; - } - else - { - colors[ColorH] = colors[ColorE]; - } - - if (x > 0) - { - colors[ColorD] = sourceSpan[sourceOffset - 1]; - } - else - { - colors[ColorD] = colors[ColorE]; - } - - if (x < sourceBitmap.Width - 1) - { - colors[ColorF] = sourceSpan[sourceOffset + 1]; - } - else - { - colors[ColorF] = colors[ColorE]; - } - - if (colors[ColorB] != colors[ColorH] && colors[ColorD] != colors[ColorF]) - { - colorsE[3] = colors[ColorH] == colors[ColorF] ? colors[ColorF] : colors[ColorE]; - colorsE[2] = colors[ColorD] == colors[ColorH] ? colors[ColorD] : colors[ColorE]; - colorsE[1] = colors[ColorB] == colors[ColorF] ? colors[ColorF] : colors[ColorE]; - colorsE[0] = colors[ColorD] == colors[ColorB] ? colors[ColorD] : colors[ColorE]; - } - else - { - colorsE[3] = colors[ColorE]; - colorsE[2] = colors[ColorE]; - colorsE[1] = colors[ColorE]; - colorsE[0] = colors[ColorE]; - } - - var destinationOffset = (x << 1) + destinationYOffset; - destinationSpan[destinationOffset + 1 + destinationWidth] = colorsE[3]; - destinationSpan[destinationOffset + destinationWidth] = colorsE[2]; - destinationSpan[destinationOffset + 1] = colorsE[1]; - destinationSpan[destinationOffset] = colorsE[0]; + colorB = ref sourceSpan[sourceOffset - sourceWidth]; } + + ref readonly uint colorH = ref colorE; + if (y != sourceBitmap.Height - 1) + { + colorH = ref sourceSpan[sourceOffset + sourceWidth]; + } + + ref readonly uint colorD = ref colorE; + if (x > 0) + { + colorD = ref sourceSpan[sourceOffset - 1]; + } + + ref readonly uint colorF = ref colorE; + if (x < sourceBitmap.Width - 1) + { + colorF = ref sourceSpan[sourceOffset + 1]; + } + + ref readonly uint colorE0 = ref colorE; + ref readonly uint colorE1 = ref colorE; + ref readonly uint colorE2 = ref colorE; + ref readonly uint colorE3 = ref colorE; + if (colorB != colorH && colorD != colorF) + { + if (colorH == colorF) + { + colorE3 = ref colorF; + } + if (colorD == colorH) + { + colorE2 = ref colorD; + } + if (colorB == colorF) + { + colorE1 = ref colorF; + } + if (colorD == colorB) + { + colorE0 = ref colorD; + } + } + var destinationOffset = (x << 1) + destinationYOffset; + destinationSpan[destinationOffset + 1 + destinationWidth] = colorE3; + destinationSpan[destinationOffset + destinationWidth] = colorE2; + destinationSpan[destinationOffset + 1] = colorE1; + destinationSpan[destinationOffset] = colorE0; } } @@ -206,7 +197,7 @@ namespace Greenshot.Gfx { colors[ColorD] = colors[ColorE]; } - + if (x < sourceWidth - 1) { colors[ColorF] = sourceSpan[sourceOffset + 1]; diff --git a/src/Greenshot.Gfx/UnmanagedBitmap.cs b/src/Greenshot.Gfx/UnmanagedBitmap.cs index 2b7dadbc8..7e1c7143a 100644 --- a/src/Greenshot.Gfx/UnmanagedBitmap.cs +++ b/src/Greenshot.Gfx/UnmanagedBitmap.cs @@ -36,12 +36,8 @@ namespace Greenshot.Gfx /// struct for the pixel information public class UnmanagedBitmap : IDisposable where TPixelLayout : unmanaged { - private readonly int _byteLength; - private readonly int _bytesPerPixel; - private readonly int _pixels; private readonly int _stride; - private bool _isDisposed; - private readonly IntPtr _hGlobal; + private IntPtr _hGlobal; /// /// Width of the bitmap @@ -60,14 +56,13 @@ namespace Greenshot.Gfx /// int public UnmanagedBitmap(int width, int height) { - _bytesPerPixel = Marshal.SizeOf(); + var bytesPerPixel = Marshal.SizeOf(); Width = width; Height = height; - _pixels = height * width; - _stride = _bytesPerPixel * width; - _byteLength = height * _stride; - _hGlobal = Marshal.AllocHGlobal(_byteLength); - GC.AddMemoryPressure(_byteLength); + _stride = bytesPerPixel * width; + var bytesAllocated = height * _stride; + _hGlobal = Marshal.AllocHGlobal(bytesAllocated); + GC.AddMemoryPressure(bytesAllocated); } /// @@ -87,7 +82,10 @@ namespace Greenshot.Gfx } } - /// + /// + /// This returns a span with all the pixels + /// + /// Span of TPixelLayout for the line public Span Span { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -95,7 +93,7 @@ namespace Greenshot.Gfx { unsafe { - return new Span(_hGlobal.ToPointer(), _pixels); + return new Span(_hGlobal.ToPointer(), Height * Width); } } } @@ -131,13 +129,13 @@ namespace Greenshot.Gfx /// public void Dispose() { - if (_isDisposed) + if (_hGlobal == IntPtr.Zero) { return; } - _isDisposed = true; Marshal.FreeHGlobal(_hGlobal); - GC.RemoveMemoryPressure(_byteLength); + _hGlobal = IntPtr.Zero; + GC.RemoveMemoryPressure(Height * _stride); } #endregion