Some small fixes, removed Span<T> as a stackalloc replacement as on .NET 4.7.1 this slows down. Not sure why the memory usage doubled for the Scale3x_Unmanaged performance test though.

This commit is contained in:
Robin 2019-03-13 09:50:17 +01:00
commit e91bf3f2d0
No known key found for this signature in database
GPG key ID: CBBB6557491B1140
7 changed files with 132 additions and 105 deletions

View file

@ -177,14 +177,14 @@ Task("EnableDNC30")
.Does(() => .Does(() =>
{ {
ReplaceRegexInFiles("./**/*.csproj", "<TargetFrameworks>.*</TargetFrameworks><!-- net472;netcoreapp3.0 -->", "<TargetFrameworks>net472;netcoreapp3.0</TargetFrameworks>"); ReplaceRegexInFiles("./**/*.csproj", "<TargetFrameworks>.*</TargetFrameworks><!-- net472;netcoreapp3.0 -->", "<TargetFrameworks>net472;netcoreapp3.0</TargetFrameworks>");
ReplaceRegexInFiles("./**/*.csproj", "<Project Sdk=\"MSBuild.Sdk.Extras/1.6.65\"><!-- Microsoft.NET.Sdk.WindowsDesktop -->", "<Project Sdk=\"Microsoft.NET.Sdk.WindowsDesktop\">"); ReplaceRegexInFiles("./**/*.csproj", "<Project Sdk=\"Microsoft.NET.Sdk\"><!-- Microsoft.NET.Sdk.WindowsDesktop -->", "<Project Sdk=\"Microsoft.NET.Sdk.WindowsDesktop\">");
}); });
Task("DisableDNC30") Task("DisableDNC30")
.Does(() => .Does(() =>
{ {
ReplaceRegexInFiles("./**/*.csproj", "<TargetFrameworks>net472;netcoreapp3.0</TargetFrameworks>", "<TargetFrameworks>net472</TargetFrameworks><!-- net472;netcoreapp3.0 -->"); ReplaceRegexInFiles("./**/*.csproj", "<TargetFrameworks>net472;netcoreapp3.0</TargetFrameworks>", "<TargetFrameworks>net472</TargetFrameworks><!-- net472;netcoreapp3.0 -->");
ReplaceRegexInFiles("./**/*.csproj", "<Project Sdk=\"Microsoft.NET.Sdk.WindowsDesktop\">", "<Project Sdk=\"MSBuild.Sdk.Extras/1.6.65\"><!-- Microsoft.NET.Sdk.WindowsDesktop -->"); ReplaceRegexInFiles("./**/*.csproj", "<Project Sdk=\"Microsoft.NET.Sdk.WindowsDesktop\">", "<Project Sdk=\"Microsoft.NET.Sdk\"><!-- Microsoft.NET.Sdk.WindowsDesktop -->");
}); });
Task("ChangeNETVersion") Task("ChangeNETVersion")

View file

@ -23,9 +23,8 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Greenshot.Gfx.Experimental;
namespace Greenshot.Gfx namespace Greenshot.Gfx.Experimental
{ {
/// <summary> /// <summary>
/// This is the ScaleX code for the UnmanagedBitmap /// This is the ScaleX code for the UnmanagedBitmap
@ -33,11 +32,11 @@ namespace Greenshot.Gfx
/// </summary> /// </summary>
public static class ScaleXUnmanaged public static class ScaleXUnmanaged
{ {
private const int ColorB = 0; private const byte ColorB = 0;
private const int ColorD = 1; private const byte ColorD = 1;
private const int ColorE = 4; private const byte ColorE = 4;
private const int ColorF = 2; private const byte ColorF = 2;
private const int ColorH = 3; private const byte ColorH = 3;
private const byte ColorA = 5; private const byte ColorA = 5;
private const byte ColorC = 6; private const byte ColorC = 6;
private const byte ColorG = 7; private const byte ColorG = 7;
@ -59,78 +58,81 @@ namespace Greenshot.Gfx
var sourceWidth = sourceBitmap.Width; var sourceWidth = sourceBitmap.Width;
var destinationWidth = destinationBitmap.Width; var destinationWidth = destinationBitmap.Width;
ReadOnlySpan<int> sourceSpan = MemoryMarshal.Cast<TPixelLayout, int>(sourceBitmap.Span); ReadOnlySpan<uint> sourceSpan = MemoryMarshal.Cast<TPixelLayout, uint>(sourceBitmap.Span);
var destinationSpan = MemoryMarshal.Cast<TPixelLayout, int>(destinationBitmap.Span); var destinationSpan = MemoryMarshal.Cast<TPixelLayout, uint>(destinationBitmap.Span);
unsafe
Span<int> colors = stackalloc int[5];
Span<int> colorsE = stackalloc int[4];
for (var y = 0; y < sourceBitmap.Height; y++)
{ {
var sourceYOffset = y * sourceWidth; var colors = stackalloc uint[5];
var destinationYOffset = (y << 1) * destinationWidth; var colorsE = stackalloc uint[4];
for (var x = 0; x < sourceWidth; x++) for (var y = 0; y < sourceBitmap.Height; y++)
{ {
var sourceOffset = sourceYOffset + x; var sourceYOffset = y * sourceWidth;
colors[ColorE] = sourceSpan[sourceOffset]; var destinationYOffset = (y << 1) * destinationWidth;
for (var x = 0; x < sourceWidth; x++)
{
var sourceOffset = sourceYOffset + x;
colors[ColorE] = sourceSpan[sourceOffset];
if (y != 0) if (y != 0)
{ {
colors[ColorB] = sourceSpan[sourceOffset - sourceWidth]; colors[ColorB] = sourceSpan[sourceOffset - sourceWidth];
} }
else else
{ {
colors[ColorB] = colors[ColorE]; colors[ColorB] = colors[ColorE];
} }
if (y != sourceBitmap.Height - 1) if (y != sourceBitmap.Height - 1)
{ {
colors[ColorH] = sourceSpan[sourceOffset + sourceWidth]; colors[ColorH] = sourceSpan[sourceOffset + sourceWidth];
} }
else else
{ {
colors[ColorH] = colors[ColorE]; colors[ColorH] = colors[ColorE];
} }
if (x > 0) if (x > 0)
{ {
colors[ColorD] = sourceSpan[sourceOffset - 1]; colors[ColorD] = sourceSpan[sourceOffset - 1];
} }
else else
{ {
colors[ColorD] = colors[ColorE]; colors[ColorD] = colors[ColorE];
} }
if (x < sourceBitmap.Width - 1) if (x < sourceBitmap.Width - 1)
{ {
colors[ColorF] = sourceSpan[sourceOffset + 1]; colors[ColorF] = sourceSpan[sourceOffset + 1];
} }
else else
{ {
colors[ColorF] = colors[ColorE]; colors[ColorF] = colors[ColorE];
} }
if (colors[ColorB] != colors[ColorH] && colors[ColorD] != colors[ColorF]) if (colors[ColorB] != colors[ColorH] && colors[ColorD] != colors[ColorF])
{ {
colorsE[3] = colors[ColorH] == colors[ColorF] ? colors[ColorF] : colors[ColorE]; colorsE[3] = colors[ColorH] == colors[ColorF] ? colors[ColorF] : colors[ColorE];
colorsE[2] = colors[ColorD] == colors[ColorH] ? colors[ColorD] : colors[ColorE]; colorsE[2] = colors[ColorD] == colors[ColorH] ? colors[ColorD] : colors[ColorE];
colorsE[1] = colors[ColorB] == colors[ColorF] ? colors[ColorF] : colors[ColorE]; colorsE[1] = colors[ColorB] == colors[ColorF] ? colors[ColorF] : colors[ColorE];
colorsE[0] = colors[ColorD] == colors[ColorB] ? colors[ColorD] : colors[ColorE]; colorsE[0] = colors[ColorD] == colors[ColorB] ? colors[ColorD] : colors[ColorE];
} }
else else
{ {
colorsE[3] = colors[ColorE]; colorsE[3] = colors[ColorE];
colorsE[2] = colors[ColorE]; colorsE[2] = colors[ColorE];
colorsE[1] = colors[ColorE]; colorsE[1] = colors[ColorE];
colorsE[0] = colors[ColorE]; colorsE[0] = colors[ColorE];
} }
var destinationOffset = (x << 1) + destinationYOffset; var destinationOffset = (x << 1) + destinationYOffset;
destinationSpan[destinationOffset + 1 + destinationWidth] = colorsE[3]; destinationSpan[destinationOffset + 1 + destinationWidth] = colorsE[3];
destinationSpan[destinationOffset + destinationWidth] = colorsE[2]; destinationSpan[destinationOffset + destinationWidth] = colorsE[2];
destinationSpan[destinationOffset + 1] = colorsE[1]; destinationSpan[destinationOffset + 1] = colorsE[1];
destinationSpan[destinationOffset] = colorsE[0]; destinationSpan[destinationOffset] = colorsE[0];
}
} }
} }
return destinationBitmap; return destinationBitmap;
} }
@ -147,18 +149,19 @@ namespace Greenshot.Gfx
throw new NotSupportedException("Only 4 byte unmanaged structs are supported."); throw new NotSupportedException("Only 4 byte unmanaged structs are supported.");
} }
var destinationBitmap = new UnmanagedBitmap<TPixelLayout>(sourceBitmap.Width * 3, sourceBitmap.Height * 3); var destinationBitmap = new UnmanagedBitmap<TPixelLayout>(sourceBitmap.Width * 3, sourceBitmap.Height * 3);
ReadOnlySpan<int> sourceSpan = MemoryMarshal.Cast<TPixelLayout, int>(sourceBitmap.Span);
var destinationSpan = MemoryMarshal.Cast<TPixelLayout, int>(destinationBitmap.Span); ReadOnlySpan<uint> sourceSpan = MemoryMarshal.Cast<TPixelLayout, uint>(sourceBitmap.Span);
var destinationSpan = MemoryMarshal.Cast<TPixelLayout, uint>(destinationBitmap.Span);
var sourceWidth = sourceBitmap.Width; var sourceWidth = sourceBitmap.Width;
var destinationWidth = destinationBitmap.Width; var destinationWidth = destinationBitmap.Width;
unsafe unsafe
{ {
Span<int> colors = stackalloc int[9]; var colors = stackalloc uint[9];
Span<int> colorsE = stackalloc int[9]; var colorsE = stackalloc uint[9];
for (int y = 0; y < sourceBitmap.Height; y++) for (var y = 0; y < sourceBitmap.Height; y++)
{ {
var sourceYOffset = y * sourceWidth; var sourceYOffset = y * sourceWidth;
var destinationYOffset = y * 3 * destinationWidth; var destinationYOffset = y * 3 * destinationWidth;
@ -166,10 +169,8 @@ namespace Greenshot.Gfx
{ {
var sourceOffset = sourceYOffset + x; var sourceOffset = sourceYOffset + x;
//source.GetColorAt(x, y, colors[ColorE]);
colors[ColorE] = sourceSpan[sourceOffset]; colors[ColorE] = sourceSpan[sourceOffset];
//source.GetColorAt(x - 1, y - 1, colors[ColorA]);
if (y != 0 && x != 0) if (y != 0 && x != 0)
{ {
colors[ColorA] = sourceSpan[(sourceOffset - 1) - sourceWidth]; colors[ColorA] = sourceSpan[(sourceOffset - 1) - sourceWidth];
@ -179,7 +180,6 @@ namespace Greenshot.Gfx
colors[ColorA] = colors[ColorE]; colors[ColorA] = colors[ColorE];
} }
//source.GetColorAt(x, y - 1, colors[ColorB]);
if (y != 0) if (y != 0)
{ {
colors[ColorB] = sourceSpan[sourceOffset - sourceWidth]; colors[ColorB] = sourceSpan[sourceOffset - sourceWidth];
@ -189,7 +189,6 @@ namespace Greenshot.Gfx
colors[ColorB] = colors[ColorE]; colors[ColorB] = colors[ColorE];
} }
//source.GetColorAt(x + 1, y - 1, colors[ColorC]);
if (x < sourceWidth - 1 && y != 0) if (x < sourceWidth - 1 && y != 0)
{ {
colors[ColorC] = sourceSpan[(sourceOffset + 1) - sourceWidth]; colors[ColorC] = sourceSpan[(sourceOffset + 1) - sourceWidth];
@ -199,7 +198,6 @@ namespace Greenshot.Gfx
colors[ColorC] = colors[ColorE]; colors[ColorC] = colors[ColorE];
} }
//source.GetColorAt(x - 1, y, colors[ColorD]);
if (x != 0) if (x != 0)
{ {
colors[ColorD] = sourceSpan[sourceOffset - 1]; colors[ColorD] = sourceSpan[sourceOffset - 1];
@ -209,7 +207,6 @@ namespace Greenshot.Gfx
colors[ColorD] = colors[ColorE]; colors[ColorD] = colors[ColorE];
} }
//source.GetColorAt(x + 1, y, colors[ColorF]);
if (x < sourceWidth - 1) if (x < sourceWidth - 1)
{ {
colors[ColorF] = sourceSpan[sourceOffset + 1]; colors[ColorF] = sourceSpan[sourceOffset + 1];
@ -219,7 +216,6 @@ namespace Greenshot.Gfx
colors[ColorF] = colors[ColorE]; colors[ColorF] = colors[ColorE];
} }
//source.GetColorAt(x - 1, y + 1, colors[ColorG]);
if (x != 0 && y < sourceBitmap.Height - 1) if (x != 0 && y < sourceBitmap.Height - 1)
{ {
colors[ColorG] = sourceSpan[(sourceOffset - 1) + sourceWidth]; colors[ColorG] = sourceSpan[(sourceOffset - 1) + sourceWidth];
@ -229,7 +225,6 @@ namespace Greenshot.Gfx
colors[ColorG] = colors[ColorE]; colors[ColorG] = colors[ColorE];
} }
//source.GetColorAt(x, y + 1, colors[ColorH]);
if (y < sourceBitmap.Height - 1) if (y < sourceBitmap.Height - 1)
{ {
colors[ColorH] = sourceSpan[sourceOffset + sourceWidth]; colors[ColorH] = sourceSpan[sourceOffset + sourceWidth];
@ -239,7 +234,6 @@ namespace Greenshot.Gfx
colors[ColorH] = colors[ColorE]; colors[ColorH] = colors[ColorE];
} }
//source.GetColorAt(x + 1, y + 1, colors[ColorI]);
if (x < sourceWidth - 1 && y < sourceBitmap.Height - 1) if (x < sourceWidth - 1 && y < sourceBitmap.Height - 1)
{ {
colors[ColorI] = sourceSpan[sourceOffset + 1 + sourceWidth]; colors[ColorI] = sourceSpan[sourceOffset + 1 + sourceWidth];
@ -251,22 +245,31 @@ namespace Greenshot.Gfx
if (colors[ColorB] != colors[ColorH] && colors[ColorD] != colors[ColorF]) if (colors[ColorB] != colors[ColorH] && colors[ColorD] != colors[ColorF])
{ {
colorsE[0] = colors[ColorD] == colors[ColorB] ? colors[ColorD] : colors[ColorE]; colorsE[8] = colors[ColorH] == colors[ColorF] ? colors[ColorF] : colors[ColorE];
colorsE[1] = colors[ColorD] == colors[ColorB] && colors[ColorE] != colors[ColorC] || colors[ColorB] == colors[ColorF] && colors[ColorE] != colors[ColorA] ? colors[ColorB] : colors[ColorE]; colorsE[7] = colors[ColorD] == colors[ColorH] && colors[ColorE] != colors[ColorI] || colors[ColorH] == colors[ColorF] && colors[ColorE] != colors[ColorG] ? colors[ColorH] : colors[ColorE];
colorsE[2] = colors[ColorB] == colors[ColorF] ? colors[ColorF]: colors[ColorE]; colorsE[6] = colors[ColorD] == colors[ColorH] ? colors[ColorD] : colors[ColorE];
colorsE[3] = colors[ColorD] == colors[ColorB] && colors[ColorE] != colors[ColorG] || colors[ColorD] == colors[ColorH] && colors[ColorE] != colors[ColorA] ? colors[ColorD] : colors[ColorE]; colorsE[5] = colors[ColorB] == colors[ColorF] && colors[ColorE] != colors[ColorI] || colors[ColorH] == colors[ColorF] && colors[ColorE] != colors[ColorC] ? colors[ColorF] : colors[ColorE];
colorsE[4] = colors[ColorE]; colorsE[4] = colors[ColorE];
colorsE[5] = colors[ColorB] == colors[ColorF] && colors[ColorE] != colors[ColorI] || colors[ColorH] == colors[ColorF] && colors[ColorE] != colors[ColorC] ? colors[ColorF] : colors[ColorE];
colorsE[6] = colors[ColorD] == colors[ColorH] ? colors[ColorD] : colors[ColorE]; colorsE[3] = colors[ColorD] == colors[ColorB] && colors[ColorE] != colors[ColorG] || colors[ColorD] == colors[ColorH] && colors[ColorE] != colors[ColorA] ? colors[ColorD] : colors[ColorE];
colorsE[7] = colors[ColorD] == colors[ColorH] && colors[ColorE] != colors[ColorI] || colors[ColorH] == colors[ColorF] && colors[ColorE] != colors[ColorG] ? colors[ColorH] : colors[ColorE]; colorsE[2] = colors[ColorB] == colors[ColorF] ? colors[ColorF] : colors[ColorE];
colorsE[8] = colors[ColorH] == colors[ColorF] ? colors[ColorF] : colors[ColorE]; colorsE[1] = colors[ColorD] == colors[ColorB] && colors[ColorE] != colors[ColorC] || colors[ColorB] == colors[ColorF] && colors[ColorE] != colors[ColorA] ? colors[ColorB] : colors[ColorE];
colorsE[0] = colors[ColorD] == colors[ColorB] ? colors[ColorD] : colors[ColorE];
} }
else else
{ {
colorsE.Fill(colors[ColorE]); colorsE[8] = colors[ColorE];
colorsE[7] = colors[ColorE];
colorsE[6] = colors[ColorE];
colorsE[5] = colors[ColorE];
colorsE[4] = colors[ColorE];
colorsE[3] = colors[ColorE];
colorsE[2] = colors[ColorE];
colorsE[1] = colors[ColorE];
colorsE[0] = colors[ColorE];
} }
var destinationOffset = (x * 3) + destinationYOffset; var destinationOffset = x * 3 + destinationYOffset;
destinationSpan[destinationOffset] = colorsE[0]; destinationSpan[destinationOffset] = colorsE[0];
destinationSpan[destinationOffset + 1] = colorsE[1]; destinationSpan[destinationOffset + 1] = colorsE[1];
@ -282,7 +285,6 @@ namespace Greenshot.Gfx
destinationSpan[destinationOffset + 1] = colorsE[7]; destinationSpan[destinationOffset + 1] = colorsE[7];
destinationSpan[destinationOffset + 2] = colorsE[8]; destinationSpan[destinationOffset + 2] = colorsE[8];
} }
} }
} }
return destinationBitmap; return destinationBitmap;

View file

@ -22,13 +22,9 @@
#endregion #endregion
using System; using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Greenshot.Gfx.Experimental;
using Greenshot.Gfx.Experimental.Structs;
namespace Greenshot.Gfx namespace Greenshot.Gfx.Experimental
{ {
/// <summary> /// <summary>
/// This is the ScaleX code for the UnmanagedBitmap /// This is the ScaleX code for the UnmanagedBitmap

View file

@ -64,7 +64,7 @@ namespace Greenshot.Gfx.Experimental.Structs
public bool Equals(Bgr32 other) => (B, G, R) == (other.B, other.G, other.R); public bool Equals(Bgr32 other) => (B, G, R) == (other.B, other.G, other.R);
/// <inheritdoc /> /// <inheritdoc />
public override int GetHashCode() => HashCode.Combine(B, G, R); public override int GetHashCode() => (B, G, R).GetHashCode();
} }
} }

