Skip to content

Commit

Permalink
Initial work on using Span<T> instead of pointers.
Browse files Browse the repository at this point in the history
This eliminates some larger unsafe blocks and seems to also have minor performance improvements. The RadialBlurEffect benchmark went from 5,923.8ms to 5,757.7ms

Switched the benchmark setup to use BenchmarkSwitcher, which allows filtering which benchmarks are run from the command line
  • Loading branch information
cameronwhite committed Dec 27, 2022
1 parent ca2df64 commit 52674d3
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 31 deletions.
14 changes: 14 additions & 0 deletions Pinta.Core/Extensions/CairoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2068,5 +2068,19 @@ public static void SetDashFromString (this Context context, string dash_pattern,
CreateDashPattern (dash_pattern, brush_width, line_cap, out var dashes, out var offset);
context.SetDash (dashes, offset);
}

public static ReadOnlySpan<ColorBgra> GetReadOnlyData (this ImageSurface surface)
{
unsafe {
return new ReadOnlySpan<ColorBgra> (surface.DataPtr.ToPointer (), surface.Width * surface.Height);
}
}

public static Span<ColorBgra> GetData (this ImageSurface surface)
{
unsafe {
return new Span<ColorBgra> (surface.DataPtr.ToPointer (), surface.Width * surface.Height);
}
}
}
}
52 changes: 27 additions & 25 deletions Pinta.Effects/Effects/RadialBlurEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
/////////////////////////////////////////////////////////////////////////////////

using System;
using System.Runtime.InteropServices;
using Cairo;
using Pinta.Core;
using Pinta.Gui.Widgets;
Expand Down Expand Up @@ -56,7 +57,7 @@ private static void Rotate (ref int fx, ref int fy, int fr)
fy = cy + ((cx >> 8) * fr >> 8) - ((cy >> 14) * (fr * fr >> 11) >> 8);
}

public unsafe override void Render (ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois)
public override void Render (ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois)
{
if (Data.Angle == 0) {
// Copy src to dest
Expand All @@ -65,19 +66,26 @@ public unsafe override void Render (ImageSurface src, ImageSurface dst, Gdk.Rect

int w = dst.Width;
int h = dst.Height;
int src_w = src.Width;
int fcx = (w << 15) + (int) (Data.Offset.X * (w << 15));
int fcy = (h << 15) + (int) (Data.Offset.Y * (h << 15));

int n = (Data.Quality * Data.Quality) * (30 + Data.Quality * Data.Quality);

int fr = (int) (Data.Angle * Math.PI * 65536.0 / 181.0);

var dst_data = dst.GetData ();
var src_data = src.GetReadOnlyData ();

foreach (Gdk.Rectangle rect in rois) {
for (int y = rect.Top; y <= rect.GetBottom (); ++y) {
ColorBgra* dstPtr = dst.GetPointAddressUnchecked (rect.Left, y);
ColorBgra* srcPtr = src.GetPointAddressUnchecked (rect.Left, y);
var dst_row = dst_data.Slice (y * w, w);
var src_row = src_data.Slice (y * src_w, src_w);

for (int x = rect.Left; x <= rect.GetRight (); ++x) {
ref ColorBgra dst_pixel = ref dst_row[x];
ref readonly ColorBgra src_pixel = ref src_row[x];

int fx = (x << 16) - fcx;
int fy = (y << 16) - fcy;

Expand All @@ -89,20 +97,17 @@ public unsafe override void Render (ImageSurface src, ImageSurface dst, Gdk.Rect
int sa = 0;
int sc = 0;

sr += srcPtr->R * srcPtr->A;
sg += srcPtr->G * srcPtr->A;
sb += srcPtr->B * srcPtr->A;
sa += srcPtr->A;
sr += src_pixel.R * src_pixel.A;
sg += src_pixel.G * src_pixel.A;
sb += src_pixel.B * src_pixel.A;
sa += src_pixel.A;
++sc;

int ox1 = fx;
int ox2 = fx;
int oy1 = fy;
int oy2 = fy;

ColorBgra* src_dataptr = (ColorBgra*) src.DataPtr;
int src_width = src.Width;

for (int i = 0; i < n; ++i) {
Rotate (ref ox1, ref oy1, fsr);
Rotate (ref ox2, ref oy2, -fsr);
Expand All @@ -111,41 +116,38 @@ public unsafe override void Render (ImageSurface src, ImageSurface dst, Gdk.Rect
int v1 = oy1 + fcy + 32768 >> 16;

if (u1 > 0 && v1 > 0 && u1 < w && v1 < h) {
ColorBgra* sample = src.GetPointAddressUnchecked (src_dataptr, src_width, u1, v1);
ref readonly ColorBgra sample = ref src_data[v1 * src_w + u1];

sr += sample->R * sample->A;
sg += sample->G * sample->A;
sb += sample->B * sample->A;
sa += sample->A;
sr += sample.R * sample.A;
sg += sample.G * sample.A;
sb += sample.B * sample.A;
sa += sample.A;
++sc;
}

int u2 = ox2 + fcx + 32768 >> 16;
int v2 = oy2 + fcy + 32768 >> 16;

if (u2 > 0 && v2 > 0 && u2 < w && v2 < h) {
ColorBgra* sample = src.GetPointAddressUnchecked (src_dataptr, src_width, u2, v2);
ref readonly ColorBgra sample = ref src_data[v2 * src_w + u2];

sr += sample->R * sample->A;
sg += sample->G * sample->A;
sb += sample->B * sample->A;
sa += sample->A;
sr += sample.R * sample.A;
sg += sample.G * sample.A;
sb += sample.B * sample.A;
sa += sample.A;
++sc;
}
}

if (sa > 0) {
*dstPtr = ColorBgra.FromBgra (
dst_pixel = ColorBgra.FromBgra (
Utility.ClampToByte (sb / sa),
Utility.ClampToByte (sg / sa),
Utility.ClampToByte (sr / sa),
Utility.ClampToByte (sa / sc));
} else {
dstPtr->Bgra = 0;
dst_pixel.Bgra = 0;
}

++dstPtr;
++srcPtr;
}
}
}
Expand Down
7 changes: 3 additions & 4 deletions Pinta.Tools/Tools/PaintBucketTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected override void OnMouseDown (Document document, ToolMouseEventArgs e)
base.OnMouseDown (document, e);
}

protected unsafe override void OnFillRegionComputed (Document document, BitMask stencil)
protected override void OnFillRegionComputed (Document document, BitMask stencil)
{
var surf = document.Layers.ToolLayer.Surface;

Expand All @@ -73,18 +73,17 @@ protected unsafe override void OnFillRegionComputed (Document document, BitMask
hist.TakeSnapshotOfLayer (document.Layers.CurrentUserLayer);

var color = fill_color.ToColorBgra ().ToPremultipliedAlpha ();
var dstPtr = (ColorBgra*) surf.DataPtr;
var width = surf.Width;

surf.Flush ();

// Color in any pixel that the stencil says we need to fill
Parallel.For (0, stencil.Height, y => {
var stencil_width = stencil.Width;
var dst_data = surf.GetData ();

for (var x = 0; x < stencil_width; ++x) {
if (stencil.Get (x, y))
surf.SetColorBgraUnchecked (dstPtr, width, color, x, y);
dst_data[y * width + x] = color;
}
});

Expand Down
4 changes: 2 additions & 2 deletions tests/PintaBenchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ namespace PintaBenchmarks;

public class Program
{
public static void Main ()
public static void Main (string[] args)
{
// Run all benchmarks
BenchmarkRunner.Run (typeof (Program).Assembly);
BenchmarkSwitcher.FromAssembly (typeof (Program).Assembly).Run (args);

// Run individual benchmark suites
//BenchmarkRunner.Run<CanvasRendererBenchmarks> ();
Expand Down

0 comments on commit 52674d3

Please sign in to comment.