From d5ec5a30bafbc5ded4a8b6b38c3f090183217b18 Mon Sep 17 00:00:00 2001 From: Jeffrey Parks Date: Mon, 1 Feb 2016 00:17:26 -0600 Subject: [PATCH] Optimized Vector usage in Color just a tiny bit Former-commit-id: 13b1f147f81828edb84e389013c2222835f17846 Former-commit-id: b443e7b10006da0643dc092c32ff2851318c73e7 Former-commit-id: 8a4bfcf1a98df71e61614e3ff1754d53bac7e2dc --- src/ImageProcessorCore/Colors/Color.cs | 62 ++++++++++++------- .../Colors/ColorTests.cs | 20 ++++++ 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/ImageProcessorCore/Colors/Color.cs b/src/ImageProcessorCore/Colors/Color.cs index 5b35205d9..f4b774e25 100644 --- a/src/ImageProcessorCore/Colors/Color.cs +++ b/src/ImageProcessorCore/Colors/Color.cs @@ -78,20 +78,26 @@ namespace ImageProcessorCore if (hex.Length == 8) { - float r = Convert.ToByte(hex.Substring(2, 2), 16) / 255f; - float g = Convert.ToByte(hex.Substring(4, 2), 16) / 255f; - float b = Convert.ToByte(hex.Substring(6, 2), 16) / 255f; - float a = Convert.ToByte(hex.Substring(0, 2), 16) / 255f; + float r = Convert.ToByte(hex.Substring(2, 2), 16); + float g = Convert.ToByte(hex.Substring(4, 2), 16); + float b = Convert.ToByte(hex.Substring(6, 2), 16); + float a = Convert.ToByte(hex.Substring(0, 2), 16); - this.backingVector = FromNonPremultiplied(new Color(r, g, b, a)).ToVector4(); + // Do division of Vector4 instead of each component to utilize SIMD optimizations + this.backingVector = new Vector4(r, g, b, a) / 255f; + + this.backingVector = FromNonPremultiplied(this.backingVector, this.A); } else if (hex.Length == 6) { - this.R = Convert.ToByte(hex.Substring(0, 2), 16) / 255f; - this.G = Convert.ToByte(hex.Substring(2, 2), 16) / 255f; - this.B = Convert.ToByte(hex.Substring(4, 2), 16) / 255f; - this.A = 1; + float r = Convert.ToByte(hex.Substring(0, 2), 16); + float g = Convert.ToByte(hex.Substring(2, 2), 16); + float b = Convert.ToByte(hex.Substring(4, 2), 16); + float a = 255f; + + // Do division of Vector4 instead of each component to utilize SIMD optimizations + this.backingVector = new Vector4(r, g, b, a) / 255f; } else { @@ -99,10 +105,12 @@ namespace ImageProcessorCore string gh = char.ToString(hex[1]); string bh = char.ToString(hex[2]); - this.B = Convert.ToByte(bh + bh, 16) / 255f; - this.G = Convert.ToByte(gh + gh, 16) / 255f; - this.R = Convert.ToByte(rh + rh, 16) / 255f; - this.A = 1; + float r = Convert.ToByte(rh + rh, 16); + float g = Convert.ToByte(gh + gh, 16); + float b = Convert.ToByte(bh + bh, 16); + float a = 255f; + + this.backingVector = new Vector4(r, g, b, a) / 255f; } } @@ -123,7 +131,7 @@ namespace ImageProcessorCore /// public Color(Vector3 vector) { - this.backingVector = new Vector4(vector.X, vector.Y, vector.Z, 1); + this.backingVector = new Vector4(vector, 1); } /// @@ -135,7 +143,7 @@ namespace ImageProcessorCore /// The alpha component. public Color(Vector3 vector, float alpha) { - this.backingVector = new Vector4(vector.X, vector.Y, vector.Z, alpha); + this.backingVector = new Vector4(vector, alpha); } /// @@ -367,8 +375,18 @@ namespace ImageProcessorCore /// The . public static Color FromNonPremultiplied(Color color) { - float a = color.A; - return new Color(color.backingVector * new Vector4(a, a, a, 1)); + return new Color(FromNonPremultiplied(color.backingVector, color.A)); + } + + /// + /// Converts a non-premultiplied alpha Vector4 to a Vector4 that contains premultiplied alpha. + /// + /// The vector to convert. + /// The alpha to use in conversion. + /// The Vector4 with premultiplied alpha. + private static Vector4 FromNonPremultiplied(Vector4 vector, float alpha) + { + return vector * new Vector4(alpha, alpha, alpha, 1); } /// @@ -443,10 +461,12 @@ namespace ImageProcessorCore /// public bool AlmostEquals(Color other, float precision) { - return Math.Abs(this.R - other.R) < precision - && Math.Abs(this.G - other.G) < precision - && Math.Abs(this.B - other.B) < precision - && Math.Abs(this.A - other.A) < precision; + Vector4 result = Vector4.Abs(this.backingVector - other.backingVector); + + return result.X < precision + && result.Y < precision + && result.Z < precision + && result.W < precision; } /// diff --git a/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs b/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs index 9ab1e8da4..0ff680b18 100644 --- a/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs +++ b/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs @@ -8,6 +8,8 @@ // // -------------------------------------------------------------------------------------------------------------------- +using System.Numerics; + namespace ImageProcessorCore.Tests { using Xunit; @@ -76,6 +78,24 @@ namespace ImageProcessorCore.Tests Assert.Equal(0, color3.G, 1); Assert.Equal(0, color3.B, 3); Assert.Equal(1, color3.A, 1); + + Color color4 = new Color(new Vector3(1, .1f, .133f)); + Assert.Equal(1, color4.R, 1); + Assert.Equal(.1f, color4.G, 1); + Assert.Equal(.133f, color4.B, 3); + Assert.Equal(1, color4.A, 1); + + Color color5 = new Color(new Vector3(1, .1f, .133f), .5f); + Assert.Equal(1, color5.R, 1); + Assert.Equal(.1f, color5.G, 1); + Assert.Equal(.133f, color5.B, 3); + Assert.Equal(.5f, color5.A, 1); + + Color color6 = new Color(new Vector4(1, .1f, .133f, .5f)); + Assert.Equal(1, color5.R, 1); + Assert.Equal(.1f, color6.G, 1); + Assert.Equal(.133f, color6.B, 3); + Assert.Equal(.5f, color6.A, 1); } ///