View file

@ -67,7 +67,6 @@ namespace Greenshot.Gfx.Experimental.Structs
public bool Equals(Bgra32 other) => (B, G, R, A) == (other.B, other.G, other.R, other.A); public bool Equals(Bgra32 other) => (B, G, R, A) == (other.B, other.G, other.R, other.A);
/// <inheritdoc /> /// <inheritdoc />
public override int GetHashCode() => HashCode.Combine(B, G, R, A); public override int GetHashCode() => (B, G, R, A).GetHashCode();
} }
} }

View file

@ -2,16 +2,46 @@
namespace Greenshot.Gfx.Experimental.Structs namespace Greenshot.Gfx.Experimental.Structs
{ {
/// <summary>
///
/// </summary>
public class SpanInfo public class SpanInfo
{ {
/// <summary>
/// Pointer to the memory
/// </summary>
public IntPtr Pointer; public IntPtr Pointer;
/// <summary>
/// How many bytes are on a single line
/// </summary>
public int PixelStride; public int PixelStride;
/// <summary>
///
/// </summary>
public int Height; public int Height;
/// <summary>
///
/// </summary>
public int Width; public int Width;
/// <summary>
///
/// </summary>
public int Left; public int Left;
/// <summary>
///
/// </summary>
public int Right; public int Right;
/// <summary>
///
/// </summary>
public int Top; public int Top;
/// <summary>
///
/// </summary>
public int Bottom; public int Bottom;
/// <summary>
///
/// </summary>
public int BitmapSize; public int BitmapSize;
} }

View file

@ -107,7 +107,7 @@ namespace Greenshot.PerformanceTests
} }
[Benchmark] //[Benchmark]
public void Blur_Old() public void Blur_Old()
{ {
using (var bitmap = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White)) using (var bitmap = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White))