mirror of
https://github.com/greenshot/greenshot
synced 2025-08-22 22:34:27 -07:00
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:
parent
1766ed6ab1
commit
969d8f004d
2 changed files with 72 additions and 83 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue