mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
22 changed files with 10256 additions and 727 deletions
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,68 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using System.Numerics; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using System.Runtime.Intrinsics; |
||||
|
using BenchmarkDotNet.Attributes; |
||||
|
using SixLabors.ImageSharp.PixelFormats.PixelBlenders; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Benchmarks.PixelBlenders; |
||||
|
|
||||
|
public class PorterDuffBulkVsSingleVector |
||||
|
{ |
||||
|
private Vector4[] backdrop; |
||||
|
private Vector4[] source; |
||||
|
|
||||
|
[GlobalSetup] |
||||
|
public void Setup() |
||||
|
{ |
||||
|
this.backdrop = new Vector4[8 * 20]; |
||||
|
this.source = new Vector4[8 * 20]; |
||||
|
|
||||
|
FillRandom(this.backdrop); |
||||
|
FillRandom(this.source); |
||||
|
} |
||||
|
|
||||
|
private static void FillRandom(Vector4[] arr) |
||||
|
{ |
||||
|
Random rng = new(); |
||||
|
for (int i = 0; i < arr.Length; i++) |
||||
|
{ |
||||
|
arr[i].X = rng.NextSingle(); |
||||
|
arr[i].Y = rng.NextSingle(); |
||||
|
arr[i].Z = rng.NextSingle(); |
||||
|
arr[i].W = rng.NextSingle(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Benchmark(Description = "Scalar", Baseline = true)] |
||||
|
public Vector4 OverlayValueFunction_Scalar() |
||||
|
{ |
||||
|
Vector4 result = default; |
||||
|
for (int i = 0; i < this.backdrop.Length; i++) |
||||
|
{ |
||||
|
result = PorterDuffFunctions.NormalSrcOver(this.backdrop[i], this.source[i], .5F); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
[Benchmark(Description = "Avx")] |
||||
|
public Vector256<float> OverlayValueFunction_Avx() |
||||
|
{ |
||||
|
ref Vector256<float> backdrop = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference<Vector4>(this.backdrop)); |
||||
|
ref Vector256<float> source = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference<Vector4>(this.source)); |
||||
|
|
||||
|
Vector256<float> result = default; |
||||
|
Vector256<float> opacity = Vector256.Create(.5F); |
||||
|
int count = this.backdrop.Length / 2; |
||||
|
for (int i = 0; i < count; i++) |
||||
|
{ |
||||
|
result = PorterDuffFunctions.NormalSrcOver(Unsafe.Add(ref backdrop, i), Unsafe.Add(ref source, i), opacity); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
@ -1,59 +1,66 @@ |
|||||
// Copyright (c) Six Labors.
|
// Copyright (c) Six Labors.
|
||||
// Licensed under the Six Labors Split License.
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders; |
|
||||
|
|
||||
using SixLabors.ImageSharp.PixelFormats; |
using SixLabors.ImageSharp.PixelFormats; |
||||
using SixLabors.ImageSharp.Processing; |
using SixLabors.ImageSharp.Processing; |
||||
|
using SixLabors.ImageSharp.Tests.TestUtilities; |
||||
|
|
||||
using Xunit; |
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders; |
||||
|
|
||||
public class PorterDuffCompositorTests |
public class PorterDuffCompositorTests |
||||
{ |
{ |
||||
// TODO: Add other modes to compare.
|
// TODO: Add other modes to compare.
|
||||
public static readonly TheoryData<PixelAlphaCompositionMode> CompositingOperators = |
public static readonly TheoryData<PixelAlphaCompositionMode> CompositingOperators = |
||||
new TheoryData<PixelAlphaCompositionMode> |
new() |
||||
{ |
{ |
||||
PixelAlphaCompositionMode.Src, |
PixelAlphaCompositionMode.Src, |
||||
PixelAlphaCompositionMode.SrcAtop, |
PixelAlphaCompositionMode.SrcAtop, |
||||
PixelAlphaCompositionMode.SrcOver, |
PixelAlphaCompositionMode.SrcOver, |
||||
PixelAlphaCompositionMode.SrcIn, |
PixelAlphaCompositionMode.SrcIn, |
||||
PixelAlphaCompositionMode.SrcOut, |
PixelAlphaCompositionMode.SrcOut, |
||||
PixelAlphaCompositionMode.Dest, |
PixelAlphaCompositionMode.Dest, |
||||
PixelAlphaCompositionMode.DestAtop, |
PixelAlphaCompositionMode.DestAtop, |
||||
PixelAlphaCompositionMode.DestOver, |
PixelAlphaCompositionMode.DestOver, |
||||
PixelAlphaCompositionMode.DestIn, |
PixelAlphaCompositionMode.DestIn, |
||||
PixelAlphaCompositionMode.DestOut, |
PixelAlphaCompositionMode.DestOut, |
||||
PixelAlphaCompositionMode.Clear, |
PixelAlphaCompositionMode.Clear, |
||||
PixelAlphaCompositionMode.Xor |
PixelAlphaCompositionMode.Xor |
||||
}; |
}; |
||||
|
|
||||
[Theory] |
[Theory] |
||||
[WithFile(TestImages.Png.PDDest, nameof(CompositingOperators), PixelTypes.Rgba32)] |
[WithFile(TestImages.Png.PDDest, nameof(CompositingOperators), PixelTypes.Rgba32)] |
||||
public void PorterDuffOutputIsCorrect(TestImageProvider<Rgba32> provider, PixelAlphaCompositionMode mode) |
public void PorterDuffOutputIsCorrect(TestImageProvider<Rgba32> provider, PixelAlphaCompositionMode mode) |
||||
{ |
{ |
||||
var srcFile = TestFile.Create(TestImages.Png.PDSrc); |
static void RunTest(string providerDump, string alphaMode) |
||||
using (Image<Rgba32> src = srcFile.CreateRgba32Image()) |
|
||||
using (Image<Rgba32> dest = provider.GetImage()) |
|
||||
{ |
{ |
||||
var options = new GraphicsOptions |
TestImageProvider<Rgba32> provider |
||||
|
= BasicSerializer.Deserialize<TestImageProvider<Rgba32>>(providerDump); |
||||
|
|
||||
|
TestFile srcFile = TestFile.Create(TestImages.Png.PDSrc); |
||||
|
using Image<Rgba32> src = srcFile.CreateRgba32Image(); |
||||
|
using Image<Rgba32> dest = provider.GetImage(); |
||||
|
GraphicsOptions options = new() |
||||
{ |
{ |
||||
Antialias = false, |
Antialias = false, |
||||
AlphaCompositionMode = mode |
AlphaCompositionMode = Enum.Parse<PixelAlphaCompositionMode>(alphaMode) |
||||
}; |
}; |
||||
|
|
||||
using (Image<Rgba32> res = dest.Clone(x => x.DrawImage(src, options))) |
using Image<Rgba32> res = dest.Clone(x => x.DrawImage(src, options)); |
||||
{ |
string combinedMode = alphaMode; |
||||
string combinedMode = mode.ToString(); |
|
||||
|
|
||||
if (combinedMode != "Src" && combinedMode.StartsWith("Src")) |
|
||||
{ |
|
||||
combinedMode = combinedMode.Substring(3); |
|
||||
} |
|
||||
|
|
||||
res.DebugSave(provider, combinedMode); |
if (combinedMode != "Src" && combinedMode.StartsWith("Src", StringComparison.OrdinalIgnoreCase)) |
||||
res.CompareToReferenceOutput(provider, combinedMode); |
{ |
||||
|
combinedMode = combinedMode[3..]; |
||||
} |
} |
||||
|
|
||||
|
res.DebugSave(provider, combinedMode); |
||||
|
res.CompareToReferenceOutput(provider, combinedMode); |
||||
} |
} |
||||
|
|
||||
|
FeatureTestRunner.RunWithHwIntrinsicsFeature( |
||||
|
RunTest, |
||||
|
HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX, |
||||
|
provider, |
||||
|
mode.ToString()); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,5 +1,6 @@ |
|||||
{ |
{ |
||||
"shadowCopy": false, |
"shadowCopy": false, |
||||
"methodDisplay": "method", |
"methodDisplay": "method", |
||||
"diagnosticMessages": true |
"diagnosticMessages": true, |
||||
|
"preEnumerateTheories": false |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue