mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
26 changed files with 419 additions and 348 deletions
@ -0,0 +1,42 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
#if NET6_0
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
|||
namespace System.Diagnostics.CodeAnalysis |
|||
{ |
|||
/// <summary>
|
|||
/// Used to indicate a byref escapes and is not scoped.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// There are several cases where the C# compiler treats a <see langword="ref"/> as implicitly
|
|||
/// <see langword="scoped"/> - where the compiler does not allow the <see langword="ref"/> to escape the method.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// For example:
|
|||
/// <list type="number">
|
|||
/// <item><see langword="this"/> for <see langword="struct"/> instance methods.</item>
|
|||
/// <item><see langword="ref"/> parameters that refer to <see langword="ref"/> <see langword="struct"/> types.</item>
|
|||
/// <item><see langword="out"/> parameters.</item>
|
|||
/// </list>
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// This attribute is used in those instances where the <see langword="ref"/> should be allowed to escape.
|
|||
/// </para>
|
|||
/// <para>
|
|||
/// Applying this attribute, in any form, has impact on consumers of the applicable API. It is necessary for
|
|||
/// API authors to understand the lifetime implications of applying this attribute and how it may impact their users.
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
[global::System.AttributeUsage( |
|||
global::System.AttributeTargets.Method | |
|||
global::System.AttributeTargets.Property | |
|||
global::System.AttributeTargets.Parameter, |
|||
AllowMultiple = false, |
|||
Inherited = false)] |
|||
internal sealed class UnscopedRefAttribute : global::System.Attribute |
|||
{ |
|||
} |
|||
} |
|||
#endif
|
|||
@ -0,0 +1,208 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
#pragma warning disable SA1117 // Parameters should be on same line or separate lines
|
|||
using System.Diagnostics.CodeAnalysis; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp; |
|||
|
|||
/// <summary>
|
|||
/// A structure encapsulating a 5x4 matrix used for transforming the color and alpha components of an image.
|
|||
/// </summary>
|
|||
public partial struct ColorMatrix |
|||
{ |
|||
[UnscopedRef] |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal ref Impl AsImpl() => ref Unsafe.As<ColorMatrix, Impl>(ref this); |
|||
|
|||
[UnscopedRef] |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal readonly ref readonly Impl AsROImpl() => ref Unsafe.As<ColorMatrix, Impl>(ref Unsafe.AsRef(in this)); |
|||
|
|||
internal struct Impl : IEquatable<Impl> |
|||
{ |
|||
public Vector4 X; |
|||
public Vector4 Y; |
|||
public Vector4 Z; |
|||
public Vector4 W; |
|||
public Vector4 V; |
|||
|
|||
public static Impl Identity |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get |
|||
{ |
|||
Impl result; |
|||
|
|||
result.X = Vector4.UnitX; |
|||
result.Y = Vector4.UnitY; |
|||
result.Z = Vector4.UnitZ; |
|||
result.W = Vector4.UnitW; |
|||
result.V = Vector4.Zero; |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
|
|||
public readonly bool IsIdentity |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => |
|||
(this.X == Vector4.UnitX) |
|||
&& (this.Y == Vector4.UnitY) |
|||
&& (this.Z == Vector4.UnitZ) |
|||
&& (this.W == Vector4.UnitW) |
|||
&& (this.V == Vector4.Zero); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Impl operator +(in Impl left, in Impl right) |
|||
{ |
|||
Impl result; |
|||
|
|||
result.X = left.X + right.X; |
|||
result.Y = left.Y + right.Y; |
|||
result.Z = left.Z + right.Z; |
|||
result.W = left.W + right.W; |
|||
result.V = left.V + right.V; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Impl operator -(in Impl left, in Impl right) |
|||
{ |
|||
Impl result; |
|||
|
|||
result.X = left.X - right.X; |
|||
result.Y = left.Y - right.Y; |
|||
result.Z = left.Z - right.Z; |
|||
result.W = left.W - right.W; |
|||
result.V = left.V - right.V; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Impl operator -(in Impl value) |
|||
{ |
|||
Impl result; |
|||
|
|||
result.X = -value.X; |
|||
result.Y = -value.Y; |
|||
result.Z = -value.Z; |
|||
result.W = -value.W; |
|||
result.V = -value.V; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Impl operator *(in Impl left, in Impl right) |
|||
{ |
|||
Impl result; |
|||
|
|||
// result.X = Transform(left.X, in right);
|
|||
result.X = right.X * left.X.X; |
|||
result.X += right.Y * left.X.Y; |
|||
result.X += right.Z * left.X.Z; |
|||
result.X += right.W * left.X.W; |
|||
|
|||
// result.Y = Transform(left.Y, in right);
|
|||
result.Y = right.X * left.Y.X; |
|||
result.Y += right.Y * left.Y.Y; |
|||
result.Y += right.Z * left.Y.Z; |
|||
result.Y += right.W * left.Y.W; |
|||
|
|||
// result.Z = Transform(left.Z, in right);
|
|||
result.Z = right.X * left.Z.X; |
|||
result.Z += right.Y * left.Z.Y; |
|||
result.Z += right.Z * left.Z.Z; |
|||
result.Z += right.W * left.Z.W; |
|||
|
|||
// result.W = Transform(left.W, in right);
|
|||
result.W = right.X * left.W.X; |
|||
result.W += right.Y * left.W.Y; |
|||
result.W += right.Z * left.W.Z; |
|||
result.W += right.W * left.W.W; |
|||
|
|||
// result.V = Transform(left.V, in right);
|
|||
result.V = right.X * left.V.X; |
|||
result.V += right.Y * left.V.Y; |
|||
result.V += right.Z * left.V.Z; |
|||
result.V += right.W * left.V.W; |
|||
|
|||
result.V += right.V; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Impl operator *(in Impl left, float right) |
|||
{ |
|||
Impl result; |
|||
|
|||
result.X = left.X * right; |
|||
result.Y = left.Y * right; |
|||
result.Z = left.Z * right; |
|||
result.W = left.W * right; |
|||
result.V = left.V * right; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(in Impl left, in Impl right) => |
|||
(left.X == right.X) |
|||
&& (left.Y == right.Y) |
|||
&& (left.Z == right.Z) |
|||
&& (left.W == right.W) |
|||
&& (left.V == right.V); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(in Impl left, in Impl right) => |
|||
(left.X != right.X) |
|||
&& (left.Y != right.Y) |
|||
&& (left.Z != right.Z) |
|||
&& (left.W != right.W) |
|||
&& (left.V != right.V); |
|||
|
|||
[UnscopedRef] |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public ref ColorMatrix AsColorMatrix() => ref Unsafe.As<Impl, ColorMatrix>(ref this); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Init( |
|||
float m11, float m12, float m13, float m14, |
|||
float m21, float m22, float m23, float m24, |
|||
float m31, float m32, float m33, float m34, |
|||
float m41, float m42, float m43, float m44, |
|||
float m51, float m52, float m53, float m54) |
|||
{ |
|||
this.X = new Vector4(m11, m12, m13, m14); |
|||
this.Y = new Vector4(m21, m22, m23, m24); |
|||
this.Z = new Vector4(m31, m32, m33, m34); |
|||
this.W = new Vector4(m41, m42, m43, m44); |
|||
this.V = new Vector4(m51, m52, m53, m54); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override readonly bool Equals([NotNullWhen(true)] object? obj) |
|||
=> (obj is ColorMatrix other) && this.Equals(in other.AsImpl()); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public readonly bool Equals(in Impl other) => |
|||
this.X.Equals(other.X) |
|||
&& this.Y.Equals(other.Y) |
|||
&& this.Z.Equals(other.Z) |
|||
&& this.W.Equals(other.W) |
|||
&& this.V.Equals(other.V); |
|||
|
|||
bool IEquatable<Impl>.Equals(Impl other) => this.Equals(in other); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override readonly int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z, this.W, this.V); |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Numerics; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.Processing; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Bulk; |
|||
|
|||
public class ColorMatrixTransforms |
|||
{ |
|||
private static readonly Vector4[] Vectors = Vector4Factory.CreateVectors(); |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void Transform() |
|||
{ |
|||
ColorMatrix matrix = KnownFilterMatrices.CreateHueFilter(45F); |
|||
for (int i = 0; i < Vectors.Length; i++) |
|||
{ |
|||
ref Vector4 input = ref Vectors[i]; |
|||
ColorNumerics.Transform(ref input, ref matrix); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void Transform_Span() |
|||
{ |
|||
ColorMatrix matrix = KnownFilterMatrices.CreateHueFilter(45F); |
|||
ColorNumerics.Transform(Vectors.AsSpan(), ref matrix); |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Numerics; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Bulk; |
|||
|
|||
internal static class Vector4Factory |
|||
{ |
|||
public static Vector4[] CreateVectors(int length = 2048, int min = 0, int max = 1) |
|||
{ |
|||
Random rnd = new(42); |
|||
return GenerateRandomVectorArray(rnd, length, min, max); |
|||
} |
|||
|
|||
private static Vector4[] GenerateRandomVectorArray(Random rnd, int length, float minVal, float maxVal) |
|||
{ |
|||
Vector4[] values = new Vector4[length]; |
|||
|
|||
for (int i = 0; i < length; i++) |
|||
{ |
|||
ref Vector4 v = ref values[i]; |
|||
v.X = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Y = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Z = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.W = GetRandomFloat(rnd, minVal, maxVal); |
|||
} |
|||
|
|||
return values; |
|||
} |
|||
|
|||
private static float GetRandomFloat(Random rnd, float minVal, float maxVal) |
|||
=> (float)rnd.NextDouble() * (maxVal - minVal) + minVal; |
|||
} |
|||
Loading…
Reference in new issue