Browse Source

Use fixed sized arrays in Vp8Matrix

pull/1811/head
Brian Popow 5 years ago
parent
commit
cb513a905c
  1. 20
      src/ImageSharp/Formats/Webp/Lossy/QuantEnc.cs
  2. 8
      src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
  3. 47
      src/ImageSharp/Formats/Webp/Lossy/Vp8Matrix.cs
  4. 12
      src/ImageSharp/Formats/Webp/Lossy/Vp8SegmentInfo.cs
  5. 17
      tests/ImageSharp.Tests/Formats/WebP/QuantEncTests.cs

20
src/ImageSharp/Formats/Webp/Lossy/QuantEnc.cs

@ -541,18 +541,18 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
// Load all inputs. // Load all inputs.
Vector128<short> input0 = Unsafe.As<short, Vector128<short>>(ref MemoryMarshal.GetReference(input)); Vector128<short> input0 = Unsafe.As<short, Vector128<short>>(ref MemoryMarshal.GetReference(input));
Vector128<short> input8 = Unsafe.As<short, Vector128<short>>(ref MemoryMarshal.GetReference(input.Slice(8, 8))); Vector128<short> input8 = Unsafe.As<short, Vector128<short>>(ref MemoryMarshal.GetReference(input.Slice(8, 8)));
Vector128<ushort> iq0 = Unsafe.As<ushort, Vector128<ushort>>(ref MemoryMarshal.GetReference(mtx.IQ.AsSpan(0, 8))); Vector128<ushort> iq0 = Unsafe.As<ushort, Vector128<ushort>>(ref mtx.IQ[0]);
Vector128<ushort> iq8 = Unsafe.As<ushort, Vector128<ushort>>(ref MemoryMarshal.GetReference(mtx.IQ.AsSpan(8, 8))); Vector128<ushort> iq8 = Unsafe.As<ushort, Vector128<ushort>>(ref mtx.IQ[8]);
Vector128<ushort> q0 = Unsafe.As<ushort, Vector128<ushort>>(ref MemoryMarshal.GetReference(mtx.Q.AsSpan(0, 8))); Vector128<ushort> q0 = Unsafe.As<ushort, Vector128<ushort>>(ref mtx.Q[0]);
Vector128<ushort> q8 = Unsafe.As<ushort, Vector128<ushort>>(ref MemoryMarshal.GetReference(mtx.Q.AsSpan(8, 8))); Vector128<ushort> q8 = Unsafe.As<ushort, Vector128<ushort>>(ref mtx.Q[8]);
// coeff = abs(in) // coeff = abs(in)
Vector128<ushort> coeff0 = Ssse3.Abs(input0); Vector128<ushort> coeff0 = Ssse3.Abs(input0);
Vector128<ushort> coeff8 = Ssse3.Abs(input8); Vector128<ushort> coeff8 = Ssse3.Abs(input8);
// coeff = abs(in) + sharpen // coeff = abs(in) + sharpen
Vector128<short> sharpen0 = Unsafe.As<short, Vector128<short>>(ref MemoryMarshal.GetReference(mtx.Sharpen.AsSpan(0, 8))); Vector128<short> sharpen0 = Unsafe.As<short, Vector128<short>>(ref mtx.Sharpen[0]);
Vector128<short> sharpen8 = Unsafe.As<short, Vector128<short>>(ref MemoryMarshal.GetReference(mtx.Sharpen.AsSpan(8, 8))); Vector128<short> sharpen8 = Unsafe.As<short, Vector128<short>>(ref mtx.Sharpen[8]);
Sse2.Add(coeff0.AsInt16(), sharpen0); Sse2.Add(coeff0.AsInt16(), sharpen0);
Sse2.Add(coeff8.AsInt16(), sharpen8); Sse2.Add(coeff8.AsInt16(), sharpen8);
@ -569,10 +569,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
Vector128<ushort> out12 = Sse2.UnpackHigh(coeffiQ8L, coeffiQ8H); Vector128<ushort> out12 = Sse2.UnpackHigh(coeffiQ8L, coeffiQ8H);
// out = (coeff * iQ + B) // out = (coeff * iQ + B)
Vector128<uint> bias00 = Unsafe.As<uint, Vector128<uint>>(ref MemoryMarshal.GetReference(mtx.Bias.AsSpan(0, 4))); Vector128<uint> bias00 = Unsafe.As<uint, Vector128<uint>>(ref mtx.Bias[0]);
Vector128<uint> bias04 = Unsafe.As<uint, Vector128<uint>>(ref MemoryMarshal.GetReference(mtx.Bias.AsSpan(4, 4))); Vector128<uint> bias04 = Unsafe.As<uint, Vector128<uint>>(ref mtx.Bias[4]);
Vector128<uint> bias08 = Unsafe.As<uint, Vector128<uint>>(ref MemoryMarshal.GetReference(mtx.Bias.AsSpan(8, 4))); Vector128<uint> bias08 = Unsafe.As<uint, Vector128<uint>>(ref mtx.Bias[8]);
Vector128<uint> bias12 = Unsafe.As<uint, Vector128<uint>>(ref MemoryMarshal.GetReference(mtx.Bias.AsSpan(12, 4))); Vector128<uint> bias12 = Unsafe.As<uint, Vector128<uint>>(ref mtx.Bias[12]);
out00 = Sse2.Add(out00.AsInt32(), bias00.AsInt32()).AsUInt16(); out00 = Sse2.Add(out00.AsInt32(), bias00.AsInt32()).AsUInt16();
out04 = Sse2.Add(out04.AsInt32(), bias04.AsInt32()).AsUInt16(); out04 = Sse2.Add(out04.AsInt32(), bias04.AsInt32()).AsUInt16();
out08 = Sse2.Add(out08.AsInt32(), bias08.AsInt32()).AsUInt16(); out08 = Sse2.Add(out08.AsInt32(), bias08.AsInt32()).AsUInt16();

