mirror of https://github.com/SixLabors/ImageSharp
66 changed files with 7955 additions and 13525 deletions
File diff suppressed because it is too large
@ -1,557 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the sixteen-point forward ADST operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Adst16Forward1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// The range table is consumed by coefficient-range-checking builds of libaom. ImageSharp preserves the same
|
|||
// staged arithmetic, while its production path relies on the bit-depth and shift invariants established by
|
|||
// the two-dimensional transform configuration.
|
|||
_ = stageRange; |
|||
|
|||
// Reordering and alternating signs express the ADST as progressively wider symmetric butterflies.
|
|||
output[0] = input[0]; |
|||
output[1] = -input[15]; |
|||
output[2] = -input[7]; |
|||
output[3] = input[8]; |
|||
output[4] = -input[3]; |
|||
output[5] = input[12]; |
|||
output[6] = input[4]; |
|||
output[7] = -input[11]; |
|||
output[8] = -input[1]; |
|||
output[9] = input[14]; |
|||
output[10] = input[6]; |
|||
output[11] = -input[9]; |
|||
output[12] = input[2]; |
|||
output[13] = -input[13]; |
|||
output[14] = -input[5]; |
|||
output[15] = input[10]; |
|||
|
|||
// Rotate four independent pairs by pi/4 so the following butterflies can double their span.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], cospi[32], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], -cospi[32], output[11], cosBit); |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], cospi[32], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], -cospi[32], output[15], cosBit); |
|||
|
|||
// Combine adjacent rotated pairs into four-sample butterflies.
|
|||
output[0] = step[0] + step[2]; |
|||
output[1] = step[1] + step[3]; |
|||
output[2] = step[0] - step[2]; |
|||
output[3] = step[1] - step[3]; |
|||
output[4] = step[4] + step[6]; |
|||
output[5] = step[5] + step[7]; |
|||
output[6] = step[4] - step[6]; |
|||
output[7] = step[5] - step[7]; |
|||
output[8] = step[8] + step[10]; |
|||
output[9] = step[9] + step[11]; |
|||
output[10] = step[8] - step[10]; |
|||
output[11] = step[9] - step[11]; |
|||
output[12] = step[12] + step[14]; |
|||
output[13] = step[13] + step[15]; |
|||
output[14] = step[12] - step[14]; |
|||
output[15] = step[13] - step[15]; |
|||
|
|||
// Rotate the upper half of each eight-sample group by pi/8 and 3pi/8.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[16], output[12], cospi[48], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[48], output[12], -cospi[16], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[14], cospi[16], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[16], output[14], cospi[48], output[15], cosBit); |
|||
|
|||
// Merge the four-sample groups into two eight-sample butterflies.
|
|||
output[0] = step[0] + step[4]; |
|||
output[1] = step[1] + step[5]; |
|||
output[2] = step[2] + step[6]; |
|||
output[3] = step[3] + step[7]; |
|||
output[4] = step[0] - step[4]; |
|||
output[5] = step[1] - step[5]; |
|||
output[6] = step[2] - step[6]; |
|||
output[7] = step[3] - step[7]; |
|||
output[8] = step[8] + step[12]; |
|||
output[9] = step[9] + step[13]; |
|||
output[10] = step[10] + step[14]; |
|||
output[11] = step[11] + step[15]; |
|||
output[12] = step[8] - step[12]; |
|||
output[13] = step[9] - step[13]; |
|||
output[14] = step[10] - step[14]; |
|||
output[15] = step[11] - step[15]; |
|||
|
|||
// Rotate the upper eight coefficients with the pi/16 odd-angle pairs.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[8], output[8], cospi[56], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[56], output[8], -cospi[8], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[40], output[10], cospi[24], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[24], output[10], -cospi[40], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(-cospi[56], output[12], cospi[8], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[8], output[12], cospi[56], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[24], output[14], cospi[40], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[40], output[14], cospi[24], output[15], cosBit); |
|||
|
|||
// Merge both eight-sample halves into the complete sixteen-sample butterfly.
|
|||
output[0] = step[0] + step[8]; |
|||
output[1] = step[1] + step[9]; |
|||
output[2] = step[2] + step[10]; |
|||
output[3] = step[3] + step[11]; |
|||
output[4] = step[4] + step[12]; |
|||
output[5] = step[5] + step[13]; |
|||
output[6] = step[6] + step[14]; |
|||
output[7] = step[7] + step[15]; |
|||
output[8] = step[0] - step[8]; |
|||
output[9] = step[1] - step[9]; |
|||
output[10] = step[2] - step[10]; |
|||
output[11] = step[3] - step[11]; |
|||
output[12] = step[4] - step[12]; |
|||
output[13] = step[5] - step[13]; |
|||
output[14] = step[6] - step[14]; |
|||
output[15] = step[7] - step[15]; |
|||
|
|||
// Apply the terminal odd-frequency rotations that define the ADST basis vectors.
|
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[2], output[0], cospi[62], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[62], output[0], -cospi[2], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[10], output[2], cospi[54], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[54], output[2], -cospi[10], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[18], output[4], cospi[46], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[46], output[4], -cospi[18], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[26], output[6], cospi[38], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[38], output[6], -cospi[26], output[7], cosBit); |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[34], output[8], cospi[30], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[30], output[8], -cospi[34], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[42], output[10], cospi[22], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[22], output[10], -cospi[42], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[50], output[12], cospi[14], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[14], output[12], -cospi[50], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[58], output[14], cospi[6], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[6], output[14], -cospi[58], output[15], cosBit); |
|||
|
|||
// Permute the rotated values into AV1 coefficient order.
|
|||
output[0] = step[1]; |
|||
output[1] = step[14]; |
|||
output[2] = step[3]; |
|||
output[3] = step[12]; |
|||
output[4] = step[5]; |
|||
output[5] = step[10]; |
|||
output[6] = step[7]; |
|||
output[7] = step[8]; |
|||
output[8] = step[9]; |
|||
output[9] = step[6]; |
|||
output[10] = step[11]; |
|||
output[11] = step[4]; |
|||
output[12] = step[13]; |
|||
output[13] = step[2]; |
|||
output[14] = step[15]; |
|||
output[15] = step[0]; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// The range table is consumed by coefficient-range-checking builds of libaom. ImageSharp preserves the same
|
|||
// staged arithmetic, while its production path relies on the bit-depth and shift invariants established by
|
|||
// the two-dimensional transform configuration.
|
|||
_ = stageRange; |
|||
|
|||
// Reordering and alternating signs express the ADST as progressively wider symmetric butterflies.
|
|||
output[0] = input[0]; |
|||
output[1] = -input[15]; |
|||
output[2] = -input[7]; |
|||
output[3] = input[8]; |
|||
output[4] = -input[3]; |
|||
output[5] = input[12]; |
|||
output[6] = input[4]; |
|||
output[7] = -input[11]; |
|||
output[8] = -input[1]; |
|||
output[9] = input[14]; |
|||
output[10] = input[6]; |
|||
output[11] = -input[9]; |
|||
output[12] = input[2]; |
|||
output[13] = -input[13]; |
|||
output[14] = -input[5]; |
|||
output[15] = input[10]; |
|||
|
|||
// Rotate four independent pairs by pi/4 so the following butterflies can double their span.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], cospi[32], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], -cospi[32], output[11], cosBit); |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], cospi[32], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], -cospi[32], output[15], cosBit); |
|||
|
|||
// Combine adjacent rotated pairs into four-sample butterflies.
|
|||
output[0] = step[0] + step[2]; |
|||
output[1] = step[1] + step[3]; |
|||
output[2] = step[0] - step[2]; |
|||
output[3] = step[1] - step[3]; |
|||
output[4] = step[4] + step[6]; |
|||
output[5] = step[5] + step[7]; |
|||
output[6] = step[4] - step[6]; |
|||
output[7] = step[5] - step[7]; |
|||
output[8] = step[8] + step[10]; |
|||
output[9] = step[9] + step[11]; |
|||
output[10] = step[8] - step[10]; |
|||
output[11] = step[9] - step[11]; |
|||
output[12] = step[12] + step[14]; |
|||
output[13] = step[13] + step[15]; |
|||
output[14] = step[12] - step[14]; |
|||
output[15] = step[13] - step[15]; |
|||
|
|||
// Rotate the upper half of each eight-sample group by pi/8 and 3pi/8.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[16], output[12], cospi[48], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[48], output[12], -cospi[16], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[14], cospi[16], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[16], output[14], cospi[48], output[15], cosBit); |
|||
|
|||
// Merge the four-sample groups into two eight-sample butterflies.
|
|||
output[0] = step[0] + step[4]; |
|||
output[1] = step[1] + step[5]; |
|||
output[2] = step[2] + step[6]; |
|||
output[3] = step[3] + step[7]; |
|||
output[4] = step[0] - step[4]; |
|||
output[5] = step[1] - step[5]; |
|||
output[6] = step[2] - step[6]; |
|||
output[7] = step[3] - step[7]; |
|||
output[8] = step[8] + step[12]; |
|||
output[9] = step[9] + step[13]; |
|||
output[10] = step[10] + step[14]; |
|||
output[11] = step[11] + step[15]; |
|||
output[12] = step[8] - step[12]; |
|||
output[13] = step[9] - step[13]; |
|||
output[14] = step[10] - step[14]; |
|||
output[15] = step[11] - step[15]; |
|||
|
|||
// Rotate the upper eight coefficients with the pi/16 odd-angle pairs.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[8], output[8], cospi[56], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[56], output[8], -cospi[8], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[40], output[10], cospi[24], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[24], output[10], -cospi[40], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(-cospi[56], output[12], cospi[8], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[8], output[12], cospi[56], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[24], output[14], cospi[40], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[40], output[14], cospi[24], output[15], cosBit); |
|||
|
|||
// Merge both eight-sample halves into the complete sixteen-sample butterfly.
|
|||
output[0] = step[0] + step[8]; |
|||
output[1] = step[1] + step[9]; |
|||
output[2] = step[2] + step[10]; |
|||
output[3] = step[3] + step[11]; |
|||
output[4] = step[4] + step[12]; |
|||
output[5] = step[5] + step[13]; |
|||
output[6] = step[6] + step[14]; |
|||
output[7] = step[7] + step[15]; |
|||
output[8] = step[0] - step[8]; |
|||
output[9] = step[1] - step[9]; |
|||
output[10] = step[2] - step[10]; |
|||
output[11] = step[3] - step[11]; |
|||
output[12] = step[4] - step[12]; |
|||
output[13] = step[5] - step[13]; |
|||
output[14] = step[6] - step[14]; |
|||
output[15] = step[7] - step[15]; |
|||
|
|||
// Apply the terminal odd-frequency rotations that define the ADST basis vectors.
|
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[2], output[0], cospi[62], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[62], output[0], -cospi[2], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[10], output[2], cospi[54], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[54], output[2], -cospi[10], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[18], output[4], cospi[46], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[46], output[4], -cospi[18], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[26], output[6], cospi[38], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[38], output[6], -cospi[26], output[7], cosBit); |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[34], output[8], cospi[30], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[30], output[8], -cospi[34], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[42], output[10], cospi[22], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[22], output[10], -cospi[42], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[50], output[12], cospi[14], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[14], output[12], -cospi[50], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[58], output[14], cospi[6], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[6], output[14], -cospi[58], output[15], cosBit); |
|||
|
|||
// Permute the rotated values into AV1 coefficient order.
|
|||
output[0] = step[1]; |
|||
output[1] = step[14]; |
|||
output[2] = step[3]; |
|||
output[3] = step[12]; |
|||
output[4] = step[5]; |
|||
output[5] = step[10]; |
|||
output[6] = step[7]; |
|||
output[7] = step[8]; |
|||
output[8] = step[9]; |
|||
output[9] = step[6]; |
|||
output[10] = step[11]; |
|||
output[11] = step[4]; |
|||
output[12] = step[13]; |
|||
output[13] = step[2]; |
|||
output[14] = step[15]; |
|||
output[15] = step[0]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// The range table is consumed by coefficient-range-checking builds of libaom. ImageSharp preserves the same
|
|||
// staged arithmetic, while its production path relies on the bit-depth and shift invariants established by
|
|||
// the two-dimensional transform configuration.
|
|||
_ = stageRange; |
|||
|
|||
// Reordering and alternating signs express the ADST as progressively wider symmetric butterflies.
|
|||
output[0] = input[0]; |
|||
output[1] = -input[15]; |
|||
output[2] = -input[7]; |
|||
output[3] = input[8]; |
|||
output[4] = -input[3]; |
|||
output[5] = input[12]; |
|||
output[6] = input[4]; |
|||
output[7] = -input[11]; |
|||
output[8] = -input[1]; |
|||
output[9] = input[14]; |
|||
output[10] = input[6]; |
|||
output[11] = -input[9]; |
|||
output[12] = input[2]; |
|||
output[13] = -input[13]; |
|||
output[14] = -input[5]; |
|||
output[15] = input[10]; |
|||
|
|||
// Rotate four independent pairs by pi/4 so the following butterflies can double their span.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], cospi[32], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], -cospi[32], output[11], cosBit); |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], cospi[32], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], -cospi[32], output[15], cosBit); |
|||
|
|||
// Combine adjacent rotated pairs into four-sample butterflies.
|
|||
output[0] = step[0] + step[2]; |
|||
output[1] = step[1] + step[3]; |
|||
output[2] = step[0] - step[2]; |
|||
output[3] = step[1] - step[3]; |
|||
output[4] = step[4] + step[6]; |
|||
output[5] = step[5] + step[7]; |
|||
output[6] = step[4] - step[6]; |
|||
output[7] = step[5] - step[7]; |
|||
output[8] = step[8] + step[10]; |
|||
output[9] = step[9] + step[11]; |
|||
output[10] = step[8] - step[10]; |
|||
output[11] = step[9] - step[11]; |
|||
output[12] = step[12] + step[14]; |
|||
output[13] = step[13] + step[15]; |
|||
output[14] = step[12] - step[14]; |
|||
output[15] = step[13] - step[15]; |
|||
|
|||
// Rotate the upper half of each eight-sample group by pi/8 and 3pi/8.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[16], output[12], cospi[48], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[48], output[12], -cospi[16], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[14], cospi[16], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[16], output[14], cospi[48], output[15], cosBit); |
|||
|
|||
// Merge the four-sample groups into two eight-sample butterflies.
|
|||
output[0] = step[0] + step[4]; |
|||
output[1] = step[1] + step[5]; |
|||
output[2] = step[2] + step[6]; |
|||
output[3] = step[3] + step[7]; |
|||
output[4] = step[0] - step[4]; |
|||
output[5] = step[1] - step[5]; |
|||
output[6] = step[2] - step[6]; |
|||
output[7] = step[3] - step[7]; |
|||
output[8] = step[8] + step[12]; |
|||
output[9] = step[9] + step[13]; |
|||
output[10] = step[10] + step[14]; |
|||
output[11] = step[11] + step[15]; |
|||
output[12] = step[8] - step[12]; |
|||
output[13] = step[9] - step[13]; |
|||
output[14] = step[10] - step[14]; |
|||
output[15] = step[11] - step[15]; |
|||
|
|||
// Rotate the upper eight coefficients with the pi/16 odd-angle pairs.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[8], output[8], cospi[56], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[56], output[8], -cospi[8], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[40], output[10], cospi[24], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[24], output[10], -cospi[40], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(-cospi[56], output[12], cospi[8], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[8], output[12], cospi[56], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[24], output[14], cospi[40], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[40], output[14], cospi[24], output[15], cosBit); |
|||
|
|||
// Merge both eight-sample halves into the complete sixteen-sample butterfly.
|
|||
output[0] = step[0] + step[8]; |
|||
output[1] = step[1] + step[9]; |
|||
output[2] = step[2] + step[10]; |
|||
output[3] = step[3] + step[11]; |
|||
output[4] = step[4] + step[12]; |
|||
output[5] = step[5] + step[13]; |
|||
output[6] = step[6] + step[14]; |
|||
output[7] = step[7] + step[15]; |
|||
output[8] = step[0] - step[8]; |
|||
output[9] = step[1] - step[9]; |
|||
output[10] = step[2] - step[10]; |
|||
output[11] = step[3] - step[11]; |
|||
output[12] = step[4] - step[12]; |
|||
output[13] = step[5] - step[13]; |
|||
output[14] = step[6] - step[14]; |
|||
output[15] = step[7] - step[15]; |
|||
|
|||
// Apply the terminal odd-frequency rotations that define the ADST basis vectors.
|
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[2], output[0], cospi[62], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[62], output[0], -cospi[2], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[10], output[2], cospi[54], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[54], output[2], -cospi[10], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[18], output[4], cospi[46], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[46], output[4], -cospi[18], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[26], output[6], cospi[38], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[38], output[6], -cospi[26], output[7], cosBit); |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[34], output[8], cospi[30], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[30], output[8], -cospi[34], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[42], output[10], cospi[22], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[22], output[10], -cospi[42], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[50], output[12], cospi[14], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[14], output[12], -cospi[50], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[58], output[14], cospi[6], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[6], output[14], -cospi[58], output[15], cosBit); |
|||
|
|||
// Permute the rotated values into AV1 coefficient order.
|
|||
output[0] = step[1]; |
|||
output[1] = step[14]; |
|||
output[2] = step[3]; |
|||
output[3] = step[12]; |
|||
output[4] = step[5]; |
|||
output[5] = step[10]; |
|||
output[6] = step[7]; |
|||
output[7] = step[8]; |
|||
output[8] = step[9]; |
|||
output[9] = step[6]; |
|||
output[10] = step[11]; |
|||
output[11] = step[4]; |
|||
output[12] = step[13]; |
|||
output[13] = step[2]; |
|||
output[14] = step[15]; |
|||
output[15] = step[0]; |
|||
} |
|||
} |
|||
@ -1,113 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the four-point forward ADST operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Adst4Forward1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
TransformCore(ref input, ref output, cosBit); |
|||
_ = step; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
TransformCore(ref input, ref output, cosBit); |
|||
_ = step; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
TransformCore(ref input, ref output, cosBit); |
|||
_ = step; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the four-point matrix to four independent axes.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for four transform axes.</param>
|
|||
/// <param name="output">The destination values for four transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the sine constants.</param>
|
|||
private static void TransformCore(ref Av1TransformVector<Vector128<int>> input, ref Av1TransformVector<Vector128<int>> output, int cosBit) |
|||
{ |
|||
ReadOnlySpan<int> sinpi = Av1SinusConstants.SinusPi(cosBit); |
|||
Vector128<int> x0 = input[0]; |
|||
Vector128<int> x1 = input[1]; |
|||
Vector128<int> x2 = input[2]; |
|||
Vector128<int> x3 = input[3]; |
|||
|
|||
// Expanding the factorization into four weighted sums keeps every lane independent while preserving the
|
|||
// wrapping 32-bit product and sum behavior used by the optimized fixed-point kernels.
|
|||
output[0] = Av1Transform1dMath.MultiplyAdd4(sinpi[1], x0, sinpi[2], x1, sinpi[3], x2, sinpi[4], x3, cosBit); |
|||
output[1] = Av1Transform1dMath.MultiplyAdd4(sinpi[3], x0, sinpi[3], x1, 0, x2, -sinpi[3], x3, cosBit); |
|||
output[2] = Av1Transform1dMath.MultiplyAdd4(sinpi[4], x0, -sinpi[1], x1, -sinpi[3], x2, sinpi[2], x3, cosBit); |
|||
output[3] = Av1Transform1dMath.MultiplyAdd4(sinpi[4] - sinpi[1], x0, -sinpi[1] - sinpi[2], x1, sinpi[3], x2, sinpi[2] - sinpi[4], x3, cosBit); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the four-point matrix to eight independent axes.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for eight transform axes.</param>
|
|||
/// <param name="output">The destination values for eight transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the sine constants.</param>
|
|||
private static void TransformCore(ref Av1TransformVector<Vector256<int>> input, ref Av1TransformVector<Vector256<int>> output, int cosBit) |
|||
{ |
|||
ReadOnlySpan<int> sinpi = Av1SinusConstants.SinusPi(cosBit); |
|||
Vector256<int> x0 = input[0]; |
|||
Vector256<int> x1 = input[1]; |
|||
Vector256<int> x2 = input[2]; |
|||
Vector256<int> x3 = input[3]; |
|||
|
|||
output[0] = Av1Transform1dMath.MultiplyAdd4(sinpi[1], x0, sinpi[2], x1, sinpi[3], x2, sinpi[4], x3, cosBit); |
|||
output[1] = Av1Transform1dMath.MultiplyAdd4(sinpi[3], x0, sinpi[3], x1, 0, x2, -sinpi[3], x3, cosBit); |
|||
output[2] = Av1Transform1dMath.MultiplyAdd4(sinpi[4], x0, -sinpi[1], x1, -sinpi[3], x2, sinpi[2], x3, cosBit); |
|||
output[3] = Av1Transform1dMath.MultiplyAdd4(sinpi[4] - sinpi[1], x0, -sinpi[1] - sinpi[2], x1, sinpi[3], x2, sinpi[2] - sinpi[4], x3, cosBit); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the four-point matrix to sixteen independent axes.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for sixteen transform axes.</param>
|
|||
/// <param name="output">The destination values for sixteen transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the sine constants.</param>
|
|||
private static void TransformCore(ref Av1TransformVector<Vector512<int>> input, ref Av1TransformVector<Vector512<int>> output, int cosBit) |
|||
{ |
|||
ReadOnlySpan<int> sinpi = Av1SinusConstants.SinusPi(cosBit); |
|||
Vector512<int> x0 = input[0]; |
|||
Vector512<int> x1 = input[1]; |
|||
Vector512<int> x2 = input[2]; |
|||
Vector512<int> x3 = input[3]; |
|||
|
|||
output[0] = Av1Transform1dMath.MultiplyAdd4(sinpi[1], x0, sinpi[2], x1, sinpi[3], x2, sinpi[4], x3, cosBit); |
|||
output[1] = Av1Transform1dMath.MultiplyAdd4(sinpi[3], x0, sinpi[3], x1, 0, x2, -sinpi[3], x3, cosBit); |
|||
output[2] = Av1Transform1dMath.MultiplyAdd4(sinpi[4], x0, -sinpi[1], x1, -sinpi[3], x2, sinpi[2], x3, cosBit); |
|||
output[3] = Av1Transform1dMath.MultiplyAdd4(sinpi[4] - sinpi[1], x0, -sinpi[1] - sinpi[2], x1, sinpi[3], x2, sinpi[2] - sinpi[4], x3, cosBit); |
|||
} |
|||
} |
|||
@ -1,278 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the eight-point forward ADST operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Adst8Forward1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 reorders and signs the inputs so the ADST can be expressed as symmetric butterflies.
|
|||
output[0] = input[0]; |
|||
output[1] = -input[7]; |
|||
output[2] = -input[3]; |
|||
output[3] = input[4]; |
|||
output[4] = -input[1]; |
|||
output[5] = input[6]; |
|||
output[6] = input[2]; |
|||
output[7] = -input[5]; |
|||
|
|||
// Stage 2 rotates the middle pairs by pi/4.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
|
|||
// Stage 3 combines adjacent rotated pairs into four-sample butterflies.
|
|||
output[0] = step[0] + step[2]; |
|||
output[1] = step[1] + step[3]; |
|||
output[2] = step[0] - step[2]; |
|||
output[3] = step[1] - step[3]; |
|||
output[4] = step[4] + step[6]; |
|||
output[5] = step[5] + step[7]; |
|||
output[6] = step[4] - step[6]; |
|||
output[7] = step[5] - step[7]; |
|||
|
|||
// Stage 4 rotates the upper half by pi/8 and 3pi/8.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
|
|||
// Stage 5 merges both four-sample halves into the complete eight-sample butterfly.
|
|||
output[0] = step[0] + step[4]; |
|||
output[1] = step[1] + step[5]; |
|||
output[2] = step[2] + step[6]; |
|||
output[3] = step[3] + step[7]; |
|||
output[4] = step[0] - step[4]; |
|||
output[5] = step[1] - step[5]; |
|||
output[6] = step[2] - step[6]; |
|||
output[7] = step[3] - step[7]; |
|||
|
|||
// Stage 6 applies the terminal odd-frequency rotations that define the ADST basis vectors.
|
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[4], output[0], cospi[60], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[60], output[0], -cospi[4], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[20], output[2], cospi[44], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[44], output[2], -cospi[20], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[36], output[4], cospi[28], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[28], output[4], -cospi[36], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[52], output[6], cospi[12], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[12], output[6], -cospi[52], output[7], cosBit); |
|||
|
|||
// Stage 7 permutes the rotated values into AV1 coefficient order.
|
|||
output[0] = step[1]; |
|||
output[1] = step[6]; |
|||
output[2] = step[3]; |
|||
output[3] = step[4]; |
|||
output[4] = step[5]; |
|||
output[5] = step[2]; |
|||
output[6] = step[7]; |
|||
output[7] = step[0]; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 reorders and signs the inputs so the ADST can be expressed as symmetric butterflies.
|
|||
output[0] = input[0]; |
|||
output[1] = -input[7]; |
|||
output[2] = -input[3]; |
|||
output[3] = input[4]; |
|||
output[4] = -input[1]; |
|||
output[5] = input[6]; |
|||
output[6] = input[2]; |
|||
output[7] = -input[5]; |
|||
|
|||
// Stage 2 rotates the middle pairs by pi/4.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
|
|||
// Stage 3 combines adjacent rotated pairs into four-sample butterflies.
|
|||
output[0] = step[0] + step[2]; |
|||
output[1] = step[1] + step[3]; |
|||
output[2] = step[0] - step[2]; |
|||
output[3] = step[1] - step[3]; |
|||
output[4] = step[4] + step[6]; |
|||
output[5] = step[5] + step[7]; |
|||
output[6] = step[4] - step[6]; |
|||
output[7] = step[5] - step[7]; |
|||
|
|||
// Stage 4 rotates the upper half by pi/8 and 3pi/8.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
|
|||
// Stage 5 merges both four-sample halves into the complete eight-sample butterfly.
|
|||
output[0] = step[0] + step[4]; |
|||
output[1] = step[1] + step[5]; |
|||
output[2] = step[2] + step[6]; |
|||
output[3] = step[3] + step[7]; |
|||
output[4] = step[0] - step[4]; |
|||
output[5] = step[1] - step[5]; |
|||
output[6] = step[2] - step[6]; |
|||
output[7] = step[3] - step[7]; |
|||
|
|||
// Stage 6 applies the terminal odd-frequency rotations that define the ADST basis vectors.
|
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[4], output[0], cospi[60], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[60], output[0], -cospi[4], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[20], output[2], cospi[44], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[44], output[2], -cospi[20], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[36], output[4], cospi[28], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[28], output[4], -cospi[36], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[52], output[6], cospi[12], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[12], output[6], -cospi[52], output[7], cosBit); |
|||
|
|||
// Stage 7 permutes the rotated values into AV1 coefficient order.
|
|||
output[0] = step[1]; |
|||
output[1] = step[6]; |
|||
output[2] = step[3]; |
|||
output[3] = step[4]; |
|||
output[4] = step[5]; |
|||
output[5] = step[2]; |
|||
output[6] = step[7]; |
|||
output[7] = step[0]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 reorders and signs the inputs so the ADST can be expressed as symmetric butterflies.
|
|||
output[0] = input[0]; |
|||
output[1] = -input[7]; |
|||
output[2] = -input[3]; |
|||
output[3] = input[4]; |
|||
output[4] = -input[1]; |
|||
output[5] = input[6]; |
|||
output[6] = input[2]; |
|||
output[7] = -input[5]; |
|||
|
|||
// Stage 2 rotates the middle pairs by pi/4.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
|
|||
// Stage 3 combines adjacent rotated pairs into four-sample butterflies.
|
|||
output[0] = step[0] + step[2]; |
|||
output[1] = step[1] + step[3]; |
|||
output[2] = step[0] - step[2]; |
|||
output[3] = step[1] - step[3]; |
|||
output[4] = step[4] + step[6]; |
|||
output[5] = step[5] + step[7]; |
|||
output[6] = step[4] - step[6]; |
|||
output[7] = step[5] - step[7]; |
|||
|
|||
// Stage 4 rotates the upper half by pi/8 and 3pi/8.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
|
|||
// Stage 5 merges both four-sample halves into the complete eight-sample butterfly.
|
|||
output[0] = step[0] + step[4]; |
|||
output[1] = step[1] + step[5]; |
|||
output[2] = step[2] + step[6]; |
|||
output[3] = step[3] + step[7]; |
|||
output[4] = step[0] - step[4]; |
|||
output[5] = step[1] - step[5]; |
|||
output[6] = step[2] - step[6]; |
|||
output[7] = step[3] - step[7]; |
|||
|
|||
// Stage 6 applies the terminal odd-frequency rotations that define the ADST basis vectors.
|
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[4], output[0], cospi[60], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[60], output[0], -cospi[4], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[20], output[2], cospi[44], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[44], output[2], -cospi[20], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[36], output[4], cospi[28], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[28], output[4], -cospi[36], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[52], output[6], cospi[12], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[12], output[6], -cospi[52], output[7], cosBit); |
|||
|
|||
// Stage 7 permutes the rotated values into AV1 coefficient order.
|
|||
output[0] = step[1]; |
|||
output[1] = step[6]; |
|||
output[2] = step[3]; |
|||
output[3] = step[4]; |
|||
output[4] = step[5]; |
|||
output[5] = step[2]; |
|||
output[6] = step[7]; |
|||
output[7] = step[0]; |
|||
} |
|||
} |
|||
@ -1,446 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the sixteen-point forward DCT operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Dct16Forward1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
output[0] = input[0] + input[15]; |
|||
output[1] = input[1] + input[14]; |
|||
output[2] = input[2] + input[13]; |
|||
output[3] = input[3] + input[12]; |
|||
output[4] = input[4] + input[11]; |
|||
output[5] = input[5] + input[10]; |
|||
output[6] = input[6] + input[9]; |
|||
output[7] = input[7] + input[8]; |
|||
output[8] = -input[8] + input[7]; |
|||
output[9] = -input[9] + input[6]; |
|||
output[10] = -input[10] + input[5]; |
|||
output[11] = -input[11] + input[4]; |
|||
output[12] = -input[12] + input[3]; |
|||
output[13] = -input[13] + input[2]; |
|||
output[14] = -input[14] + input[1]; |
|||
output[15] = -input[15] + input[0]; |
|||
|
|||
// Stage 2 factorizes the even half and rotates the central odd pairs by pi/4.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0] + output[7]; |
|||
step[1] = output[1] + output[6]; |
|||
step[2] = output[2] + output[5]; |
|||
step[3] = output[3] + output[4]; |
|||
step[4] = -output[4] + output[3]; |
|||
step[5] = -output[5] + output[2]; |
|||
step[6] = -output[6] + output[1]; |
|||
step[7] = -output[7] + output[0]; |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[10], cospi[32], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[11], cospi[32], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[32], output[12], cospi[32], output[11], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[32], output[13], cospi[32], output[10], cosBit); |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 3 recursively factorizes both eight-sample groups into four-sample butterflies.
|
|||
output[0] = step[0] + step[3]; |
|||
output[1] = step[1] + step[2]; |
|||
output[2] = -step[2] + step[1]; |
|||
output[3] = -step[3] + step[0]; |
|||
output[4] = step[4]; |
|||
output[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[5], cospi[32], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[32], step[6], cospi[32], step[5], cosBit); |
|||
output[7] = step[7]; |
|||
output[8] = step[8] + step[11]; |
|||
output[9] = step[9] + step[10]; |
|||
output[10] = -step[10] + step[9]; |
|||
output[11] = -step[11] + step[8]; |
|||
output[12] = -step[12] + step[15]; |
|||
output[13] = -step[13] + step[14]; |
|||
output[14] = step[14] + step[13]; |
|||
output[15] = step[15] + step[12]; |
|||
|
|||
// Stage 4 completes the low-frequency four-point DCT and rotates the first odd-frequency pairs.
|
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[1], cospi[32], output[0], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[48], output[3], -cospi[16], output[2], cosBit); |
|||
step[4] = output[4] + output[5]; |
|||
step[5] = -output[5] + output[4]; |
|||
step[6] = -output[6] + output[7]; |
|||
step[7] = output[7] + output[6]; |
|||
step[8] = output[8]; |
|||
step[9] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[9], cospi[48], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[10], -cospi[16], output[13], cosBit); |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[48], output[13], -cospi[16], output[10], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[16], output[14], cospi[48], output[9], cosBit); |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 5 combines the remaining odd terms into the sign pattern required by the next rotations.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = Av1Transform1dMath.HalfButterfly(cospi[56], step[4], cospi[8], step[7], cosBit); |
|||
output[5] = Av1Transform1dMath.HalfButterfly(cospi[24], step[5], cospi[40], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[24], step[6], -cospi[40], step[5], cosBit); |
|||
output[7] = Av1Transform1dMath.HalfButterfly(cospi[56], step[7], -cospi[8], step[4], cosBit); |
|||
output[8] = step[8] + step[9]; |
|||
output[9] = -step[9] + step[8]; |
|||
output[10] = -step[10] + step[11]; |
|||
output[11] = step[11] + step[10]; |
|||
output[12] = step[12] + step[13]; |
|||
output[13] = -step[13] + step[12]; |
|||
output[14] = -step[14] + step[15]; |
|||
output[15] = step[15] + step[14]; |
|||
|
|||
// Stage 6 applies the final pi/32 odd-frequency rotations.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[60], output[8], cospi[4], output[15], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[28], output[9], cospi[36], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[44], output[10], cospi[20], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[12], output[11], cospi[52], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[12], output[12], -cospi[52], output[11], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[44], output[13], -cospi[20], output[10], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[28], output[14], -cospi[36], output[9], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[60], output[15], -cospi[4], output[8], cosBit); |
|||
|
|||
// Stage 7 permutes the staged values into ascending AV1 coefficient order.
|
|||
output[0] = step[0]; |
|||
output[1] = step[8]; |
|||
output[2] = step[4]; |
|||
output[3] = step[12]; |
|||
output[4] = step[2]; |
|||
output[5] = step[10]; |
|||
output[6] = step[6]; |
|||
output[7] = step[14]; |
|||
output[8] = step[1]; |
|||
output[9] = step[9]; |
|||
output[10] = step[5]; |
|||
output[11] = step[13]; |
|||
output[12] = step[3]; |
|||
output[13] = step[11]; |
|||
output[14] = step[7]; |
|||
output[15] = step[15]; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
output[0] = input[0] + input[15]; |
|||
output[1] = input[1] + input[14]; |
|||
output[2] = input[2] + input[13]; |
|||
output[3] = input[3] + input[12]; |
|||
output[4] = input[4] + input[11]; |
|||
output[5] = input[5] + input[10]; |
|||
output[6] = input[6] + input[9]; |
|||
output[7] = input[7] + input[8]; |
|||
output[8] = -input[8] + input[7]; |
|||
output[9] = -input[9] + input[6]; |
|||
output[10] = -input[10] + input[5]; |
|||
output[11] = -input[11] + input[4]; |
|||
output[12] = -input[12] + input[3]; |
|||
output[13] = -input[13] + input[2]; |
|||
output[14] = -input[14] + input[1]; |
|||
output[15] = -input[15] + input[0]; |
|||
|
|||
// Stage 2 factorizes the even half and rotates the central odd pairs by pi/4.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0] + output[7]; |
|||
step[1] = output[1] + output[6]; |
|||
step[2] = output[2] + output[5]; |
|||
step[3] = output[3] + output[4]; |
|||
step[4] = -output[4] + output[3]; |
|||
step[5] = -output[5] + output[2]; |
|||
step[6] = -output[6] + output[1]; |
|||
step[7] = -output[7] + output[0]; |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[10], cospi[32], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[11], cospi[32], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[32], output[12], cospi[32], output[11], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[32], output[13], cospi[32], output[10], cosBit); |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 3 recursively factorizes both eight-sample groups into four-sample butterflies.
|
|||
output[0] = step[0] + step[3]; |
|||
output[1] = step[1] + step[2]; |
|||
output[2] = -step[2] + step[1]; |
|||
output[3] = -step[3] + step[0]; |
|||
output[4] = step[4]; |
|||
output[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[5], cospi[32], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[32], step[6], cospi[32], step[5], cosBit); |
|||
output[7] = step[7]; |
|||
output[8] = step[8] + step[11]; |
|||
output[9] = step[9] + step[10]; |
|||
output[10] = -step[10] + step[9]; |
|||
output[11] = -step[11] + step[8]; |
|||
output[12] = -step[12] + step[15]; |
|||
output[13] = -step[13] + step[14]; |
|||
output[14] = step[14] + step[13]; |
|||
output[15] = step[15] + step[12]; |
|||
|
|||
// Stage 4 completes the low-frequency four-point DCT and rotates the first odd-frequency pairs.
|
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[1], cospi[32], output[0], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[48], output[3], -cospi[16], output[2], cosBit); |
|||
step[4] = output[4] + output[5]; |
|||
step[5] = -output[5] + output[4]; |
|||
step[6] = -output[6] + output[7]; |
|||
step[7] = output[7] + output[6]; |
|||
step[8] = output[8]; |
|||
step[9] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[9], cospi[48], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[10], -cospi[16], output[13], cosBit); |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[48], output[13], -cospi[16], output[10], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[16], output[14], cospi[48], output[9], cosBit); |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 5 combines the remaining odd terms into the sign pattern required by the next rotations.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = Av1Transform1dMath.HalfButterfly(cospi[56], step[4], cospi[8], step[7], cosBit); |
|||
output[5] = Av1Transform1dMath.HalfButterfly(cospi[24], step[5], cospi[40], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[24], step[6], -cospi[40], step[5], cosBit); |
|||
output[7] = Av1Transform1dMath.HalfButterfly(cospi[56], step[7], -cospi[8], step[4], cosBit); |
|||
output[8] = step[8] + step[9]; |
|||
output[9] = -step[9] + step[8]; |
|||
output[10] = -step[10] + step[11]; |
|||
output[11] = step[11] + step[10]; |
|||
output[12] = step[12] + step[13]; |
|||
output[13] = -step[13] + step[12]; |
|||
output[14] = -step[14] + step[15]; |
|||
output[15] = step[15] + step[14]; |
|||
|
|||
// Stage 6 applies the final pi/32 odd-frequency rotations.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[60], output[8], cospi[4], output[15], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[28], output[9], cospi[36], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[44], output[10], cospi[20], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[12], output[11], cospi[52], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[12], output[12], -cospi[52], output[11], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[44], output[13], -cospi[20], output[10], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[28], output[14], -cospi[36], output[9], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[60], output[15], -cospi[4], output[8], cosBit); |
|||
|
|||
// Stage 7 permutes the staged values into ascending AV1 coefficient order.
|
|||
output[0] = step[0]; |
|||
output[1] = step[8]; |
|||
output[2] = step[4]; |
|||
output[3] = step[12]; |
|||
output[4] = step[2]; |
|||
output[5] = step[10]; |
|||
output[6] = step[6]; |
|||
output[7] = step[14]; |
|||
output[8] = step[1]; |
|||
output[9] = step[9]; |
|||
output[10] = step[5]; |
|||
output[11] = step[13]; |
|||
output[12] = step[3]; |
|||
output[13] = step[11]; |
|||
output[14] = step[7]; |
|||
output[15] = step[15]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
output[0] = input[0] + input[15]; |
|||
output[1] = input[1] + input[14]; |
|||
output[2] = input[2] + input[13]; |
|||
output[3] = input[3] + input[12]; |
|||
output[4] = input[4] + input[11]; |
|||
output[5] = input[5] + input[10]; |
|||
output[6] = input[6] + input[9]; |
|||
output[7] = input[7] + input[8]; |
|||
output[8] = -input[8] + input[7]; |
|||
output[9] = -input[9] + input[6]; |
|||
output[10] = -input[10] + input[5]; |
|||
output[11] = -input[11] + input[4]; |
|||
output[12] = -input[12] + input[3]; |
|||
output[13] = -input[13] + input[2]; |
|||
output[14] = -input[14] + input[1]; |
|||
output[15] = -input[15] + input[0]; |
|||
|
|||
// Stage 2 factorizes the even half and rotates the central odd pairs by pi/4.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0] + output[7]; |
|||
step[1] = output[1] + output[6]; |
|||
step[2] = output[2] + output[5]; |
|||
step[3] = output[3] + output[4]; |
|||
step[4] = -output[4] + output[3]; |
|||
step[5] = -output[5] + output[2]; |
|||
step[6] = -output[6] + output[1]; |
|||
step[7] = -output[7] + output[0]; |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[10], cospi[32], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[11], cospi[32], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[32], output[12], cospi[32], output[11], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[32], output[13], cospi[32], output[10], cosBit); |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 3 recursively factorizes both eight-sample groups into four-sample butterflies.
|
|||
output[0] = step[0] + step[3]; |
|||
output[1] = step[1] + step[2]; |
|||
output[2] = -step[2] + step[1]; |
|||
output[3] = -step[3] + step[0]; |
|||
output[4] = step[4]; |
|||
output[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[5], cospi[32], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[32], step[6], cospi[32], step[5], cosBit); |
|||
output[7] = step[7]; |
|||
output[8] = step[8] + step[11]; |
|||
output[9] = step[9] + step[10]; |
|||
output[10] = -step[10] + step[9]; |
|||
output[11] = -step[11] + step[8]; |
|||
output[12] = -step[12] + step[15]; |
|||
output[13] = -step[13] + step[14]; |
|||
output[14] = step[14] + step[13]; |
|||
output[15] = step[15] + step[12]; |
|||
|
|||
// Stage 4 completes the low-frequency four-point DCT and rotates the first odd-frequency pairs.
|
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[1], cospi[32], output[0], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[48], output[3], -cospi[16], output[2], cosBit); |
|||
step[4] = output[4] + output[5]; |
|||
step[5] = -output[5] + output[4]; |
|||
step[6] = -output[6] + output[7]; |
|||
step[7] = output[7] + output[6]; |
|||
step[8] = output[8]; |
|||
step[9] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[9], cospi[48], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[10], -cospi[16], output[13], cosBit); |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[48], output[13], -cospi[16], output[10], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[16], output[14], cospi[48], output[9], cosBit); |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 5 combines the remaining odd terms into the sign pattern required by the next rotations.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = Av1Transform1dMath.HalfButterfly(cospi[56], step[4], cospi[8], step[7], cosBit); |
|||
output[5] = Av1Transform1dMath.HalfButterfly(cospi[24], step[5], cospi[40], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[24], step[6], -cospi[40], step[5], cosBit); |
|||
output[7] = Av1Transform1dMath.HalfButterfly(cospi[56], step[7], -cospi[8], step[4], cosBit); |
|||
output[8] = step[8] + step[9]; |
|||
output[9] = -step[9] + step[8]; |
|||
output[10] = -step[10] + step[11]; |
|||
output[11] = step[11] + step[10]; |
|||
output[12] = step[12] + step[13]; |
|||
output[13] = -step[13] + step[12]; |
|||
output[14] = -step[14] + step[15]; |
|||
output[15] = step[15] + step[14]; |
|||
|
|||
// Stage 6 applies the final pi/32 odd-frequency rotations.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[60], output[8], cospi[4], output[15], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[28], output[9], cospi[36], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[44], output[10], cospi[20], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[12], output[11], cospi[52], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[12], output[12], -cospi[52], output[11], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[44], output[13], -cospi[20], output[10], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[28], output[14], -cospi[36], output[9], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[60], output[15], -cospi[4], output[8], cosBit); |
|||
|
|||
// Stage 7 permutes the staged values into ascending AV1 coefficient order.
|
|||
output[0] = step[0]; |
|||
output[1] = step[8]; |
|||
output[2] = step[4]; |
|||
output[3] = step[12]; |
|||
output[4] = step[2]; |
|||
output[5] = step[10]; |
|||
output[6] = step[6]; |
|||
output[7] = step[14]; |
|||
output[8] = step[1]; |
|||
output[9] = step[9]; |
|||
output[10] = step[5]; |
|||
output[11] = step[13]; |
|||
output[12] = step[3]; |
|||
output[13] = step[11]; |
|||
output[14] = step[7]; |
|||
output[15] = step[15]; |
|||
} |
|||
} |
|||
@ -1,986 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the thirty-two-point forward DCT operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Dct32Forward1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
output[0] = input[0] + input[31]; |
|||
output[1] = input[1] + input[30]; |
|||
output[2] = input[2] + input[29]; |
|||
output[3] = input[3] + input[28]; |
|||
output[4] = input[4] + input[27]; |
|||
output[5] = input[5] + input[26]; |
|||
output[6] = input[6] + input[25]; |
|||
output[7] = input[7] + input[24]; |
|||
output[8] = input[8] + input[23]; |
|||
output[9] = input[9] + input[22]; |
|||
output[10] = input[10] + input[21]; |
|||
output[11] = input[11] + input[20]; |
|||
output[12] = input[12] + input[19]; |
|||
output[13] = input[13] + input[18]; |
|||
output[14] = input[14] + input[17]; |
|||
output[15] = input[15] + input[16]; |
|||
output[16] = -input[16] + input[15]; |
|||
output[17] = -input[17] + input[14]; |
|||
output[18] = -input[18] + input[13]; |
|||
output[19] = -input[19] + input[12]; |
|||
output[20] = -input[20] + input[11]; |
|||
output[21] = -input[21] + input[10]; |
|||
output[22] = -input[22] + input[9]; |
|||
output[23] = -input[23] + input[8]; |
|||
output[24] = -input[24] + input[7]; |
|||
output[25] = -input[25] + input[6]; |
|||
output[26] = -input[26] + input[5]; |
|||
output[27] = -input[27] + input[4]; |
|||
output[28] = -input[28] + input[3]; |
|||
output[29] = -input[29] + input[2]; |
|||
output[30] = -input[30] + input[1]; |
|||
output[31] = -input[31] + input[0]; |
|||
|
|||
// Stage 2 begins the recursive radix-2 factorization and rotates the central odd pairs.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0] + output[15]; |
|||
step[1] = output[1] + output[14]; |
|||
step[2] = output[2] + output[13]; |
|||
step[3] = output[3] + output[12]; |
|||
step[4] = output[4] + output[11]; |
|||
step[5] = output[5] + output[10]; |
|||
step[6] = output[6] + output[9]; |
|||
step[7] = output[7] + output[8]; |
|||
step[8] = -output[8] + output[7]; |
|||
step[9] = -output[9] + output[6]; |
|||
step[10] = -output[10] + output[5]; |
|||
step[11] = -output[11] + output[4]; |
|||
step[12] = -output[12] + output[3]; |
|||
step[13] = -output[13] + output[2]; |
|||
step[14] = -output[14] + output[1]; |
|||
step[15] = -output[15] + output[0]; |
|||
step[16] = output[16]; |
|||
step[17] = output[17]; |
|||
step[18] = output[18]; |
|||
step[19] = output[19]; |
|||
step[20] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[20], cospi[32], output[27], cosBit); |
|||
step[21] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[21], cospi[32], output[26], cosBit); |
|||
step[22] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[22], cospi[32], output[25], cosBit); |
|||
step[23] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[23], cospi[32], output[24], cosBit); |
|||
step[24] = Av1Transform1dMath.HalfButterfly(cospi[32], output[24], cospi[32], output[23], cosBit); |
|||
step[25] = Av1Transform1dMath.HalfButterfly(cospi[32], output[25], cospi[32], output[22], cosBit); |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[32], output[26], cospi[32], output[21], cosBit); |
|||
step[27] = Av1Transform1dMath.HalfButterfly(cospi[32], output[27], cospi[32], output[20], cosBit); |
|||
step[28] = output[28]; |
|||
step[29] = output[29]; |
|||
step[30] = output[30]; |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 3 reduces the even half and folds the next odd-frequency groups into butterflies.
|
|||
output[0] = step[0] + step[7]; |
|||
output[1] = step[1] + step[6]; |
|||
output[2] = step[2] + step[5]; |
|||
output[3] = step[3] + step[4]; |
|||
output[4] = -step[4] + step[3]; |
|||
output[5] = -step[5] + step[2]; |
|||
output[6] = -step[6] + step[1]; |
|||
output[7] = -step[7] + step[0]; |
|||
output[8] = step[8]; |
|||
output[9] = step[9]; |
|||
output[10] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[10], cospi[32], step[13], cosBit); |
|||
output[11] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[11], cospi[32], step[12], cosBit); |
|||
output[12] = Av1Transform1dMath.HalfButterfly(cospi[32], step[12], cospi[32], step[11], cosBit); |
|||
output[13] = Av1Transform1dMath.HalfButterfly(cospi[32], step[13], cospi[32], step[10], cosBit); |
|||
output[14] = step[14]; |
|||
output[15] = step[15]; |
|||
output[16] = step[16] + step[23]; |
|||
output[17] = step[17] + step[22]; |
|||
output[18] = step[18] + step[21]; |
|||
output[19] = step[19] + step[20]; |
|||
output[20] = -step[20] + step[19]; |
|||
output[21] = -step[21] + step[18]; |
|||
output[22] = -step[22] + step[17]; |
|||
output[23] = -step[23] + step[16]; |
|||
output[24] = -step[24] + step[31]; |
|||
output[25] = -step[25] + step[30]; |
|||
output[26] = -step[26] + step[29]; |
|||
output[27] = -step[27] + step[28]; |
|||
output[28] = step[28] + step[27]; |
|||
output[29] = step[29] + step[26]; |
|||
output[30] = step[30] + step[25]; |
|||
output[31] = step[31] + step[24]; |
|||
|
|||
// Stage 4 continues the factorization as independent eight-sample groups.
|
|||
step[0] = output[0] + output[3]; |
|||
step[1] = output[1] + output[2]; |
|||
step[2] = -output[2] + output[1]; |
|||
step[3] = -output[3] + output[0]; |
|||
step[4] = output[4]; |
|||
step[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[5], cosBit); |
|||
step[7] = output[7]; |
|||
step[8] = output[8] + output[11]; |
|||
step[9] = output[9] + output[10]; |
|||
step[10] = -output[10] + output[9]; |
|||
step[11] = -output[11] + output[8]; |
|||
step[12] = -output[12] + output[15]; |
|||
step[13] = -output[13] + output[14]; |
|||
step[14] = output[14] + output[13]; |
|||
step[15] = output[15] + output[12]; |
|||
step[16] = output[16]; |
|||
step[17] = output[17]; |
|||
step[18] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[18], cospi[48], output[29], cosBit); |
|||
step[19] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[19], cospi[48], output[28], cosBit); |
|||
step[20] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[20], -cospi[16], output[27], cosBit); |
|||
step[21] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[21], -cospi[16], output[26], cosBit); |
|||
step[22] = output[22]; |
|||
step[23] = output[23]; |
|||
step[24] = output[24]; |
|||
step[25] = output[25]; |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[48], output[26], -cospi[16], output[21], cosBit); |
|||
step[27] = Av1Transform1dMath.HalfButterfly(cospi[48], output[27], -cospi[16], output[20], cosBit); |
|||
step[28] = Av1Transform1dMath.HalfButterfly(cospi[16], output[28], cospi[48], output[19], cosBit); |
|||
step[29] = Av1Transform1dMath.HalfButterfly(cospi[16], output[29], cospi[48], output[18], cosBit); |
|||
step[30] = output[30]; |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 5 completes the low-frequency DCT and rotates the first separated odd groups.
|
|||
output[0] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], cospi[32], step[1], cosBit); |
|||
output[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[1], cospi[32], step[0], cosBit); |
|||
output[2] = Av1Transform1dMath.HalfButterfly(cospi[48], step[2], cospi[16], step[3], cosBit); |
|||
output[3] = Av1Transform1dMath.HalfButterfly(cospi[48], step[3], -cospi[16], step[2], cosBit); |
|||
output[4] = step[4] + step[5]; |
|||
output[5] = -step[5] + step[4]; |
|||
output[6] = -step[6] + step[7]; |
|||
output[7] = step[7] + step[6]; |
|||
output[8] = step[8]; |
|||
output[9] = Av1Transform1dMath.HalfButterfly(-cospi[16], step[9], cospi[48], step[14], cosBit); |
|||
output[10] = Av1Transform1dMath.HalfButterfly(-cospi[48], step[10], -cospi[16], step[13], cosBit); |
|||
output[11] = step[11]; |
|||
output[12] = step[12]; |
|||
output[13] = Av1Transform1dMath.HalfButterfly(cospi[48], step[13], -cospi[16], step[10], cosBit); |
|||
output[14] = Av1Transform1dMath.HalfButterfly(cospi[16], step[14], cospi[48], step[9], cosBit); |
|||
output[15] = step[15]; |
|||
output[16] = step[16] + step[19]; |
|||
output[17] = step[17] + step[18]; |
|||
output[18] = -step[18] + step[17]; |
|||
output[19] = -step[19] + step[16]; |
|||
output[20] = -step[20] + step[23]; |
|||
output[21] = -step[21] + step[22]; |
|||
output[22] = step[22] + step[21]; |
|||
output[23] = step[23] + step[20]; |
|||
output[24] = step[24] + step[27]; |
|||
output[25] = step[25] + step[26]; |
|||
output[26] = -step[26] + step[25]; |
|||
output[27] = -step[27] + step[24]; |
|||
output[28] = -step[28] + step[31]; |
|||
output[29] = -step[29] + step[30]; |
|||
output[30] = step[30] + step[29]; |
|||
output[31] = step[31] + step[28]; |
|||
|
|||
// Stage 6 merges adjacent odd-frequency terms with the required AV1 sign pattern.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[56], output[4], cospi[8], output[7], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[24], output[5], cospi[40], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[24], output[6], -cospi[40], output[5], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[56], output[7], -cospi[8], output[4], cosBit); |
|||
step[8] = output[8] + output[9]; |
|||
step[9] = -output[9] + output[8]; |
|||
step[10] = -output[10] + output[11]; |
|||
step[11] = output[11] + output[10]; |
|||
step[12] = output[12] + output[13]; |
|||
step[13] = -output[13] + output[12]; |
|||
step[14] = -output[14] + output[15]; |
|||
step[15] = output[15] + output[14]; |
|||
step[16] = output[16]; |
|||
step[17] = Av1Transform1dMath.HalfButterfly(-cospi[8], output[17], cospi[56], output[30], cosBit); |
|||
step[18] = Av1Transform1dMath.HalfButterfly(-cospi[56], output[18], -cospi[8], output[29], cosBit); |
|||
step[19] = output[19]; |
|||
step[20] = output[20]; |
|||
step[21] = Av1Transform1dMath.HalfButterfly(-cospi[40], output[21], cospi[24], output[26], cosBit); |
|||
step[22] = Av1Transform1dMath.HalfButterfly(-cospi[24], output[22], -cospi[40], output[25], cosBit); |
|||
step[23] = output[23]; |
|||
step[24] = output[24]; |
|||
step[25] = Av1Transform1dMath.HalfButterfly(cospi[24], output[25], -cospi[40], output[22], cosBit); |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[40], output[26], cospi[24], output[21], cosBit); |
|||
step[27] = output[27]; |
|||
step[28] = output[28]; |
|||
step[29] = Av1Transform1dMath.HalfButterfly(cospi[56], output[29], -cospi[8], output[18], cosBit); |
|||
step[30] = Av1Transform1dMath.HalfButterfly(cospi[8], output[30], cospi[56], output[17], cosBit); |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 7 applies the pi/32 rotations to the next odd-frequency level.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = step[4]; |
|||
output[5] = step[5]; |
|||
output[6] = step[6]; |
|||
output[7] = step[7]; |
|||
output[8] = Av1Transform1dMath.HalfButterfly(cospi[60], step[8], cospi[4], step[15], cosBit); |
|||
output[9] = Av1Transform1dMath.HalfButterfly(cospi[28], step[9], cospi[36], step[14], cosBit); |
|||
output[10] = Av1Transform1dMath.HalfButterfly(cospi[44], step[10], cospi[20], step[13], cosBit); |
|||
output[11] = Av1Transform1dMath.HalfButterfly(cospi[12], step[11], cospi[52], step[12], cosBit); |
|||
output[12] = Av1Transform1dMath.HalfButterfly(cospi[12], step[12], -cospi[52], step[11], cosBit); |
|||
output[13] = Av1Transform1dMath.HalfButterfly(cospi[44], step[13], -cospi[20], step[10], cosBit); |
|||
output[14] = Av1Transform1dMath.HalfButterfly(cospi[28], step[14], -cospi[36], step[9], cosBit); |
|||
output[15] = Av1Transform1dMath.HalfButterfly(cospi[60], step[15], -cospi[4], step[8], cosBit); |
|||
output[16] = step[16] + step[17]; |
|||
output[17] = -step[17] + step[16]; |
|||
output[18] = -step[18] + step[19]; |
|||
output[19] = step[19] + step[18]; |
|||
output[20] = step[20] + step[21]; |
|||
output[21] = -step[21] + step[20]; |
|||
output[22] = -step[22] + step[23]; |
|||
output[23] = step[23] + step[22]; |
|||
output[24] = step[24] + step[25]; |
|||
output[25] = -step[25] + step[24]; |
|||
output[26] = -step[26] + step[27]; |
|||
output[27] = step[27] + step[26]; |
|||
output[28] = step[28] + step[29]; |
|||
output[29] = -step[29] + step[28]; |
|||
output[30] = -step[30] + step[31]; |
|||
output[31] = step[31] + step[30]; |
|||
|
|||
// Stage 8 merges the final odd-frequency pairs before their terminal rotations.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
step[16] = Av1Transform1dMath.HalfButterfly(cospi[62], output[16], cospi[2], output[31], cosBit); |
|||
step[17] = Av1Transform1dMath.HalfButterfly(cospi[30], output[17], cospi[34], output[30], cosBit); |
|||
step[18] = Av1Transform1dMath.HalfButterfly(cospi[46], output[18], cospi[18], output[29], cosBit); |
|||
step[19] = Av1Transform1dMath.HalfButterfly(cospi[14], output[19], cospi[50], output[28], cosBit); |
|||
step[20] = Av1Transform1dMath.HalfButterfly(cospi[54], output[20], cospi[10], output[27], cosBit); |
|||
step[21] = Av1Transform1dMath.HalfButterfly(cospi[22], output[21], cospi[42], output[26], cosBit); |
|||
step[22] = Av1Transform1dMath.HalfButterfly(cospi[38], output[22], cospi[26], output[25], cosBit); |
|||
step[23] = Av1Transform1dMath.HalfButterfly(cospi[6], output[23], cospi[58], output[24], cosBit); |
|||
step[24] = Av1Transform1dMath.HalfButterfly(cospi[6], output[24], -cospi[58], output[23], cosBit); |
|||
step[25] = Av1Transform1dMath.HalfButterfly(cospi[38], output[25], -cospi[26], output[22], cosBit); |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[22], output[26], -cospi[42], output[21], cosBit); |
|||
step[27] = Av1Transform1dMath.HalfButterfly(cospi[54], output[27], -cospi[10], output[20], cosBit); |
|||
step[28] = Av1Transform1dMath.HalfButterfly(cospi[14], output[28], -cospi[50], output[19], cosBit); |
|||
step[29] = Av1Transform1dMath.HalfButterfly(cospi[46], output[29], -cospi[18], output[18], cosBit); |
|||
step[30] = Av1Transform1dMath.HalfButterfly(cospi[30], output[30], -cospi[34], output[17], cosBit); |
|||
step[31] = Av1Transform1dMath.HalfButterfly(cospi[62], output[31], -cospi[2], output[16], cosBit); |
|||
|
|||
// Stage 9 applies the terminal pi/64 rotations and produces the staged coefficient values.
|
|||
output[0] = step[0]; |
|||
output[1] = step[16]; |
|||
output[2] = step[8]; |
|||
output[3] = step[24]; |
|||
output[4] = step[4]; |
|||
output[5] = step[20]; |
|||
output[6] = step[12]; |
|||
output[7] = step[28]; |
|||
output[8] = step[2]; |
|||
output[9] = step[18]; |
|||
output[10] = step[10]; |
|||
output[11] = step[26]; |
|||
output[12] = step[6]; |
|||
output[13] = step[22]; |
|||
output[14] = step[14]; |
|||
output[15] = step[30]; |
|||
output[16] = step[1]; |
|||
output[17] = step[17]; |
|||
output[18] = step[9]; |
|||
output[19] = step[25]; |
|||
output[20] = step[5]; |
|||
output[21] = step[21]; |
|||
output[22] = step[13]; |
|||
output[23] = step[29]; |
|||
output[24] = step[3]; |
|||
output[25] = step[19]; |
|||
output[26] = step[11]; |
|||
output[27] = step[27]; |
|||
output[28] = step[7]; |
|||
output[29] = step[23]; |
|||
output[30] = step[15]; |
|||
output[31] = step[31]; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
output[0] = input[0] + input[31]; |
|||
output[1] = input[1] + input[30]; |
|||
output[2] = input[2] + input[29]; |
|||
output[3] = input[3] + input[28]; |
|||
output[4] = input[4] + input[27]; |
|||
output[5] = input[5] + input[26]; |
|||
output[6] = input[6] + input[25]; |
|||
output[7] = input[7] + input[24]; |
|||
output[8] = input[8] + input[23]; |
|||
output[9] = input[9] + input[22]; |
|||
output[10] = input[10] + input[21]; |
|||
output[11] = input[11] + input[20]; |
|||
output[12] = input[12] + input[19]; |
|||
output[13] = input[13] + input[18]; |
|||
output[14] = input[14] + input[17]; |
|||
output[15] = input[15] + input[16]; |
|||
output[16] = -input[16] + input[15]; |
|||
output[17] = -input[17] + input[14]; |
|||
output[18] = -input[18] + input[13]; |
|||
output[19] = -input[19] + input[12]; |
|||
output[20] = -input[20] + input[11]; |
|||
output[21] = -input[21] + input[10]; |
|||
output[22] = -input[22] + input[9]; |
|||
output[23] = -input[23] + input[8]; |
|||
output[24] = -input[24] + input[7]; |
|||
output[25] = -input[25] + input[6]; |
|||
output[26] = -input[26] + input[5]; |
|||
output[27] = -input[27] + input[4]; |
|||
output[28] = -input[28] + input[3]; |
|||
output[29] = -input[29] + input[2]; |
|||
output[30] = -input[30] + input[1]; |
|||
output[31] = -input[31] + input[0]; |
|||
|
|||
// Stage 2 begins the recursive radix-2 factorization and rotates the central odd pairs.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0] + output[15]; |
|||
step[1] = output[1] + output[14]; |
|||
step[2] = output[2] + output[13]; |
|||
step[3] = output[3] + output[12]; |
|||
step[4] = output[4] + output[11]; |
|||
step[5] = output[5] + output[10]; |
|||
step[6] = output[6] + output[9]; |
|||
step[7] = output[7] + output[8]; |
|||
step[8] = -output[8] + output[7]; |
|||
step[9] = -output[9] + output[6]; |
|||
step[10] = -output[10] + output[5]; |
|||
step[11] = -output[11] + output[4]; |
|||
step[12] = -output[12] + output[3]; |
|||
step[13] = -output[13] + output[2]; |
|||
step[14] = -output[14] + output[1]; |
|||
step[15] = -output[15] + output[0]; |
|||
step[16] = output[16]; |
|||
step[17] = output[17]; |
|||
step[18] = output[18]; |
|||
step[19] = output[19]; |
|||
step[20] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[20], cospi[32], output[27], cosBit); |
|||
step[21] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[21], cospi[32], output[26], cosBit); |
|||
step[22] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[22], cospi[32], output[25], cosBit); |
|||
step[23] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[23], cospi[32], output[24], cosBit); |
|||
step[24] = Av1Transform1dMath.HalfButterfly(cospi[32], output[24], cospi[32], output[23], cosBit); |
|||
step[25] = Av1Transform1dMath.HalfButterfly(cospi[32], output[25], cospi[32], output[22], cosBit); |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[32], output[26], cospi[32], output[21], cosBit); |
|||
step[27] = Av1Transform1dMath.HalfButterfly(cospi[32], output[27], cospi[32], output[20], cosBit); |
|||
step[28] = output[28]; |
|||
step[29] = output[29]; |
|||
step[30] = output[30]; |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 3 reduces the even half and folds the next odd-frequency groups into butterflies.
|
|||
output[0] = step[0] + step[7]; |
|||
output[1] = step[1] + step[6]; |
|||
output[2] = step[2] + step[5]; |
|||
output[3] = step[3] + step[4]; |
|||
output[4] = -step[4] + step[3]; |
|||
output[5] = -step[5] + step[2]; |
|||
output[6] = -step[6] + step[1]; |
|||
output[7] = -step[7] + step[0]; |
|||
output[8] = step[8]; |
|||
output[9] = step[9]; |
|||
output[10] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[10], cospi[32], step[13], cosBit); |
|||
output[11] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[11], cospi[32], step[12], cosBit); |
|||
output[12] = Av1Transform1dMath.HalfButterfly(cospi[32], step[12], cospi[32], step[11], cosBit); |
|||
output[13] = Av1Transform1dMath.HalfButterfly(cospi[32], step[13], cospi[32], step[10], cosBit); |
|||
output[14] = step[14]; |
|||
output[15] = step[15]; |
|||
output[16] = step[16] + step[23]; |
|||
output[17] = step[17] + step[22]; |
|||
output[18] = step[18] + step[21]; |
|||
output[19] = step[19] + step[20]; |
|||
output[20] = -step[20] + step[19]; |
|||
output[21] = -step[21] + step[18]; |
|||
output[22] = -step[22] + step[17]; |
|||
output[23] = -step[23] + step[16]; |
|||
output[24] = -step[24] + step[31]; |
|||
output[25] = -step[25] + step[30]; |
|||
output[26] = -step[26] + step[29]; |
|||
output[27] = -step[27] + step[28]; |
|||
output[28] = step[28] + step[27]; |
|||
output[29] = step[29] + step[26]; |
|||
output[30] = step[30] + step[25]; |
|||
output[31] = step[31] + step[24]; |
|||
|
|||
// Stage 4 continues the factorization as independent eight-sample groups.
|
|||
step[0] = output[0] + output[3]; |
|||
step[1] = output[1] + output[2]; |
|||
step[2] = -output[2] + output[1]; |
|||
step[3] = -output[3] + output[0]; |
|||
step[4] = output[4]; |
|||
step[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[5], cosBit); |
|||
step[7] = output[7]; |
|||
step[8] = output[8] + output[11]; |
|||
step[9] = output[9] + output[10]; |
|||
step[10] = -output[10] + output[9]; |
|||
step[11] = -output[11] + output[8]; |
|||
step[12] = -output[12] + output[15]; |
|||
step[13] = -output[13] + output[14]; |
|||
step[14] = output[14] + output[13]; |
|||
step[15] = output[15] + output[12]; |
|||
step[16] = output[16]; |
|||
step[17] = output[17]; |
|||
step[18] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[18], cospi[48], output[29], cosBit); |
|||
step[19] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[19], cospi[48], output[28], cosBit); |
|||
step[20] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[20], -cospi[16], output[27], cosBit); |
|||
step[21] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[21], -cospi[16], output[26], cosBit); |
|||
step[22] = output[22]; |
|||
step[23] = output[23]; |
|||
step[24] = output[24]; |
|||
step[25] = output[25]; |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[48], output[26], -cospi[16], output[21], cosBit); |
|||
step[27] = Av1Transform1dMath.HalfButterfly(cospi[48], output[27], -cospi[16], output[20], cosBit); |
|||
step[28] = Av1Transform1dMath.HalfButterfly(cospi[16], output[28], cospi[48], output[19], cosBit); |
|||
step[29] = Av1Transform1dMath.HalfButterfly(cospi[16], output[29], cospi[48], output[18], cosBit); |
|||
step[30] = output[30]; |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 5 completes the low-frequency DCT and rotates the first separated odd groups.
|
|||
output[0] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], cospi[32], step[1], cosBit); |
|||
output[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[1], cospi[32], step[0], cosBit); |
|||
output[2] = Av1Transform1dMath.HalfButterfly(cospi[48], step[2], cospi[16], step[3], cosBit); |
|||
output[3] = Av1Transform1dMath.HalfButterfly(cospi[48], step[3], -cospi[16], step[2], cosBit); |
|||
output[4] = step[4] + step[5]; |
|||
output[5] = -step[5] + step[4]; |
|||
output[6] = -step[6] + step[7]; |
|||
output[7] = step[7] + step[6]; |
|||
output[8] = step[8]; |
|||
output[9] = Av1Transform1dMath.HalfButterfly(-cospi[16], step[9], cospi[48], step[14], cosBit); |
|||
output[10] = Av1Transform1dMath.HalfButterfly(-cospi[48], step[10], -cospi[16], step[13], cosBit); |
|||
output[11] = step[11]; |
|||
output[12] = step[12]; |
|||
output[13] = Av1Transform1dMath.HalfButterfly(cospi[48], step[13], -cospi[16], step[10], cosBit); |
|||
output[14] = Av1Transform1dMath.HalfButterfly(cospi[16], step[14], cospi[48], step[9], cosBit); |
|||
output[15] = step[15]; |
|||
output[16] = step[16] + step[19]; |
|||
output[17] = step[17] + step[18]; |
|||
output[18] = -step[18] + step[17]; |
|||
output[19] = -step[19] + step[16]; |
|||
output[20] = -step[20] + step[23]; |
|||
output[21] = -step[21] + step[22]; |
|||
output[22] = step[22] + step[21]; |
|||
output[23] = step[23] + step[20]; |
|||
output[24] = step[24] + step[27]; |
|||
output[25] = step[25] + step[26]; |
|||
output[26] = -step[26] + step[25]; |
|||
output[27] = -step[27] + step[24]; |
|||
output[28] = -step[28] + step[31]; |
|||
output[29] = -step[29] + step[30]; |
|||
output[30] = step[30] + step[29]; |
|||
output[31] = step[31] + step[28]; |
|||
|
|||
// Stage 6 merges adjacent odd-frequency terms with the required AV1 sign pattern.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[56], output[4], cospi[8], output[7], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[24], output[5], cospi[40], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[24], output[6], -cospi[40], output[5], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[56], output[7], -cospi[8], output[4], cosBit); |
|||
step[8] = output[8] + output[9]; |
|||
step[9] = -output[9] + output[8]; |
|||
step[10] = -output[10] + output[11]; |
|||
step[11] = output[11] + output[10]; |
|||
step[12] = output[12] + output[13]; |
|||
step[13] = -output[13] + output[12]; |
|||
step[14] = -output[14] + output[15]; |
|||
step[15] = output[15] + output[14]; |
|||
step[16] = output[16]; |
|||
step[17] = Av1Transform1dMath.HalfButterfly(-cospi[8], output[17], cospi[56], output[30], cosBit); |
|||
step[18] = Av1Transform1dMath.HalfButterfly(-cospi[56], output[18], -cospi[8], output[29], cosBit); |
|||
step[19] = output[19]; |
|||
step[20] = output[20]; |
|||
step[21] = Av1Transform1dMath.HalfButterfly(-cospi[40], output[21], cospi[24], output[26], cosBit); |
|||
step[22] = Av1Transform1dMath.HalfButterfly(-cospi[24], output[22], -cospi[40], output[25], cosBit); |
|||
step[23] = output[23]; |
|||
step[24] = output[24]; |
|||
step[25] = Av1Transform1dMath.HalfButterfly(cospi[24], output[25], -cospi[40], output[22], cosBit); |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[40], output[26], cospi[24], output[21], cosBit); |
|||
step[27] = output[27]; |
|||
step[28] = output[28]; |
|||
step[29] = Av1Transform1dMath.HalfButterfly(cospi[56], output[29], -cospi[8], output[18], cosBit); |
|||
step[30] = Av1Transform1dMath.HalfButterfly(cospi[8], output[30], cospi[56], output[17], cosBit); |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 7 applies the pi/32 rotations to the next odd-frequency level.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = step[4]; |
|||
output[5] = step[5]; |
|||
output[6] = step[6]; |
|||
output[7] = step[7]; |
|||
output[8] = Av1Transform1dMath.HalfButterfly(cospi[60], step[8], cospi[4], step[15], cosBit); |
|||
output[9] = Av1Transform1dMath.HalfButterfly(cospi[28], step[9], cospi[36], step[14], cosBit); |
|||
output[10] = Av1Transform1dMath.HalfButterfly(cospi[44], step[10], cospi[20], step[13], cosBit); |
|||
output[11] = Av1Transform1dMath.HalfButterfly(cospi[12], step[11], cospi[52], step[12], cosBit); |
|||
output[12] = Av1Transform1dMath.HalfButterfly(cospi[12], step[12], -cospi[52], step[11], cosBit); |
|||
output[13] = Av1Transform1dMath.HalfButterfly(cospi[44], step[13], -cospi[20], step[10], cosBit); |
|||
output[14] = Av1Transform1dMath.HalfButterfly(cospi[28], step[14], -cospi[36], step[9], cosBit); |
|||
output[15] = Av1Transform1dMath.HalfButterfly(cospi[60], step[15], -cospi[4], step[8], cosBit); |
|||
output[16] = step[16] + step[17]; |
|||
output[17] = -step[17] + step[16]; |
|||
output[18] = -step[18] + step[19]; |
|||
output[19] = step[19] + step[18]; |
|||
output[20] = step[20] + step[21]; |
|||
output[21] = -step[21] + step[20]; |
|||
output[22] = -step[22] + step[23]; |
|||
output[23] = step[23] + step[22]; |
|||
output[24] = step[24] + step[25]; |
|||
output[25] = -step[25] + step[24]; |
|||
output[26] = -step[26] + step[27]; |
|||
output[27] = step[27] + step[26]; |
|||
output[28] = step[28] + step[29]; |
|||
output[29] = -step[29] + step[28]; |
|||
output[30] = -step[30] + step[31]; |
|||
output[31] = step[31] + step[30]; |
|||
|
|||
// Stage 8 merges the final odd-frequency pairs before their terminal rotations.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
step[16] = Av1Transform1dMath.HalfButterfly(cospi[62], output[16], cospi[2], output[31], cosBit); |
|||
step[17] = Av1Transform1dMath.HalfButterfly(cospi[30], output[17], cospi[34], output[30], cosBit); |
|||
step[18] = Av1Transform1dMath.HalfButterfly(cospi[46], output[18], cospi[18], output[29], cosBit); |
|||
step[19] = Av1Transform1dMath.HalfButterfly(cospi[14], output[19], cospi[50], output[28], cosBit); |
|||
step[20] = Av1Transform1dMath.HalfButterfly(cospi[54], output[20], cospi[10], output[27], cosBit); |
|||
step[21] = Av1Transform1dMath.HalfButterfly(cospi[22], output[21], cospi[42], output[26], cosBit); |
|||
step[22] = Av1Transform1dMath.HalfButterfly(cospi[38], output[22], cospi[26], output[25], cosBit); |
|||
step[23] = Av1Transform1dMath.HalfButterfly(cospi[6], output[23], cospi[58], output[24], cosBit); |
|||
step[24] = Av1Transform1dMath.HalfButterfly(cospi[6], output[24], -cospi[58], output[23], cosBit); |
|||
step[25] = Av1Transform1dMath.HalfButterfly(cospi[38], output[25], -cospi[26], output[22], cosBit); |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[22], output[26], -cospi[42], output[21], cosBit); |
|||
step[27] = Av1Transform1dMath.HalfButterfly(cospi[54], output[27], -cospi[10], output[20], cosBit); |
|||
step[28] = Av1Transform1dMath.HalfButterfly(cospi[14], output[28], -cospi[50], output[19], cosBit); |
|||
step[29] = Av1Transform1dMath.HalfButterfly(cospi[46], output[29], -cospi[18], output[18], cosBit); |
|||
step[30] = Av1Transform1dMath.HalfButterfly(cospi[30], output[30], -cospi[34], output[17], cosBit); |
|||
step[31] = Av1Transform1dMath.HalfButterfly(cospi[62], output[31], -cospi[2], output[16], cosBit); |
|||
|
|||
// Stage 9 applies the terminal pi/64 rotations and produces the staged coefficient values.
|
|||
output[0] = step[0]; |
|||
output[1] = step[16]; |
|||
output[2] = step[8]; |
|||
output[3] = step[24]; |
|||
output[4] = step[4]; |
|||
output[5] = step[20]; |
|||
output[6] = step[12]; |
|||
output[7] = step[28]; |
|||
output[8] = step[2]; |
|||
output[9] = step[18]; |
|||
output[10] = step[10]; |
|||
output[11] = step[26]; |
|||
output[12] = step[6]; |
|||
output[13] = step[22]; |
|||
output[14] = step[14]; |
|||
output[15] = step[30]; |
|||
output[16] = step[1]; |
|||
output[17] = step[17]; |
|||
output[18] = step[9]; |
|||
output[19] = step[25]; |
|||
output[20] = step[5]; |
|||
output[21] = step[21]; |
|||
output[22] = step[13]; |
|||
output[23] = step[29]; |
|||
output[24] = step[3]; |
|||
output[25] = step[19]; |
|||
output[26] = step[11]; |
|||
output[27] = step[27]; |
|||
output[28] = step[7]; |
|||
output[29] = step[23]; |
|||
output[30] = step[15]; |
|||
output[31] = step[31]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
output[0] = input[0] + input[31]; |
|||
output[1] = input[1] + input[30]; |
|||
output[2] = input[2] + input[29]; |
|||
output[3] = input[3] + input[28]; |
|||
output[4] = input[4] + input[27]; |
|||
output[5] = input[5] + input[26]; |
|||
output[6] = input[6] + input[25]; |
|||
output[7] = input[7] + input[24]; |
|||
output[8] = input[8] + input[23]; |
|||
output[9] = input[9] + input[22]; |
|||
output[10] = input[10] + input[21]; |
|||
output[11] = input[11] + input[20]; |
|||
output[12] = input[12] + input[19]; |
|||
output[13] = input[13] + input[18]; |
|||
output[14] = input[14] + input[17]; |
|||
output[15] = input[15] + input[16]; |
|||
output[16] = -input[16] + input[15]; |
|||
output[17] = -input[17] + input[14]; |
|||
output[18] = -input[18] + input[13]; |
|||
output[19] = -input[19] + input[12]; |
|||
output[20] = -input[20] + input[11]; |
|||
output[21] = -input[21] + input[10]; |
|||
output[22] = -input[22] + input[9]; |
|||
output[23] = -input[23] + input[8]; |
|||
output[24] = -input[24] + input[7]; |
|||
output[25] = -input[25] + input[6]; |
|||
output[26] = -input[26] + input[5]; |
|||
output[27] = -input[27] + input[4]; |
|||
output[28] = -input[28] + input[3]; |
|||
output[29] = -input[29] + input[2]; |
|||
output[30] = -input[30] + input[1]; |
|||
output[31] = -input[31] + input[0]; |
|||
|
|||
// Stage 2 begins the recursive radix-2 factorization and rotates the central odd pairs.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0] + output[15]; |
|||
step[1] = output[1] + output[14]; |
|||
step[2] = output[2] + output[13]; |
|||
step[3] = output[3] + output[12]; |
|||
step[4] = output[4] + output[11]; |
|||
step[5] = output[5] + output[10]; |
|||
step[6] = output[6] + output[9]; |
|||
step[7] = output[7] + output[8]; |
|||
step[8] = -output[8] + output[7]; |
|||
step[9] = -output[9] + output[6]; |
|||
step[10] = -output[10] + output[5]; |
|||
step[11] = -output[11] + output[4]; |
|||
step[12] = -output[12] + output[3]; |
|||
step[13] = -output[13] + output[2]; |
|||
step[14] = -output[14] + output[1]; |
|||
step[15] = -output[15] + output[0]; |
|||
step[16] = output[16]; |
|||
step[17] = output[17]; |
|||
step[18] = output[18]; |
|||
step[19] = output[19]; |
|||
step[20] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[20], cospi[32], output[27], cosBit); |
|||
step[21] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[21], cospi[32], output[26], cosBit); |
|||
step[22] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[22], cospi[32], output[25], cosBit); |
|||
step[23] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[23], cospi[32], output[24], cosBit); |
|||
step[24] = Av1Transform1dMath.HalfButterfly(cospi[32], output[24], cospi[32], output[23], cosBit); |
|||
step[25] = Av1Transform1dMath.HalfButterfly(cospi[32], output[25], cospi[32], output[22], cosBit); |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[32], output[26], cospi[32], output[21], cosBit); |
|||
step[27] = Av1Transform1dMath.HalfButterfly(cospi[32], output[27], cospi[32], output[20], cosBit); |
|||
step[28] = output[28]; |
|||
step[29] = output[29]; |
|||
step[30] = output[30]; |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 3 reduces the even half and folds the next odd-frequency groups into butterflies.
|
|||
output[0] = step[0] + step[7]; |
|||
output[1] = step[1] + step[6]; |
|||
output[2] = step[2] + step[5]; |
|||
output[3] = step[3] + step[4]; |
|||
output[4] = -step[4] + step[3]; |
|||
output[5] = -step[5] + step[2]; |
|||
output[6] = -step[6] + step[1]; |
|||
output[7] = -step[7] + step[0]; |
|||
output[8] = step[8]; |
|||
output[9] = step[9]; |
|||
output[10] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[10], cospi[32], step[13], cosBit); |
|||
output[11] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[11], cospi[32], step[12], cosBit); |
|||
output[12] = Av1Transform1dMath.HalfButterfly(cospi[32], step[12], cospi[32], step[11], cosBit); |
|||
output[13] = Av1Transform1dMath.HalfButterfly(cospi[32], step[13], cospi[32], step[10], cosBit); |
|||
output[14] = step[14]; |
|||
output[15] = step[15]; |
|||
output[16] = step[16] + step[23]; |
|||
output[17] = step[17] + step[22]; |
|||
output[18] = step[18] + step[21]; |
|||
output[19] = step[19] + step[20]; |
|||
output[20] = -step[20] + step[19]; |
|||
output[21] = -step[21] + step[18]; |
|||
output[22] = -step[22] + step[17]; |
|||
output[23] = -step[23] + step[16]; |
|||
output[24] = -step[24] + step[31]; |
|||
output[25] = -step[25] + step[30]; |
|||
output[26] = -step[26] + step[29]; |
|||
output[27] = -step[27] + step[28]; |
|||
output[28] = step[28] + step[27]; |
|||
output[29] = step[29] + step[26]; |
|||
output[30] = step[30] + step[25]; |
|||
output[31] = step[31] + step[24]; |
|||
|
|||
// Stage 4 continues the factorization as independent eight-sample groups.
|
|||
step[0] = output[0] + output[3]; |
|||
step[1] = output[1] + output[2]; |
|||
step[2] = -output[2] + output[1]; |
|||
step[3] = -output[3] + output[0]; |
|||
step[4] = output[4]; |
|||
step[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[5], cosBit); |
|||
step[7] = output[7]; |
|||
step[8] = output[8] + output[11]; |
|||
step[9] = output[9] + output[10]; |
|||
step[10] = -output[10] + output[9]; |
|||
step[11] = -output[11] + output[8]; |
|||
step[12] = -output[12] + output[15]; |
|||
step[13] = -output[13] + output[14]; |
|||
step[14] = output[14] + output[13]; |
|||
step[15] = output[15] + output[12]; |
|||
step[16] = output[16]; |
|||
step[17] = output[17]; |
|||
step[18] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[18], cospi[48], output[29], cosBit); |
|||
step[19] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[19], cospi[48], output[28], cosBit); |
|||
step[20] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[20], -cospi[16], output[27], cosBit); |
|||
step[21] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[21], -cospi[16], output[26], cosBit); |
|||
step[22] = output[22]; |
|||
step[23] = output[23]; |
|||
step[24] = output[24]; |
|||
step[25] = output[25]; |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[48], output[26], -cospi[16], output[21], cosBit); |
|||
step[27] = Av1Transform1dMath.HalfButterfly(cospi[48], output[27], -cospi[16], output[20], cosBit); |
|||
step[28] = Av1Transform1dMath.HalfButterfly(cospi[16], output[28], cospi[48], output[19], cosBit); |
|||
step[29] = Av1Transform1dMath.HalfButterfly(cospi[16], output[29], cospi[48], output[18], cosBit); |
|||
step[30] = output[30]; |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 5 completes the low-frequency DCT and rotates the first separated odd groups.
|
|||
output[0] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], cospi[32], step[1], cosBit); |
|||
output[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[1], cospi[32], step[0], cosBit); |
|||
output[2] = Av1Transform1dMath.HalfButterfly(cospi[48], step[2], cospi[16], step[3], cosBit); |
|||
output[3] = Av1Transform1dMath.HalfButterfly(cospi[48], step[3], -cospi[16], step[2], cosBit); |
|||
output[4] = step[4] + step[5]; |
|||
output[5] = -step[5] + step[4]; |
|||
output[6] = -step[6] + step[7]; |
|||
output[7] = step[7] + step[6]; |
|||
output[8] = step[8]; |
|||
output[9] = Av1Transform1dMath.HalfButterfly(-cospi[16], step[9], cospi[48], step[14], cosBit); |
|||
output[10] = Av1Transform1dMath.HalfButterfly(-cospi[48], step[10], -cospi[16], step[13], cosBit); |
|||
output[11] = step[11]; |
|||
output[12] = step[12]; |
|||
output[13] = Av1Transform1dMath.HalfButterfly(cospi[48], step[13], -cospi[16], step[10], cosBit); |
|||
output[14] = Av1Transform1dMath.HalfButterfly(cospi[16], step[14], cospi[48], step[9], cosBit); |
|||
output[15] = step[15]; |
|||
output[16] = step[16] + step[19]; |
|||
output[17] = step[17] + step[18]; |
|||
output[18] = -step[18] + step[17]; |
|||
output[19] = -step[19] + step[16]; |
|||
output[20] = -step[20] + step[23]; |
|||
output[21] = -step[21] + step[22]; |
|||
output[22] = step[22] + step[21]; |
|||
output[23] = step[23] + step[20]; |
|||
output[24] = step[24] + step[27]; |
|||
output[25] = step[25] + step[26]; |
|||
output[26] = -step[26] + step[25]; |
|||
output[27] = -step[27] + step[24]; |
|||
output[28] = -step[28] + step[31]; |
|||
output[29] = -step[29] + step[30]; |
|||
output[30] = step[30] + step[29]; |
|||
output[31] = step[31] + step[28]; |
|||
|
|||
// Stage 6 merges adjacent odd-frequency terms with the required AV1 sign pattern.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[56], output[4], cospi[8], output[7], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[24], output[5], cospi[40], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[24], output[6], -cospi[40], output[5], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[56], output[7], -cospi[8], output[4], cosBit); |
|||
step[8] = output[8] + output[9]; |
|||
step[9] = -output[9] + output[8]; |
|||
step[10] = -output[10] + output[11]; |
|||
step[11] = output[11] + output[10]; |
|||
step[12] = output[12] + output[13]; |
|||
step[13] = -output[13] + output[12]; |
|||
step[14] = -output[14] + output[15]; |
|||
step[15] = output[15] + output[14]; |
|||
step[16] = output[16]; |
|||
step[17] = Av1Transform1dMath.HalfButterfly(-cospi[8], output[17], cospi[56], output[30], cosBit); |
|||
step[18] = Av1Transform1dMath.HalfButterfly(-cospi[56], output[18], -cospi[8], output[29], cosBit); |
|||
step[19] = output[19]; |
|||
step[20] = output[20]; |
|||
step[21] = Av1Transform1dMath.HalfButterfly(-cospi[40], output[21], cospi[24], output[26], cosBit); |
|||
step[22] = Av1Transform1dMath.HalfButterfly(-cospi[24], output[22], -cospi[40], output[25], cosBit); |
|||
step[23] = output[23]; |
|||
step[24] = output[24]; |
|||
step[25] = Av1Transform1dMath.HalfButterfly(cospi[24], output[25], -cospi[40], output[22], cosBit); |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[40], output[26], cospi[24], output[21], cosBit); |
|||
step[27] = output[27]; |
|||
step[28] = output[28]; |
|||
step[29] = Av1Transform1dMath.HalfButterfly(cospi[56], output[29], -cospi[8], output[18], cosBit); |
|||
step[30] = Av1Transform1dMath.HalfButterfly(cospi[8], output[30], cospi[56], output[17], cosBit); |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 7 applies the pi/32 rotations to the next odd-frequency level.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = step[4]; |
|||
output[5] = step[5]; |
|||
output[6] = step[6]; |
|||
output[7] = step[7]; |
|||
output[8] = Av1Transform1dMath.HalfButterfly(cospi[60], step[8], cospi[4], step[15], cosBit); |
|||
output[9] = Av1Transform1dMath.HalfButterfly(cospi[28], step[9], cospi[36], step[14], cosBit); |
|||
output[10] = Av1Transform1dMath.HalfButterfly(cospi[44], step[10], cospi[20], step[13], cosBit); |
|||
output[11] = Av1Transform1dMath.HalfButterfly(cospi[12], step[11], cospi[52], step[12], cosBit); |
|||
output[12] = Av1Transform1dMath.HalfButterfly(cospi[12], step[12], -cospi[52], step[11], cosBit); |
|||
output[13] = Av1Transform1dMath.HalfButterfly(cospi[44], step[13], -cospi[20], step[10], cosBit); |
|||
output[14] = Av1Transform1dMath.HalfButterfly(cospi[28], step[14], -cospi[36], step[9], cosBit); |
|||
output[15] = Av1Transform1dMath.HalfButterfly(cospi[60], step[15], -cospi[4], step[8], cosBit); |
|||
output[16] = step[16] + step[17]; |
|||
output[17] = -step[17] + step[16]; |
|||
output[18] = -step[18] + step[19]; |
|||
output[19] = step[19] + step[18]; |
|||
output[20] = step[20] + step[21]; |
|||
output[21] = -step[21] + step[20]; |
|||
output[22] = -step[22] + step[23]; |
|||
output[23] = step[23] + step[22]; |
|||
output[24] = step[24] + step[25]; |
|||
output[25] = -step[25] + step[24]; |
|||
output[26] = -step[26] + step[27]; |
|||
output[27] = step[27] + step[26]; |
|||
output[28] = step[28] + step[29]; |
|||
output[29] = -step[29] + step[28]; |
|||
output[30] = -step[30] + step[31]; |
|||
output[31] = step[31] + step[30]; |
|||
|
|||
// Stage 8 merges the final odd-frequency pairs before their terminal rotations.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
step[16] = Av1Transform1dMath.HalfButterfly(cospi[62], output[16], cospi[2], output[31], cosBit); |
|||
step[17] = Av1Transform1dMath.HalfButterfly(cospi[30], output[17], cospi[34], output[30], cosBit); |
|||
step[18] = Av1Transform1dMath.HalfButterfly(cospi[46], output[18], cospi[18], output[29], cosBit); |
|||
step[19] = Av1Transform1dMath.HalfButterfly(cospi[14], output[19], cospi[50], output[28], cosBit); |
|||
step[20] = Av1Transform1dMath.HalfButterfly(cospi[54], output[20], cospi[10], output[27], cosBit); |
|||
step[21] = Av1Transform1dMath.HalfButterfly(cospi[22], output[21], cospi[42], output[26], cosBit); |
|||
step[22] = Av1Transform1dMath.HalfButterfly(cospi[38], output[22], cospi[26], output[25], cosBit); |
|||
step[23] = Av1Transform1dMath.HalfButterfly(cospi[6], output[23], cospi[58], output[24], cosBit); |
|||
step[24] = Av1Transform1dMath.HalfButterfly(cospi[6], output[24], -cospi[58], output[23], cosBit); |
|||
step[25] = Av1Transform1dMath.HalfButterfly(cospi[38], output[25], -cospi[26], output[22], cosBit); |
|||
step[26] = Av1Transform1dMath.HalfButterfly(cospi[22], output[26], -cospi[42], output[21], cosBit); |
|||
step[27] = Av1Transform1dMath.HalfButterfly(cospi[54], output[27], -cospi[10], output[20], cosBit); |
|||
step[28] = Av1Transform1dMath.HalfButterfly(cospi[14], output[28], -cospi[50], output[19], cosBit); |
|||
step[29] = Av1Transform1dMath.HalfButterfly(cospi[46], output[29], -cospi[18], output[18], cosBit); |
|||
step[30] = Av1Transform1dMath.HalfButterfly(cospi[30], output[30], -cospi[34], output[17], cosBit); |
|||
step[31] = Av1Transform1dMath.HalfButterfly(cospi[62], output[31], -cospi[2], output[16], cosBit); |
|||
|
|||
// Stage 9 applies the terminal pi/64 rotations and produces the staged coefficient values.
|
|||
output[0] = step[0]; |
|||
output[1] = step[16]; |
|||
output[2] = step[8]; |
|||
output[3] = step[24]; |
|||
output[4] = step[4]; |
|||
output[5] = step[20]; |
|||
output[6] = step[12]; |
|||
output[7] = step[28]; |
|||
output[8] = step[2]; |
|||
output[9] = step[18]; |
|||
output[10] = step[10]; |
|||
output[11] = step[26]; |
|||
output[12] = step[6]; |
|||
output[13] = step[22]; |
|||
output[14] = step[14]; |
|||
output[15] = step[30]; |
|||
output[16] = step[1]; |
|||
output[17] = step[17]; |
|||
output[18] = step[9]; |
|||
output[19] = step[25]; |
|||
output[20] = step[5]; |
|||
output[21] = step[21]; |
|||
output[22] = step[13]; |
|||
output[23] = step[29]; |
|||
output[24] = step[3]; |
|||
output[25] = step[19]; |
|||
output[26] = step[11]; |
|||
output[27] = step[27]; |
|||
output[28] = step[7]; |
|||
output[29] = step[23]; |
|||
output[30] = step[15]; |
|||
output[31] = step[31]; |
|||
} |
|||
} |
|||
@ -1,119 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the four-point forward DCT operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Dct4Forward1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
_ = stageRange; |
|||
|
|||
// Mirror butterflies separate the even and odd spatial symmetries used by the four DCT basis vectors.
|
|||
output[0] = input[0] + input[3]; |
|||
output[1] = input[1] + input[2]; |
|||
output[2] = input[1] - input[2]; |
|||
output[3] = input[0] - input[3]; |
|||
|
|||
// Each half-butterfly keeps the optimized kernels' wrapping 32-bit arithmetic before applying the
|
|||
// normative fixed-point rounding shift.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[1], cospi[32], output[0], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[48], output[3], -cospi[16], output[2], cosBit); |
|||
|
|||
// The staged order groups butterfly partners; AV1 coefficient order interleaves their frequency indices.
|
|||
output[0] = step[0]; |
|||
output[1] = step[2]; |
|||
output[2] = step[1]; |
|||
output[3] = step[3]; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
_ = stageRange; |
|||
|
|||
// Mirror butterflies separate the even and odd spatial symmetries used by the four DCT basis vectors.
|
|||
output[0] = input[0] + input[3]; |
|||
output[1] = input[1] + input[2]; |
|||
output[2] = input[1] - input[2]; |
|||
output[3] = input[0] - input[3]; |
|||
|
|||
// Each half-butterfly keeps the optimized kernels' wrapping 32-bit arithmetic before applying the
|
|||
// normative fixed-point rounding shift.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[1], cospi[32], output[0], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[48], output[3], -cospi[16], output[2], cosBit); |
|||
|
|||
// The staged order groups butterfly partners; AV1 coefficient order interleaves their frequency indices.
|
|||
output[0] = step[0]; |
|||
output[1] = step[2]; |
|||
output[2] = step[1]; |
|||
output[3] = step[3]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
_ = stageRange; |
|||
|
|||
// Mirror butterflies separate the even and odd spatial symmetries used by the four DCT basis vectors.
|
|||
output[0] = input[0] + input[3]; |
|||
output[1] = input[1] + input[2]; |
|||
output[2] = input[1] - input[2]; |
|||
output[3] = input[0] - input[3]; |
|||
|
|||
// Each half-butterfly keeps the optimized kernels' wrapping 32-bit arithmetic before applying the
|
|||
// normative fixed-point rounding shift.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[1], cospi[32], output[0], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[48], output[3], -cospi[16], output[2], cosBit); |
|||
|
|||
// The staged order groups butterfly partners; AV1 coefficient order interleaves their frequency indices.
|
|||
output[0] = step[0]; |
|||
output[1] = step[2]; |
|||
output[2] = step[1]; |
|||
output[3] = step[3]; |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -1,218 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the eight-point forward DCT operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Dct8Forward1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
output[0] = input[0] + input[7]; |
|||
output[1] = input[1] + input[6]; |
|||
output[2] = input[2] + input[5]; |
|||
output[3] = input[3] + input[4]; |
|||
output[4] = -input[4] + input[3]; |
|||
output[5] = -input[5] + input[2]; |
|||
output[6] = -input[6] + input[1]; |
|||
output[7] = -input[7] + input[0]; |
|||
|
|||
// Stage 2 applies a four-point DCT to the even half and a pi/4 rotation to the middle odd pair.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0] + output[3]; |
|||
step[1] = output[1] + output[2]; |
|||
step[2] = -output[2] + output[1]; |
|||
step[3] = -output[3] + output[0]; |
|||
step[4] = output[4]; |
|||
step[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[5], cosBit); |
|||
step[7] = output[7]; |
|||
|
|||
// Stage 3 completes the even transform and combines the odd terms into sum and difference pairs.
|
|||
output[0] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], cospi[32], step[1], cosBit); |
|||
output[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[1], cospi[32], step[0], cosBit); |
|||
output[2] = Av1Transform1dMath.HalfButterfly(cospi[48], step[2], cospi[16], step[3], cosBit); |
|||
output[3] = Av1Transform1dMath.HalfButterfly(cospi[48], step[3], -cospi[16], step[2], cosBit); |
|||
output[4] = step[4] + step[5]; |
|||
output[5] = -step[5] + step[4]; |
|||
output[6] = -step[6] + step[7]; |
|||
output[7] = step[7] + step[6]; |
|||
|
|||
// Stage 4 rotates the odd-frequency pairs by the remaining pi/16 angles.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[56], output[4], cospi[8], output[7], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[24], output[5], cospi[40], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[24], output[6], -cospi[40], output[5], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[56], output[7], -cospi[8], output[4], cosBit); |
|||
|
|||
// Stage 5 permutes the staged values into ascending AV1 coefficient order.
|
|||
output[0] = step[0]; |
|||
output[1] = step[4]; |
|||
output[2] = step[2]; |
|||
output[3] = step[6]; |
|||
output[4] = step[1]; |
|||
output[5] = step[5]; |
|||
output[6] = step[3]; |
|||
output[7] = step[7]; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
output[0] = input[0] + input[7]; |
|||
output[1] = input[1] + input[6]; |
|||
output[2] = input[2] + input[5]; |
|||
output[3] = input[3] + input[4]; |
|||
output[4] = -input[4] + input[3]; |
|||
output[5] = -input[5] + input[2]; |
|||
output[6] = -input[6] + input[1]; |
|||
output[7] = -input[7] + input[0]; |
|||
|
|||
// Stage 2 applies a four-point DCT to the even half and a pi/4 rotation to the middle odd pair.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0] + output[3]; |
|||
step[1] = output[1] + output[2]; |
|||
step[2] = -output[2] + output[1]; |
|||
step[3] = -output[3] + output[0]; |
|||
step[4] = output[4]; |
|||
step[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[5], cosBit); |
|||
step[7] = output[7]; |
|||
|
|||
// Stage 3 completes the even transform and combines the odd terms into sum and difference pairs.
|
|||
output[0] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], cospi[32], step[1], cosBit); |
|||
output[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[1], cospi[32], step[0], cosBit); |
|||
output[2] = Av1Transform1dMath.HalfButterfly(cospi[48], step[2], cospi[16], step[3], cosBit); |
|||
output[3] = Av1Transform1dMath.HalfButterfly(cospi[48], step[3], -cospi[16], step[2], cosBit); |
|||
output[4] = step[4] + step[5]; |
|||
output[5] = -step[5] + step[4]; |
|||
output[6] = -step[6] + step[7]; |
|||
output[7] = step[7] + step[6]; |
|||
|
|||
// Stage 4 rotates the odd-frequency pairs by the remaining pi/16 angles.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[56], output[4], cospi[8], output[7], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[24], output[5], cospi[40], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[24], output[6], -cospi[40], output[5], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[56], output[7], -cospi[8], output[4], cosBit); |
|||
|
|||
// Stage 5 permutes the staged values into ascending AV1 coefficient order.
|
|||
output[0] = step[0]; |
|||
output[1] = step[4]; |
|||
output[2] = step[2]; |
|||
output[3] = step[6]; |
|||
output[4] = step[1]; |
|||
output[5] = step[5]; |
|||
output[6] = step[3]; |
|||
output[7] = step[7]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// libaom uses this table only when coefficient-range checking is enabled. The production transform relies on
|
|||
// the ranges already established from the coded bit depth and the normative two-dimensional shifts.
|
|||
_ = stageRange; |
|||
|
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
output[0] = input[0] + input[7]; |
|||
output[1] = input[1] + input[6]; |
|||
output[2] = input[2] + input[5]; |
|||
output[3] = input[3] + input[4]; |
|||
output[4] = -input[4] + input[3]; |
|||
output[5] = -input[5] + input[2]; |
|||
output[6] = -input[6] + input[1]; |
|||
output[7] = -input[7] + input[0]; |
|||
|
|||
// Stage 2 applies a four-point DCT to the even half and a pi/4 rotation to the middle odd pair.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = output[0] + output[3]; |
|||
step[1] = output[1] + output[2]; |
|||
step[2] = -output[2] + output[1]; |
|||
step[3] = -output[3] + output[0]; |
|||
step[4] = output[4]; |
|||
step[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[5], cosBit); |
|||
step[7] = output[7]; |
|||
|
|||
// Stage 3 completes the even transform and combines the odd terms into sum and difference pairs.
|
|||
output[0] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], cospi[32], step[1], cosBit); |
|||
output[1] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[1], cospi[32], step[0], cosBit); |
|||
output[2] = Av1Transform1dMath.HalfButterfly(cospi[48], step[2], cospi[16], step[3], cosBit); |
|||
output[3] = Av1Transform1dMath.HalfButterfly(cospi[48], step[3], -cospi[16], step[2], cosBit); |
|||
output[4] = step[4] + step[5]; |
|||
output[5] = -step[5] + step[4]; |
|||
output[6] = -step[6] + step[7]; |
|||
output[7] = step[7] + step[6]; |
|||
|
|||
// Stage 4 rotates the odd-frequency pairs by the remaining pi/16 angles.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[56], output[4], cospi[8], output[7], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[24], output[5], cospi[40], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[24], output[6], -cospi[40], output[5], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[56], output[7], -cospi[8], output[4], cosBit); |
|||
|
|||
// Stage 5 permutes the staged values into ascending AV1 coefficient order.
|
|||
output[0] = step[0]; |
|||
output[1] = step[4]; |
|||
output[2] = step[2]; |
|||
output[3] = step[6]; |
|||
output[4] = step[1]; |
|||
output[5] = step[5]; |
|||
output[6] = step[3]; |
|||
output[7] = step[7]; |
|||
} |
|||
} |
|||
@ -0,0 +1,848 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.Intrinsics; |
|||
using System.Runtime.Intrinsics.X86; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <summary>
|
|||
/// Provides the sample-type and vector-width arithmetic used by the shared AV1 forward-transform stage networks.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing independent transform axes.</typeparam>
|
|||
internal static class Av1ForwardTransformArithmetic<TValue> |
|||
where TValue : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Creates the rounding value used by fixed-point transform multiplications.
|
|||
/// </summary>
|
|||
/// <param name="cosBit">The number of fractional bits in the transform constants.</param>
|
|||
/// <returns>The rounding value in the widened lane shape used by <typeparamref name="TValue"/>.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static Av1TransformRounding CreateRounding(int cosBit) |
|||
{ |
|||
int value = 1 << (cosBit - 1); |
|||
Av1TransformRounding rounding = default; |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<short>) || typeof(TValue) == typeof(Vector128<int>)) |
|||
{ |
|||
rounding.Vector128 = Vector128.Create(value); |
|||
} |
|||
else if (typeof(TValue) == typeof(Vector256<short>) || typeof(TValue) == typeof(Vector256<int>)) |
|||
{ |
|||
rounding.Vector256 = Vector256.Create(value); |
|||
} |
|||
else if (typeof(TValue) == typeof(Vector512<short>) || typeof(TValue) == typeof(Vector512<int>)) |
|||
{ |
|||
rounding.Vector512 = Vector512.Create(value); |
|||
} |
|||
else |
|||
{ |
|||
rounding.Scalar = value; |
|||
} |
|||
|
|||
return rounding; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds two transform values using the lane arithmetic required by the selected sample type.
|
|||
/// </summary>
|
|||
/// <param name="left">The left operand.</param>
|
|||
/// <param name="right">The right operand.</param>
|
|||
/// <returns>The lane-wise sum.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TValue Add(TValue left, TValue right) |
|||
{ |
|||
if (typeof(TValue) == typeof(short)) |
|||
{ |
|||
int resultValue = As<TValue, short>(left) + As<TValue, short>(right); |
|||
short result = (short)Math.Clamp(resultValue, short.MinValue, short.MaxValue); |
|||
return As<short, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(int)) |
|||
{ |
|||
int result = As<TValue, int>(left) + As<TValue, int>(right); |
|||
return As<int, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<short>)) |
|||
{ |
|||
Vector128<short> result = Vector128.AddSaturate(As<TValue, Vector128<short>>(left), As<TValue, Vector128<short>>(right)); |
|||
return As<Vector128<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<int>)) |
|||
{ |
|||
Vector128<int> result = As<TValue, Vector128<int>>(left) + As<TValue, Vector128<int>>(right); |
|||
return As<Vector128<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<short>)) |
|||
{ |
|||
Vector256<short> result = Vector256.AddSaturate(As<TValue, Vector256<short>>(left), As<TValue, Vector256<short>>(right)); |
|||
return As<Vector256<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<int>)) |
|||
{ |
|||
Vector256<int> result = As<TValue, Vector256<int>>(left) + As<TValue, Vector256<int>>(right); |
|||
return As<Vector256<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector512<short>)) |
|||
{ |
|||
Vector512<short> result = Vector512.AddSaturate(As<TValue, Vector512<short>>(left), As<TValue, Vector512<short>>(right)); |
|||
return As<Vector512<short>, TValue>(result); |
|||
} |
|||
|
|||
Vector512<int> vector = As<TValue, Vector512<int>>(left) + As<TValue, Vector512<int>>(right); |
|||
return As<Vector512<int>, TValue>(vector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Subtracts one transform value from another using the lane arithmetic required by the selected sample type.
|
|||
/// </summary>
|
|||
/// <param name="left">The left operand.</param>
|
|||
/// <param name="right">The right operand.</param>
|
|||
/// <returns>The lane-wise difference.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TValue Subtract(TValue left, TValue right) |
|||
{ |
|||
if (typeof(TValue) == typeof(short)) |
|||
{ |
|||
int resultValue = As<TValue, short>(left) - As<TValue, short>(right); |
|||
short result = (short)Math.Clamp(resultValue, short.MinValue, short.MaxValue); |
|||
return As<short, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(int)) |
|||
{ |
|||
int result = As<TValue, int>(left) - As<TValue, int>(right); |
|||
return As<int, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<short>)) |
|||
{ |
|||
Vector128<short> result = Vector128.SubtractSaturate(As<TValue, Vector128<short>>(left), As<TValue, Vector128<short>>(right)); |
|||
return As<Vector128<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<int>)) |
|||
{ |
|||
Vector128<int> result = As<TValue, Vector128<int>>(left) - As<TValue, Vector128<int>>(right); |
|||
return As<Vector128<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<short>)) |
|||
{ |
|||
Vector256<short> result = Vector256.SubtractSaturate(As<TValue, Vector256<short>>(left), As<TValue, Vector256<short>>(right)); |
|||
return As<Vector256<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<int>)) |
|||
{ |
|||
Vector256<int> result = As<TValue, Vector256<int>>(left) - As<TValue, Vector256<int>>(right); |
|||
return As<Vector256<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector512<short>)) |
|||
{ |
|||
Vector512<short> result = Vector512.SubtractSaturate(As<TValue, Vector512<short>>(left), As<TValue, Vector512<short>>(right)); |
|||
return As<Vector512<short>, TValue>(result); |
|||
} |
|||
|
|||
Vector512<int> vector = As<TValue, Vector512<int>>(left) - As<TValue, Vector512<int>>(right); |
|||
return As<Vector512<int>, TValue>(vector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Negates a transform value using wrapping lane arithmetic.
|
|||
/// </summary>
|
|||
/// <param name="value">The value to negate.</param>
|
|||
/// <returns>The lane-wise negated value.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TValue Negate(TValue value) |
|||
{ |
|||
if (typeof(TValue) == typeof(short)) |
|||
{ |
|||
short result = unchecked((short)-As<TValue, short>(value)); |
|||
return As<short, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(int)) |
|||
{ |
|||
int result = -As<TValue, int>(value); |
|||
return As<int, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<short>)) |
|||
{ |
|||
Vector128<short> result = Vector128<short>.Zero - As<TValue, Vector128<short>>(value); |
|||
return As<Vector128<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<int>)) |
|||
{ |
|||
Vector128<int> result = -As<TValue, Vector128<int>>(value); |
|||
return As<Vector128<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<short>)) |
|||
{ |
|||
Vector256<short> result = Vector256<short>.Zero - As<TValue, Vector256<short>>(value); |
|||
return As<Vector256<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<int>)) |
|||
{ |
|||
Vector256<int> result = -As<TValue, Vector256<int>>(value); |
|||
return As<Vector256<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector512<short>)) |
|||
{ |
|||
Vector512<short> result = Vector512<short>.Zero - As<TValue, Vector512<short>>(value); |
|||
return As<Vector512<short>, TValue>(result); |
|||
} |
|||
|
|||
Vector512<int> vector = -As<TValue, Vector512<int>>(value); |
|||
return As<Vector512<int>, TValue>(vector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds and subtracts two transform values, saturating only the signed sixteen-bit representations.
|
|||
/// </summary>
|
|||
/// <param name="left">The left operand.</param>
|
|||
/// <param name="right">The right operand.</param>
|
|||
/// <param name="sum">The lane-wise sum.</param>
|
|||
/// <param name="difference">The lane-wise difference.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void AddSubtract(TValue left, TValue right, out TValue sum, out TValue difference) |
|||
{ |
|||
if (typeof(TValue) == typeof(short)) |
|||
{ |
|||
int leftValue = As<TValue, short>(left); |
|||
int rightValue = As<TValue, short>(right); |
|||
short sumValue = (short)Math.Clamp(leftValue + rightValue, short.MinValue, short.MaxValue); |
|||
short differenceValue = (short)Math.Clamp(leftValue - rightValue, short.MinValue, short.MaxValue); |
|||
|
|||
sum = As<short, TValue>(sumValue); |
|||
difference = As<short, TValue>(differenceValue); |
|||
return; |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(int)) |
|||
{ |
|||
int leftValue = As<TValue, int>(left); |
|||
int rightValue = As<TValue, int>(right); |
|||
int sumValue = leftValue + rightValue; |
|||
int differenceValue = leftValue - rightValue; |
|||
|
|||
sum = As<int, TValue>(sumValue); |
|||
difference = As<int, TValue>(differenceValue); |
|||
return; |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<short>)) |
|||
{ |
|||
Vector128<short> leftValue = As<TValue, Vector128<short>>(left); |
|||
Vector128<short> rightValue = As<TValue, Vector128<short>>(right); |
|||
Vector128<short> sumValue = Vector128.AddSaturate(leftValue, rightValue); |
|||
Vector128<short> differenceValue = Vector128.SubtractSaturate(leftValue, rightValue); |
|||
|
|||
sum = As<Vector128<short>, TValue>(sumValue); |
|||
difference = As<Vector128<short>, TValue>(differenceValue); |
|||
return; |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<int>)) |
|||
{ |
|||
Vector128<int> leftValue = As<TValue, Vector128<int>>(left); |
|||
Vector128<int> rightValue = As<TValue, Vector128<int>>(right); |
|||
|
|||
sum = As<Vector128<int>, TValue>(leftValue + rightValue); |
|||
difference = As<Vector128<int>, TValue>(leftValue - rightValue); |
|||
return; |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<short>)) |
|||
{ |
|||
Vector256<short> leftValue = As<TValue, Vector256<short>>(left); |
|||
Vector256<short> rightValue = As<TValue, Vector256<short>>(right); |
|||
Vector256<short> sumValue = Vector256.AddSaturate(leftValue, rightValue); |
|||
Vector256<short> differenceValue = Vector256.SubtractSaturate(leftValue, rightValue); |
|||
|
|||
sum = As<Vector256<short>, TValue>(sumValue); |
|||
difference = As<Vector256<short>, TValue>(differenceValue); |
|||
return; |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<int>)) |
|||
{ |
|||
Vector256<int> leftValue = As<TValue, Vector256<int>>(left); |
|||
Vector256<int> rightValue = As<TValue, Vector256<int>>(right); |
|||
|
|||
sum = As<Vector256<int>, TValue>(leftValue + rightValue); |
|||
difference = As<Vector256<int>, TValue>(leftValue - rightValue); |
|||
return; |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector512<short>)) |
|||
{ |
|||
Vector512<short> leftValue = As<TValue, Vector512<short>>(left); |
|||
Vector512<short> rightValue = As<TValue, Vector512<short>>(right); |
|||
Vector512<short> sumValue = Vector512.AddSaturate(leftValue, rightValue); |
|||
Vector512<short> differenceValue = Vector512.SubtractSaturate(leftValue, rightValue); |
|||
|
|||
sum = As<Vector512<short>, TValue>(sumValue); |
|||
difference = As<Vector512<short>, TValue>(differenceValue); |
|||
return; |
|||
} |
|||
|
|||
Vector512<int> leftVector = As<TValue, Vector512<int>>(left); |
|||
Vector512<int> rightVector = As<TValue, Vector512<int>>(right); |
|||
|
|||
sum = As<Vector512<int>, TValue>(leftVector + rightVector); |
|||
difference = As<Vector512<int>, TValue>(leftVector - rightVector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates both outputs of a rounded, weighted two-input butterfly.
|
|||
/// </summary>
|
|||
/// <param name="weight0">The first fixed-point weight.</param>
|
|||
/// <param name="weight1">The second fixed-point weight.</param>
|
|||
/// <param name="input0">The first transform value.</param>
|
|||
/// <param name="input1">The second transform value.</param>
|
|||
/// <param name="output0">The first rounded result.</param>
|
|||
/// <param name="output1">The second rounded result.</param>
|
|||
/// <param name="cosBit">The number of fractional bits in each weight.</param>
|
|||
/// <param name="rounding">The rounding value created for this transform.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void Butterfly( |
|||
int weight0, |
|||
int weight1, |
|||
TValue input0, |
|||
TValue input1, |
|||
out TValue output0, |
|||
out TValue output1, |
|||
int cosBit, |
|||
in Av1TransformRounding rounding) |
|||
{ |
|||
if (typeof(TValue) == typeof(Vector128<short>)) |
|||
{ |
|||
Vector128<short> left = As<TValue, Vector128<short>>(input0); |
|||
Vector128<short> right = As<TValue, Vector128<short>>(input1); |
|||
|
|||
Av1Transform1dMath.Butterfly(weight0, weight1, in left, in right, out Vector128<short> result0, out Vector128<short> result1, cosBit, in rounding.Vector128); |
|||
output0 = As<Vector128<short>, TValue>(result0); |
|||
output1 = As<Vector128<short>, TValue>(result1); |
|||
return; |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<short>)) |
|||
{ |
|||
Vector256<short> left = As<TValue, Vector256<short>>(input0); |
|||
Vector256<short> right = As<TValue, Vector256<short>>(input1); |
|||
|
|||
Av1Transform1dMath.Butterfly(weight0, weight1, in left, in right, out Vector256<short> result0, out Vector256<short> result1, cosBit, in rounding.Vector256); |
|||
output0 = As<Vector256<short>, TValue>(result0); |
|||
output1 = As<Vector256<short>, TValue>(result1); |
|||
return; |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector512<short>)) |
|||
{ |
|||
Vector512<short> left = As<TValue, Vector512<short>>(input0); |
|||
Vector512<short> right = As<TValue, Vector512<short>>(input1); |
|||
|
|||
Av1Transform1dMath.Butterfly(weight0, weight1, in left, in right, out Vector512<short> result0, out Vector512<short> result1, cosBit, in rounding.Vector512); |
|||
output0 = As<Vector512<short>, TValue>(result0); |
|||
output1 = As<Vector512<short>, TValue>(result1); |
|||
return; |
|||
} |
|||
|
|||
output0 = HalfButterfly(weight0, input0, weight1, input1, cosBit, in rounding); |
|||
output1 = HalfButterfly(weight1, input0, -weight0, input1, cosBit, in rounding); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates one output of a rounded, weighted two-input butterfly.
|
|||
/// </summary>
|
|||
/// <param name="weight0">The first fixed-point weight.</param>
|
|||
/// <param name="input0">The first transform value.</param>
|
|||
/// <param name="weight1">The second fixed-point weight.</param>
|
|||
/// <param name="input1">The second transform value.</param>
|
|||
/// <param name="cosBit">The number of fractional bits in each weight.</param>
|
|||
/// <param name="rounding">The rounding value created for this transform.</param>
|
|||
/// <returns>The rounded lane-wise weighted sum.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TValue HalfButterfly( |
|||
int weight0, |
|||
TValue input0, |
|||
int weight1, |
|||
TValue input1, |
|||
int cosBit, |
|||
in Av1TransformRounding rounding) |
|||
{ |
|||
if (typeof(TValue) == typeof(short)) |
|||
{ |
|||
int weighted = (weight0 * As<TValue, short>(input0)) + (weight1 * As<TValue, short>(input1)); |
|||
short result = (short)Math.Clamp((weighted + rounding.Scalar) >> cosBit, short.MinValue, short.MaxValue); |
|||
return As<short, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(int)) |
|||
{ |
|||
int weighted = (weight0 * As<TValue, int>(input0)) + (weight1 * As<TValue, int>(input1)); |
|||
int result = (weighted + rounding.Scalar) >> cosBit; |
|||
return As<int, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<short>)) |
|||
{ |
|||
Vector128<short> result = MultiplyRound( |
|||
As<TValue, Vector128<short>>(input0), |
|||
weight0, |
|||
As<TValue, Vector128<short>>(input1), |
|||
weight1, |
|||
cosBit, |
|||
rounding.Vector128); |
|||
|
|||
return As<Vector128<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<int>)) |
|||
{ |
|||
Vector128<int> result = ((As<TValue, Vector128<int>>(input0) * Vector128.Create(weight0)) |
|||
+ (As<TValue, Vector128<int>>(input1) * Vector128.Create(weight1)) |
|||
+ rounding.Vector128) >> cosBit; |
|||
|
|||
return As<Vector128<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<short>)) |
|||
{ |
|||
Vector256<short> result = MultiplyRound( |
|||
As<TValue, Vector256<short>>(input0), |
|||
weight0, |
|||
As<TValue, Vector256<short>>(input1), |
|||
weight1, |
|||
cosBit, |
|||
rounding.Vector256); |
|||
|
|||
return As<Vector256<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<int>)) |
|||
{ |
|||
Vector256<int> result = ((As<TValue, Vector256<int>>(input0) * Vector256.Create(weight0)) |
|||
+ (As<TValue, Vector256<int>>(input1) * Vector256.Create(weight1)) |
|||
+ rounding.Vector256) >> cosBit; |
|||
|
|||
return As<Vector256<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector512<short>)) |
|||
{ |
|||
Vector512<short> result = MultiplyRound( |
|||
As<TValue, Vector512<short>>(input0), |
|||
weight0, |
|||
As<TValue, Vector512<short>>(input1), |
|||
weight1, |
|||
cosBit, |
|||
rounding.Vector512); |
|||
|
|||
return As<Vector512<short>, TValue>(result); |
|||
} |
|||
|
|||
Vector512<int> vector = ((As<TValue, Vector512<int>>(input0) * Vector512.Create(weight0)) |
|||
+ (As<TValue, Vector512<int>>(input1) * Vector512.Create(weight1)) |
|||
+ rounding.Vector512) >> cosBit; |
|||
|
|||
return As<Vector512<int>, TValue>(vector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Multiplies a transform value by a fixed-point constant and applies the requested rounding shift.
|
|||
/// </summary>
|
|||
/// <param name="value">The transform value.</param>
|
|||
/// <param name="multiplier">The fixed-point multiplier.</param>
|
|||
/// <param name="shift">The number of fractional bits in the multiplier.</param>
|
|||
/// <returns>The rounded lane-wise product.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TValue MultiplyRound(TValue value, int multiplier, int shift) |
|||
{ |
|||
Av1TransformRounding rounding = CreateRounding(shift); |
|||
return HalfButterfly(multiplier, value, 0, default, shift, in rounding); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Shifts each transform lane left without saturation.
|
|||
/// </summary>
|
|||
/// <param name="value">The transform value.</param>
|
|||
/// <param name="count">The shift count.</param>
|
|||
/// <returns>The shifted lane values.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TValue ShiftLeft(TValue value, int count) |
|||
{ |
|||
if (typeof(TValue) == typeof(short)) |
|||
{ |
|||
short result = unchecked((short)(As<TValue, short>(value) << count)); |
|||
return As<short, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(int)) |
|||
{ |
|||
int result = As<TValue, int>(value) << count; |
|||
return As<int, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<short>)) |
|||
{ |
|||
Vector128<short> result = As<TValue, Vector128<short>>(value) << count; |
|||
return As<Vector128<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<int>)) |
|||
{ |
|||
Vector128<int> result = As<TValue, Vector128<int>>(value) << count; |
|||
return As<Vector128<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<short>)) |
|||
{ |
|||
Vector256<short> result = As<TValue, Vector256<short>>(value) << count; |
|||
return As<Vector256<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<int>)) |
|||
{ |
|||
Vector256<int> result = As<TValue, Vector256<int>>(value) << count; |
|||
return As<Vector256<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector512<short>)) |
|||
{ |
|||
Vector512<short> result = As<TValue, Vector512<short>>(value) << count; |
|||
return As<Vector512<short>, TValue>(result); |
|||
} |
|||
|
|||
Vector512<int> vector = As<TValue, Vector512<int>>(value) << count; |
|||
return As<Vector512<int>, TValue>(vector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates one rounded sum containing four independently weighted transform values.
|
|||
/// </summary>
|
|||
/// <param name="weight0">The first fixed-point weight.</param>
|
|||
/// <param name="input0">The first transform value.</param>
|
|||
/// <param name="weight1">The second fixed-point weight.</param>
|
|||
/// <param name="input1">The second transform value.</param>
|
|||
/// <param name="weight2">The third fixed-point weight.</param>
|
|||
/// <param name="input2">The third transform value.</param>
|
|||
/// <param name="weight3">The fourth fixed-point weight.</param>
|
|||
/// <param name="input3">The fourth transform value.</param>
|
|||
/// <param name="cosBit">The number of fractional bits in each weight.</param>
|
|||
/// <param name="rounding">The rounding value created for this transform.</param>
|
|||
/// <returns>The rounded lane-wise weighted sum.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static TValue MultiplyAddRound( |
|||
int weight0, |
|||
TValue input0, |
|||
int weight1, |
|||
TValue input1, |
|||
int weight2, |
|||
TValue input2, |
|||
int weight3, |
|||
TValue input3, |
|||
int cosBit, |
|||
in Av1TransformRounding rounding) |
|||
{ |
|||
if (typeof(TValue) == typeof(short)) |
|||
{ |
|||
int weighted = (weight0 * As<TValue, short>(input0)) |
|||
+ (weight1 * As<TValue, short>(input1)) |
|||
+ (weight2 * As<TValue, short>(input2)) |
|||
+ (weight3 * As<TValue, short>(input3)); |
|||
|
|||
short result = (short)Math.Clamp((weighted + rounding.Scalar) >> cosBit, short.MinValue, short.MaxValue); |
|||
return As<short, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(int)) |
|||
{ |
|||
int weighted = (weight0 * As<TValue, int>(input0)) |
|||
+ (weight1 * As<TValue, int>(input1)) |
|||
+ (weight2 * As<TValue, int>(input2)) |
|||
+ (weight3 * As<TValue, int>(input3)); |
|||
|
|||
int result = (weighted + rounding.Scalar) >> cosBit; |
|||
return As<int, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<short>)) |
|||
{ |
|||
Vector128<short> result = MultiplyRound( |
|||
As<TValue, Vector128<short>>(input0), |
|||
weight0, |
|||
As<TValue, Vector128<short>>(input1), |
|||
weight1, |
|||
As<TValue, Vector128<short>>(input2), |
|||
weight2, |
|||
As<TValue, Vector128<short>>(input3), |
|||
weight3, |
|||
cosBit, |
|||
rounding.Vector128); |
|||
|
|||
return As<Vector128<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector128<int>)) |
|||
{ |
|||
Vector128<int> result = ((As<TValue, Vector128<int>>(input0) * Vector128.Create(weight0)) |
|||
+ (As<TValue, Vector128<int>>(input1) * Vector128.Create(weight1)) |
|||
+ (As<TValue, Vector128<int>>(input2) * Vector128.Create(weight2)) |
|||
+ (As<TValue, Vector128<int>>(input3) * Vector128.Create(weight3)) |
|||
+ rounding.Vector128) >> cosBit; |
|||
|
|||
return As<Vector128<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<short>)) |
|||
{ |
|||
Vector256<short> result = MultiplyRound( |
|||
As<TValue, Vector256<short>>(input0), |
|||
weight0, |
|||
As<TValue, Vector256<short>>(input1), |
|||
weight1, |
|||
As<TValue, Vector256<short>>(input2), |
|||
weight2, |
|||
As<TValue, Vector256<short>>(input3), |
|||
weight3, |
|||
cosBit, |
|||
rounding.Vector256); |
|||
|
|||
return As<Vector256<short>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector256<int>)) |
|||
{ |
|||
Vector256<int> result = ((As<TValue, Vector256<int>>(input0) * Vector256.Create(weight0)) |
|||
+ (As<TValue, Vector256<int>>(input1) * Vector256.Create(weight1)) |
|||
+ (As<TValue, Vector256<int>>(input2) * Vector256.Create(weight2)) |
|||
+ (As<TValue, Vector256<int>>(input3) * Vector256.Create(weight3)) |
|||
+ rounding.Vector256) >> cosBit; |
|||
|
|||
return As<Vector256<int>, TValue>(result); |
|||
} |
|||
|
|||
if (typeof(TValue) == typeof(Vector512<short>)) |
|||
{ |
|||
Vector512<short> result = MultiplyRound( |
|||
As<TValue, Vector512<short>>(input0), |
|||
weight0, |
|||
As<TValue, Vector512<short>>(input1), |
|||
weight1, |
|||
As<TValue, Vector512<short>>(input2), |
|||
weight2, |
|||
As<TValue, Vector512<short>>(input3), |
|||
weight3, |
|||
cosBit, |
|||
rounding.Vector512); |
|||
|
|||
return As<Vector512<short>, TValue>(result); |
|||
} |
|||
|
|||
Vector512<int> vector = ((As<TValue, Vector512<int>>(input0) * Vector512.Create(weight0)) |
|||
+ (As<TValue, Vector512<int>>(input1) * Vector512.Create(weight1)) |
|||
+ (As<TValue, Vector512<int>>(input2) * Vector512.Create(weight2)) |
|||
+ (As<TValue, Vector512<int>>(input3) * Vector512.Create(weight3)) |
|||
+ rounding.Vector512) >> cosBit; |
|||
|
|||
return As<Vector512<int>, TValue>(vector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts one value type to another equal-sized value type without changing its bits.
|
|||
/// </summary>
|
|||
/// <typeparam name="TFrom">The source value type.</typeparam>
|
|||
/// <typeparam name="TTo">The destination value type.</typeparam>
|
|||
/// <param name="value">The value to reinterpret.</param>
|
|||
/// <returns>The reinterpreted value.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static TTo As<TFrom, TTo>(TFrom value) |
|||
where TFrom : struct |
|||
where TTo : struct |
|||
=> Unsafe.As<TFrom, TTo>(ref value); |
|||
|
|||
/// <summary>
|
|||
/// Calculates and narrows two weighted 128-bit signed sixteen-bit vectors.
|
|||
/// </summary>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Vector128<short> MultiplyRound( |
|||
Vector128<short> input0, |
|||
int weight0, |
|||
Vector128<short> input1, |
|||
int weight1, |
|||
int cosBit, |
|||
Vector128<int> rounding) |
|||
{ |
|||
// Widening preserves lane order on every Vector128 implementation. The explicit clamp gives Narrow the
|
|||
// signed-saturating demotion semantics used by Highway on x86, Arm, and WebAssembly.
|
|||
(Vector128<int> input0Lower, Vector128<int> input0Upper) = Vector128.Widen(input0); |
|||
(Vector128<int> input1Lower, Vector128<int> input1Upper) = Vector128.Widen(input1); |
|||
|
|||
Vector128<int> weight0Vector = Vector128.Create(weight0); |
|||
Vector128<int> weight1Vector = Vector128.Create(weight1); |
|||
Vector128<int> lower = ((input0Lower * weight0Vector) + (input1Lower * weight1Vector) + rounding) >> cosBit; |
|||
Vector128<int> upper = ((input0Upper * weight0Vector) + (input1Upper * weight1Vector) + rounding) >> cosBit; |
|||
Vector128<int> minimum = Vector128.Create((int)short.MinValue); |
|||
Vector128<int> maximum = Vector128.Create((int)short.MaxValue); |
|||
|
|||
lower = Vector128.Clamp(lower, minimum, maximum); |
|||
upper = Vector128.Clamp(upper, minimum, maximum); |
|||
return Vector128.Narrow(lower, upper); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates and narrows two weighted 256-bit signed sixteen-bit vectors.
|
|||
/// </summary>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Vector256<short> MultiplyRound( |
|||
Vector256<short> input0, |
|||
int weight0, |
|||
Vector256<short> input1, |
|||
int weight1, |
|||
int cosBit, |
|||
Vector256<int> rounding) |
|||
{ |
|||
// The AVX2 path mirrors Highway's WidenMulPairwiseAdd primitive: adjacent Int16 products become Int32
|
|||
// sums, then VPACKSSDW restores the original lane width with signed saturation.
|
|||
Vector256<short> lowerInputs = Avx2.UnpackLow(input0, input1); |
|||
Vector256<short> upperInputs = Avx2.UnpackHigh(input0, input1); |
|||
Vector256<short> weights = Avx2.UnpackLow(Vector256.Create((short)weight0), Vector256.Create((short)weight1)); |
|||
Vector256<int> lower = (Avx2.MultiplyAddAdjacent(lowerInputs, weights) + rounding) >> cosBit; |
|||
Vector256<int> upper = (Avx2.MultiplyAddAdjacent(upperInputs, weights) + rounding) >> cosBit; |
|||
return Avx2.PackSignedSaturate(lower, upper); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates and narrows two weighted 512-bit signed sixteen-bit vectors.
|
|||
/// </summary>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Vector512<short> MultiplyRound( |
|||
Vector512<short> input0, |
|||
int weight0, |
|||
Vector512<short> input1, |
|||
int weight1, |
|||
int cosBit, |
|||
Vector512<int> rounding) |
|||
{ |
|||
Vector512<short> lowerInputs = Avx512BW.UnpackLow(input0, input1); |
|||
Vector512<short> upperInputs = Avx512BW.UnpackHigh(input0, input1); |
|||
Vector512<short> weights = Avx512BW.UnpackLow(Vector512.Create((short)weight0), Vector512.Create((short)weight1)); |
|||
Vector512<int> lower = (Avx512BW.MultiplyAddAdjacent(lowerInputs, weights) + rounding) >> cosBit; |
|||
Vector512<int> upper = (Avx512BW.MultiplyAddAdjacent(upperInputs, weights) + rounding) >> cosBit; |
|||
return Avx512BW.PackSignedSaturate(lower, upper); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates and narrows four weighted 128-bit signed sixteen-bit vectors.
|
|||
/// </summary>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Vector128<short> MultiplyRound( |
|||
Vector128<short> input0, |
|||
int weight0, |
|||
Vector128<short> input1, |
|||
int weight1, |
|||
Vector128<short> input2, |
|||
int weight2, |
|||
Vector128<short> input3, |
|||
int weight3, |
|||
int cosBit, |
|||
Vector128<int> rounding) |
|||
{ |
|||
(Vector128<int> input0Lower, Vector128<int> input0Upper) = Vector128.Widen(input0); |
|||
(Vector128<int> input1Lower, Vector128<int> input1Upper) = Vector128.Widen(input1); |
|||
(Vector128<int> input2Lower, Vector128<int> input2Upper) = Vector128.Widen(input2); |
|||
(Vector128<int> input3Lower, Vector128<int> input3Upper) = Vector128.Widen(input3); |
|||
|
|||
Vector128<int> lower = ((input0Lower * Vector128.Create(weight0)) |
|||
+ (input1Lower * Vector128.Create(weight1)) |
|||
+ (input2Lower * Vector128.Create(weight2)) |
|||
+ (input3Lower * Vector128.Create(weight3)) |
|||
+ rounding) >> cosBit; |
|||
|
|||
Vector128<int> upper = ((input0Upper * Vector128.Create(weight0)) |
|||
+ (input1Upper * Vector128.Create(weight1)) |
|||
+ (input2Upper * Vector128.Create(weight2)) |
|||
+ (input3Upper * Vector128.Create(weight3)) |
|||
+ rounding) >> cosBit; |
|||
|
|||
Vector128<int> minimum = Vector128.Create((int)short.MinValue); |
|||
Vector128<int> maximum = Vector128.Create((int)short.MaxValue); |
|||
lower = Vector128.Clamp(lower, minimum, maximum); |
|||
upper = Vector128.Clamp(upper, minimum, maximum); |
|||
return Vector128.Narrow(lower, upper); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates and narrows four weighted 256-bit signed sixteen-bit vectors.
|
|||
/// </summary>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Vector256<short> MultiplyRound( |
|||
Vector256<short> input0, |
|||
int weight0, |
|||
Vector256<short> input1, |
|||
int weight1, |
|||
Vector256<short> input2, |
|||
int weight2, |
|||
Vector256<short> input3, |
|||
int weight3, |
|||
int cosBit, |
|||
Vector256<int> rounding) |
|||
{ |
|||
Vector256<short> weights01 = Avx2.UnpackLow(Vector256.Create((short)weight0), Vector256.Create((short)weight1)); |
|||
Vector256<short> weights23 = Avx2.UnpackLow(Vector256.Create((short)weight2), Vector256.Create((short)weight3)); |
|||
Vector256<int> lower = Avx2.MultiplyAddAdjacent(Avx2.UnpackLow(input0, input1), weights01) |
|||
+ Avx2.MultiplyAddAdjacent(Avx2.UnpackLow(input2, input3), weights23); |
|||
|
|||
Vector256<int> upper = Avx2.MultiplyAddAdjacent(Avx2.UnpackHigh(input0, input1), weights01) |
|||
+ Avx2.MultiplyAddAdjacent(Avx2.UnpackHigh(input2, input3), weights23); |
|||
|
|||
lower = (lower + rounding) >> cosBit; |
|||
upper = (upper + rounding) >> cosBit; |
|||
return Avx2.PackSignedSaturate(lower, upper); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates and narrows four weighted 512-bit signed sixteen-bit vectors.
|
|||
/// </summary>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Vector512<short> MultiplyRound( |
|||
Vector512<short> input0, |
|||
int weight0, |
|||
Vector512<short> input1, |
|||
int weight1, |
|||
Vector512<short> input2, |
|||
int weight2, |
|||
Vector512<short> input3, |
|||
int weight3, |
|||
int cosBit, |
|||
Vector512<int> rounding) |
|||
{ |
|||
Vector512<short> weights01 = Avx512BW.UnpackLow(Vector512.Create((short)weight0), Vector512.Create((short)weight1)); |
|||
Vector512<short> weights23 = Avx512BW.UnpackLow(Vector512.Create((short)weight2), Vector512.Create((short)weight3)); |
|||
Vector512<int> lower = Avx512BW.MultiplyAddAdjacent(Avx512BW.UnpackLow(input0, input1), weights01) |
|||
+ Avx512BW.MultiplyAddAdjacent(Avx512BW.UnpackLow(input2, input3), weights23); |
|||
|
|||
Vector512<int> upper = Avx512BW.MultiplyAddAdjacent(Avx512BW.UnpackHigh(input0, input1), weights01) |
|||
+ Avx512BW.MultiplyAddAdjacent(Avx512BW.UnpackHigh(input2, input3), weights23); |
|||
|
|||
lower = (lower + rounding) >> cosBit; |
|||
upper = (upper + rounding) >> cosBit; |
|||
return Avx512BW.PackSignedSaturate(lower, upper); |
|||
} |
|||
} |
|||
@ -0,0 +1,311 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Implements the forward asymmetric discrete sine transform stage networks.
|
|||
/// </content>
|
|||
internal static partial class Av1ForwardTransformOperations |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the four-point forward asymmetric discrete sine transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The unused transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the sine constants.</param>
|
|||
public static void Adst4<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
{ |
|||
_ = step; |
|||
|
|||
ReadOnlySpan<int> sinpi = Av1SinusConstants.SinusPi(cosBit); |
|||
Av1TransformRounding rounding = Av1ForwardTransformArithmetic<TValue>.CreateRounding(cosBit); |
|||
TValue input0 = input[0]; |
|||
TValue input1 = input[1]; |
|||
TValue input2 = input[2]; |
|||
TValue input3 = input[3]; |
|||
TValue input01 = Av1ForwardTransformArithmetic<TValue>.Add(input0, input1); |
|||
|
|||
// Highway forms x0 + x1 in the native lane width before widening the products. Retaining that intermediate
|
|||
// is observable for Int16 overflow and is therefore part of the reference stage network, not an algebraic
|
|||
// simplification opportunity.
|
|||
output[0] = Av1ForwardTransformArithmetic<TValue>.MultiplyAddRound( |
|||
sinpi[1], input0, sinpi[2], input1, sinpi[3], input2, sinpi[4], input3, cosBit, in rounding); |
|||
output[1] = Av1ForwardTransformArithmetic<TValue>.MultiplyAddRound( |
|||
sinpi[3], input01, -sinpi[3], input3, 0, input0, 0, input0, cosBit, in rounding); |
|||
output[2] = Av1ForwardTransformArithmetic<TValue>.MultiplyAddRound( |
|||
sinpi[4], input0, -sinpi[1], input1, -sinpi[3], input2, sinpi[2], input3, cosBit, in rounding); |
|||
|
|||
// The final output is Highway's widened w2 - w0 + 3 * v5 sequence expressed with the same unrounded
|
|||
// products. All four outputs then share the single normative fixed-point rounding point.
|
|||
output[3] = Av1ForwardTransformArithmetic<TValue>.MultiplyAddRound( |
|||
sinpi[4] - sinpi[1], |
|||
input0, |
|||
-sinpi[1] - sinpi[2], |
|||
input1, |
|||
sinpi[3], |
|||
input2, |
|||
sinpi[2] - sinpi[4], |
|||
input3, |
|||
cosBit, |
|||
in rounding); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the eight-point forward asymmetric discrete sine transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values and first transform-stage buffer.</param>
|
|||
/// <param name="step">The second transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
public static void Adst8<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
Av1TransformRounding rounding = Av1ForwardTransformArithmetic<TValue>.CreateRounding(cosBit); |
|||
|
|||
// Stage 1 applies the ADST input permutation and signs. The following stages can then use the same adjacent
|
|||
// butterfly layout across every scalar and SIMD instantiation.
|
|||
output[0] = input[0]; |
|||
output[1] = Av1ForwardTransformArithmetic<TValue>.Negate(input[7]); |
|||
output[2] = Av1ForwardTransformArithmetic<TValue>.Negate(input[3]); |
|||
output[3] = input[4]; |
|||
output[4] = Av1ForwardTransformArithmetic<TValue>.Negate(input[1]); |
|||
output[5] = input[6]; |
|||
output[6] = input[2]; |
|||
output[7] = Av1ForwardTransformArithmetic<TValue>.Negate(input[5]); |
|||
|
|||
// Stage 2 rotates the second pair in each four-value group while copying the already aligned pairs.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly( |
|||
cospi[32], cospi[32], output[2], output[3], out step[2], out step[3], cosBit, in rounding); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly( |
|||
cospi[32], cospi[32], output[6], output[7], out step[6], out step[7], cosBit, in rounding); |
|||
|
|||
// Stage 3 combines the rotated and copied pairs into two independent four-value groups.
|
|||
for (int group = 0; group < 8; group += 4) |
|||
{ |
|||
for (int i = 0; i < 2; i++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
step[group + i], |
|||
step[group + i + 2], |
|||
out output[group + i], |
|||
out output[group + i + 2]); |
|||
} |
|||
} |
|||
|
|||
// Stage 4 rotates the upper group by pi/8 and retains the completed lower group.
|
|||
for (int i = 0; i < 4; i++) |
|||
{ |
|||
step[i] = output[i]; |
|||
} |
|||
|
|||
step[4] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[16], output[4], cospi[48], output[5], cosBit, in rounding); |
|||
step[5] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[48], output[4], -cospi[16], output[5], cosBit, in rounding); |
|||
step[6] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
-cospi[48], output[6], cospi[16], output[7], cosBit, in rounding); |
|||
step[7] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[16], output[6], cospi[48], output[7], cosBit, in rounding); |
|||
|
|||
// Stage 5 creates the four final butterfly pairs spanning the two groups.
|
|||
for (int i = 0; i < 4; i++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[i], step[i + 4], out output[i], out output[i + 4]); |
|||
} |
|||
|
|||
// Stage 6 applies the remaining odd angles. Each result is placed in step for the fixed ADST permutation.
|
|||
step[0] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[4], output[0], cospi[60], output[1], cosBit, in rounding); |
|||
step[1] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[60], output[0], -cospi[4], output[1], cosBit, in rounding); |
|||
step[2] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[20], output[2], cospi[44], output[3], cosBit, in rounding); |
|||
step[3] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[44], output[2], -cospi[20], output[3], cosBit, in rounding); |
|||
step[4] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[36], output[4], cospi[28], output[5], cosBit, in rounding); |
|||
step[5] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[28], output[4], -cospi[36], output[5], cosBit, in rounding); |
|||
step[6] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[52], output[6], cospi[12], output[7], cosBit, in rounding); |
|||
step[7] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[12], output[6], -cospi[52], output[7], cosBit, in rounding); |
|||
|
|||
// Stage 7 is the normative ADST output permutation.
|
|||
output[0] = step[1]; |
|||
output[1] = step[6]; |
|||
output[2] = step[3]; |
|||
output[3] = step[4]; |
|||
output[4] = step[5]; |
|||
output[5] = step[2]; |
|||
output[6] = step[7]; |
|||
output[7] = step[0]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the sixteen-point forward asymmetric discrete sine transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values and first transform-stage buffer.</param>
|
|||
/// <param name="step">The second transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
public static void Adst16<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
Av1TransformRounding rounding = Av1ForwardTransformArithmetic<TValue>.CreateRounding(cosBit); |
|||
|
|||
// Stage 1 applies the bit-reversed ADST input order and its alternating signs.
|
|||
output[0] = input[0]; |
|||
output[1] = Av1ForwardTransformArithmetic<TValue>.Negate(input[15]); |
|||
output[2] = Av1ForwardTransformArithmetic<TValue>.Negate(input[7]); |
|||
output[3] = input[8]; |
|||
output[4] = Av1ForwardTransformArithmetic<TValue>.Negate(input[3]); |
|||
output[5] = input[12]; |
|||
output[6] = input[4]; |
|||
output[7] = Av1ForwardTransformArithmetic<TValue>.Negate(input[11]); |
|||
output[8] = Av1ForwardTransformArithmetic<TValue>.Negate(input[1]); |
|||
output[9] = input[14]; |
|||
output[10] = input[6]; |
|||
output[11] = Av1ForwardTransformArithmetic<TValue>.Negate(input[9]); |
|||
output[12] = input[2]; |
|||
output[13] = Av1ForwardTransformArithmetic<TValue>.Negate(input[13]); |
|||
output[14] = Av1ForwardTransformArithmetic<TValue>.Negate(input[5]); |
|||
output[15] = input[10]; |
|||
|
|||
// Stage 2 rotates the second pair in each group of four and copies the first pair unchanged.
|
|||
for (int group = 0; group < 16; group += 4) |
|||
{ |
|||
step[group] = output[group]; |
|||
step[group + 1] = output[group + 1]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly( |
|||
cospi[32], |
|||
cospi[32], |
|||
output[group + 2], |
|||
output[group + 3], |
|||
out step[group + 2], |
|||
out step[group + 3], |
|||
cosBit, |
|||
in rounding); |
|||
} |
|||
|
|||
// Stage 3 combines adjacent pairs within each group of four.
|
|||
for (int group = 0; group < 16; group += 4) |
|||
{ |
|||
for (int i = 0; i < 2; i++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
step[group + i], |
|||
step[group + i + 2], |
|||
out output[group + i], |
|||
out output[group + i + 2]); |
|||
} |
|||
} |
|||
|
|||
// Stage 4 rotates the upper pair of each eight-value group by pi/8.
|
|||
for (int group = 0; group < 16; group += 8) |
|||
{ |
|||
for (int i = 0; i < 4; i++) |
|||
{ |
|||
step[group + i] = output[group + i]; |
|||
} |
|||
|
|||
step[group + 4] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[16], output[group + 4], cospi[48], output[group + 5], cosBit, in rounding); |
|||
step[group + 5] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[48], output[group + 4], -cospi[16], output[group + 5], cosBit, in rounding); |
|||
step[group + 6] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
-cospi[48], output[group + 6], cospi[16], output[group + 7], cosBit, in rounding); |
|||
step[group + 7] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[16], output[group + 6], cospi[48], output[group + 7], cosBit, in rounding); |
|||
} |
|||
|
|||
// Stage 5 combines the lower and upper quartets within each eight-value group.
|
|||
for (int group = 0; group < 16; group += 8) |
|||
{ |
|||
for (int i = 0; i < 4; i++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
step[group + i], |
|||
step[group + i + 4], |
|||
out output[group + i], |
|||
out output[group + i + 4]); |
|||
} |
|||
} |
|||
|
|||
// Stage 6 rotates the upper octet by pi/16 while retaining the completed lower octet.
|
|||
for (int i = 0; i < 8; i++) |
|||
{ |
|||
step[i] = output[i]; |
|||
} |
|||
|
|||
step[8] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[8], output[8], cospi[56], output[9], cosBit, in rounding); |
|||
step[9] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[56], output[8], -cospi[8], output[9], cosBit, in rounding); |
|||
step[10] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[40], output[10], cospi[24], output[11], cosBit, in rounding); |
|||
step[11] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[24], output[10], -cospi[40], output[11], cosBit, in rounding); |
|||
step[12] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
-cospi[56], output[12], cospi[8], output[13], cosBit, in rounding); |
|||
step[13] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[8], output[12], cospi[56], output[13], cosBit, in rounding); |
|||
step[14] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
-cospi[24], output[14], cospi[40], output[15], cosBit, in rounding); |
|||
step[15] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[40], output[14], cospi[24], output[15], cosBit, in rounding); |
|||
|
|||
// Stage 7 creates the eight final butterfly pairs spanning both octets.
|
|||
for (int i = 0; i < 8; i++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[i], step[i + 8], out output[i], out output[i + 8]); |
|||
} |
|||
|
|||
// Stage 8 applies the final odd-angle rotations before the fixed output permutation.
|
|||
ReadOnlySpan<int> firstWeights = [2, 10, 18, 26, 34, 42, 50, 58]; |
|||
|
|||
for (int pair = 0; pair < 8; pair++) |
|||
{ |
|||
int first = firstWeights[pair]; |
|||
int second = 64 - first; |
|||
int index = pair * 2; |
|||
|
|||
step[index] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[first], output[index], cospi[second], output[index + 1], cosBit, in rounding); |
|||
step[index + 1] = Av1ForwardTransformArithmetic<TValue>.HalfButterfly( |
|||
cospi[second], output[index], -cospi[first], output[index + 1], cosBit, in rounding); |
|||
} |
|||
|
|||
// Stage 9 maps the rotated input to ascending AV1 ADST coefficient order.
|
|||
ReadOnlySpan<byte> permutation = [1, 14, 3, 12, 5, 10, 7, 8, 9, 6, 11, 4, 13, 2, 15, 0]; |
|||
|
|||
for (int i = 0; i < 16; i++) |
|||
{ |
|||
output[i] = step[permutation[i]]; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,120 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Implements the sixteen-point forward DCT stage network.
|
|||
/// </content>
|
|||
internal static partial class Av1ForwardTransformOperations |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the sixteen-point forward discrete cosine transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The fixed transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
public static void Dct16<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
{ |
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[0], input[15], out output[0], out output[15]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[1], input[14], out output[1], out output[14]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[2], input[13], out output[2], out output[13]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[3], input[12], out output[3], out output[12]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[4], input[11], out output[4], out output[11]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[5], input[10], out output[5], out output[10]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[6], input[9], out output[6], out output[9]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[7], input[8], out output[7], out output[8]); |
|||
|
|||
// Stage 2 factorizes the even half and rotates the central odd pairs by pi/4.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
Av1TransformRounding rounding = Av1ForwardTransformArithmetic<TValue>.CreateRounding(cosBit); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[0], output[7], out step[0], out step[7]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[1], output[6], out step[1], out step[6]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[2], output[5], out step[2], out step[5]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[3], output[4], out step[3], out step[4]); |
|||
|
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[10], output[13], out step[10], out step[13], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[11], output[12], out step[11], out step[12], cosBit, in rounding); |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 3 recursively factorizes both eight-sample groups into four-sample butterflies.
|
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[0], step[3], out output[0], out output[3]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[1], step[2], out output[1], out output[2]); |
|||
|
|||
output[4] = step[4]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], step[5], step[6], out output[5], out output[6], cosBit, in rounding); |
|||
output[7] = step[7]; |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[8], step[11], out output[8], out output[11]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[9], step[10], out output[9], out output[10]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[14], step[13], out output[14], out output[13]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[15], step[12], out output[15], out output[12]); |
|||
|
|||
// Stage 4 completes the low-frequency four-point DCT and rotates the first odd-frequency pairs.
|
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[32], cospi[32], output[0], output[1], out step[0], out step[1], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[16], cospi[48], output[3], output[2], out step[2], out step[3], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[4], output[5], out step[4], out step[5]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[7], output[6], out step[7], out step[6]); |
|||
|
|||
step[8] = output[8]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[16], cospi[48], output[9], output[14], out step[9], out step[14], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[48], -cospi[16], output[10], output[13], out step[10], out step[13], cosBit, in rounding); |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 5 combines the remaining odd terms into the sign pattern required by the next rotations.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[8], cospi[56], step[7], step[4], out output[4], out output[7], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[40], cospi[24], step[6], step[5], out output[5], out output[6], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[8], step[9], out output[8], out output[9]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[11], step[10], out output[11], out output[10]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[12], step[13], out output[12], out output[13]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[15], step[14], out output[15], out output[14]); |
|||
|
|||
// Stage 6 applies the final pi/32 odd-frequency rotations.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[4], cospi[60], output[15], output[8], out step[8], out step[15], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[36], cospi[28], output[14], output[9], out step[9], out step[14], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[20], cospi[44], output[13], output[10], out step[10], out step[13], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[52], cospi[12], output[12], output[11], out step[11], out step[12], cosBit, in rounding); |
|||
|
|||
// Stage 7 permutes the staged values into ascending AV1 coefficient order.
|
|||
output[0] = step[0]; |
|||
output[1] = step[8]; |
|||
output[2] = step[4]; |
|||
output[3] = step[12]; |
|||
output[4] = step[2]; |
|||
output[5] = step[10]; |
|||
output[6] = step[6]; |
|||
output[7] = step[14]; |
|||
output[8] = step[1]; |
|||
output[9] = step[9]; |
|||
output[10] = step[5]; |
|||
output[11] = step[13]; |
|||
output[12] = step[3]; |
|||
output[13] = step[11]; |
|||
output[14] = step[7]; |
|||
output[15] = step[15]; |
|||
} |
|||
} |
|||
@ -0,0 +1,224 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Implements the thirty-two-point forward DCT stage network.
|
|||
/// </content>
|
|||
internal static partial class Av1ForwardTransformOperations |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the thirty-two-point forward discrete cosine transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The fixed transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
public static void Dct32<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
{ |
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
for (int index = 0; index < 16; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[index], input[31 - index], out output[index], out output[31 - index]); |
|||
} |
|||
|
|||
// Stage 2 begins the recursive radix-2 factorization and rotates the central odd pairs.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
Av1TransformRounding rounding = Av1ForwardTransformArithmetic<TValue>.CreateRounding(cosBit); |
|||
for (int index = 0; index < 8; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[index], output[15 - index], out step[index], out step[15 - index]); |
|||
} |
|||
|
|||
step[16] = output[16]; |
|||
step[17] = output[17]; |
|||
step[18] = output[18]; |
|||
step[19] = output[19]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[20], output[27], out step[20], out step[27], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[21], output[26], out step[21], out step[26], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[22], output[25], out step[22], out step[25], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[23], output[24], out step[23], out step[24], cosBit, in rounding); |
|||
step[28] = output[28]; |
|||
step[29] = output[29]; |
|||
step[30] = output[30]; |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 3 reduces the even half and folds the next odd-frequency groups into butterflies.
|
|||
for (int index = 0; index < 4; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[index], step[7 - index], out output[index], out output[7 - index]); |
|||
} |
|||
|
|||
output[8] = step[8]; |
|||
output[9] = step[9]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], step[10], step[13], out output[10], out output[13], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], step[11], step[12], out output[11], out output[12], cosBit, in rounding); |
|||
output[14] = step[14]; |
|||
output[15] = step[15]; |
|||
for (int index = 0; index < 4; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[16 + index], step[23 - index], out output[16 + index], out output[23 - index]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[31 - index], step[24 + index], out output[31 - index], out output[24 + index]); |
|||
} |
|||
|
|||
// Stage 4 continues the factorization as independent eight-sample groups.
|
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[0], output[3], out step[0], out step[3]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[1], output[2], out step[1], out step[2]); |
|||
|
|||
step[4] = output[4]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[5], output[6], out step[5], out step[6], cosBit, in rounding); |
|||
step[7] = output[7]; |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[8], output[11], out step[8], out step[11]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[9], output[10], out step[9], out step[10]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[14], output[13], out step[14], out step[13]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[15], output[12], out step[15], out step[12]); |
|||
|
|||
step[16] = output[16]; |
|||
step[17] = output[17]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[16], cospi[48], output[18], output[29], out step[18], out step[29], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[16], cospi[48], output[19], output[28], out step[19], out step[28], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[48], -cospi[16], output[20], output[27], out step[20], out step[27], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[48], -cospi[16], output[21], output[26], out step[21], out step[26], cosBit, in rounding); |
|||
step[22] = output[22]; |
|||
step[23] = output[23]; |
|||
step[24] = output[24]; |
|||
step[25] = output[25]; |
|||
step[30] = output[30]; |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 5 completes the low-frequency DCT and rotates the first separated odd groups.
|
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[32], cospi[32], step[0], step[1], out output[0], out output[1], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[16], cospi[48], step[3], step[2], out output[2], out output[3], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[4], step[5], out output[4], out output[5]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[7], step[6], out output[7], out output[6]); |
|||
|
|||
output[8] = step[8]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[16], cospi[48], step[9], step[14], out output[9], out output[14], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[48], -cospi[16], step[10], step[13], out output[10], out output[13], cosBit, in rounding); |
|||
output[11] = step[11]; |
|||
output[12] = step[12]; |
|||
output[15] = step[15]; |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[16], step[19], out output[16], out output[19]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[17], step[18], out output[17], out output[18]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[23], step[20], out output[23], out output[20]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[22], step[21], out output[22], out output[21]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[24], step[27], out output[24], out output[27]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[25], step[26], out output[25], out output[26]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[31], step[28], out output[31], out output[28]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[30], step[29], out output[30], out output[29]); |
|||
|
|||
// Stage 6 merges adjacent odd-frequency terms with the required AV1 sign pattern.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[8], cospi[56], output[7], output[4], out step[4], out step[7], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[40], cospi[24], output[6], output[5], out step[5], out step[6], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[8], output[9], out step[8], out step[9]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[11], output[10], out step[11], out step[10]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[12], output[13], out step[12], out step[13]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[15], output[14], out step[15], out step[14]); |
|||
|
|||
step[16] = output[16]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[8], cospi[56], output[17], output[30], out step[17], out step[30], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[56], -cospi[8], output[18], output[29], out step[18], out step[29], cosBit, in rounding); |
|||
step[19] = output[19]; |
|||
step[20] = output[20]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[40], cospi[24], output[21], output[26], out step[21], out step[26], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[24], -cospi[40], output[22], output[25], out step[22], out step[25], cosBit, in rounding); |
|||
step[23] = output[23]; |
|||
step[24] = output[24]; |
|||
step[27] = output[27]; |
|||
step[28] = output[28]; |
|||
step[31] = output[31]; |
|||
|
|||
// Stage 7 applies the pi/32 rotations to the next odd-frequency level.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = step[4]; |
|||
output[5] = step[5]; |
|||
output[6] = step[6]; |
|||
output[7] = step[7]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[4], cospi[60], step[15], step[8], out output[8], out output[15], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[36], cospi[28], step[14], step[9], out output[9], out output[14], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[20], cospi[44], step[13], step[10], out output[10], out output[13], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[52], cospi[12], step[12], step[11], out output[11], out output[12], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[16], step[17], out output[16], out output[17]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[19], step[18], out output[19], out output[18]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[20], step[21], out output[20], out output[21]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[23], step[22], out output[23], out output[22]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[24], step[25], out output[24], out output[25]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[27], step[26], out output[27], out output[26]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[28], step[29], out output[28], out output[29]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[31], step[30], out output[31], out output[30]); |
|||
|
|||
// Stage 8 merges the final odd-frequency pairs before their terminal rotations.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[2], cospi[62], output[31], output[16], out step[16], out step[31], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[34], cospi[30], output[30], output[17], out step[17], out step[30], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[18], cospi[46], output[29], output[18], out step[18], out step[29], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[50], cospi[14], output[28], output[19], out step[19], out step[28], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[10], cospi[54], output[27], output[20], out step[20], out step[27], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[42], cospi[22], output[26], output[21], out step[21], out step[26], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[26], cospi[38], output[25], output[22], out step[22], out step[25], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[58], cospi[6], output[24], output[23], out step[23], out step[24], cosBit, in rounding); |
|||
|
|||
// Stage 9 applies the terminal pi/64 rotations and produces the staged coefficient values.
|
|||
output[0] = step[0]; |
|||
output[1] = step[16]; |
|||
output[2] = step[8]; |
|||
output[3] = step[24]; |
|||
output[4] = step[4]; |
|||
output[5] = step[20]; |
|||
output[6] = step[12]; |
|||
output[7] = step[28]; |
|||
output[8] = step[2]; |
|||
output[9] = step[18]; |
|||
output[10] = step[10]; |
|||
output[11] = step[26]; |
|||
output[12] = step[6]; |
|||
output[13] = step[22]; |
|||
output[14] = step[14]; |
|||
output[15] = step[30]; |
|||
output[16] = step[1]; |
|||
output[17] = step[17]; |
|||
output[18] = step[9]; |
|||
output[19] = step[25]; |
|||
output[20] = step[5]; |
|||
output[21] = step[21]; |
|||
output[22] = step[13]; |
|||
output[23] = step[29]; |
|||
output[24] = step[3]; |
|||
output[25] = step[19]; |
|||
output[26] = step[11]; |
|||
output[27] = step[27]; |
|||
output[28] = step[7]; |
|||
output[29] = step[23]; |
|||
output[30] = step[15]; |
|||
output[31] = step[31]; |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Implements the four-point forward DCT stage network.
|
|||
/// </content>
|
|||
internal static partial class Av1ForwardTransformOperations |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the four-point forward discrete cosine transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The fixed transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
public static void Dct4<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
{ |
|||
// Libaom forms both outputs of each mirror pair together. This preserves the saturating Int16 AddSub
|
|||
// primitive used by Highway while the Int32 and scalar specializations retain their native arithmetic.
|
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[0], input[3], out output[0], out output[3]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[1], input[2], out output[1], out output[2]); |
|||
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
Av1TransformRounding rounding = Av1ForwardTransformArithmetic<TValue>.CreateRounding(cosBit); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[32], cospi[32], output[0], output[1], out step[0], out step[2], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[16], cospi[48], output[3], output[2], out step[1], out step[3], cosBit, in rounding); |
|||
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
} |
|||
} |
|||
@ -0,0 +1,437 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Implements the sixty-four-point forward DCT stage network.
|
|||
/// </content>
|
|||
internal static partial class Av1ForwardTransformOperations |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the sixty-four-point forward discrete cosine transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The fixed transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
public static void Dct64<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
{ |
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
for (int index = 0; index < 32; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[index], input[63 - index], out output[index], out output[63 - index]); |
|||
} |
|||
|
|||
// Stage 2 begins the recursive radix-2 factorization and rotates the central odd pairs.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
Av1TransformRounding rounding = Av1ForwardTransformArithmetic<TValue>.CreateRounding(cosBit); |
|||
for (int index = 0; index < 16; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[index], output[31 - index], out step[index], out step[31 - index]); |
|||
} |
|||
|
|||
step[32] = output[32]; |
|||
step[33] = output[33]; |
|||
step[34] = output[34]; |
|||
step[35] = output[35]; |
|||
step[36] = output[36]; |
|||
step[37] = output[37]; |
|||
step[38] = output[38]; |
|||
step[39] = output[39]; |
|||
for (int index = 0; index < 8; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly( |
|||
-cospi[32], cospi[32], output[40 + index], output[55 - index], out step[40 + index], out step[55 - index], cosBit, in rounding); |
|||
} |
|||
|
|||
step[56] = output[56]; |
|||
step[57] = output[57]; |
|||
step[58] = output[58]; |
|||
step[59] = output[59]; |
|||
step[60] = output[60]; |
|||
step[61] = output[61]; |
|||
step[62] = output[62]; |
|||
step[63] = output[63]; |
|||
|
|||
// Stage 3 reduces the even half and folds the next odd-frequency groups into butterflies.
|
|||
for (int index = 0; index < 8; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[index], step[15 - index], out output[index], out output[15 - index]); |
|||
} |
|||
|
|||
output[16] = step[16]; |
|||
output[17] = step[17]; |
|||
output[18] = step[18]; |
|||
output[19] = step[19]; |
|||
for (int index = 0; index < 4; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly( |
|||
-cospi[32], cospi[32], step[20 + index], step[27 - index], out output[20 + index], out output[27 - index], cosBit, in rounding); |
|||
} |
|||
|
|||
output[28] = step[28]; |
|||
output[29] = step[29]; |
|||
output[30] = step[30]; |
|||
output[31] = step[31]; |
|||
for (int index = 0; index < 8; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
step[32 + index], step[47 - index], out output[32 + index], out output[47 - index]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
step[63 - index], step[48 + index], out output[63 - index], out output[48 + index]); |
|||
} |
|||
|
|||
// Stage 4 continues the factorization as independent sixteen-sample groups.
|
|||
for (int index = 0; index < 4; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[index], output[7 - index], out step[index], out step[7 - index]); |
|||
} |
|||
|
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[10], output[13], out step[10], out step[13], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[11], output[12], out step[11], out step[12], cosBit, in rounding); |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
for (int index = 0; index < 4; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
output[16 + index], output[23 - index], out step[16 + index], out step[23 - index]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
output[31 - index], output[24 + index], out step[31 - index], out step[24 + index]); |
|||
} |
|||
|
|||
step[32] = output[32]; |
|||
step[33] = output[33]; |
|||
step[34] = output[34]; |
|||
step[35] = output[35]; |
|||
for (int index = 0; index < 4; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly( |
|||
-cospi[16], cospi[48], output[36 + index], output[59 - index], out step[36 + index], out step[59 - index], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly( |
|||
-cospi[48], -cospi[16], output[40 + index], output[55 - index], out step[40 + index], out step[55 - index], cosBit, in rounding); |
|||
} |
|||
|
|||
step[44] = output[44]; |
|||
step[45] = output[45]; |
|||
step[46] = output[46]; |
|||
step[47] = output[47]; |
|||
step[48] = output[48]; |
|||
step[49] = output[49]; |
|||
step[50] = output[50]; |
|||
step[51] = output[51]; |
|||
step[60] = output[60]; |
|||
step[61] = output[61]; |
|||
step[62] = output[62]; |
|||
step[63] = output[63]; |
|||
|
|||
// Stage 5 reduces those groups into the eight-sample DCT and ADST building blocks.
|
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[0], step[3], out output[0], out output[3]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[1], step[2], out output[1], out output[2]); |
|||
|
|||
output[4] = step[4]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], step[5], step[6], out output[5], out output[6], cosBit, in rounding); |
|||
output[7] = step[7]; |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[8], step[11], out output[8], out output[11]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[9], step[10], out output[9], out output[10]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[14], step[13], out output[14], out output[13]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[15], step[12], out output[15], out output[12]); |
|||
output[16] = step[16]; |
|||
output[17] = step[17]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[16], cospi[48], step[18], step[29], out output[18], out output[29], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[16], cospi[48], step[19], step[28], out output[19], out output[28], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[48], -cospi[16], step[20], step[27], out output[20], out output[27], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[48], -cospi[16], step[21], step[26], out output[21], out output[26], cosBit, in rounding); |
|||
output[22] = step[22]; |
|||
output[23] = step[23]; |
|||
output[24] = step[24]; |
|||
output[25] = step[25]; |
|||
output[30] = step[30]; |
|||
output[31] = step[31]; |
|||
for (int index = 0; index < 4; index++) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
step[32 + index], step[39 - index], out output[32 + index], out output[39 - index]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
step[47 - index], step[40 + index], out output[47 - index], out output[40 + index]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
step[48 + index], step[55 - index], out output[48 + index], out output[55 - index]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract( |
|||
step[63 - index], step[56 + index], out output[63 - index], out output[56 + index]); |
|||
} |
|||
|
|||
// Stage 6 completes the low-frequency DCT and rotates the first separated odd groups.
|
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[32], cospi[32], output[0], output[1], out step[0], out step[1], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[16], cospi[48], output[3], output[2], out step[2], out step[3], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[4], output[5], out step[4], out step[5]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[7], output[6], out step[7], out step[6]); |
|||
step[8] = output[8]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[16], cospi[48], output[9], output[14], out step[9], out step[14], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[48], -cospi[16], output[10], output[13], out step[10], out step[13], cosBit, in rounding); |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[15] = output[15]; |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[16], output[19], out step[16], out step[19]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[17], output[18], out step[17], out step[18]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[23], output[20], out step[23], out step[20]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[22], output[21], out step[22], out step[21]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[24], output[27], out step[24], out step[27]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[25], output[26], out step[25], out step[26]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[31], output[28], out step[31], out step[28]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[30], output[29], out step[30], out step[29]); |
|||
step[32] = output[32]; |
|||
step[33] = output[33]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[8], cospi[56], output[34], output[61], out step[34], out step[61], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[8], cospi[56], output[35], output[60], out step[35], out step[60], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[56], -cospi[8], output[36], output[59], out step[36], out step[59], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[56], -cospi[8], output[37], output[58], out step[37], out step[58], cosBit, in rounding); |
|||
step[38] = output[38]; |
|||
step[39] = output[39]; |
|||
step[40] = output[40]; |
|||
step[41] = output[41]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[40], cospi[24], output[42], output[53], out step[42], out step[53], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[40], cospi[24], output[43], output[52], out step[43], out step[52], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[24], -cospi[40], output[44], output[51], out step[44], out step[51], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[24], -cospi[40], output[45], output[50], out step[45], out step[50], cosBit, in rounding); |
|||
step[46] = output[46]; |
|||
step[47] = output[47]; |
|||
step[48] = output[48]; |
|||
step[49] = output[49]; |
|||
step[54] = output[54]; |
|||
step[55] = output[55]; |
|||
step[56] = output[56]; |
|||
step[57] = output[57]; |
|||
step[62] = output[62]; |
|||
step[63] = output[63]; |
|||
|
|||
// Stage 7 merges adjacent odd-frequency terms with the required AV1 sign pattern.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[8], cospi[56], step[7], step[4], out output[4], out output[7], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[40], cospi[24], step[6], step[5], out output[5], out output[6], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[8], step[9], out output[8], out output[9]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[11], step[10], out output[11], out output[10]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[12], step[13], out output[12], out output[13]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[15], step[14], out output[15], out output[14]); |
|||
output[16] = step[16]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[8], cospi[56], step[17], step[30], out output[17], out output[30], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[56], -cospi[8], step[18], step[29], out output[18], out output[29], cosBit, in rounding); |
|||
output[19] = step[19]; |
|||
output[20] = step[20]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[40], cospi[24], step[21], step[26], out output[21], out output[26], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[24], -cospi[40], step[22], step[25], out output[22], out output[25], cosBit, in rounding); |
|||
output[23] = step[23]; |
|||
output[24] = step[24]; |
|||
output[27] = step[27]; |
|||
output[28] = step[28]; |
|||
output[31] = step[31]; |
|||
for (int offset = 32; offset < 64; offset += 8) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[offset], step[offset + 3], out output[offset], out output[offset + 3]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[offset + 1], step[offset + 2], out output[offset + 1], out output[offset + 2]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[offset + 7], step[offset + 4], out output[offset + 7], out output[offset + 4]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[offset + 6], step[offset + 5], out output[offset + 6], out output[offset + 5]); |
|||
} |
|||
|
|||
// Stage 8 applies the next level of odd-frequency rotations.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[4], cospi[60], output[15], output[8], out step[8], out step[15], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[36], cospi[28], output[14], output[9], out step[9], out step[14], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[20], cospi[44], output[13], output[10], out step[10], out step[13], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[52], cospi[12], output[12], output[11], out step[11], out step[12], cosBit, in rounding); |
|||
for (int offset = 16; offset < 32; offset += 4) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[offset], output[offset + 1], out step[offset], out step[offset + 1]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[offset + 3], output[offset + 2], out step[offset + 3], out step[offset + 2]); |
|||
} |
|||
|
|||
step[32] = output[32]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[4], cospi[60], output[33], output[62], out step[33], out step[62], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[60], -cospi[4], output[34], output[61], out step[34], out step[61], cosBit, in rounding); |
|||
step[35] = output[35]; |
|||
step[36] = output[36]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[36], cospi[28], output[37], output[58], out step[37], out step[58], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[28], -cospi[36], output[38], output[57], out step[38], out step[57], cosBit, in rounding); |
|||
step[39] = output[39]; |
|||
step[40] = output[40]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[20], cospi[44], output[41], output[54], out step[41], out step[54], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[44], -cospi[20], output[42], output[53], out step[42], out step[53], cosBit, in rounding); |
|||
step[43] = output[43]; |
|||
step[44] = output[44]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[52], cospi[12], output[45], output[50], out step[45], out step[50], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[12], -cospi[52], output[46], output[49], out step[46], out step[49], cosBit, in rounding); |
|||
step[47] = output[47]; |
|||
step[48] = output[48]; |
|||
step[51] = output[51]; |
|||
step[52] = output[52]; |
|||
step[55] = output[55]; |
|||
step[56] = output[56]; |
|||
step[59] = output[59]; |
|||
step[60] = output[60]; |
|||
step[63] = output[63]; |
|||
|
|||
// Stage 9 merges the remaining odd-frequency pairs before their terminal rotations.
|
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = step[4]; |
|||
output[5] = step[5]; |
|||
output[6] = step[6]; |
|||
output[7] = step[7]; |
|||
output[8] = step[8]; |
|||
output[9] = step[9]; |
|||
output[10] = step[10]; |
|||
output[11] = step[11]; |
|||
output[12] = step[12]; |
|||
output[13] = step[13]; |
|||
output[14] = step[14]; |
|||
output[15] = step[15]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[2], cospi[62], step[31], step[16], out output[16], out output[31], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[34], cospi[30], step[30], step[17], out output[17], out output[30], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[18], cospi[46], step[29], step[18], out output[18], out output[29], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[50], cospi[14], step[28], step[19], out output[19], out output[28], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[10], cospi[54], step[27], step[20], out output[20], out output[27], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[42], cospi[22], step[26], step[21], out output[21], out output[26], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[26], cospi[38], step[25], step[22], out output[22], out output[25], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[58], cospi[6], step[24], step[23], out output[23], out output[24], cosBit, in rounding); |
|||
for (int offset = 32; offset < 64; offset += 4) |
|||
{ |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[offset], step[offset + 1], out output[offset], out output[offset + 1]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[offset + 3], step[offset + 2], out output[offset + 3], out output[offset + 2]); |
|||
} |
|||
|
|||
// Stage 10 applies the pi/64 rotations to the penultimate odd-frequency level.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
step[16] = output[16]; |
|||
step[17] = output[17]; |
|||
step[18] = output[18]; |
|||
step[19] = output[19]; |
|||
step[20] = output[20]; |
|||
step[21] = output[21]; |
|||
step[22] = output[22]; |
|||
step[23] = output[23]; |
|||
step[24] = output[24]; |
|||
step[25] = output[25]; |
|||
step[26] = output[26]; |
|||
step[27] = output[27]; |
|||
step[28] = output[28]; |
|||
step[29] = output[29]; |
|||
step[30] = output[30]; |
|||
step[31] = output[31]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[1], cospi[63], output[63], output[32], out step[32], out step[63], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[33], cospi[31], output[62], output[33], out step[33], out step[62], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[17], cospi[47], output[61], output[34], out step[34], out step[61], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[49], cospi[15], output[60], output[35], out step[35], out step[60], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[9], cospi[55], output[59], output[36], out step[36], out step[59], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[41], cospi[23], output[58], output[37], out step[37], out step[58], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[25], cospi[39], output[57], output[38], out step[38], out step[57], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[57], cospi[7], output[56], output[39], out step[39], out step[56], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[5], cospi[59], output[55], output[40], out step[40], out step[55], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[37], cospi[27], output[54], output[41], out step[41], out step[54], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[21], cospi[43], output[53], output[42], out step[42], out step[53], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[53], cospi[11], output[52], output[43], out step[43], out step[52], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[13], cospi[51], output[51], output[44], out step[44], out step[51], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[45], cospi[19], output[50], output[45], out step[45], out step[50], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[29], cospi[35], output[49], output[46], out step[46], out step[49], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[61], cospi[3], output[48], output[47], out step[47], out step[48], cosBit, in rounding); |
|||
|
|||
// Stage 11 applies the terminal pi/128 rotations and produces the staged coefficient values.
|
|||
output[0] = step[0]; |
|||
output[1] = step[32]; |
|||
output[2] = step[16]; |
|||
output[3] = step[48]; |
|||
output[4] = step[8]; |
|||
output[5] = step[40]; |
|||
output[6] = step[24]; |
|||
output[7] = step[56]; |
|||
output[8] = step[4]; |
|||
output[9] = step[36]; |
|||
output[10] = step[20]; |
|||
output[11] = step[52]; |
|||
output[12] = step[12]; |
|||
output[13] = step[44]; |
|||
output[14] = step[28]; |
|||
output[15] = step[60]; |
|||
output[16] = step[2]; |
|||
output[17] = step[34]; |
|||
output[18] = step[18]; |
|||
output[19] = step[50]; |
|||
output[20] = step[10]; |
|||
output[21] = step[42]; |
|||
output[22] = step[26]; |
|||
output[23] = step[58]; |
|||
output[24] = step[6]; |
|||
output[25] = step[38]; |
|||
output[26] = step[22]; |
|||
output[27] = step[54]; |
|||
output[28] = step[14]; |
|||
output[29] = step[46]; |
|||
output[30] = step[30]; |
|||
output[31] = step[62]; |
|||
output[32] = step[1]; |
|||
output[33] = step[33]; |
|||
output[34] = step[17]; |
|||
output[35] = step[49]; |
|||
output[36] = step[9]; |
|||
output[37] = step[41]; |
|||
output[38] = step[25]; |
|||
output[39] = step[57]; |
|||
output[40] = step[5]; |
|||
output[41] = step[37]; |
|||
output[42] = step[21]; |
|||
output[43] = step[53]; |
|||
output[44] = step[13]; |
|||
output[45] = step[45]; |
|||
output[46] = step[29]; |
|||
output[47] = step[61]; |
|||
output[48] = step[3]; |
|||
output[49] = step[35]; |
|||
output[50] = step[19]; |
|||
output[51] = step[51]; |
|||
output[52] = step[11]; |
|||
output[53] = step[43]; |
|||
output[54] = step[27]; |
|||
output[55] = step[59]; |
|||
output[56] = step[7]; |
|||
output[57] = step[39]; |
|||
output[58] = step[23]; |
|||
output[59] = step[55]; |
|||
output[60] = step[15]; |
|||
output[61] = step[47]; |
|||
output[62] = step[31]; |
|||
output[63] = step[63]; |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Implements the eight-point forward DCT stage network.
|
|||
/// </content>
|
|||
internal static partial class Av1ForwardTransformOperations |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the eight-point forward discrete cosine transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The fixed transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
public static void Dct8<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
{ |
|||
// Stage 1 forms mirror-symmetric sums and differences, separating the even and odd DCT terms.
|
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[0], input[7], out output[0], out output[7]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[1], input[6], out output[1], out output[6]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[2], input[5], out output[2], out output[5]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(input[3], input[4], out output[3], out output[4]); |
|||
|
|||
// Stage 2 applies a four-point DCT to the even half and a pi/4 rotation to the middle odd pair.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
Av1TransformRounding rounding = Av1ForwardTransformArithmetic<TValue>.CreateRounding(cosBit); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[0], output[3], out step[0], out step[3]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(output[1], output[2], out step[1], out step[2]); |
|||
|
|||
step[4] = output[4]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(-cospi[32], cospi[32], output[5], output[6], out step[5], out step[6], cosBit, in rounding); |
|||
step[7] = output[7]; |
|||
|
|||
// Stage 3 completes the even transform and combines the odd terms into sum and difference pairs.
|
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[32], cospi[32], step[0], step[1], out output[0], out output[1], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[16], cospi[48], step[3], step[2], out output[2], out output[3], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[4], step[5], out output[4], out output[5]); |
|||
Av1ForwardTransformArithmetic<TValue>.AddSubtract(step[7], step[6], out output[7], out output[6]); |
|||
|
|||
// Stage 4 rotates the odd-frequency pairs by the remaining pi/16 angles.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[8], cospi[56], output[7], output[4], out step[4], out step[7], cosBit, in rounding); |
|||
Av1ForwardTransformArithmetic<TValue>.Butterfly(cospi[40], cospi[24], output[6], output[5], out step[5], out step[6], cosBit, in rounding); |
|||
|
|||
// Stage 5 permutes the staged values into ascending AV1 coefficient order.
|
|||
output[0] = step[0]; |
|||
output[1] = step[4]; |
|||
output[2] = step[2]; |
|||
output[3] = step[6]; |
|||
output[4] = step[1]; |
|||
output[5] = step[5]; |
|||
output[6] = step[3]; |
|||
output[7] = step[7]; |
|||
} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Implements the length-specific forward identity transform scaling.
|
|||
/// </content>
|
|||
internal static partial class Av1ForwardTransformOperations |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the four-point forward identity transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The unused transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The unused fixed-point precision.</param>
|
|||
public static void Identity4<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
=> Identity(ref input, ref output, ref step, cosBit, 4, 1, 0); |
|||
|
|||
/// <summary>
|
|||
/// Applies the eight-point forward identity transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The unused transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The unused fixed-point precision.</param>
|
|||
public static void Identity8<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
=> Identity(ref input, ref output, ref step, cosBit, 8, 0, 1); |
|||
|
|||
/// <summary>
|
|||
/// Applies the sixteen-point forward identity transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The unused transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The unused fixed-point precision.</param>
|
|||
public static void Identity16<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
=> Identity(ref input, ref output, ref step, cosBit, 16, 2, 0); |
|||
|
|||
/// <summary>
|
|||
/// Applies the thirty-two-point forward identity transform to every independent lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The unused transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The unused fixed-point precision.</param>
|
|||
public static void Identity32<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct |
|||
=> Identity(ref input, ref output, ref step, cosBit, 32, 0, 2); |
|||
|
|||
/// <summary>
|
|||
/// Applies the length-specific AV1 identity scaling to every transform value.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain values.</param>
|
|||
/// <param name="output">The frequency-domain values.</param>
|
|||
/// <param name="step">The unused transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The unused fixed-point precision.</param>
|
|||
/// <param name="length">The number of transform values.</param>
|
|||
/// <param name="sqrt2Scale">The multiplier applied with the fixed-point square-root-of-two constant.</param>
|
|||
/// <param name="leftShift">The direct left shift applied when square-root scaling is not required.</param>
|
|||
private static void Identity<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit, |
|||
int length, |
|||
int sqrt2Scale, |
|||
int leftShift) |
|||
where TValue : struct |
|||
{ |
|||
_ = step; |
|||
_ = cosBit; |
|||
|
|||
// AV1 defines identity normalization by transform length: 4 and 16 use NewSqrt2 scaling, while 8 and 32
|
|||
// are exact powers of two. The same operation applies independently to each SIMD lane.
|
|||
for (int i = 0; i < length; i++) |
|||
{ |
|||
output[i] = sqrt2Scale != 0 |
|||
? Av1ForwardTransformArithmetic<TValue>.MultiplyRound( |
|||
input[i], |
|||
sqrt2Scale * Av1Transform1dMath.NewSqrt2, |
|||
Av1Transform1dMath.NewSqrt2Bits) |
|||
: Av1ForwardTransformArithmetic<TValue>.ShiftLeft(input[i], leftShift); |
|||
} |
|||
} |
|||
} |
|||
@ -1,198 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the four-point forward identity-transform operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Identity4Forward1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 4, Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 4, Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 4, Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
} |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the eight-point forward identity-transform operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Identity8Forward1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 8, 2, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 8, 2, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 8, 2, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
} |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the sixteen-point forward identity-transform operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Identity16Forward1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 16, 2 * Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 16, 2 * Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 16, 2 * Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
} |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the thirty-two-point forward identity-transform operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Identity32Forward1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 32, 4, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 32, 4, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 32, 4, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.InteropServices; |
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <summary>
|
|||
/// Stores the fixed-point rounding value in the lane shape selected for one forward transform.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The fields overlap because a closed transform instantiation reads exactly one representation. This keeps the
|
|||
/// rounding broadcast outside the butterfly sequence without increasing the caller-owned transform workspace.
|
|||
/// </remarks>
|
|||
[StructLayout(LayoutKind.Explicit)] |
|||
internal struct Av1TransformRounding |
|||
{ |
|||
/// <summary>
|
|||
/// The scalar rounding value.
|
|||
/// </summary>
|
|||
[FieldOffset(0)] |
|||
public int Scalar; |
|||
|
|||
/// <summary>
|
|||
/// The four-lane rounding value used by 128-bit widened arithmetic.
|
|||
/// </summary>
|
|||
[FieldOffset(0)] |
|||
public Vector128<int> Vector128; |
|||
|
|||
/// <summary>
|
|||
/// The eight-lane rounding value used by 256-bit widened arithmetic.
|
|||
/// </summary>
|
|||
[FieldOffset(0)] |
|||
public Vector256<int> Vector256; |
|||
|
|||
/// <summary>
|
|||
/// The sixteen-lane rounding value used by 512-bit widened arithmetic.
|
|||
/// </summary>
|
|||
[FieldOffset(0)] |
|||
public Vector512<int> Vector512; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; |
|||
|
|||
/// <summary>
|
|||
/// Defines one AV1 forward transform which can be specialized for the selected sample and SIMD lane type.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// A concrete operator identifies the transform stage network. The two-dimensional driver selects the sample type
|
|||
/// and vector width once per block, allowing the JIT to specialize the complete network without interface dispatch
|
|||
/// inside the transform stages.
|
|||
/// </remarks>
|
|||
internal interface IAv1ForwardTransform1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Transforms the independent axes stored in each value lane.
|
|||
/// </summary>
|
|||
/// <typeparam name="TValue">The scalar or SIMD value containing the independent transform axes.</typeparam>
|
|||
/// <param name="input">The spatial-domain transform values.</param>
|
|||
/// <param name="output">The frequency-domain transform values.</param>
|
|||
/// <param name="step">The fixed transform-stage buffer.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
public static abstract void Transform<TValue>( |
|||
ref Av1TransformVector<TValue> input, |
|||
ref Av1TransformVector<TValue> output, |
|||
ref Av1TransformVector<TValue> step, |
|||
int cosBit) |
|||
where TValue : struct; |
|||
} |
|||
@ -1,569 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the sixteen-point inverse ADST operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Adst16Inverse1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes the coefficients into the signed order used by the ADST factorization.
|
|||
stage++; |
|||
output[0] = input[15]; |
|||
output[1] = input[0]; |
|||
output[2] = input[13]; |
|||
output[3] = input[2]; |
|||
output[4] = input[11]; |
|||
output[5] = input[4]; |
|||
output[6] = input[9]; |
|||
output[7] = input[6]; |
|||
output[8] = input[7]; |
|||
output[9] = input[8]; |
|||
output[10] = input[5]; |
|||
output[11] = input[10]; |
|||
output[12] = input[3]; |
|||
output[13] = input[12]; |
|||
output[14] = input[1]; |
|||
output[15] = input[14]; |
|||
|
|||
// Stage 2 applies the terminal odd-angle rotations in reverse.
|
|||
stage++; |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[2], output[0], cospi[62], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[62], output[0], -cospi[2], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[10], output[2], cospi[54], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[54], output[2], -cospi[10], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[18], output[4], cospi[46], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[46], output[4], -cospi[18], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[26], output[6], cospi[38], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[38], output[6], -cospi[26], output[7], cosBit); |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[34], output[8], cospi[30], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[30], output[8], -cospi[34], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[42], output[10], cospi[22], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[22], output[10], -cospi[42], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[50], output[12], cospi[14], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[14], output[12], -cospi[50], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[58], output[14], cospi[6], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[6], output[14], -cospi[58], output[15], cosBit); |
|||
|
|||
// Stage 3 separates the complete butterfly into two eight-sample halves and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[8], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[9], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[10], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[11], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[12], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[13], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[6] + step[14], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[7] + step[15], stageRange[stage]); |
|||
output[8] = Av1Transform1dMath.Clamp(step[0] - step[8], stageRange[stage]); |
|||
output[9] = Av1Transform1dMath.Clamp(step[1] - step[9], stageRange[stage]); |
|||
output[10] = Av1Transform1dMath.Clamp(step[2] - step[10], stageRange[stage]); |
|||
output[11] = Av1Transform1dMath.Clamp(step[3] - step[11], stageRange[stage]); |
|||
output[12] = Av1Transform1dMath.Clamp(step[4] - step[12], stageRange[stage]); |
|||
output[13] = Av1Transform1dMath.Clamp(step[5] - step[13], stageRange[stage]); |
|||
output[14] = Av1Transform1dMath.Clamp(step[6] - step[14], stageRange[stage]); |
|||
output[15] = Av1Transform1dMath.Clamp(step[7] - step[15], stageRange[stage]); |
|||
|
|||
// Stage 4 reverses the pi/16 rotations in the upper half.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[8], output[8], cospi[56], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[56], output[8], -cospi[8], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[40], output[10], cospi[24], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[24], output[10], -cospi[40], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(-cospi[56], output[12], cospi[8], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[8], output[12], cospi[56], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[24], output[14], cospi[40], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[40], output[14], cospi[24], output[15], cosBit); |
|||
|
|||
// Stage 5 separates each eight-sample half into four-sample groups and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[4], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[5], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[6], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[7], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[0] - step[4], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[1] - step[5], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[2] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[3] - step[7], stageRange[stage]); |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[12], stageRange[stage]); |
|||
output[9] = Av1Transform1dMath.Clamp(step[9] + step[13], stageRange[stage]); |
|||
output[10] = Av1Transform1dMath.Clamp(step[10] + step[14], stageRange[stage]); |
|||
output[11] = Av1Transform1dMath.Clamp(step[11] + step[15], stageRange[stage]); |
|||
output[12] = Av1Transform1dMath.Clamp(step[8] - step[12], stageRange[stage]); |
|||
output[13] = Av1Transform1dMath.Clamp(step[9] - step[13], stageRange[stage]); |
|||
output[14] = Av1Transform1dMath.Clamp(step[10] - step[14], stageRange[stage]); |
|||
output[15] = Av1Transform1dMath.Clamp(step[11] - step[15], stageRange[stage]); |
|||
|
|||
// Stage 6 reverses the pi/8 and 3pi/8 rotations.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[16], output[12], cospi[48], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[48], output[12], -cospi[16], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[14], cospi[16], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[16], output[14], cospi[48], output[15], cosBit); |
|||
|
|||
// Stage 7 separates the four-sample groups into adjacent coefficient pairs and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[2], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[3], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[0] - step[2], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[1] - step[3], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[6], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[7], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[4] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[5] - step[7], stageRange[stage]); |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[10], stageRange[stage]); |
|||
output[9] = Av1Transform1dMath.Clamp(step[9] + step[11], stageRange[stage]); |
|||
output[10] = Av1Transform1dMath.Clamp(step[8] - step[10], stageRange[stage]); |
|||
output[11] = Av1Transform1dMath.Clamp(step[9] - step[11], stageRange[stage]); |
|||
output[12] = Av1Transform1dMath.Clamp(step[12] + step[14], stageRange[stage]); |
|||
output[13] = Av1Transform1dMath.Clamp(step[13] + step[15], stageRange[stage]); |
|||
output[14] = Av1Transform1dMath.Clamp(step[12] - step[14], stageRange[stage]); |
|||
output[15] = Av1Transform1dMath.Clamp(step[13] - step[15], stageRange[stage]); |
|||
|
|||
// Stage 8 reverses the pi/4 rotations for the middle pairs.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], cospi[32], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], -cospi[32], output[11], cosBit); |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], cospi[32], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], -cospi[32], output[15], cosBit); |
|||
|
|||
// Stage 9 applies the AV1 signs and permutation that restore spatial sample order.
|
|||
output[0] = step[0]; |
|||
output[1] = -step[8]; |
|||
output[2] = step[12]; |
|||
output[3] = -step[4]; |
|||
output[4] = step[6]; |
|||
output[5] = -step[14]; |
|||
output[6] = step[10]; |
|||
output[7] = -step[2]; |
|||
output[8] = step[3]; |
|||
output[9] = -step[11]; |
|||
output[10] = step[15]; |
|||
output[11] = -step[7]; |
|||
output[12] = step[5]; |
|||
output[13] = -step[13]; |
|||
output[14] = step[9]; |
|||
output[15] = -step[1]; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes the coefficients into the signed order used by the ADST factorization.
|
|||
stage++; |
|||
output[0] = input[15]; |
|||
output[1] = input[0]; |
|||
output[2] = input[13]; |
|||
output[3] = input[2]; |
|||
output[4] = input[11]; |
|||
output[5] = input[4]; |
|||
output[6] = input[9]; |
|||
output[7] = input[6]; |
|||
output[8] = input[7]; |
|||
output[9] = input[8]; |
|||
output[10] = input[5]; |
|||
output[11] = input[10]; |
|||
output[12] = input[3]; |
|||
output[13] = input[12]; |
|||
output[14] = input[1]; |
|||
output[15] = input[14]; |
|||
|
|||
// Stage 2 applies the terminal odd-angle rotations in reverse.
|
|||
stage++; |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[2], output[0], cospi[62], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[62], output[0], -cospi[2], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[10], output[2], cospi[54], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[54], output[2], -cospi[10], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[18], output[4], cospi[46], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[46], output[4], -cospi[18], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[26], output[6], cospi[38], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[38], output[6], -cospi[26], output[7], cosBit); |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[34], output[8], cospi[30], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[30], output[8], -cospi[34], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[42], output[10], cospi[22], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[22], output[10], -cospi[42], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[50], output[12], cospi[14], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[14], output[12], -cospi[50], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[58], output[14], cospi[6], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[6], output[14], -cospi[58], output[15], cosBit); |
|||
|
|||
// Stage 3 separates the complete butterfly into two eight-sample halves and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[8], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[9], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[10], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[11], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[12], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[13], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[6] + step[14], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[7] + step[15], stageRange[stage]); |
|||
output[8] = Av1Transform1dMath.Clamp(step[0] - step[8], stageRange[stage]); |
|||
output[9] = Av1Transform1dMath.Clamp(step[1] - step[9], stageRange[stage]); |
|||
output[10] = Av1Transform1dMath.Clamp(step[2] - step[10], stageRange[stage]); |
|||
output[11] = Av1Transform1dMath.Clamp(step[3] - step[11], stageRange[stage]); |
|||
output[12] = Av1Transform1dMath.Clamp(step[4] - step[12], stageRange[stage]); |
|||
output[13] = Av1Transform1dMath.Clamp(step[5] - step[13], stageRange[stage]); |
|||
output[14] = Av1Transform1dMath.Clamp(step[6] - step[14], stageRange[stage]); |
|||
output[15] = Av1Transform1dMath.Clamp(step[7] - step[15], stageRange[stage]); |
|||
|
|||
// Stage 4 reverses the pi/16 rotations in the upper half.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[8], output[8], cospi[56], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[56], output[8], -cospi[8], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[40], output[10], cospi[24], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[24], output[10], -cospi[40], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(-cospi[56], output[12], cospi[8], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[8], output[12], cospi[56], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[24], output[14], cospi[40], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[40], output[14], cospi[24], output[15], cosBit); |
|||
|
|||
// Stage 5 separates each eight-sample half into four-sample groups and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[4], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[5], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[6], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[7], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[0] - step[4], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[1] - step[5], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[2] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[3] - step[7], stageRange[stage]); |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[12], stageRange[stage]); |
|||
output[9] = Av1Transform1dMath.Clamp(step[9] + step[13], stageRange[stage]); |
|||
output[10] = Av1Transform1dMath.Clamp(step[10] + step[14], stageRange[stage]); |
|||
output[11] = Av1Transform1dMath.Clamp(step[11] + step[15], stageRange[stage]); |
|||
output[12] = Av1Transform1dMath.Clamp(step[8] - step[12], stageRange[stage]); |
|||
output[13] = Av1Transform1dMath.Clamp(step[9] - step[13], stageRange[stage]); |
|||
output[14] = Av1Transform1dMath.Clamp(step[10] - step[14], stageRange[stage]); |
|||
output[15] = Av1Transform1dMath.Clamp(step[11] - step[15], stageRange[stage]); |
|||
|
|||
// Stage 6 reverses the pi/8 and 3pi/8 rotations.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[16], output[12], cospi[48], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[48], output[12], -cospi[16], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[14], cospi[16], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[16], output[14], cospi[48], output[15], cosBit); |
|||
|
|||
// Stage 7 separates the four-sample groups into adjacent coefficient pairs and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[2], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[3], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[0] - step[2], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[1] - step[3], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[6], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[7], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[4] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[5] - step[7], stageRange[stage]); |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[10], stageRange[stage]); |
|||
output[9] = Av1Transform1dMath.Clamp(step[9] + step[11], stageRange[stage]); |
|||
output[10] = Av1Transform1dMath.Clamp(step[8] - step[10], stageRange[stage]); |
|||
output[11] = Av1Transform1dMath.Clamp(step[9] - step[11], stageRange[stage]); |
|||
output[12] = Av1Transform1dMath.Clamp(step[12] + step[14], stageRange[stage]); |
|||
output[13] = Av1Transform1dMath.Clamp(step[13] + step[15], stageRange[stage]); |
|||
output[14] = Av1Transform1dMath.Clamp(step[12] - step[14], stageRange[stage]); |
|||
output[15] = Av1Transform1dMath.Clamp(step[13] - step[15], stageRange[stage]); |
|||
|
|||
// Stage 8 reverses the pi/4 rotations for the middle pairs.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], cospi[32], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], -cospi[32], output[11], cosBit); |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], cospi[32], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], -cospi[32], output[15], cosBit); |
|||
|
|||
// Stage 9 applies the AV1 signs and permutation that restore spatial sample order.
|
|||
output[0] = step[0]; |
|||
output[1] = -step[8]; |
|||
output[2] = step[12]; |
|||
output[3] = -step[4]; |
|||
output[4] = step[6]; |
|||
output[5] = -step[14]; |
|||
output[6] = step[10]; |
|||
output[7] = -step[2]; |
|||
output[8] = step[3]; |
|||
output[9] = -step[11]; |
|||
output[10] = step[15]; |
|||
output[11] = -step[7]; |
|||
output[12] = step[5]; |
|||
output[13] = -step[13]; |
|||
output[14] = step[9]; |
|||
output[15] = -step[1]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes the coefficients into the signed order used by the ADST factorization.
|
|||
stage++; |
|||
output[0] = input[15]; |
|||
output[1] = input[0]; |
|||
output[2] = input[13]; |
|||
output[3] = input[2]; |
|||
output[4] = input[11]; |
|||
output[5] = input[4]; |
|||
output[6] = input[9]; |
|||
output[7] = input[6]; |
|||
output[8] = input[7]; |
|||
output[9] = input[8]; |
|||
output[10] = input[5]; |
|||
output[11] = input[10]; |
|||
output[12] = input[3]; |
|||
output[13] = input[12]; |
|||
output[14] = input[1]; |
|||
output[15] = input[14]; |
|||
|
|||
// Stage 2 applies the terminal odd-angle rotations in reverse.
|
|||
stage++; |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[2], output[0], cospi[62], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[62], output[0], -cospi[2], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[10], output[2], cospi[54], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[54], output[2], -cospi[10], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[18], output[4], cospi[46], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[46], output[4], -cospi[18], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[26], output[6], cospi[38], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[38], output[6], -cospi[26], output[7], cosBit); |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[34], output[8], cospi[30], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[30], output[8], -cospi[34], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[42], output[10], cospi[22], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[22], output[10], -cospi[42], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[50], output[12], cospi[14], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[14], output[12], -cospi[50], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[58], output[14], cospi[6], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[6], output[14], -cospi[58], output[15], cosBit); |
|||
|
|||
// Stage 3 separates the complete butterfly into two eight-sample halves and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[8], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[9], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[10], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[11], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[12], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[13], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[6] + step[14], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[7] + step[15], stageRange[stage]); |
|||
output[8] = Av1Transform1dMath.Clamp(step[0] - step[8], stageRange[stage]); |
|||
output[9] = Av1Transform1dMath.Clamp(step[1] - step[9], stageRange[stage]); |
|||
output[10] = Av1Transform1dMath.Clamp(step[2] - step[10], stageRange[stage]); |
|||
output[11] = Av1Transform1dMath.Clamp(step[3] - step[11], stageRange[stage]); |
|||
output[12] = Av1Transform1dMath.Clamp(step[4] - step[12], stageRange[stage]); |
|||
output[13] = Av1Transform1dMath.Clamp(step[5] - step[13], stageRange[stage]); |
|||
output[14] = Av1Transform1dMath.Clamp(step[6] - step[14], stageRange[stage]); |
|||
output[15] = Av1Transform1dMath.Clamp(step[7] - step[15], stageRange[stage]); |
|||
|
|||
// Stage 4 reverses the pi/16 rotations in the upper half.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[8], output[8], cospi[56], output[9], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[56], output[8], -cospi[8], output[9], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[40], output[10], cospi[24], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[24], output[10], -cospi[40], output[11], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(-cospi[56], output[12], cospi[8], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[8], output[12], cospi[56], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[24], output[14], cospi[40], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[40], output[14], cospi[24], output[15], cosBit); |
|||
|
|||
// Stage 5 separates each eight-sample half into four-sample groups and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[4], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[5], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[6], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[7], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[0] - step[4], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[1] - step[5], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[2] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[3] - step[7], stageRange[stage]); |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[12], stageRange[stage]); |
|||
output[9] = Av1Transform1dMath.Clamp(step[9] + step[13], stageRange[stage]); |
|||
output[10] = Av1Transform1dMath.Clamp(step[10] + step[14], stageRange[stage]); |
|||
output[11] = Av1Transform1dMath.Clamp(step[11] + step[15], stageRange[stage]); |
|||
output[12] = Av1Transform1dMath.Clamp(step[8] - step[12], stageRange[stage]); |
|||
output[13] = Av1Transform1dMath.Clamp(step[9] - step[13], stageRange[stage]); |
|||
output[14] = Av1Transform1dMath.Clamp(step[10] - step[14], stageRange[stage]); |
|||
output[15] = Av1Transform1dMath.Clamp(step[11] - step[15], stageRange[stage]); |
|||
|
|||
// Stage 6 reverses the pi/8 and 3pi/8 rotations.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = output[10]; |
|||
step[11] = output[11]; |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[16], output[12], cospi[48], output[13], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[48], output[12], -cospi[16], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[14], cospi[16], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[16], output[14], cospi[48], output[15], cosBit); |
|||
|
|||
// Stage 7 separates the four-sample groups into adjacent coefficient pairs and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[2], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[3], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[0] - step[2], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[1] - step[3], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[6], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[7], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[4] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[5] - step[7], stageRange[stage]); |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[10], stageRange[stage]); |
|||
output[9] = Av1Transform1dMath.Clamp(step[9] + step[11], stageRange[stage]); |
|||
output[10] = Av1Transform1dMath.Clamp(step[8] - step[10], stageRange[stage]); |
|||
output[11] = Av1Transform1dMath.Clamp(step[9] - step[11], stageRange[stage]); |
|||
output[12] = Av1Transform1dMath.Clamp(step[12] + step[14], stageRange[stage]); |
|||
output[13] = Av1Transform1dMath.Clamp(step[13] + step[15], stageRange[stage]); |
|||
output[14] = Av1Transform1dMath.Clamp(step[12] - step[14], stageRange[stage]); |
|||
output[15] = Av1Transform1dMath.Clamp(step[13] - step[15], stageRange[stage]); |
|||
|
|||
// Stage 8 reverses the pi/4 rotations for the middle pairs.
|
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], cospi[32], output[11], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], -cospi[32], output[11], cosBit); |
|||
step[12] = output[12]; |
|||
step[13] = output[13]; |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], cospi[32], output[15], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[32], output[14], -cospi[32], output[15], cosBit); |
|||
|
|||
// Stage 9 applies the AV1 signs and permutation that restore spatial sample order.
|
|||
output[0] = step[0]; |
|||
output[1] = -step[8]; |
|||
output[2] = step[12]; |
|||
output[3] = -step[4]; |
|||
output[4] = step[6]; |
|||
output[5] = -step[14]; |
|||
output[6] = step[10]; |
|||
output[7] = -step[2]; |
|||
output[8] = step[3]; |
|||
output[9] = -step[11]; |
|||
output[10] = step[15]; |
|||
output[11] = -step[7]; |
|||
output[12] = step[5]; |
|||
output[13] = -step[13]; |
|||
output[14] = step[9]; |
|||
output[15] = -step[1]; |
|||
} |
|||
} |
|||
@ -1,113 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the four-point inverse ADST operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Adst4Inverse1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
TransformCore(ref input, ref output, cosBit); |
|||
_ = step; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
TransformCore(ref input, ref output, cosBit); |
|||
_ = step; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
TransformCore(ref input, ref output, cosBit); |
|||
_ = step; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the inverse four-point matrix to four independent axes.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for four transform axes.</param>
|
|||
/// <param name="output">The destination values for four transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the sine constants.</param>
|
|||
private static void TransformCore(ref Av1TransformVector<Vector128<int>> input, ref Av1TransformVector<Vector128<int>> output, int cosBit) |
|||
{ |
|||
ReadOnlySpan<int> sinpi = Av1SinusConstants.SinusPi(cosBit); |
|||
Vector128<int> x0 = input[0]; |
|||
Vector128<int> x1 = input[1]; |
|||
Vector128<int> x2 = input[2]; |
|||
Vector128<int> x3 = input[3]; |
|||
|
|||
// The products retain the sine-table scale across the complete matrix. The bounded transform inputs make
|
|||
// the optimized kernels' wrapping 32-bit multiply/add sequence valid until the terminal rounding shift.
|
|||
output[0] = Av1Transform1dMath.MultiplyAdd4(sinpi[1], x0, sinpi[3], x1, sinpi[4], x2, sinpi[2], x3, cosBit); |
|||
output[1] = Av1Transform1dMath.MultiplyAdd4(sinpi[2], x0, sinpi[3], x1, -sinpi[1], x2, -sinpi[4], x3, cosBit); |
|||
output[2] = Av1Transform1dMath.MultiplyAdd4(sinpi[3], x0, 0, x1, -sinpi[3], x2, sinpi[3], x3, cosBit); |
|||
output[3] = Av1Transform1dMath.MultiplyAdd4(sinpi[1] + sinpi[2], x0, -sinpi[3], x1, sinpi[4] - sinpi[1], x2, sinpi[2] - sinpi[4], x3, cosBit); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the inverse four-point matrix to eight independent axes.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for eight transform axes.</param>
|
|||
/// <param name="output">The destination values for eight transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the sine constants.</param>
|
|||
private static void TransformCore(ref Av1TransformVector<Vector256<int>> input, ref Av1TransformVector<Vector256<int>> output, int cosBit) |
|||
{ |
|||
ReadOnlySpan<int> sinpi = Av1SinusConstants.SinusPi(cosBit); |
|||
Vector256<int> x0 = input[0]; |
|||
Vector256<int> x1 = input[1]; |
|||
Vector256<int> x2 = input[2]; |
|||
Vector256<int> x3 = input[3]; |
|||
|
|||
output[0] = Av1Transform1dMath.MultiplyAdd4(sinpi[1], x0, sinpi[3], x1, sinpi[4], x2, sinpi[2], x3, cosBit); |
|||
output[1] = Av1Transform1dMath.MultiplyAdd4(sinpi[2], x0, sinpi[3], x1, -sinpi[1], x2, -sinpi[4], x3, cosBit); |
|||
output[2] = Av1Transform1dMath.MultiplyAdd4(sinpi[3], x0, 0, x1, -sinpi[3], x2, sinpi[3], x3, cosBit); |
|||
output[3] = Av1Transform1dMath.MultiplyAdd4(sinpi[1] + sinpi[2], x0, -sinpi[3], x1, sinpi[4] - sinpi[1], x2, sinpi[2] - sinpi[4], x3, cosBit); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the inverse four-point matrix to sixteen independent axes.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for sixteen transform axes.</param>
|
|||
/// <param name="output">The destination values for sixteen transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the sine constants.</param>
|
|||
private static void TransformCore(ref Av1TransformVector<Vector512<int>> input, ref Av1TransformVector<Vector512<int>> output, int cosBit) |
|||
{ |
|||
ReadOnlySpan<int> sinpi = Av1SinusConstants.SinusPi(cosBit); |
|||
Vector512<int> x0 = input[0]; |
|||
Vector512<int> x1 = input[1]; |
|||
Vector512<int> x2 = input[2]; |
|||
Vector512<int> x3 = input[3]; |
|||
|
|||
output[0] = Av1Transform1dMath.MultiplyAdd4(sinpi[1], x0, sinpi[3], x1, sinpi[4], x2, sinpi[2], x3, cosBit); |
|||
output[1] = Av1Transform1dMath.MultiplyAdd4(sinpi[2], x0, sinpi[3], x1, -sinpi[1], x2, -sinpi[4], x3, cosBit); |
|||
output[2] = Av1Transform1dMath.MultiplyAdd4(sinpi[3], x0, 0, x1, -sinpi[3], x2, sinpi[3], x3, cosBit); |
|||
output[3] = Av1Transform1dMath.MultiplyAdd4(sinpi[1] + sinpi[2], x0, -sinpi[3], x1, sinpi[4] - sinpi[1], x2, sinpi[2] - sinpi[4], x3, cosBit); |
|||
} |
|||
} |
|||
@ -1,290 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the eight-point inverse ADST operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Adst8Inverse1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes the coefficients into the signed order used by the ADST factorization.
|
|||
stage++; |
|||
output[0] = input[7]; |
|||
output[1] = input[0]; |
|||
output[2] = input[5]; |
|||
output[3] = input[2]; |
|||
output[4] = input[3]; |
|||
output[5] = input[4]; |
|||
output[6] = input[1]; |
|||
output[7] = input[6]; |
|||
|
|||
// Stage 2 applies the terminal odd-angle rotations in reverse.
|
|||
stage++; |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[4], output[0], cospi[60], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[60], output[0], -cospi[4], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[20], output[2], cospi[44], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[44], output[2], -cospi[20], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[36], output[4], cospi[28], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[28], output[4], -cospi[36], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[52], output[6], cospi[12], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[12], output[6], -cospi[52], output[7], cosBit); |
|||
|
|||
// Stage 3 separates the complete butterfly into two four-sample halves and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[4], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[5], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[6], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[7], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[0] - step[4], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[1] - step[5], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[2] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[3] - step[7], stageRange[stage]); |
|||
|
|||
// Stage 4 reverses the pi/8 and 3pi/8 rotations in the upper half.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
|
|||
// Stage 5 separates the four-sample halves into adjacent coefficient pairs and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[2], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[3], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[0] - step[2], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[1] - step[3], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[6], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[7], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[4] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[5] - step[7], stageRange[stage]); |
|||
|
|||
// Stage 6 reverses the pi/4 rotations for the middle pairs.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
|
|||
// Stage 7 applies the AV1 signs and permutation that restore spatial sample order.
|
|||
output[0] = step[0]; |
|||
output[1] = -step[4]; |
|||
output[2] = step[6]; |
|||
output[3] = -step[2]; |
|||
output[4] = step[3]; |
|||
output[5] = -step[7]; |
|||
output[6] = step[5]; |
|||
output[7] = -step[1]; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes the coefficients into the signed order used by the ADST factorization.
|
|||
stage++; |
|||
output[0] = input[7]; |
|||
output[1] = input[0]; |
|||
output[2] = input[5]; |
|||
output[3] = input[2]; |
|||
output[4] = input[3]; |
|||
output[5] = input[4]; |
|||
output[6] = input[1]; |
|||
output[7] = input[6]; |
|||
|
|||
// Stage 2 applies the terminal odd-angle rotations in reverse.
|
|||
stage++; |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[4], output[0], cospi[60], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[60], output[0], -cospi[4], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[20], output[2], cospi[44], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[44], output[2], -cospi[20], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[36], output[4], cospi[28], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[28], output[4], -cospi[36], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[52], output[6], cospi[12], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[12], output[6], -cospi[52], output[7], cosBit); |
|||
|
|||
// Stage 3 separates the complete butterfly into two four-sample halves and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[4], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[5], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[6], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[7], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[0] - step[4], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[1] - step[5], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[2] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[3] - step[7], stageRange[stage]); |
|||
|
|||
// Stage 4 reverses the pi/8 and 3pi/8 rotations in the upper half.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
|
|||
// Stage 5 separates the four-sample halves into adjacent coefficient pairs and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[2], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[3], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[0] - step[2], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[1] - step[3], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[6], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[7], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[4] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[5] - step[7], stageRange[stage]); |
|||
|
|||
// Stage 6 reverses the pi/4 rotations for the middle pairs.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
|
|||
// Stage 7 applies the AV1 signs and permutation that restore spatial sample order.
|
|||
output[0] = step[0]; |
|||
output[1] = -step[4]; |
|||
output[2] = step[6]; |
|||
output[3] = -step[2]; |
|||
output[4] = step[3]; |
|||
output[5] = -step[7]; |
|||
output[6] = step[5]; |
|||
output[7] = -step[1]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes the coefficients into the signed order used by the ADST factorization.
|
|||
stage++; |
|||
output[0] = input[7]; |
|||
output[1] = input[0]; |
|||
output[2] = input[5]; |
|||
output[3] = input[2]; |
|||
output[4] = input[3]; |
|||
output[5] = input[4]; |
|||
output[6] = input[1]; |
|||
output[7] = input[6]; |
|||
|
|||
// Stage 2 applies the terminal odd-angle rotations in reverse.
|
|||
stage++; |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[4], output[0], cospi[60], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[60], output[0], -cospi[4], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[20], output[2], cospi[44], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[44], output[2], -cospi[20], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[36], output[4], cospi[28], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[28], output[4], -cospi[36], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[52], output[6], cospi[12], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[12], output[6], -cospi[52], output[7], cosBit); |
|||
|
|||
// Stage 3 separates the complete butterfly into two four-sample halves and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[4], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[5], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[6], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[7], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[0] - step[4], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[1] - step[5], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[2] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[3] - step[7], stageRange[stage]); |
|||
|
|||
// Stage 4 reverses the pi/8 and 3pi/8 rotations in the upper half.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[16], output[4], cospi[48], output[5], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[48], output[4], -cospi[16], output[5], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[6], cospi[16], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[16], output[6], cospi[48], output[7], cosBit); |
|||
|
|||
// Stage 5 separates the four-sample halves into adjacent coefficient pairs and clamps each lane.
|
|||
stage++; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[2], stageRange[stage]); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[3], stageRange[stage]); |
|||
output[2] = Av1Transform1dMath.Clamp(step[0] - step[2], stageRange[stage]); |
|||
output[3] = Av1Transform1dMath.Clamp(step[1] - step[3], stageRange[stage]); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[6], stageRange[stage]); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[7], stageRange[stage]); |
|||
output[6] = Av1Transform1dMath.Clamp(step[4] - step[6], stageRange[stage]); |
|||
output[7] = Av1Transform1dMath.Clamp(step[5] - step[7], stageRange[stage]); |
|||
|
|||
// Stage 6 reverses the pi/4 rotations for the middle pairs.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], cospi[32], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[32], output[2], -cospi[32], output[3], cosBit); |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], cospi[32], output[7], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[32], output[6], -cospi[32], output[7], cosBit); |
|||
|
|||
// Stage 7 applies the AV1 signs and permutation that restore spatial sample order.
|
|||
output[0] = step[0]; |
|||
output[1] = -step[4]; |
|||
output[2] = step[6]; |
|||
output[3] = -step[2]; |
|||
output[4] = step[3]; |
|||
output[5] = -step[7]; |
|||
output[6] = step[5]; |
|||
output[7] = -step[1]; |
|||
} |
|||
} |
|||
@ -1,476 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the sixteen-point inverse DCT operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Dct16Inverse1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes frequency-ordered coefficients into the recursive DCT factorization order.
|
|||
stage++; |
|||
output[0] = input[0]; |
|||
output[1] = input[8]; |
|||
output[2] = input[4]; |
|||
output[3] = input[12]; |
|||
output[4] = input[2]; |
|||
output[5] = input[10]; |
|||
output[6] = input[6]; |
|||
output[7] = input[14]; |
|||
output[8] = input[1]; |
|||
output[9] = input[9]; |
|||
output[10] = input[5]; |
|||
output[11] = input[13]; |
|||
output[12] = input[3]; |
|||
output[13] = input[11]; |
|||
output[14] = input[7]; |
|||
output[15] = input[15]; |
|||
|
|||
// Stage 2 rotates the highest odd-frequency coefficient pairs by their pi/32 angles.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[60], output[8], -cospi[4], output[15], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[28], output[9], -cospi[36], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[44], output[10], -cospi[20], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[12], output[11], -cospi[52], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[52], output[11], cospi[12], output[12], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[20], output[10], cospi[44], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[36], output[9], cospi[28], output[14], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[4], output[8], cospi[60], output[15], cosBit); |
|||
|
|||
// Stage 3 reconstructs the embedded eight-point groups and combines adjacent odd terms.
|
|||
stage++; |
|||
byte range = stageRange[stage]; |
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = Av1Transform1dMath.HalfButterfly(cospi[56], step[4], -cospi[8], step[7], cosBit); |
|||
output[5] = Av1Transform1dMath.HalfButterfly(cospi[24], step[5], -cospi[40], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[40], step[5], cospi[24], step[6], cosBit); |
|||
output[7] = Av1Transform1dMath.HalfButterfly(cospi[8], step[4], cospi[56], step[7], cosBit); |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[9], range); |
|||
output[9] = Av1Transform1dMath.Clamp(step[8] - step[9], range); |
|||
output[10] = Av1Transform1dMath.Clamp(step[11] - step[10], range); |
|||
output[11] = Av1Transform1dMath.Clamp(step[10] + step[11], range); |
|||
output[12] = Av1Transform1dMath.Clamp(step[12] + step[13], range); |
|||
output[13] = Av1Transform1dMath.Clamp(step[12] - step[13], range); |
|||
output[14] = Av1Transform1dMath.Clamp(step[15] - step[14], range); |
|||
output[15] = Av1Transform1dMath.Clamp(step[14] + step[15], range); |
|||
|
|||
// Stage 4 completes the low-frequency four-point DCT and rotates the next odd-frequency pairs.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], -cospi[32], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], -cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[16], output[2], cospi[48], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.Clamp(output[4] + output[5], range); |
|||
step[5] = Av1Transform1dMath.Clamp(output[4] - output[5], range); |
|||
step[6] = Av1Transform1dMath.Clamp(output[7] - output[6], range); |
|||
step[7] = Av1Transform1dMath.Clamp(output[6] + output[7], range); |
|||
step[8] = output[8]; |
|||
step[9] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[9], cospi[48], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[10], -cospi[16], output[13], cosBit); |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[10], cospi[48], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[48], output[9], cospi[16], output[14], cosBit); |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 5 widens the reconstructed groups through their next butterfly level.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[3], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[2], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[1] - step[2], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[0] - step[3], range); |
|||
output[4] = step[4]; |
|||
output[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[5], cospi[32], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[32], step[5], cospi[32], step[6], cosBit); |
|||
output[7] = step[7]; |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[11], range); |
|||
output[9] = Av1Transform1dMath.Clamp(step[9] + step[10], range); |
|||
output[10] = Av1Transform1dMath.Clamp(step[9] - step[10], range); |
|||
output[11] = Av1Transform1dMath.Clamp(step[8] - step[11], range); |
|||
output[12] = Av1Transform1dMath.Clamp(step[15] - step[12], range); |
|||
output[13] = Av1Transform1dMath.Clamp(step[14] - step[13], range); |
|||
output[14] = Av1Transform1dMath.Clamp(step[13] + step[14], range); |
|||
output[15] = Av1Transform1dMath.Clamp(step[12] + step[15], range); |
|||
|
|||
// Stage 6 applies the remaining pi/4 rotations before the terminal spatial merge.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
step[0] = Av1Transform1dMath.Clamp(output[0] + output[7], range); |
|||
step[1] = Av1Transform1dMath.Clamp(output[1] + output[6], range); |
|||
step[2] = Av1Transform1dMath.Clamp(output[2] + output[5], range); |
|||
step[3] = Av1Transform1dMath.Clamp(output[3] + output[4], range); |
|||
step[4] = Av1Transform1dMath.Clamp(output[3] - output[4], range); |
|||
step[5] = Av1Transform1dMath.Clamp(output[2] - output[5], range); |
|||
step[6] = Av1Transform1dMath.Clamp(output[1] - output[6], range); |
|||
step[7] = Av1Transform1dMath.Clamp(output[0] - output[7], range); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[10], cospi[32], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[11], cospi[32], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[32], output[11], cospi[32], output[12], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], cospi[32], output[13], cosBit); |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 7 merges the even and odd halves into spatial order and clamps every result.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[15], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[14], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[13], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[12], range); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[11], range); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[10], range); |
|||
output[6] = Av1Transform1dMath.Clamp(step[6] + step[9], range); |
|||
output[7] = Av1Transform1dMath.Clamp(step[7] + step[8], range); |
|||
output[8] = Av1Transform1dMath.Clamp(step[7] - step[8], range); |
|||
output[9] = Av1Transform1dMath.Clamp(step[6] - step[9], range); |
|||
output[10] = Av1Transform1dMath.Clamp(step[5] - step[10], range); |
|||
output[11] = Av1Transform1dMath.Clamp(step[4] - step[11], range); |
|||
output[12] = Av1Transform1dMath.Clamp(step[3] - step[12], range); |
|||
output[13] = Av1Transform1dMath.Clamp(step[2] - step[13], range); |
|||
output[14] = Av1Transform1dMath.Clamp(step[1] - step[14], range); |
|||
output[15] = Av1Transform1dMath.Clamp(step[0] - step[15], range); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes frequency-ordered coefficients into the recursive DCT factorization order.
|
|||
stage++; |
|||
output[0] = input[0]; |
|||
output[1] = input[8]; |
|||
output[2] = input[4]; |
|||
output[3] = input[12]; |
|||
output[4] = input[2]; |
|||
output[5] = input[10]; |
|||
output[6] = input[6]; |
|||
output[7] = input[14]; |
|||
output[8] = input[1]; |
|||
output[9] = input[9]; |
|||
output[10] = input[5]; |
|||
output[11] = input[13]; |
|||
output[12] = input[3]; |
|||
output[13] = input[11]; |
|||
output[14] = input[7]; |
|||
output[15] = input[15]; |
|||
|
|||
// Stage 2 rotates the highest odd-frequency coefficient pairs by their pi/32 angles.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[60], output[8], -cospi[4], output[15], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[28], output[9], -cospi[36], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[44], output[10], -cospi[20], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[12], output[11], -cospi[52], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[52], output[11], cospi[12], output[12], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[20], output[10], cospi[44], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[36], output[9], cospi[28], output[14], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[4], output[8], cospi[60], output[15], cosBit); |
|||
|
|||
// Stage 3 reconstructs the embedded eight-point groups and combines adjacent odd terms.
|
|||
stage++; |
|||
byte range = stageRange[stage]; |
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = Av1Transform1dMath.HalfButterfly(cospi[56], step[4], -cospi[8], step[7], cosBit); |
|||
output[5] = Av1Transform1dMath.HalfButterfly(cospi[24], step[5], -cospi[40], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[40], step[5], cospi[24], step[6], cosBit); |
|||
output[7] = Av1Transform1dMath.HalfButterfly(cospi[8], step[4], cospi[56], step[7], cosBit); |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[9], range); |
|||
output[9] = Av1Transform1dMath.Clamp(step[8] - step[9], range); |
|||
output[10] = Av1Transform1dMath.Clamp(step[11] - step[10], range); |
|||
output[11] = Av1Transform1dMath.Clamp(step[10] + step[11], range); |
|||
output[12] = Av1Transform1dMath.Clamp(step[12] + step[13], range); |
|||
output[13] = Av1Transform1dMath.Clamp(step[12] - step[13], range); |
|||
output[14] = Av1Transform1dMath.Clamp(step[15] - step[14], range); |
|||
output[15] = Av1Transform1dMath.Clamp(step[14] + step[15], range); |
|||
|
|||
// Stage 4 completes the low-frequency four-point DCT and rotates the next odd-frequency pairs.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], -cospi[32], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], -cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[16], output[2], cospi[48], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.Clamp(output[4] + output[5], range); |
|||
step[5] = Av1Transform1dMath.Clamp(output[4] - output[5], range); |
|||
step[6] = Av1Transform1dMath.Clamp(output[7] - output[6], range); |
|||
step[7] = Av1Transform1dMath.Clamp(output[6] + output[7], range); |
|||
step[8] = output[8]; |
|||
step[9] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[9], cospi[48], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[10], -cospi[16], output[13], cosBit); |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[10], cospi[48], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[48], output[9], cospi[16], output[14], cosBit); |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 5 widens the reconstructed groups through their next butterfly level.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[3], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[2], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[1] - step[2], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[0] - step[3], range); |
|||
output[4] = step[4]; |
|||
output[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[5], cospi[32], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[32], step[5], cospi[32], step[6], cosBit); |
|||
output[7] = step[7]; |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[11], range); |
|||
output[9] = Av1Transform1dMath.Clamp(step[9] + step[10], range); |
|||
output[10] = Av1Transform1dMath.Clamp(step[9] - step[10], range); |
|||
output[11] = Av1Transform1dMath.Clamp(step[8] - step[11], range); |
|||
output[12] = Av1Transform1dMath.Clamp(step[15] - step[12], range); |
|||
output[13] = Av1Transform1dMath.Clamp(step[14] - step[13], range); |
|||
output[14] = Av1Transform1dMath.Clamp(step[13] + step[14], range); |
|||
output[15] = Av1Transform1dMath.Clamp(step[12] + step[15], range); |
|||
|
|||
// Stage 6 applies the remaining pi/4 rotations before the terminal spatial merge.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
step[0] = Av1Transform1dMath.Clamp(output[0] + output[7], range); |
|||
step[1] = Av1Transform1dMath.Clamp(output[1] + output[6], range); |
|||
step[2] = Av1Transform1dMath.Clamp(output[2] + output[5], range); |
|||
step[3] = Av1Transform1dMath.Clamp(output[3] + output[4], range); |
|||
step[4] = Av1Transform1dMath.Clamp(output[3] - output[4], range); |
|||
step[5] = Av1Transform1dMath.Clamp(output[2] - output[5], range); |
|||
step[6] = Av1Transform1dMath.Clamp(output[1] - output[6], range); |
|||
step[7] = Av1Transform1dMath.Clamp(output[0] - output[7], range); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[10], cospi[32], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[11], cospi[32], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[32], output[11], cospi[32], output[12], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], cospi[32], output[13], cosBit); |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 7 merges the even and odd halves into spatial order and clamps every result.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[15], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[14], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[13], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[12], range); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[11], range); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[10], range); |
|||
output[6] = Av1Transform1dMath.Clamp(step[6] + step[9], range); |
|||
output[7] = Av1Transform1dMath.Clamp(step[7] + step[8], range); |
|||
output[8] = Av1Transform1dMath.Clamp(step[7] - step[8], range); |
|||
output[9] = Av1Transform1dMath.Clamp(step[6] - step[9], range); |
|||
output[10] = Av1Transform1dMath.Clamp(step[5] - step[10], range); |
|||
output[11] = Av1Transform1dMath.Clamp(step[4] - step[11], range); |
|||
output[12] = Av1Transform1dMath.Clamp(step[3] - step[12], range); |
|||
output[13] = Av1Transform1dMath.Clamp(step[2] - step[13], range); |
|||
output[14] = Av1Transform1dMath.Clamp(step[1] - step[14], range); |
|||
output[15] = Av1Transform1dMath.Clamp(step[0] - step[15], range); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes frequency-ordered coefficients into the recursive DCT factorization order.
|
|||
stage++; |
|||
output[0] = input[0]; |
|||
output[1] = input[8]; |
|||
output[2] = input[4]; |
|||
output[3] = input[12]; |
|||
output[4] = input[2]; |
|||
output[5] = input[10]; |
|||
output[6] = input[6]; |
|||
output[7] = input[14]; |
|||
output[8] = input[1]; |
|||
output[9] = input[9]; |
|||
output[10] = input[5]; |
|||
output[11] = input[13]; |
|||
output[12] = input[3]; |
|||
output[13] = input[11]; |
|||
output[14] = input[7]; |
|||
output[15] = input[15]; |
|||
|
|||
// Stage 2 rotates the highest odd-frequency coefficient pairs by their pi/32 angles.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = output[4]; |
|||
step[5] = output[5]; |
|||
step[6] = output[6]; |
|||
step[7] = output[7]; |
|||
step[8] = Av1Transform1dMath.HalfButterfly(cospi[60], output[8], -cospi[4], output[15], cosBit); |
|||
step[9] = Av1Transform1dMath.HalfButterfly(cospi[28], output[9], -cospi[36], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(cospi[44], output[10], -cospi[20], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(cospi[12], output[11], -cospi[52], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[52], output[11], cospi[12], output[12], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[20], output[10], cospi[44], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[36], output[9], cospi[28], output[14], cosBit); |
|||
step[15] = Av1Transform1dMath.HalfButterfly(cospi[4], output[8], cospi[60], output[15], cosBit); |
|||
|
|||
// Stage 3 reconstructs the embedded eight-point groups and combines adjacent odd terms.
|
|||
stage++; |
|||
byte range = stageRange[stage]; |
|||
output[0] = step[0]; |
|||
output[1] = step[1]; |
|||
output[2] = step[2]; |
|||
output[3] = step[3]; |
|||
output[4] = Av1Transform1dMath.HalfButterfly(cospi[56], step[4], -cospi[8], step[7], cosBit); |
|||
output[5] = Av1Transform1dMath.HalfButterfly(cospi[24], step[5], -cospi[40], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[40], step[5], cospi[24], step[6], cosBit); |
|||
output[7] = Av1Transform1dMath.HalfButterfly(cospi[8], step[4], cospi[56], step[7], cosBit); |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[9], range); |
|||
output[9] = Av1Transform1dMath.Clamp(step[8] - step[9], range); |
|||
output[10] = Av1Transform1dMath.Clamp(step[11] - step[10], range); |
|||
output[11] = Av1Transform1dMath.Clamp(step[10] + step[11], range); |
|||
output[12] = Av1Transform1dMath.Clamp(step[12] + step[13], range); |
|||
output[13] = Av1Transform1dMath.Clamp(step[12] - step[13], range); |
|||
output[14] = Av1Transform1dMath.Clamp(step[15] - step[14], range); |
|||
output[15] = Av1Transform1dMath.Clamp(step[14] + step[15], range); |
|||
|
|||
// Stage 4 completes the low-frequency four-point DCT and rotates the next odd-frequency pairs.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], -cospi[32], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], -cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[16], output[2], cospi[48], output[3], cosBit); |
|||
step[4] = Av1Transform1dMath.Clamp(output[4] + output[5], range); |
|||
step[5] = Av1Transform1dMath.Clamp(output[4] - output[5], range); |
|||
step[6] = Av1Transform1dMath.Clamp(output[7] - output[6], range); |
|||
step[7] = Av1Transform1dMath.Clamp(output[6] + output[7], range); |
|||
step[8] = output[8]; |
|||
step[9] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[9], cospi[48], output[14], cosBit); |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[48], output[10], -cospi[16], output[13], cosBit); |
|||
step[11] = output[11]; |
|||
step[12] = output[12]; |
|||
step[13] = Av1Transform1dMath.HalfButterfly(-cospi[16], output[10], cospi[48], output[13], cosBit); |
|||
step[14] = Av1Transform1dMath.HalfButterfly(cospi[48], output[9], cospi[16], output[14], cosBit); |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 5 widens the reconstructed groups through their next butterfly level.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[3], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[2], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[1] - step[2], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[0] - step[3], range); |
|||
output[4] = step[4]; |
|||
output[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], step[5], cospi[32], step[6], cosBit); |
|||
output[6] = Av1Transform1dMath.HalfButterfly(cospi[32], step[5], cospi[32], step[6], cosBit); |
|||
output[7] = step[7]; |
|||
output[8] = Av1Transform1dMath.Clamp(step[8] + step[11], range); |
|||
output[9] = Av1Transform1dMath.Clamp(step[9] + step[10], range); |
|||
output[10] = Av1Transform1dMath.Clamp(step[9] - step[10], range); |
|||
output[11] = Av1Transform1dMath.Clamp(step[8] - step[11], range); |
|||
output[12] = Av1Transform1dMath.Clamp(step[15] - step[12], range); |
|||
output[13] = Av1Transform1dMath.Clamp(step[14] - step[13], range); |
|||
output[14] = Av1Transform1dMath.Clamp(step[13] + step[14], range); |
|||
output[15] = Av1Transform1dMath.Clamp(step[12] + step[15], range); |
|||
|
|||
// Stage 6 applies the remaining pi/4 rotations before the terminal spatial merge.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
step[0] = Av1Transform1dMath.Clamp(output[0] + output[7], range); |
|||
step[1] = Av1Transform1dMath.Clamp(output[1] + output[6], range); |
|||
step[2] = Av1Transform1dMath.Clamp(output[2] + output[5], range); |
|||
step[3] = Av1Transform1dMath.Clamp(output[3] + output[4], range); |
|||
step[4] = Av1Transform1dMath.Clamp(output[3] - output[4], range); |
|||
step[5] = Av1Transform1dMath.Clamp(output[2] - output[5], range); |
|||
step[6] = Av1Transform1dMath.Clamp(output[1] - output[6], range); |
|||
step[7] = Av1Transform1dMath.Clamp(output[0] - output[7], range); |
|||
step[8] = output[8]; |
|||
step[9] = output[9]; |
|||
step[10] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[10], cospi[32], output[13], cosBit); |
|||
step[11] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[11], cospi[32], output[12], cosBit); |
|||
step[12] = Av1Transform1dMath.HalfButterfly(cospi[32], output[11], cospi[32], output[12], cosBit); |
|||
step[13] = Av1Transform1dMath.HalfButterfly(cospi[32], output[10], cospi[32], output[13], cosBit); |
|||
step[14] = output[14]; |
|||
step[15] = output[15]; |
|||
|
|||
// Stage 7 merges the even and odd halves into spatial order and clamps every result.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[15], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[14], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[13], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[12], range); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[11], range); |
|||
output[5] = Av1Transform1dMath.Clamp(step[5] + step[10], range); |
|||
output[6] = Av1Transform1dMath.Clamp(step[6] + step[9], range); |
|||
output[7] = Av1Transform1dMath.Clamp(step[7] + step[8], range); |
|||
output[8] = Av1Transform1dMath.Clamp(step[7] - step[8], range); |
|||
output[9] = Av1Transform1dMath.Clamp(step[6] - step[9], range); |
|||
output[10] = Av1Transform1dMath.Clamp(step[5] - step[10], range); |
|||
output[11] = Av1Transform1dMath.Clamp(step[4] - step[11], range); |
|||
output[12] = Av1Transform1dMath.Clamp(step[3] - step[12], range); |
|||
output[13] = Av1Transform1dMath.Clamp(step[2] - step[13], range); |
|||
output[14] = Av1Transform1dMath.Clamp(step[1] - step[14], range); |
|||
output[15] = Av1Transform1dMath.Clamp(step[0] - step[15], range); |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -1,113 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the four-point inverse DCT operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Dct4Inverse1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// AV1 stores coefficients in frequency order; this permutation restores the order expected by the staged DCT.
|
|||
output[0] = input[0]; |
|||
output[1] = input[2]; |
|||
output[2] = input[1]; |
|||
output[3] = input[3]; |
|||
|
|||
// Rotate the even and odd coefficient pairs using the same fixed-point basis as the forward transform.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], -cospi[32], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], -cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[16], output[2], cospi[48], output[3], cosBit); |
|||
|
|||
// The terminal butterflies reconstruct spatial order and clamp every result to the normative stage range.
|
|||
byte range = stageRange[3]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[3], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[2], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[1] - step[2], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[0] - step[3], range); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// AV1 stores coefficients in frequency order; this permutation restores the order expected by the staged DCT.
|
|||
output[0] = input[0]; |
|||
output[1] = input[2]; |
|||
output[2] = input[1]; |
|||
output[3] = input[3]; |
|||
|
|||
// Rotate the even and odd coefficient pairs using the same fixed-point basis as the forward transform.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], -cospi[32], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], -cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[16], output[2], cospi[48], output[3], cosBit); |
|||
|
|||
// The terminal butterflies reconstruct spatial order and clamp every result to the normative stage range.
|
|||
byte range = stageRange[3]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[3], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[2], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[1] - step[2], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[0] - step[3], range); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
// AV1 stores coefficients in frequency order; this permutation restores the order expected by the staged DCT.
|
|||
output[0] = input[0]; |
|||
output[1] = input[2]; |
|||
output[2] = input[1]; |
|||
output[3] = input[3]; |
|||
|
|||
// Rotate the even and odd coefficient pairs using the same fixed-point basis as the forward transform.
|
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
step[0] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], cospi[32], output[1], cosBit); |
|||
step[1] = Av1Transform1dMath.HalfButterfly(cospi[32], output[0], -cospi[32], output[1], cosBit); |
|||
step[2] = Av1Transform1dMath.HalfButterfly(cospi[48], output[2], -cospi[16], output[3], cosBit); |
|||
step[3] = Av1Transform1dMath.HalfButterfly(cospi[16], output[2], cospi[48], output[3], cosBit); |
|||
|
|||
// The terminal butterflies reconstruct spatial order and clamp every result to the normative stage range.
|
|||
byte range = stageRange[3]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[3], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[2], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[1] - step[2], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[0] - step[3], range); |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -1,233 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the eight-point inverse DCT operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Dct8Inverse1dOperator |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the transform to sixteen independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes frequency-ordered coefficients into the recursive DCT factorization order.
|
|||
stage++; |
|||
output[0] = input[0]; |
|||
output[1] = input[4]; |
|||
output[2] = input[2]; |
|||
output[3] = input[6]; |
|||
output[4] = input[1]; |
|||
output[5] = input[5]; |
|||
output[6] = input[3]; |
|||
output[7] = input[7]; |
|||
|
|||
// Stage 2 rotates the odd-frequency coefficient pairs by their pi/16 angles.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[56], output[4], -cospi[8], output[7], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[24], output[5], -cospi[40], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[40], output[5], cospi[24], output[6], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[8], output[4], cospi[56], output[7], cosBit); |
|||
|
|||
// Stage 3 reconstructs the even four-point DCT and combines adjacent odd terms.
|
|||
stage++; |
|||
byte range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], cospi[32], step[1], cosBit); |
|||
output[1] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], -cospi[32], step[1], cosBit); |
|||
output[2] = Av1Transform1dMath.HalfButterfly(cospi[48], step[2], -cospi[16], step[3], cosBit); |
|||
output[3] = Av1Transform1dMath.HalfButterfly(cospi[16], step[2], cospi[48], step[3], cosBit); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[5], range); |
|||
output[5] = Av1Transform1dMath.Clamp(step[4] - step[5], range); |
|||
output[6] = Av1Transform1dMath.Clamp(step[7] - step[6], range); |
|||
output[7] = Av1Transform1dMath.Clamp(step[6] + step[7], range); |
|||
|
|||
// Stage 4 completes the even butterflies and applies the remaining pi/4 odd rotation.
|
|||
stage++; |
|||
step[0] = Av1Transform1dMath.Clamp(output[0] + output[3], range); |
|||
step[1] = Av1Transform1dMath.Clamp(output[1] + output[2], range); |
|||
step[2] = Av1Transform1dMath.Clamp(output[1] - output[2], range); |
|||
step[3] = Av1Transform1dMath.Clamp(output[0] - output[3], range); |
|||
step[4] = output[4]; |
|||
step[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[7] = output[7]; |
|||
|
|||
// Stage 5 merges the even and odd halves into spatial order and clamps every result.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[7], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[6], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[5], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[4], range); |
|||
output[4] = Av1Transform1dMath.Clamp(step[3] - step[4], range); |
|||
output[5] = Av1Transform1dMath.Clamp(step[2] - step[5], range); |
|||
output[6] = Av1Transform1dMath.Clamp(step[1] - step[6], range); |
|||
output[7] = Av1Transform1dMath.Clamp(step[0] - step[7], range); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes frequency-ordered coefficients into the recursive DCT factorization order.
|
|||
stage++; |
|||
output[0] = input[0]; |
|||
output[1] = input[4]; |
|||
output[2] = input[2]; |
|||
output[3] = input[6]; |
|||
output[4] = input[1]; |
|||
output[5] = input[5]; |
|||
output[6] = input[3]; |
|||
output[7] = input[7]; |
|||
|
|||
// Stage 2 rotates the odd-frequency coefficient pairs by their pi/16 angles.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[56], output[4], -cospi[8], output[7], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[24], output[5], -cospi[40], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[40], output[5], cospi[24], output[6], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[8], output[4], cospi[56], output[7], cosBit); |
|||
|
|||
// Stage 3 reconstructs the even four-point DCT and combines adjacent odd terms.
|
|||
stage++; |
|||
byte range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], cospi[32], step[1], cosBit); |
|||
output[1] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], -cospi[32], step[1], cosBit); |
|||
output[2] = Av1Transform1dMath.HalfButterfly(cospi[48], step[2], -cospi[16], step[3], cosBit); |
|||
output[3] = Av1Transform1dMath.HalfButterfly(cospi[16], step[2], cospi[48], step[3], cosBit); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[5], range); |
|||
output[5] = Av1Transform1dMath.Clamp(step[4] - step[5], range); |
|||
output[6] = Av1Transform1dMath.Clamp(step[7] - step[6], range); |
|||
output[7] = Av1Transform1dMath.Clamp(step[6] + step[7], range); |
|||
|
|||
// Stage 4 completes the even butterflies and applies the remaining pi/4 odd rotation.
|
|||
stage++; |
|||
step[0] = Av1Transform1dMath.Clamp(output[0] + output[3], range); |
|||
step[1] = Av1Transform1dMath.Clamp(output[1] + output[2], range); |
|||
step[2] = Av1Transform1dMath.Clamp(output[1] - output[2], range); |
|||
step[3] = Av1Transform1dMath.Clamp(output[0] - output[3], range); |
|||
step[4] = output[4]; |
|||
step[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[7] = output[7]; |
|||
|
|||
// Stage 5 merges the even and odd halves into spatial order and clamps every result.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[7], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[6], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[5], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[4], range); |
|||
output[4] = Av1Transform1dMath.Clamp(step[3] - step[4], range); |
|||
output[5] = Av1Transform1dMath.Clamp(step[2] - step[5], range); |
|||
output[6] = Av1Transform1dMath.Clamp(step[1] - step[6], range); |
|||
output[7] = Av1Transform1dMath.Clamp(step[0] - step[7], range); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the transform to four independent axes in parallel.
|
|||
/// </summary>
|
|||
/// <param name="input">The source values for the parallel transform axes.</param>
|
|||
/// <param name="output">The destination values for the parallel transform axes.</param>
|
|||
/// <param name="step">The fixed stage storage for the parallel transform axes.</param>
|
|||
/// <param name="cosBit">The fixed-point precision of the cosine constants.</param>
|
|||
/// <param name="stageRange">The signed-bit range assigned to each transform stage.</param>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
ReadOnlySpan<int> cospi = Av1SinusConstants.CosinusPi(cosBit); |
|||
int stage = 0; |
|||
|
|||
// Stage 1 permutes frequency-ordered coefficients into the recursive DCT factorization order.
|
|||
stage++; |
|||
output[0] = input[0]; |
|||
output[1] = input[4]; |
|||
output[2] = input[2]; |
|||
output[3] = input[6]; |
|||
output[4] = input[1]; |
|||
output[5] = input[5]; |
|||
output[6] = input[3]; |
|||
output[7] = input[7]; |
|||
|
|||
// Stage 2 rotates the odd-frequency coefficient pairs by their pi/16 angles.
|
|||
stage++; |
|||
step[0] = output[0]; |
|||
step[1] = output[1]; |
|||
step[2] = output[2]; |
|||
step[3] = output[3]; |
|||
step[4] = Av1Transform1dMath.HalfButterfly(cospi[56], output[4], -cospi[8], output[7], cosBit); |
|||
step[5] = Av1Transform1dMath.HalfButterfly(cospi[24], output[5], -cospi[40], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[40], output[5], cospi[24], output[6], cosBit); |
|||
step[7] = Av1Transform1dMath.HalfButterfly(cospi[8], output[4], cospi[56], output[7], cosBit); |
|||
|
|||
// Stage 3 reconstructs the even four-point DCT and combines adjacent odd terms.
|
|||
stage++; |
|||
byte range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], cospi[32], step[1], cosBit); |
|||
output[1] = Av1Transform1dMath.HalfButterfly(cospi[32], step[0], -cospi[32], step[1], cosBit); |
|||
output[2] = Av1Transform1dMath.HalfButterfly(cospi[48], step[2], -cospi[16], step[3], cosBit); |
|||
output[3] = Av1Transform1dMath.HalfButterfly(cospi[16], step[2], cospi[48], step[3], cosBit); |
|||
output[4] = Av1Transform1dMath.Clamp(step[4] + step[5], range); |
|||
output[5] = Av1Transform1dMath.Clamp(step[4] - step[5], range); |
|||
output[6] = Av1Transform1dMath.Clamp(step[7] - step[6], range); |
|||
output[7] = Av1Transform1dMath.Clamp(step[6] + step[7], range); |
|||
|
|||
// Stage 4 completes the even butterflies and applies the remaining pi/4 odd rotation.
|
|||
stage++; |
|||
step[0] = Av1Transform1dMath.Clamp(output[0] + output[3], range); |
|||
step[1] = Av1Transform1dMath.Clamp(output[1] + output[2], range); |
|||
step[2] = Av1Transform1dMath.Clamp(output[1] - output[2], range); |
|||
step[3] = Av1Transform1dMath.Clamp(output[0] - output[3], range); |
|||
step[4] = output[4]; |
|||
step[5] = Av1Transform1dMath.HalfButterfly(-cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[6] = Av1Transform1dMath.HalfButterfly(cospi[32], output[5], cospi[32], output[6], cosBit); |
|||
step[7] = output[7]; |
|||
|
|||
// Stage 5 merges the even and odd halves into spatial order and clamps every result.
|
|||
stage++; |
|||
range = stageRange[stage]; |
|||
output[0] = Av1Transform1dMath.Clamp(step[0] + step[7], range); |
|||
output[1] = Av1Transform1dMath.Clamp(step[1] + step[6], range); |
|||
output[2] = Av1Transform1dMath.Clamp(step[2] + step[5], range); |
|||
output[3] = Av1Transform1dMath.Clamp(step[3] + step[4], range); |
|||
output[4] = Av1Transform1dMath.Clamp(step[3] - step[4], range); |
|||
output[5] = Av1Transform1dMath.Clamp(step[2] - step[5], range); |
|||
output[6] = Av1Transform1dMath.Clamp(step[1] - step[6], range); |
|||
output[7] = Av1Transform1dMath.Clamp(step[0] - step[7], range); |
|||
} |
|||
} |
|||
@ -1,198 +0,0 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.Intrinsics; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the four-point inverse identity-transform operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Identity4Inverse1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 4, Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 4, Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 4, Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
} |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the eight-point inverse identity-transform operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Identity8Inverse1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 8, 2, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 8, 2, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 8, 2, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
} |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the sixteen-point inverse identity-transform operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Identity16Inverse1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 16, 2 * Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 16, 2 * Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 16, 2 * Av1Transform1dMath.NewSqrt2, Av1Transform1dMath.NewSqrt2Bits); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
} |
|||
|
|||
/// <content>
|
|||
/// Provides the SIMD kernels for the thirty-two-point inverse identity-transform operator.
|
|||
/// </content>
|
|||
internal readonly partial struct Av1Identity32Inverse1dOperator |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector128<int>> input, |
|||
ref Av1TransformVector<Vector128<int>> output, |
|||
ref Av1TransformVector<Vector128<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 32, 4, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector256<int>> input, |
|||
ref Av1TransformVector<Vector256<int>> output, |
|||
ref Av1TransformVector<Vector256<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 32, 4, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public static void Transform( |
|||
ref Av1TransformVector<Vector512<int>> input, |
|||
ref Av1TransformVector<Vector512<int>> output, |
|||
ref Av1TransformVector<Vector512<int>> step, |
|||
int cosBit, |
|||
Av1TransformStageRange stageRange) |
|||
{ |
|||
Av1IdentityTransform1d.Transform(ref input, ref output, 32, 4, 0); |
|||
_ = step; |
|||
_ = cosBit; |
|||
_ = stageRange; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue