Browse Source

Optimized vector rgb pixel matrix scaling

pull/1632/head
Dmitry Pentin 5 years ago
parent
commit
0013c54460
  1. 18
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  2. 28
      src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrConverterVectorized.cs

18
src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs

@ -577,6 +577,24 @@ namespace SixLabors.ImageSharp
}
}
/// <summary>
/// Scales 8x8 matrix to 4x2 using 2x2 average
/// </summary>
/// <param name="v">Input matrix consisting of 4 256bit vectors, first row: (v[0], v[2]), second row: (v[1], v[3])</param>
/// <returns>256bit vector containing upper and lower scaled parts of the input matrix</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Scale16x2_8x1(ReadOnlySpan<Vector256<float>> v)
{
DebugGuard.IsTrue(v.Length == 4, "Input span must consist of 4 elements");
var f025 = Vector256.Create(0.25f);
Vector256<float> left = Avx.Add(v[0], v[2]);
Vector256<float> right = Avx.Add(v[1], v[3]);
Vector256<float> avg2x2 = Avx.Multiply(Avx.HorizontalAdd(left, right), f025);
return Avx2.Permute4x64(avg2x2.AsDouble(), 0b11_01_10_00).AsSingle();
}
/// <summary>
/// <see cref="ByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).

28
src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrConverterVectorized.cs

@ -221,9 +221,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
bDataLanes[j] = b;
}
r = Scale_8x4_4x2(rDataLanes);
g = Scale_8x4_4x2(gDataLanes);
b = Scale_8x4_4x2(bDataLanes);
r = SimdUtils.HwIntrinsics.Scale16x2_8x1(rDataLanes);
g = SimdUtils.HwIntrinsics.Scale16x2_8x1(gDataLanes);
b = SimdUtils.HwIntrinsics.Scale16x2_8x1(bDataLanes);
// 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b))
Unsafe.Add(ref destCbRef, i) = Avx.Add(f128, SimdUtils.HwIntrinsics.MultiplyAdd(SimdUtils.HwIntrinsics.MultiplyAdd(Avx.Multiply(f05, b), fn0331264, g), fn0168736, r));
@ -233,27 +233,5 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
}
#endif
}
#if SUPPORTS_RUNTIME_INTRINSICS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> Scale_8x4_4x2(Span<Vector256<float>> v)
{
Vector256<int> switchInnerDoubleWords = Unsafe.As<byte, Vector256<int>>(ref MemoryMarshal.GetReference(SimdUtils.HwIntrinsics.PermuteMaskSwitchInnerDWords8x32));
var f025 = Vector256.Create(0.25f);
Vector256<float> topPairSum = SumHorizontalPairs(v[0], v[2]);
Vector256<float> botPairSum = SumHorizontalPairs(v[1], v[3]);
return Avx2.PermuteVar8x32(Avx.Multiply(SumVerticalPairs(topPairSum, botPairSum), f025), switchInnerDoubleWords);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> SumHorizontalPairs(Vector256<float> v0, Vector256<float> v1)
=> Avx.Add(Avx.Shuffle(v0, v1, 0b10_00_10_00), Avx.Shuffle(v0, v1, 0b11_01_11_01));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<float> SumVerticalPairs(Vector256<float> v0, Vector256<float> v1)
=> Avx.Add(Avx.Shuffle(v0, v1, 0b01_00_01_00), Avx.Shuffle(v0, v1, 0b11_10_11_10));
#endif
}
}

Loading…
Cancel
Save