-
-
Notifications
You must be signed in to change notification settings - Fork 888
Port colorconverter YCbCr and YCCk to arm #2417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
JimBobSquarePants
merged 10 commits into
SixLabors:main
from
stefannikolei:stefannikolei/arm/colorconverter_ycbcrarm
Mar 29, 2023
Merged
Changes from 7 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
9dddb8c
Port YCbCr ColorConverter to ARM
stefannikolei 2c534ea
Add arm benchmark
stefannikolei d6a3d7c
Merge branch 'main' into stefannikolei/arm/colorconverter_ycbcrarm
stefannikolei 60c39bb
Port YCCK to arm
stefannikolei 8178945
Merge branch 'main' into stefannikolei/arm/colorconverter_ycbcrarm
stefannikolei 7b13ae2
Adapt testchanges
stefannikolei 33fe244
Arm needs to come before vector
stefannikolei 996f767
Change test, only expect it for ARM64
stefannikolei b2dc1e5
Update tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
stefannikolei ba5ae6e
Merge branch 'main' into stefannikolei/arm/colorconverter_ycbcrarm
JimBobSquarePants File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
122 changes: 122 additions & 0 deletions
122
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrArm.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| // Copyright (c) Six Labors. | ||
| // Licensed under the Six Labors Split License. | ||
|
|
||
| using System.Runtime.CompilerServices; | ||
| using System.Runtime.InteropServices; | ||
| using System.Runtime.Intrinsics; | ||
| using System.Runtime.Intrinsics.Arm; | ||
| using System.Runtime.Intrinsics.X86; | ||
| using static SixLabors.ImageSharp.SimdUtils; | ||
|
|
||
| // ReSharper disable ImpureMethodCallOnReadonlyValueField | ||
| namespace SixLabors.ImageSharp.Formats.Jpeg.Components; | ||
|
|
||
| internal abstract partial class JpegColorConverterBase | ||
| { | ||
| internal sealed class YCbCrArm : JpegColorConverterArm | ||
| { | ||
| public YCbCrArm(int precision) | ||
| : base(JpegColorSpace.YCbCr, precision) | ||
| { | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| public override void ConvertToRgbInplace(in ComponentValues values) | ||
| { | ||
| ref Vector128<float> c0Base = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0)); | ||
| ref Vector128<float> c1Base = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1)); | ||
| ref Vector128<float> c2Base = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2)); | ||
|
|
||
| // Used for the color conversion | ||
| var chromaOffset = Vector128.Create(-this.HalfValue); | ||
| var scale = Vector128.Create(1 / this.MaximumValue); | ||
| var rCrMult = Vector128.Create(YCbCrScalar.RCrMult); | ||
| var gCbMult = Vector128.Create(-YCbCrScalar.GCbMult); | ||
| var gCrMult = Vector128.Create(-YCbCrScalar.GCrMult); | ||
| var bCbMult = Vector128.Create(YCbCrScalar.BCbMult); | ||
|
|
||
| // Walking 8 elements at one step: | ||
| nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count; | ||
| for (nuint i = 0; i < n; i++) | ||
| { | ||
| // y = yVals[i]; | ||
| // cb = cbVals[i] - 128F; | ||
| // cr = crVals[i] - 128F; | ||
| ref Vector128<float> c0 = ref Unsafe.Add(ref c0Base, i); | ||
| ref Vector128<float> c1 = ref Unsafe.Add(ref c1Base, i); | ||
| ref Vector128<float> c2 = ref Unsafe.Add(ref c2Base, i); | ||
|
|
||
| Vector128<float> y = c0; | ||
| Vector128<float> cb = AdvSimd.Add(c1, chromaOffset); | ||
| Vector128<float> cr = AdvSimd.Add(c2, chromaOffset); | ||
|
|
||
| // r = y + (1.402F * cr); | ||
| // g = y - (0.344136F * cb) - (0.714136F * cr); | ||
| // b = y + (1.772F * cb); | ||
| Vector128<float> r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult); | ||
| Vector128<float> g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); | ||
| Vector128<float> b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult); | ||
|
|
||
| r = AdvSimd.Multiply(AdvSimd.RoundToNearest(r), scale); | ||
| g = AdvSimd.Multiply(AdvSimd.RoundToNearest(g), scale); | ||
| b = AdvSimd.Multiply(AdvSimd.RoundToNearest(b), scale); | ||
|
|
||
| c0 = r; | ||
| c1 = g; | ||
| c2 = b; | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane) | ||
| { | ||
| ref Vector128<float> destY = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0)); | ||
| ref Vector128<float> destCb = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1)); | ||
| ref Vector128<float> destCr = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2)); | ||
|
|
||
| ref Vector128<float> srcR = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(rLane)); | ||
| ref Vector128<float> srcG = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(gLane)); | ||
| ref Vector128<float> srcB = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(bLane)); | ||
|
|
||
| // Used for the color conversion | ||
| var chromaOffset = Vector128.Create(this.HalfValue); | ||
|
|
||
| var f0299 = Vector128.Create(0.299f); | ||
| var f0587 = Vector128.Create(0.587f); | ||
| var f0114 = Vector128.Create(0.114f); | ||
| var fn0168736 = Vector128.Create(-0.168736f); | ||
| var fn0331264 = Vector128.Create(-0.331264f); | ||
| var fn0418688 = Vector128.Create(-0.418688f); | ||
| var fn0081312F = Vector128.Create(-0.081312F); | ||
| var f05 = Vector128.Create(0.5f); | ||
|
|
||
| nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count; | ||
| for (nuint i = 0; i < n; i++) | ||
| { | ||
| Vector128<float> r = Unsafe.Add(ref srcR, i); | ||
| Vector128<float> g = Unsafe.Add(ref srcG, i); | ||
| Vector128<float> b = Unsafe.Add(ref srcB, i); | ||
|
|
||
| // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) | ||
| // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) | ||
| // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) | ||
| Vector128<float> y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r); | ||
| Vector128<float> cb = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f05, b), fn0331264, g), fn0168736, r)); | ||
| Vector128<float> cr = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(fn0081312F, b), fn0418688, g), f05, r)); | ||
|
|
||
| Unsafe.Add(ref destY, i) = y; | ||
| Unsafe.Add(ref destCb, i) = cb; | ||
| Unsafe.Add(ref destCr, i) = cr; | ||
| } | ||
| } | ||
| } | ||
| } |
133 changes: 133 additions & 0 deletions
133
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKArm64.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| // Copyright (c) Six Labors. | ||
| // Licensed under the Six Labors Split License. | ||
|
|
||
| using System.Runtime.CompilerServices; | ||
| using System.Runtime.InteropServices; | ||
| using System.Runtime.Intrinsics; | ||
| using System.Runtime.Intrinsics.Arm; | ||
| using System.Runtime.Intrinsics.X86; | ||
| using static SixLabors.ImageSharp.SimdUtils; | ||
|
|
||
| namespace SixLabors.ImageSharp.Formats.Jpeg.Components; | ||
|
|
||
| internal abstract partial class JpegColorConverterBase | ||
| { | ||
| internal sealed class YccKArm64 : JpegColorConverterArm64 | ||
| { | ||
| public YccKArm64(int precision) | ||
| : base(JpegColorSpace.Ycck, precision) | ||
| { | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| public override void ConvertToRgbInplace(in ComponentValues values) | ||
| { | ||
| ref Vector128<float> c0Base = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0)); | ||
| ref Vector128<float> c1Base = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1)); | ||
| ref Vector128<float> c2Base = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2)); | ||
| ref Vector128<float> kBase = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component3)); | ||
|
|
||
| // Used for the color conversion | ||
| var chromaOffset = Vector128.Create(-this.HalfValue); | ||
| var scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue)); | ||
| var max = Vector128.Create(this.MaximumValue); | ||
| var rCrMult = Vector128.Create(YCbCrScalar.RCrMult); | ||
| var gCbMult = Vector128.Create(-YCbCrScalar.GCbMult); | ||
| var gCrMult = Vector128.Create(-YCbCrScalar.GCrMult); | ||
| var bCbMult = Vector128.Create(YCbCrScalar.BCbMult); | ||
|
|
||
| // Walking 8 elements at one step: | ||
| nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count; | ||
| for (nuint i = 0; i < n; i++) | ||
| { | ||
| // y = yVals[i]; | ||
| // cb = cbVals[i] - 128F; | ||
| // cr = crVals[i] - 128F; | ||
| // k = kVals[i] / 256F; | ||
| ref Vector128<float> c0 = ref Unsafe.Add(ref c0Base, i); | ||
| ref Vector128<float> c1 = ref Unsafe.Add(ref c1Base, i); | ||
| ref Vector128<float> c2 = ref Unsafe.Add(ref c2Base, i); | ||
| Vector128<float> y = c0; | ||
| Vector128<float> cb = AdvSimd.Add(c1, chromaOffset); | ||
| Vector128<float> cr = AdvSimd.Add(c2, chromaOffset); | ||
| Vector128<float> scaledK = AdvSimd.Multiply(Unsafe.Add(ref kBase, i), scale); | ||
|
|
||
| // r = y + (1.402F * cr); | ||
| // g = y - (0.344136F * cb) - (0.714136F * cr); | ||
| // b = y + (1.772F * cb); | ||
| Vector128<float> r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult); | ||
| Vector128<float> g = | ||
| HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult); | ||
| Vector128<float> b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult); | ||
|
|
||
| r = AdvSimd.Subtract(max, AdvSimd.RoundToNearest(r)); | ||
| g = AdvSimd.Subtract(max, AdvSimd.RoundToNearest(g)); | ||
| b = AdvSimd.Subtract(max, AdvSimd.RoundToNearest(b)); | ||
|
|
||
| r = AdvSimd.Multiply(r, scaledK); | ||
| g = AdvSimd.Multiply(g, scaledK); | ||
| b = AdvSimd.Multiply(b, scaledK); | ||
|
|
||
| c0 = r; | ||
| c1 = g; | ||
| c2 = b; | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc/> | ||
| public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane) | ||
| { | ||
| // rgb -> cmyk | ||
| CmykArm64.ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane); | ||
|
|
||
| // cmyk -> ycck | ||
| ref Vector128<float> destY = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0)); | ||
| ref Vector128<float> destCb = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1)); | ||
| ref Vector128<float> destCr = | ||
| ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2)); | ||
|
|
||
| ref Vector128<float> srcR = ref destY; | ||
| ref Vector128<float> srcG = ref destCb; | ||
| ref Vector128<float> srcB = ref destCr; | ||
|
|
||
| // Used for the color conversion | ||
| var maxSampleValue = Vector128.Create(this.MaximumValue); | ||
|
|
||
| var chromaOffset = Vector128.Create(this.HalfValue); | ||
|
|
||
| var f0299 = Vector128.Create(0.299f); | ||
| var f0587 = Vector128.Create(0.587f); | ||
| var f0114 = Vector128.Create(0.114f); | ||
| var fn0168736 = Vector128.Create(-0.168736f); | ||
| var fn0331264 = Vector128.Create(-0.331264f); | ||
| var fn0418688 = Vector128.Create(-0.418688f); | ||
| var fn0081312F = Vector128.Create(-0.081312F); | ||
| var f05 = Vector128.Create(0.5f); | ||
|
|
||
| nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count; | ||
| for (nuint i = 0; i < n; i++) | ||
| { | ||
| Vector128<float> r = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcR, i)); | ||
| Vector128<float> g = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcG, i)); | ||
| Vector128<float> b = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcB, i)); | ||
|
|
||
| // y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b) | ||
| // cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b) | ||
| // cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b) | ||
| Vector128<float> y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r); | ||
| Vector128<float> cb = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f05, b), fn0331264, g), fn0168736, r)); | ||
| Vector128<float> cr = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(fn0081312F, b), fn0418688, g), f05, r)); | ||
|
|
||
| Unsafe.Add(ref destY, i) = y; | ||
| Unsafe.Add(ref destCb, i) = cb; | ||
| Unsafe.Add(ref destCr, i) = cr; | ||
| } | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.