diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs
index e832bc97f..c49f3f834 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs
@@ -44,13 +44,13 @@ namespace SixLabors.ImageSharp.PixelFormats
///
internal override void FromVector4(Configuration configuration, Span sourceVectors, Span destPixels, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
+ Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, modifiers.Remove(PixelConversionModifiers.Scale));
}
///
internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
+ Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale));
}
///
internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels)
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs
index f1885c71b..a9eca8994 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs
@@ -44,13 +44,13 @@ namespace SixLabors.ImageSharp.PixelFormats
///
internal override void FromVector4(Configuration configuration, Span sourceVectors, Span destPixels, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
+ Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, modifiers.Remove(PixelConversionModifiers.Scale));
}
///
internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
+ Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale));
}
///
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs
index 2409f6784..73eddc235 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs
@@ -44,13 +44,13 @@ namespace SixLabors.ImageSharp.PixelFormats
///
internal override void FromVector4(Configuration configuration, Span sourceVectors, Span destPixels, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
+ Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, modifiers.Remove(PixelConversionModifiers.Scale));
}
///
internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
+ Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale));
}
///
internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels)
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs
index ddf9813ab..1648f5341 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs
@@ -44,13 +44,13 @@ namespace SixLabors.ImageSharp.PixelFormats
///
internal override void FromVector4(Configuration configuration, Span sourceVectors, Span destPixels, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
+ Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, modifiers.Remove(PixelConversionModifiers.Scale));
}
///
internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
+ Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale));
}
///
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude
index 0ff5b8605..6286eaf72 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude
@@ -113,13 +113,13 @@ using System.Runtime.InteropServices;
///
internal override void FromVector4(Configuration configuration, Span sourceVectors, Span<<#=pixelType#>> destPixels, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
+ Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, modifiers.Remove(PixelConversionModifiers.Scale));
}
///
internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors, PixelConversionModifiers modifiers)
{
- Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
+ Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale));
}
<#+
}
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs
index 7e8bb7f29..aa9b82be7 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs
@@ -4,6 +4,8 @@
using System;
using System.Numerics;
using System.Runtime.InteropServices;
+
+using SixLabors.ImageSharp.PixelFormats.Utils;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.PixelFormats
@@ -28,10 +30,10 @@ namespace SixLabors.ImageSharp.PixelFormats
Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors));
destVectors = destVectors.Slice(0, sourcePixels.Length);
-
SimdUtils.BulkConvertByteToNormalizedFloat(
MemoryMarshal.Cast(sourcePixels),
MemoryMarshal.Cast(destVectors));
+ Vector4Converters.ApplyForwardConversionModifiers(destVectors, modifiers);
}
///
@@ -44,7 +46,7 @@ namespace SixLabors.ImageSharp.PixelFormats
Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels));
destPixels = destPixels.Slice(0, sourceVectors.Length);
-
+ Vector4Converters.ApplyBackwardConversionModifiers(sourceVectors, modifiers);
SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(
MemoryMarshal.Cast(sourceVectors),
MemoryMarshal.Cast(destPixels));
diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs
index 777d0da6d..3c4d951ee 100644
--- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs
+++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs
@@ -5,6 +5,8 @@ using System;
using System.Numerics;
using System.Runtime.InteropServices;
+using SixLabors.ImageSharp.PixelFormats.Utils;
+
namespace SixLabors.ImageSharp.PixelFormats
{
///
@@ -26,6 +28,8 @@ namespace SixLabors.ImageSharp.PixelFormats
{
Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors));
+ Vector4Converters.ApplyBackwardConversionModifiers(sourceVectors, modifiers);
+
// TODO: Repeating previous override behavior here. Not sure if this is correct!
if (modifiers.IsDefined(PixelConversionModifiers.Scale))
{
@@ -55,6 +59,8 @@ namespace SixLabors.ImageSharp.PixelFormats
{
MemoryMarshal.Cast(sourcePixels).CopyTo(destVectors);
}
+
+ Vector4Converters.ApplyForwardConversionModifiers(destVectors, modifiers);
}
}
}
diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
index ea5bc876f..53181e7a9 100644
--- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
+++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
@@ -37,16 +37,8 @@ namespace SixLabors.ImageSharp.PixelFormats
PixelConversionModifiers modifiers)
{
Guard.NotNull(configuration, nameof(configuration));
- Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels));
- if (modifiers.IsDefined(PixelConversionModifiers.Scale))
- {
- Utils.Vector4Converters.Default.DangerousFromScaledVector4(sourceVectors, destPixels);
- }
- else
- {
- Utils.Vector4Converters.Default.DangerousFromVector4(sourceVectors, destPixels);
- }
+ Utils.Vector4Converters.Default.FromVector4(sourceVectors, destPixels, modifiers);
}
///
@@ -82,16 +74,8 @@ namespace SixLabors.ImageSharp.PixelFormats
PixelConversionModifiers modifiers)
{
Guard.NotNull(configuration, nameof(configuration));
- Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors));
- if (modifiers.IsDefined(PixelConversionModifiers.Scale))
- {
- Utils.Vector4Converters.Default.DangerousToScaledVector4(sourcePixels, destVectors);
- }
- else
- {
- Utils.Vector4Converters.Default.DangerousToVector4(sourcePixels, destVectors);
- }
+ Utils.Vector4Converters.Default.ToVector4(sourcePixels, destVectors, modifiers);
}
///
diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs
index e784e3b5a..4c4e60276 100644
--- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs
+++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs
@@ -6,6 +6,8 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using SixLabors.ImageSharp.ColorSpaces.Companding;
+
namespace SixLabors.ImageSharp.PixelFormats.Utils
{
///
@@ -15,13 +17,75 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
{
///
/// Provides default implementations for batched to/from conversion.
- /// WARNING: The methods are operating without bounds checking and input validation!
+ /// WARNING: The methods prefixed with "Unsafe" are operating without bounds checking and input validation!
/// Input validation is the responsibility of the caller!
///
public static class Default
{
[MethodImpl(InliningOptions.ShortMethod)]
- internal static void DangerousFromVector4(
+ public static void FromVector4(
+ Span sourceVectors,
+ Span destPixels,
+ PixelConversionModifiers modifiers)
+ where TPixel : struct, IPixel
+ {
+ Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels));
+
+ UnsafeFromVector4(sourceVectors, destPixels, modifiers);
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static void ToVector4(
+ ReadOnlySpan sourcePixels,
+ Span destVectors,
+ PixelConversionModifiers modifiers)
+ where TPixel : struct, IPixel
+ {
+ Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors));
+
+ UnsafeToVector4(sourcePixels, destVectors, modifiers);
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static void UnsafeFromVector4(
+ Span sourceVectors,
+ Span destPixels,
+ PixelConversionModifiers modifiers)
+ where TPixel : struct, IPixel
+ {
+ ApplyBackwardConversionModifiers(sourceVectors, modifiers);
+
+ if (modifiers.IsDefined(PixelConversionModifiers.Scale))
+ {
+ UnsafeFromScaledVector4Core(sourceVectors, destPixels);
+ }
+ else
+ {
+ UnsafeFromVector4Core(sourceVectors, destPixels);
+ }
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static void UnsafeToVector4(
+ ReadOnlySpan sourcePixels,
+ Span destVectors,
+ PixelConversionModifiers modifiers)
+ where TPixel : struct, IPixel
+ {
+ if (modifiers.IsDefined(PixelConversionModifiers.Scale))
+ {
+ UnsafeToScaledVector4Core(sourcePixels, destVectors);
+ }
+ else
+ {
+ UnsafeToVector4Core(sourcePixels, destVectors);
+ }
+
+ ApplyForwardConversionModifiers(destVectors, modifiers);
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ private static void UnsafeFromVector4Core(
ReadOnlySpan sourceVectors,
Span destPixels)
where TPixel : struct, IPixel
@@ -38,7 +102,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
}
[MethodImpl(InliningOptions.ShortMethod)]
- internal static void DangerousToVector4(
+ private static void UnsafeToVector4Core(
ReadOnlySpan sourcePixels,
Span destVectors)
where TPixel : struct, IPixel
@@ -55,7 +119,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
}
[MethodImpl(InliningOptions.ShortMethod)]
- internal static void DangerousFromScaledVector4(
+ private static void UnsafeFromScaledVector4Core(
ReadOnlySpan sourceVectors,
Span destinationColors)
where TPixel : struct, IPixel
@@ -72,7 +136,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
}
[MethodImpl(InliningOptions.ShortMethod)]
- internal static void DangerousToScaledVector4(
+ private static void UnsafeToScaledVector4Core(
ReadOnlySpan sourceColors,
Span destinationVectors)
where TPixel : struct, IPixel
diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs
index 006ebe828..efe4dc69a 100644
--- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs
+++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs
@@ -7,6 +7,8 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using SixLabors.ImageSharp.ColorSpaces.Companding;
+
namespace SixLabors.ImageSharp.PixelFormats.Utils
{
///
@@ -41,7 +43,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
PixelOperations pixelOperations,
ReadOnlySpan sourcePixels,
Span destVectors,
- bool scaled)
+ PixelConversionModifiers modifiers)
where TPixel : struct, IPixel
{
Guard.NotNull(configuration, nameof(configuration));
@@ -52,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
// Not worth for small buffers:
if (count < Vector4ConversionThreshold)
{
- ToVector4Fallback(sourcePixels, destVectors, scaled);
+ Default.UnsafeToVector4(sourcePixels, destVectors, modifiers);
return;
}
@@ -70,6 +72,9 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem)));
destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4();
+
+ // TODO: Investigate optimized 1-pass approach!
+ ApplyForwardConversionModifiers(destVectors, modifiers);
}
///
@@ -83,9 +88,9 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
internal static void FromVector4(
Configuration configuration,
PixelOperations pixelOperations,
- ReadOnlySpan sourceVectors,
+ Span sourceVectors,
Span destPixels,
- bool scaled)
+ PixelConversionModifiers modifiers)
where TPixel : struct, IPixel
{
Guard.NotNull(configuration, nameof(configuration));
@@ -96,11 +101,14 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
// Not worth for small buffers:
if (count < Vector4ConversionThreshold)
{
- FromVector4Fallback(sourceVectors, destPixels, scaled);
+ Default.UnsafeFromVector4(sourceVectors, destPixels, modifiers);
return;
}
+ // TODO: Investigate optimized 1-pass approach!
+ ApplyBackwardConversionModifiers(sourceVectors, modifiers);
+
// For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion,
// so let's allocate a temporary buffer as usually:
using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count))
@@ -115,34 +123,6 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
}
}
- [MethodImpl(InliningOptions.ColdPath)]
- private static void ToVector4Fallback(ReadOnlySpan sourcePixels, Span destVectors, bool scaled)
- where TPixel : struct, IPixel
- {
- if (scaled)
- {
- Default.DangerousToScaledVector4(sourcePixels, destVectors);
- }
- else
- {
- Default.DangerousToVector4(sourcePixels, destVectors);
- }
- }
-
- [MethodImpl(InliningOptions.ColdPath)]
- private static void FromVector4Fallback(ReadOnlySpan sourceVectors, Span destPixels, bool scaled)
- where TPixel : struct, IPixel
- {
- if (scaled)
- {
- Default.DangerousFromScaledVector4(sourceVectors, destPixels);
- }
- else
- {
- Default.DangerousFromVector4(sourceVectors, destPixels);
- }
- }
-
private static int CalculateVector4ConversionThreshold()
{
if (!Vector.IsHardwareAccelerated)
diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs
new file mode 100644
index 000000000..447869a7d
--- /dev/null
+++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+using SixLabors.ImageSharp.ColorSpaces.Companding;
+
+namespace SixLabors.ImageSharp.PixelFormats.Utils
+{
+ internal static partial class Vector4Converters
+ {
+ ///
+ /// Apply modifiers used requested by ToVector4() conversion.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void ApplyForwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers)
+ {
+ if (modifiers.IsDefined(PixelConversionModifiers.SRgbCompand))
+ {
+ SRgbCompanding.Expand(vectors);
+ }
+
+ if (modifiers.IsDefined(PixelConversionModifiers.Premultiply))
+ {
+ Vector4Utils.Premultiply(vectors);
+ }
+ }
+
+ ///
+ /// Apply modifiers used requested by FromVector4() conversion.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void ApplyBackwardConversionModifiers(Span vectors, PixelConversionModifiers modifiers)
+ {
+ if (modifiers.IsDefined(PixelConversionModifiers.Premultiply))
+ {
+ Vector4Utils.UnPremultiply(vectors);
+ }
+
+ if (modifiers.IsDefined(PixelConversionModifiers.SRgbCompand))
+ {
+ SRgbCompanding.Compress(vectors);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs
index 9433e19c9..f51c79034 100644
--- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs
+++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs
@@ -148,7 +148,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
TestOperation(
source,
expected,
- (s, d) => Operations.FromVector4(this.Configuration, s, d.GetSpan(), PixelConversionModifiers.SRgbCompand | PixelConversionModifiers.Scale)
+ (s, d) => Operations.FromVector4(
+ this.Configuration,
+ s,
+ d.GetSpan(),
+ PixelConversionModifiers.SRgbCompand | PixelConversionModifiers.Scale)
);
}
@@ -230,7 +234,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
this.Configuration,
s,
d.GetSpan(),
- PixelConversionModifiers.SRgbCompand | PixelConversionModifiers.Premultiply)
+ PixelConversionModifiers.SRgbCompand | PixelConversionModifiers.Premultiply | PixelConversionModifiers.Scale)
);
}