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)

This commit is contained in:
Robin 2019-03-20 10:38:42 +01:00
commit 969d8f004d
No known key found for this signature in database
GPG key ID: CBBB6557491B1140
2 changed files with 72 additions and 83 deletions

View file

@ -60,76 +60,67 @@ namespace Greenshot.Gfx
var destinationWidth = destinationBitmap.Width; var destinationWidth = destinationBitmap.Width;
ReadOnlySpan<uint> sourceSpan = MemoryMarshal.Cast<TPixelLayout, uint>(sourceBitmap.Span); ReadOnlySpan<uint> sourceSpan = MemoryMarshal.Cast<TPixelLayout, uint>(sourceBitmap.Span);
var destinationSpan = MemoryMarshal.Cast<TPixelLayout, uint>(destinationBitmap.Span); var destinationSpan = MemoryMarshal.Cast<TPixelLayout, uint>(destinationBitmap.Span);
unsafe for (var y = 0; y < sourceBitmap.Height; y++)
{ {
var colors = stackalloc uint[5]; var sourceYOffset = y * sourceWidth;
var colorsE = stackalloc uint[4]; var destinationYOffset = (y << 1) * destinationWidth;
for (var y = 0; y < sourceBitmap.Height; y++) for (var x = 0; x < sourceWidth; x++)
{ {
var sourceYOffset = y * sourceWidth; var sourceOffset = sourceYOffset + x;
var destinationYOffset = (y << 1) * destinationWidth; ref readonly uint colorE = ref sourceSpan[sourceOffset];
for (var x = 0; x < sourceWidth; x++)
ref readonly uint colorB = ref colorE;
if (y != 0)
{ {
var sourceOffset = sourceYOffset + x; colorB = ref sourceSpan[sourceOffset - sourceWidth];
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];
} }
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]; colors[ColorD] = colors[ColorE];
} }
if (x < sourceWidth - 1) if (x < sourceWidth - 1)
{ {
colors[ColorF] = sourceSpan[sourceOffset + 1]; colors[ColorF] = sourceSpan[sourceOffset + 1];

View file

@ -36,12 +36,8 @@ namespace Greenshot.Gfx
/// <typeparam name="TPixelLayout">struct for the pixel information</typeparam> /// <typeparam name="TPixelLayout">struct for the pixel information</typeparam>
public class UnmanagedBitmap<TPixelLayout> : IDisposable where TPixelLayout : unmanaged public class UnmanagedBitmap<TPixelLayout> : IDisposable where TPixelLayout : unmanaged
{ {
private readonly int _byteLength;
private readonly int _bytesPerPixel;
private readonly int _pixels;
private readonly int _stride; private readonly int _stride;
private bool _isDisposed; private IntPtr _hGlobal;
private readonly IntPtr _hGlobal;
/// <summary> /// <summary>
/// Width of the bitmap /// Width of the bitmap
@ -60,14 +56,13 @@ namespace Greenshot.Gfx
/// <param name="height">int</param> /// <param name="height">int</param>
public UnmanagedBitmap(int width, int height) public UnmanagedBitmap(int width, int height)
{ {
_bytesPerPixel = Marshal.SizeOf<TPixelLayout>(); var bytesPerPixel = Marshal.SizeOf<TPixelLayout>();
Width = width; Width = width;
Height = height; Height = height;
_pixels = height * width; _stride = bytesPerPixel * width;
_stride = _bytesPerPixel * width; var bytesAllocated = height * _stride;
_byteLength = height * _stride; _hGlobal = Marshal.AllocHGlobal(bytesAllocated);
_hGlobal = Marshal.AllocHGlobal(_byteLength); GC.AddMemoryPressure(bytesAllocated);
GC.AddMemoryPressure(_byteLength);
} }
/// <summary> /// <summary>
@ -87,7 +82,10 @@ namespace Greenshot.Gfx
} }
} }
/// <inheritdoc /> /// <summary>
/// This returns a span with all the pixels
/// </summary>
/// <returns>Span of TPixelLayout for the line</returns>
public Span<TPixelLayout> Span public Span<TPixelLayout> Span
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -95,7 +93,7 @@ namespace Greenshot.Gfx
{ {
unsafe unsafe
{ {
return new Span<TPixelLayout>(_hGlobal.ToPointer(), _pixels); return new Span<TPixelLayout>(_hGlobal.ToPointer(), Height * Width);
} }
} }
} }
@ -131,13 +129,13 @@ namespace Greenshot.Gfx
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
if (_isDisposed) if (_hGlobal == IntPtr.Zero)
{ {
return; return;
} }
_isDisposed = true;
Marshal.FreeHGlobal(_hGlobal); Marshal.FreeHGlobal(_hGlobal);
GC.RemoveMemoryPressure(_byteLength); _hGlobal = IntPtr.Zero;
GC.RemoveMemoryPressure(Height * _stride);
} }
#endregion #endregion