From 02ac45971b4a56e34772758aecaa4407dbcae3f1 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 5 Dec 2020 21:20:10 +0100 Subject: [PATCH] add benchmark results and fix PixelOperations --- .../PixelOperations/Rgb24.PixelOperations.cs | 1 + .../PixelOperations/Rgba32.PixelOperations.cs | 1 + .../PixelFormats/PixelOperations{TPixel}.cs | 23 +++++++++++++++---- .../PixelConversion_PackFromRgbPlanes.cs | 14 +++++++++++ .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 4 ++-- 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs index ebed7aadd..f345f58bc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs @@ -30,6 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats ReadOnlySpan blueChannel, Span destination) { + Guard.NotNull(configuration, nameof(configuration)); int count = redChannel.Length; Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!"); Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!"); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs index 0ddc2f8b1..963305977 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs @@ -65,6 +65,7 @@ namespace SixLabors.ImageSharp.PixelFormats ReadOnlySpan blueChannel, Span destination) { + Guard.NotNull(configuration, nameof(configuration)); int count = redChannel.Length; Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!"); Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!"); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 57e5e8582..c5450538e 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -4,6 +4,8 @@ using System; using System.Buffers; using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; @@ -177,13 +179,26 @@ namespace SixLabors.ImageSharp.PixelFormats Span destination) { Guard.NotNull(configuration, nameof(configuration)); + + int count = redChannel.Length; + Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!"); + Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!"); + Guard.IsTrue(destination.Length > count + 2, nameof(destination), "'destination' must contain a padding of 3 elements!"); + Guard.DestinationShouldNotBeTooShort(redChannel, destination, nameof(destination)); - for (int i = 0; i < destination.Length; i++) - { - var rgb24 = new Rgb24(redChannel[i], greenChannel[i], blueChannel[i]); + Rgb24 rgb24 = default; + ref byte r = ref MemoryMarshal.GetReference(redChannel); + ref byte g = ref MemoryMarshal.GetReference(greenChannel); + ref byte b = ref MemoryMarshal.GetReference(blueChannel); + ref TPixel d = ref MemoryMarshal.GetReference(destination); - destination[i].FromRgb24(rgb24); + for (int i = 0; i < count; i++) + { + rgb24.R = Unsafe.Add(ref r, i); + rgb24.G = Unsafe.Add(ref g, i); + rgb24.B = Unsafe.Add(ref b, i); + Unsafe.Add(ref d, i).FromRgb24(rgb24); } } } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_PackFromRgbPlanes.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_PackFromRgbPlanes.cs index 11714027a..6b2ff90f7 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_PackFromRgbPlanes.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_PackFromRgbPlanes.cs @@ -268,5 +268,19 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion public byte V0, V1, V2, V3; } #pragma warning restore + + // Results @ Anton's PC, 2020 Dec 05 + // .NET Core 3.1.1 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // + // | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | + // |--------------------------------- |------ |-----------:|---------:|---------:|------:|--------:| + // | Rgb24_Scalar_PerElement_Span | 1024 | 1,634.6 ns | 26.56 ns | 24.84 ns | 3.12 | 0.05 | + // | Rgb24_Scalar_PerElement_Unsafe | 1024 | 1,284.7 ns | 4.70 ns | 4.16 ns | 2.46 | 0.01 | + // | Rgb24_Scalar_PerElement_Batched8 | 1024 | 1,182.3 ns | 5.12 ns | 4.27 ns | 2.26 | 0.01 | + // | Rgb24_Scalar_PerElement_Batched4 | 1024 | 1,146.2 ns | 16.38 ns | 14.52 ns | 2.19 | 0.02 | + // | Rgba32_Avx2_Float | 1024 | 522.7 ns | 1.78 ns | 1.39 ns | 1.00 | 0.00 | + // | Rgba24_Avx2_Bytes | 1024 | 243.3 ns | 1.56 ns | 1.30 ns | 0.47 | 0.00 | + // | Rgba32_Avx2_Bytes | 1024 | 146.0 ns | 2.48 ns | 2.32 ns | 0.28 | 0.01 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 565ea5f6d..0ee43d74b 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -443,10 +443,10 @@ namespace SixLabors.ImageSharp.Tests.Common expected[i].FromRgb24(new Rgb24(r[i], g[i], b[i])); } - TPixel[] actual = new TPixel[count]; + TPixel[] actual = new TPixel[count + 3]; // padding for Rgb24 AVX2 packMethod(r, g, b, actual); - Assert.Equal(expected, actual); + Assert.True(expected.AsSpan().SequenceEqual(actual.AsSpan().Slice(0, count))); } private static void TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(