Optimized the ScaleX code, now working on the blur [skip ci]

This commit is contained in:
Robin 2019-05-21 13:00:43 +02:00
commit 803ddf3b24
No known key found for this signature in database
GPG key ID: CBBB6557491B1140
6 changed files with 345 additions and 354 deletions

View file

@ -18,7 +18,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Threading.Tasks;
using Greenshot.Gfx.Structs; using Greenshot.Gfx.Structs;
namespace Greenshot.Gfx namespace Greenshot.Gfx
@ -89,9 +88,8 @@ namespace Greenshot.Gfx
{ {
var halfRange = range / 2; var halfRange = range / 2;
Parallel.For(0, unmanagedBitmap.Height, y => for(var y = 0; y <unmanagedBitmap.Height; y++)
{ {
unsafe {
var rgb32 = unmanagedBitmap[y]; var rgb32 = unmanagedBitmap[y];
Span<Bgr32> averages = stackalloc Bgr32[range]; Span<Bgr32> averages = stackalloc Bgr32[range];
var r = 0; var r = 0;
@ -100,7 +98,7 @@ namespace Greenshot.Gfx
var hits = halfRange; var hits = halfRange;
for (var x = 0; x < halfRange; x++) for (var x = 0; x < halfRange; x++)
{ {
ref Bgr32 color = ref rgb32[x]; ref var color = ref rgb32[x];
r += color.R; r += color.R;
g += color.G; g += color.G;
@ -112,7 +110,7 @@ namespace Greenshot.Gfx
if (leftSide >= 0) if (leftSide >= 0)
{ {
// Get value at the left side of range // Get value at the left side of range
ref Bgr32 color = ref rgb32[leftSide]; ref var color = ref rgb32[leftSide];
r -= color.R; r -= color.R;
g -= color.G; g -= color.G;
b -= color.B; b -= color.B;
@ -122,29 +120,30 @@ namespace Greenshot.Gfx
var rightSide = x + halfRange; var rightSide = x + halfRange;
if (rightSide < unmanagedBitmap.Width) if (rightSide < unmanagedBitmap.Width)
{ {
ref Bgr32 color = ref rgb32[rightSide]; ref var color = ref rgb32[rightSide];
r += color.R; r += color.R;
g += color.G; g += color.G;
b += color.B; b += color.B;
hits++; hits++;
} }
ref Bgr32 average = ref averages[x % range]; ref var average = ref averages[x % range];
average.R = (byte)(r / hits); average.R = (byte)(r / hits);
average.G = (byte)(g / hits); average.G = (byte)(g / hits);
average.B = (byte)(b / hits); average.B = (byte)(b / hits);
if (leftSide >= 0) if (leftSide < 0)
{ {
// Now we can write the value from the calculated avarages continue;
}
// Now we can write the value from the calculated averages
var readLocation = (leftSide % range); var readLocation = (leftSide % range);
rgb32[leftSide] = averages[readLocation]; rgb32[leftSide] = averages[readLocation];
} }
} }
} }
});
}
/// <summary> /// <summary>
/// BoxBlurVertical is a private helper method for the BoxBlur /// BoxBlurVertical is a private helper method for the BoxBlur
@ -154,9 +153,8 @@ namespace Greenshot.Gfx
private static void BoxBlurVertical(UnmanagedBitmap<Bgr32> unmanagedBitmap, int range) private static void BoxBlurVertical(UnmanagedBitmap<Bgr32> unmanagedBitmap, int range)
{ {
var halfRange = range / 2; var halfRange = range / 2;
Parallel.For(0, unmanagedBitmap.Width, x => for(var x = 0; x <unmanagedBitmap.Width; x++)
{ {
unsafe {
var rgb32 = unmanagedBitmap.Span; var rgb32 = unmanagedBitmap.Span;
Span<Bgr32> averages = stackalloc Bgr32[range]; Span<Bgr32> averages = stackalloc Bgr32[range];
var hits = 0; var hits = 0;
@ -165,7 +163,7 @@ namespace Greenshot.Gfx
var b = 0; var b = 0;
for (var y = 0; y < halfRange; y++) for (var y = 0; y < halfRange; y++)
{ {
ref Bgr32 color = ref rgb32[(y * unmanagedBitmap.Width) + x]; ref var color = ref rgb32[(y * unmanagedBitmap.Width) + x];
r += color.R; r += color.R;
g += color.G; g += color.G;
b += color.B; b += color.B;
@ -177,7 +175,7 @@ namespace Greenshot.Gfx
if (topSide >= 0) if (topSide >= 0)
{ {
// Get value at the top side of range // Get value at the top side of range
ref Bgr32 color = ref rgb32[x + (topSide * unmanagedBitmap.Width)]; ref var color = ref rgb32[x + (topSide * unmanagedBitmap.Width)];
r -= color.R; r -= color.R;
g -= color.G; g -= color.G;
b -= color.B; b -= color.B;
@ -187,29 +185,30 @@ namespace Greenshot.Gfx
var bottomSide = y + halfRange; var bottomSide = y + halfRange;
if (bottomSide < unmanagedBitmap.Height) if (bottomSide < unmanagedBitmap.Height)
{ {
ref Bgr32 color = ref rgb32[x + (bottomSide * unmanagedBitmap.Width)]; ref var color = ref rgb32[x + (bottomSide * unmanagedBitmap.Width)];
r += color.R; r += color.R;
g += color.G; g += color.G;
b += color.B; b += color.B;
hits++; hits++;
} }
ref Bgr32 average = ref averages[y % range]; ref var average = ref averages[y % range];
average.R = (byte)(r / hits); average.R = (byte)(r / hits);
average.G = (byte)(g / hits); average.G = (byte)(g / hits);
average.B = (byte)(b / hits); average.B = (byte)(b / hits);
if (topSide >= 0) if (topSide < 0)
{ {
// Write the value from the calculated avarages continue;
}
// Write the value from the calculated averages
var readLocation = topSide % range; var readLocation = topSide % range;
rgb32[x + (topSide * unmanagedBitmap.Width)] = averages[readLocation]; rgb32[x + (topSide * unmanagedBitmap.Width)] = averages[readLocation];
} }
} }
} }
});
}
/// <summary> /// <summary>
/// BoxBlurHorizontal is a private helper method for the BoxBlur, only for IFastBitmaps with alpha channel /// BoxBlurHorizontal is a private helper method for the BoxBlur, only for IFastBitmaps with alpha channel
@ -220,9 +219,8 @@ namespace Greenshot.Gfx
{ {
var halfRange = range / 2; var halfRange = range / 2;
Parallel.For(0, unmanagedBitmap.Height, y => for(var y = 0; y <unmanagedBitmap.Height; y++)
{ {
unsafe {
var argb32 = unmanagedBitmap[y]; var argb32 = unmanagedBitmap[y];
Span<Bgra32> averages = stackalloc Bgra32[range]; Span<Bgra32> averages = stackalloc Bgra32[range];
var a = 0; var a = 0;
@ -232,7 +230,7 @@ namespace Greenshot.Gfx
var hits = halfRange; var hits = halfRange;
for (var x = 0; x < halfRange; x++) for (var x = 0; x < halfRange; x++)
{ {
ref Bgra32 color = ref argb32[x]; ref var color = ref argb32[x];
a += color.A; a += color.A;
r += color.R; r += color.R;
g += color.G; g += color.G;
@ -244,7 +242,7 @@ namespace Greenshot.Gfx
if (leftSide >= 0) if (leftSide >= 0)
{ {
// Get value at the left side of range // Get value at the left side of range
ref Bgra32 color = ref argb32[leftSide]; ref var color = ref argb32[leftSide];
a -= color.A; a -= color.A;
r -= color.R; r -= color.R;
g -= color.G; g -= color.G;
@ -255,7 +253,7 @@ namespace Greenshot.Gfx
var rightSide = x + halfRange; var rightSide = x + halfRange;
if (rightSide < unmanagedBitmap.Width) if (rightSide < unmanagedBitmap.Width)
{ {
ref Bgra32 color = ref argb32[rightSide]; ref var color = ref argb32[rightSide];
a += color.A; a += color.A;
r += color.R; r += color.R;
g += color.G; g += color.G;
@ -263,23 +261,24 @@ namespace Greenshot.Gfx
hits++; hits++;
} }
ref Bgra32 average = ref averages[x % range]; ref var average = ref averages[x % range];
average.A = (byte)(a / hits); average.A = (byte)(a / hits);
average.R = (byte)(r / hits); average.R = (byte)(r / hits);
average.G = (byte)(g / hits); average.G = (byte)(g / hits);
average.B = (byte)(b / hits); average.B = (byte)(b / hits);
if (leftSide >= 0) if (leftSide < 0)
{ {
// Now we can write the value from the calculated avarages continue;
}
// Now we can write the value from the calculated averages
var readLocation = leftSide % range; var readLocation = leftSide % range;
argb32[leftSide] = averages[readLocation]; argb32[leftSide] = averages[readLocation];
} }
} }
} }
});
}
/// <summary> /// <summary>
/// BoxBlurVertical is a private helper method for the BoxBlur /// BoxBlurVertical is a private helper method for the BoxBlur
@ -289,9 +288,7 @@ namespace Greenshot.Gfx
private static void BoxBlurVertical(UnmanagedBitmap<Bgra32> unmanagedBitmap, int range) private static void BoxBlurVertical(UnmanagedBitmap<Bgra32> unmanagedBitmap, int range)
{ {
var halfRange = range / 2; var halfRange = range / 2;
Parallel.For(0, unmanagedBitmap.Width, x => for(var x = 0; x <unmanagedBitmap.Width; x++)
{
unsafe
{ {
var argb32 = unmanagedBitmap.Span; var argb32 = unmanagedBitmap.Span;
Span<Bgra32> averages = stackalloc Bgra32[range]; Span<Bgra32> averages = stackalloc Bgra32[range];
@ -302,7 +299,7 @@ namespace Greenshot.Gfx
var b = 0; var b = 0;
for (var y = 0; y < halfRange; y++) for (var y = 0; y < halfRange; y++)
{ {
ref Bgra32 color = ref argb32[x + (y * unmanagedBitmap.Width)]; ref var color = ref argb32[x + (y * unmanagedBitmap.Width)];
a += color.A; a += color.A;
r += color.R; r += color.R;
g += color.G; g += color.G;
@ -315,7 +312,7 @@ namespace Greenshot.Gfx
if (topSide >= 0) if (topSide >= 0)
{ {
// Get value at the top side of range // Get value at the top side of range
ref Bgra32 color = ref argb32[x + (topSide * unmanagedBitmap.Width)]; ref var color = ref argb32[x + (topSide * unmanagedBitmap.Width)];
a -= color.A; a -= color.A;
r -= color.R; r -= color.R;
g -= color.G; g -= color.G;
@ -326,7 +323,7 @@ namespace Greenshot.Gfx
var bottomSide = y + halfRange; var bottomSide = y + halfRange;
if (bottomSide < unmanagedBitmap.Height) if (bottomSide < unmanagedBitmap.Height)
{ {
ref Bgra32 color = ref argb32[x + (bottomSide * unmanagedBitmap.Width)]; ref var color = ref argb32[x + (bottomSide * unmanagedBitmap.Width)];
a += color.A; a += color.A;
r += color.R; r += color.R;
g += color.G; g += color.G;
@ -334,22 +331,23 @@ namespace Greenshot.Gfx
hits++; hits++;
} }
ref Bgra32 average = ref averages[(y % range)]; ref var average = ref averages[(y % range)];
average.A = (byte)(a / hits); average.A = (byte)(a / hits);
average.R = (byte)(r / hits); average.R = (byte)(r / hits);
average.G = (byte)(g / hits); average.G = (byte)(g / hits);
average.B = (byte)(b / hits); average.B = (byte)(b / hits);
if (topSide >= 0) if (topSide < 0)
{ {
// Write the value from the calculated avarages continue;
}
// Write the value from the calculated averages
var readLocation = (topSide % range); var readLocation = (topSide % range);
argb32[x + (topSide * unmanagedBitmap.Width)] = averages[readLocation]; argb32[x + (topSide * unmanagedBitmap.Width)] = averages[readLocation];
} }
} }
} }
});
}
} }
} }

View file

@ -18,6 +18,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Greenshot.Gfx namespace Greenshot.Gfx
@ -44,45 +45,44 @@ namespace Greenshot.Gfx
var sourceWidth = sourceBitmap.Width; var sourceWidth = sourceBitmap.Width;
var destinationWidth = destinationBitmap.Width; var destinationWidth = destinationBitmap.Width;
ReadOnlySpan<uint> sourceSpan = MemoryMarshal.Cast<TPixelLayout, uint>(sourceBitmap.Span); ref var destinationPointer = ref Unsafe.As<TPixelLayout, uint>(ref destinationBitmap.Span.GetPinnableReference());
var destinationSpan = MemoryMarshal.Cast<TPixelLayout, uint>(destinationBitmap.Span); ref var sourcePointer = ref Unsafe.As<TPixelLayout, uint>(ref sourceBitmap.Span.GetPinnableReference());
for (var 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 << 1) * destinationWidth; var destinationYOffset = (y << 1) * destinationWidth;
for (var x = 0; x < sourceWidth; x++) for (var x = 0; x < sourceWidth; x++)
{ {
var sourceOffset = sourceYOffset + x; ref var colorE = ref Unsafe.Add(ref sourcePointer, sourceYOffset + x);
ref readonly uint colorE = ref sourceSpan[sourceOffset];
ref readonly uint colorB = ref colorE; ref readonly var colorB = ref colorE;
if (y != 0) if (y != 0)
{ {
colorB = ref sourceSpan[sourceOffset - sourceWidth]; colorB = ref Unsafe.Subtract(ref colorE, sourceWidth);
} }
ref readonly uint colorH = ref colorE; ref readonly var colorH = ref colorE;
if (y != sourceBitmap.Height - 1) if (y != sourceBitmap.Height - 1)
{ {
colorH = ref sourceSpan[sourceOffset + sourceWidth]; colorH = ref Unsafe.Add(ref colorE, sourceWidth);
} }
ref readonly uint colorD = ref colorE; ref readonly var colorD = ref colorE;
if (x > 0) if (x > 0)
{ {
colorD = ref sourceSpan[sourceOffset - 1]; colorD = ref Unsafe.Subtract(ref colorE, 1);
} }
ref readonly uint colorF = ref colorE; ref readonly var colorF = ref colorE;
if (x < sourceBitmap.Width - 1) if (x < sourceBitmap.Width - 1)
{ {
colorF = ref sourceSpan[sourceOffset + 1]; colorF = ref Unsafe.Add(ref colorE, 1);
} }
ref readonly uint colorE0 = ref colorE; ref readonly var colorE0 = ref colorE;
ref readonly uint colorE1 = ref colorE; ref readonly var colorE1 = ref colorE;
ref readonly uint colorE2 = ref colorE; ref readonly var colorE2 = ref colorE;
ref readonly uint colorE3 = ref colorE; ref readonly var colorE3 = ref colorE;
if (colorB != colorH && colorD != colorF) if (colorB != colorH && colorD != colorF)
{ {
if (colorH == colorF) if (colorH == colorF)
@ -102,17 +102,19 @@ namespace Greenshot.Gfx
colorE0 = ref colorD; colorE0 = ref colorD;
} }
} }
var destinationOffset = (x << 1) + destinationYOffset;
destinationSpan[destinationOffset + 1 + destinationWidth] = colorE3; ref var destColorE0 = ref Unsafe.Add(ref destinationPointer, (x << 1) + destinationYOffset);
destinationSpan[destinationOffset + destinationWidth] = colorE2; destColorE0 = colorE0;
destinationSpan[destinationOffset + 1] = colorE1; Unsafe.Add(ref destColorE0, 1 + destinationWidth) = colorE3;
destinationSpan[destinationOffset] = colorE0; Unsafe.Add(ref destColorE0, destinationWidth) = colorE2;
Unsafe.Add(ref destColorE0, 1) = colorE1;
} }
} }
return destinationBitmap; return destinationBitmap;
} }
/// <summary> /// <summary>
/// Use "Scale3x" algorithm to produce bitmap from the original. /// Use "Scale3x" algorithm to produce bitmap from the original.
/// Every pixel from input texture produces 6 output pixels, for more details check out http://scale2x.sourceforge.net/algorithm.html /// Every pixel from input texture produces 6 output pixels, for more details check out http://scale2x.sourceforge.net/algorithm.html
@ -128,80 +130,77 @@ namespace Greenshot.Gfx
// Create destination bitmap, where the scaled image is written to // Create destination bitmap, where the scaled image is written to
var destinationBitmap = new UnmanagedBitmap<TPixelLayout>(sourceBitmap.Width * 3, sourceBitmap.Height * 3); var destinationBitmap = new UnmanagedBitmap<TPixelLayout>(sourceBitmap.Width * 3, sourceBitmap.Height * 3);
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;
unchecked ref var destinationPointer = ref Unsafe.As<TPixelLayout, uint>(ref destinationBitmap.Span.GetPinnableReference());
{ ref var sourcePointer = ref Unsafe.As<TPixelLayout, uint>(ref sourceBitmap.Span.GetPinnableReference());
for (var 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;
for (var x = 0; x < sourceWidth; x++) for (var x = 0; x < sourceWidth; x++)
{ {
var sourceOffset = sourceYOffset + x; ref var colorE = ref Unsafe.Add(ref sourcePointer, sourceYOffset + x);
ref readonly uint colorE = ref sourceSpan[sourceOffset]; ref readonly var colorA = ref colorE;
ref readonly uint colorA = ref colorE; ref readonly var colorB = ref colorE;
ref readonly uint colorB = ref colorE; ref readonly var colorC = ref colorE;
ref readonly uint colorC = ref colorE; ref readonly var colorD = ref colorE;
ref readonly uint colorD = ref colorE; ref readonly var colorF = ref colorE;
ref readonly uint colorF = ref colorE; ref readonly var colorG = ref colorE;
ref readonly uint colorG = ref colorE; ref readonly var colorH = ref colorE;
ref readonly uint colorH = ref colorE; ref readonly var colorI = ref colorE;
ref readonly uint colorI = ref colorE;
if (y != 0 && x != 0) if (y != 0 && x != 0)
{ {
colorA = ref sourceSpan[sourceOffset - 1 - sourceWidth]; colorA = ref Unsafe.Subtract(ref colorE, 1 + sourceWidth);
} }
if (y != 0) if (y != 0)
{ {
colorB = ref sourceSpan[sourceOffset - sourceWidth]; colorB = ref Unsafe.Subtract(ref colorE, sourceWidth);
} }
if (x < sourceWidth - 1 && y != 0) if (x < sourceWidth - 1 && y != 0)
{ {
colorC = ref sourceSpan[sourceOffset + 1 - sourceWidth]; colorC = ref Unsafe.Subtract(ref colorE, sourceWidth - 1);
} }
if (x != 0) if (x != 0)
{ {
colorD = ref sourceSpan[sourceOffset - 1]; colorD = ref Unsafe.Subtract(ref colorE, 1);
} }
if (x < sourceWidth - 1) if (x < sourceWidth - 1)
{ {
colorF = ref sourceSpan[sourceOffset + 1]; colorF = ref Unsafe.Add(ref colorE, 1);
} }
if (x != 0 && y < sourceBitmap.Height - 1) if (x != 0 && y < sourceBitmap.Height - 1)
{ {
colorG = ref sourceSpan[sourceOffset - 1 + sourceWidth]; colorG = ref Unsafe.Add(ref colorE, sourceWidth - 1);
} }
if (y < sourceBitmap.Height - 1) if (y < sourceBitmap.Height - 1)
{ {
colorH = ref sourceSpan[sourceOffset + sourceWidth]; colorH = ref Unsafe.Add(ref colorE, sourceWidth);
} }
if (x < sourceWidth - 1 && y < sourceBitmap.Height - 1) if (x < sourceWidth - 1 && y < sourceBitmap.Height - 1)
{ {
colorI = ref sourceSpan[sourceOffset + 1 + sourceWidth]; colorI = ref Unsafe.Add(ref colorE, sourceWidth + 1);
} }
ref readonly uint colorE0 = ref colorE; ref readonly var colorE0 = ref colorE;
ref readonly uint colorE1 = ref colorE; ref readonly var colorE1 = ref colorE;
ref readonly uint colorE2 = ref colorE; ref readonly var colorE2 = ref colorE;
ref readonly uint colorE3 = ref colorE; ref readonly var colorE3 = ref colorE;
ref readonly uint colorE4 = ref colorE; ref readonly var colorE4 = ref colorE;
ref readonly uint colorE5 = ref colorE; ref readonly var colorE5 = ref colorE;
ref readonly uint colorE6 = ref colorE; ref readonly var colorE6 = ref colorE;
ref readonly uint colorE7 = ref colorE; ref readonly var colorE7 = ref colorE;
ref readonly uint colorE8 = ref colorE; ref readonly var colorE8 = ref colorE;
if (colorB != colorH && colorD != colorF) if (colorB != colorH && colorD != colorF)
{ {
if (colorH == colorF) if (colorH == colorF)
@ -241,20 +240,19 @@ namespace Greenshot.Gfx
var destinationOffset = x * 3 + destinationYOffset; var destinationOffset = x * 3 + destinationYOffset;
destinationSpan[destinationOffset] = colorE0; Unsafe.Add(ref destinationPointer, destinationOffset) = colorE0;
destinationSpan[destinationOffset + 1] = colorE1; Unsafe.Add(ref destinationPointer, destinationOffset + 1) = colorE1;
destinationSpan[destinationOffset + 2] = colorE2; Unsafe.Add(ref destinationPointer, destinationOffset + 2) = colorE2;
destinationOffset += destinationWidth; destinationOffset += destinationWidth;
destinationSpan[destinationOffset] = colorE3; Unsafe.Add(ref destinationPointer, destinationOffset) = colorE3;
destinationSpan[destinationOffset + 1] = colorE4; Unsafe.Add(ref destinationPointer, destinationOffset + 1) = colorE4;
destinationSpan[destinationOffset + 2] = colorE5; Unsafe.Add(ref destinationPointer, destinationOffset + 2) = colorE5;
destinationOffset += destinationWidth; destinationOffset += destinationWidth;
destinationSpan[destinationOffset] = colorE6; Unsafe.Add(ref destinationPointer, destinationOffset) = colorE6;
destinationSpan[destinationOffset + 1] = colorE7; Unsafe.Add(ref destinationPointer, destinationOffset + 1) = colorE7;
destinationSpan[destinationOffset + 2] = colorE8; Unsafe.Add(ref destinationPointer, destinationOffset + 2) = colorE8;
}
} }
} }

View file

@ -21,8 +21,7 @@ namespace Greenshot.PerformanceTests
{ {
_unmanagedTestBitmap = new UnmanagedBitmap<Bgr32>(400, 400); _unmanagedTestBitmap = new UnmanagedBitmap<Bgr32>(400, 400);
_unmanagedTestBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0}); _unmanagedTestBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0});
using (var bitmap = _unmanagedTestBitmap.NativeBitmap) using (var graphics = Graphics.FromImage(_unmanagedTestBitmap.NativeBitmap))
using (var graphics = Graphics.FromImage(bitmap))
using (var pen = new SolidBrush(Color.Blue)) using (var pen = new SolidBrush(Color.Blue))
{ {
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340)); graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
@ -57,7 +56,7 @@ namespace Greenshot.PerformanceTests
} }
} }
//[Benchmark] [Benchmark]
public void Blur_FastBitmap() public void Blur_FastBitmap()
{ {
using (var bitmap = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White)) using (var bitmap = BitmapFactory.CreateEmpty(400, 400, PixelFormat.Format32bppRgb, Color.White))
@ -71,14 +70,13 @@ namespace Greenshot.PerformanceTests
} }
} }
//[Benchmark] [Benchmark]
public void Blur_UnmanagedBitmap() public void Blur_UnmanagedBitmap()
{ {
using (var unmanagedBitmap = new UnmanagedBitmap<Bgr32>(400, 400)) using (var unmanagedBitmap = new UnmanagedBitmap<Bgr32>(400, 400))
{ {
unmanagedBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 }); unmanagedBitmap.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 });
using (var bitmap = unmanagedBitmap.NativeBitmap) using (var graphics = Graphics.FromImage(unmanagedBitmap.NativeBitmap))
using (var graphics = Graphics.FromImage(bitmap))
using (var pen = new SolidBrush(Color.Blue)) using (var pen = new SolidBrush(Color.Blue))
{ {
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340)); graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
@ -89,7 +87,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))
@ -121,19 +119,19 @@ namespace Greenshot.PerformanceTests
_unmanagedTestBitmap.Scale2XReference().Dispose(); _unmanagedTestBitmap.Scale2XReference().Dispose();
} }
[Benchmark] //[Benchmark]
public void Scale3x_FastBitmap() public void Scale3x_FastBitmap()
{ {
ScaleX.Scale3X(_unmanagedTestBitmap).Dispose(); ScaleX.Scale3X(_unmanagedTestBitmap).Dispose();
} }
[Benchmark] //[Benchmark]
public void Scale3x_Unmanaged() public void Scale3x_Unmanaged()
{ {
_unmanagedTestBitmap.Scale3X().Dispose(); _unmanagedTestBitmap.Scale3X().Dispose();
} }
[Benchmark] //[Benchmark]
public void Scale3x_Unmanaged_Reference() public void Scale3x_Unmanaged_Reference()
{ {
_unmanagedTestBitmap.Scale3XReference().Dispose(); _unmanagedTestBitmap.Scale3XReference().Dispose();

View file

@ -30,8 +30,8 @@ namespace Greenshot.PerformanceTests
// ReSharper disable once UnusedParameter.Local // ReSharper disable once UnusedParameter.Local
private static void Main(string[] args) private static void Main(string[] args)
{ {
//BenchmarkRunner.Run<GfxPerformance>(); BenchmarkRunner.Run<GfxPerformance>();
BenchmarkRunner.Run<CapturePerformance>(); //BenchmarkRunner.Run<CapturePerformance>();
Console.ReadLine(); Console.ReadLine();
} }
} }

View file

@ -70,19 +70,18 @@ namespace Greenshot.Tests
using (var pen = new SolidBrush(Color.Blue)) using (var pen = new SolidBrush(Color.Blue))
{ {
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340)); graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
BoxBlurOld.ApplyOldBoxBlur(bitmapOld, 10);
} }
BoxBlurOld.ApplyOldBoxBlur(bitmapOld, 10);
bitmapOld.NativeBitmap.Save(@"old.png", ImageFormat.Png); bitmapOld.NativeBitmap.Save(@"old.png", ImageFormat.Png);
bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 }); bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255 });
using (var bitmap = bitmapNew.NativeBitmap) using (var graphics = Graphics.FromImage(bitmapNew.NativeBitmap))
using (var graphics = Graphics.FromImage(bitmap))
using (var pen = new SolidBrush(Color.Blue)) using (var pen = new SolidBrush(Color.Blue))
{ {
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340)); graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
bitmapNew.ApplyBoxBlur(10);
bitmap.Save(@"new.png", ImageFormat.Png);
} }
bitmapNew.ApplyBoxBlur(10);
bitmapNew.NativeBitmap.Save(@"new.png", ImageFormat.Png);
Assert.True(bitmapOld.IsEqualTo(bitmapNew), "New blur doesn't compare to old."); Assert.True(bitmapOld.IsEqualTo(bitmapNew), "New blur doesn't compare to old.");
} }

View file

@ -50,8 +50,7 @@ namespace Greenshot.Tests
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340)); graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
} }
bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0 }); bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0 });
using (var bitmap = bitmapNew.NativeBitmap) using (var graphics = Graphics.FromImage(bitmapNew.NativeBitmap))
using (var graphics = Graphics.FromImage(bitmap))
using (var pen = new SolidBrush(Color.Blue)) using (var pen = new SolidBrush(Color.Blue))
{ {
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340)); graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
@ -78,13 +77,12 @@ namespace Greenshot.Tests
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340)); graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
} }
bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0 }); bitmapNew.Span.Fill(new Bgr32 { B = 255, G = 255, R = 255, Unused = 0 });
using (var bitmap = bitmapNew.NativeBitmap) using (var graphics = Graphics.FromImage(bitmapNew.NativeBitmap))
using (var graphics = Graphics.FromImage(bitmap))
using (var pen = new SolidBrush(Color.Blue)) using (var pen = new SolidBrush(Color.Blue))
{ {
graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340)); graphics.FillRectangle(pen, new Rectangle(30, 30, 340, 340));
using (var scaledUnmanagedBitmap = bitmapNew.Scale3X()) using (var scaledUnmanagedBitmap = bitmapNew.Scale3X())
using (var scaledBitmap = ScaleX.Scale2X(bitmapOld)) using (var scaledBitmap = ScaleX.Scale3X(bitmapOld))
{ {
scaledUnmanagedBitmap.NativeBitmap.Save(@"new3x.png", ImageFormat.Png); scaledUnmanagedBitmap.NativeBitmap.Save(@"new3x.png", ImageFormat.Png);
scaledBitmap.NativeBitmap.Save(@"old3x.png", ImageFormat.Png); scaledBitmap.NativeBitmap.Save(@"old3x.png", ImageFormat.Png);