8
src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs

@ -502,7 +502,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
this.ResetStats(); this.ResetStats();
} }
private void AdjustFilterStrength() private unsafe void AdjustFilterStrength()
{ {
if (this.filterStrength > 0) if (this.filterStrength > 0)
{ {
@ -806,7 +806,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
proba.NbSkip = 0; proba.NbSkip = 0;
} }
private void SetupMatrices(Vp8SegmentInfo[] dqm) private unsafe void SetupMatrices(Vp8SegmentInfo[] dqm)
{ {
int tlambdaScale = this.method >= WebpEncodingMethod.Default ? this.spatialNoiseShaping : 0; int tlambdaScale = this.method >= WebpEncodingMethod.Default ? this.spatialNoiseShaping : 0;
for (int i = 0; i < dqm.Length; i++) for (int i = 0; i < dqm.Length; i++)
@ -814,10 +814,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
Vp8SegmentInfo m = dqm[i]; Vp8SegmentInfo m = dqm[i];
int q = m.Quant; int q = m.Quant;
m.Y1 = new Vp8Matrix();
m.Y2 = new Vp8Matrix();
m.Uv = new Vp8Matrix();
m.Y1.Q[0] = WebpLookupTables.DcTable[Numerics.Clamp(q + this.DqY1Dc, 0, 127)]; m.Y1.Q[0] = WebpLookupTables.DcTable[Numerics.Clamp(q + this.DqY1Dc, 0, 127)];
m.Y1.Q[1] = WebpLookupTables.AcTable[Numerics.Clamp(q, 0, 127)]; m.Y1.Q[1] = WebpLookupTables.AcTable[Numerics.Clamp(q, 0, 127)];

47
src/ImageSharp/Formats/Webp/Lossy/Vp8Matrix.cs

@ -3,7 +3,7 @@
namespace SixLabors.ImageSharp.Formats.Webp.Lossy namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{ {
internal class Vp8Matrix internal unsafe struct Vp8Matrix
{ {
private static readonly int[][] BiasMatrices = private static readonly int[][] BiasMatrices =
{ {
@ -23,50 +23,29 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private const int SharpenBits = 11; private const int SharpenBits = 11;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Vp8Matrix"/> class. /// The quantizer steps.
/// </summary> /// </summary>
public Vp8Matrix() public fixed ushort Q[16];
{
this.Q = new ushort[16];
this.IQ = new ushort[16];
this.Bias = new uint[16];
this.ZThresh = new uint[16];
this.Sharpen = new short[16];
}
public Vp8Matrix(ushort[] q, ushort[] iq, uint[] bias, uint[] zThresh, short[] sharpen)
{
this.Q = q;
this.IQ = iq;
this.Bias = bias;
this.ZThresh = zThresh;
this.Sharpen = sharpen;
}
/// <summary>
/// Gets the quantizer steps.
/// </summary>
public ushort[] Q { get; }
/// <summary> /// <summary>
/// Gets the reciprocals, fixed point. /// The reciprocals, fixed point.
/// </summary> /// </summary>
public ushort[] IQ { get; } public fixed ushort IQ[16];
/// <summary> /// <summary>
/// Gets the rounding bias. /// The rounding bias.
/// </summary> /// </summary>
public uint[] Bias { get; } public fixed uint Bias[16];
/// <summary> /// <summary>
/// Gets the value below which a coefficient is zeroed. /// The value below which a coefficient is zeroed.
/// </summary> /// </summary>
public uint[] ZThresh { get; } public fixed uint ZThresh[16];
/// <summary> /// <summary>
/// Gets the frequency boosters for slight sharpening. /// The frequency boosters for slight sharpening.
/// </summary> /// </summary>
public short[] Sharpen { get; } public fixed short Sharpen[16];
/// <summary> /// <summary>
/// Returns the average quantizer. /// Returns the average quantizer.
@ -81,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int isAcCoeff = i > 0 ? 1 : 0; int isAcCoeff = i > 0 ? 1 : 0;
int bias = BiasMatrices[type][isAcCoeff]; int bias = BiasMatrices[type][isAcCoeff];
this.IQ[i] = (ushort)((1 << WebpConstants.QFix) / this.Q[i]); this.IQ[i] = (ushort)((1 << WebpConstants.QFix) / this.Q[i]);
this.Bias[i] = (uint)this.BIAS(bias); this.Bias[i] = (uint)BIAS(bias);
// zthresh is the exact value such that QUANTDIV(coeff, iQ, B) is: // zthresh is the exact value such that QUANTDIV(coeff, iQ, B) is:
// * zero if coeff <= zthresh // * zero if coeff <= zthresh
@ -115,6 +94,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
return (sum + 8) >> 4; return (sum + 8) >> 4;
} }
private int BIAS(int b) => b << (WebpConstants.QFix - 8); private static int BIAS(int b) => b << (WebpConstants.QFix - 8);
} }
} }

12
src/ImageSharp/Formats/Webp/Lossy/Vp8SegmentInfo.cs

@ -8,19 +8,19 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
internal class Vp8SegmentInfo internal class Vp8SegmentInfo
{ {
/// <summary> /// <summary>
/// Gets or sets the quantization matrix y1. /// Gets the quantization matrix y1.
/// </summary> /// </summary>
public Vp8Matrix Y1 { get; set; } public Vp8Matrix Y1;
/// <summary> /// <summary>
/// Gets or sets the quantization matrix y2. /// Gets the quantization matrix y2.
/// </summary> /// </summary>
public Vp8Matrix Y2 { get; set; } public Vp8Matrix Y2;
/// <summary> /// <summary>
/// Gets or sets the quantization matrix uv. /// Gets the quantization matrix uv.
/// </summary> /// </summary>
public Vp8Matrix Uv { get; set; } public Vp8Matrix Uv;
/// <summary> /// <summary>
/// Gets or sets the quant-susceptibility, range [-127,127]. Zero is neutral. Lower values indicate a lower risk of blurriness. /// Gets or sets the quant-susceptibility, range [-127,127]. Zero is neutral. Lower values indicate a lower risk of blurriness.

17
tests/ImageSharp.Tests/Formats/WebP/QuantEncTests.cs

@ -11,22 +11,25 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP
[Trait("Format", "Webp")] [Trait("Format", "Webp")]
public class QuantEncTests public class QuantEncTests
{ {
private static void RunQuantizeBlockTest() private static unsafe void RunQuantizeBlockTest()
{ {
// arrange // arrange
short[] input = { 378, 777, -851, 888, 259, 148, 0, -111, -185, -185, -74, -37, 148, 74, 111, 74 }; short[] input = { 378, 777, -851, 888, 259, 148, 0, -111, -185, -185, -74, -37, 148, 74, 111, 74 };
short[] output = new short[16]; short[] output = new short[16];
ushort[] q = { 42, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37 }; ushort[] q = { 42, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37 };
ushort[] iq = { 3120, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542 }; ushort[] iq = { 3120, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542, 3542 };
uint[] bias = uint[] bias = { 49152, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296 };
{
49152, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296, 55296,
55296, 55296
};
uint[] zthresh = { 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21 }; uint[] zthresh = { 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21 };
short[] expectedOutput = { 9, 21, 7, -5, 4, -23, 24, 0, -5, 4, 2, -2, -3, -1, 3, 2 }; short[] expectedOutput = { 9, 21, 7, -5, 4, -23, 24, 0, -5, 4, 2, -2, -3, -1, 3, 2 };
int expectedResult = 1; int expectedResult = 1;
var vp8Matrix = new Vp8Matrix(q, iq, bias, zthresh, new short[16]); Vp8Matrix vp8Matrix = default;
for (int i = 0; i < 16; i++)
{
vp8Matrix.Q[i] = q[i];
vp8Matrix.IQ[i] = iq[i];
vp8Matrix.Bias[i] = bias[i];
vp8Matrix.ZThresh[i] = zthresh[i];
}
// act // act
int actualResult = QuantEnc.QuantizeBlock(input, output, vp8Matrix); int actualResult = QuantEnc.QuantizeBlock(input, output, vp8Matrix);

Loading…
Cancel
Save