Browse Source

cleanup and docs

pull/337/head
Anton Firszov 9 years ago
parent
commit
347dd15ea2
  1. 5
      src/ImageSharp/Common/Tuples/Tuple8.cs
  2. 8
      src/ImageSharp/Common/Tuples/Vector4Pair.cs
  3. 89
      src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs
  4. 23
      src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt
  5. 91
      src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
  6. 22
      src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs
  7. 5
      src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs
  8. 47
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs

5
src/ImageSharp/Common/Tuples/Tuple8.cs

@ -4,7 +4,7 @@ namespace SixLabors.ImageSharp.Common.Tuples
{
/// <summary>
/// Contains value type tuples of 8 elements.
/// TODO: Should T4 this stuff to be DRY
/// TODO: We should T4 this stuff to be DRY
/// </summary>
internal static class Tuple8
{
@ -79,6 +79,9 @@ namespace SixLabors.ImageSharp.Common.Tuples
return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]";
}
/// <summary>
/// Sets the values of this tuple by casting all elements of the given <see cref="OfUInt32"/> tuple to <see cref="byte"/>.
/// </summary>
public void LoadFrom(ref OfUInt32 i)
{
this.V0 = (byte)i.V0;

8
src/ImageSharp/Common/Tuples/Vector4Pair.cs

@ -39,10 +39,11 @@ namespace SixLabors.ImageSharp.Common.Tuples
}
/// <summary>
/// Color-conversion specific downscale method.
/// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4!
/// TODO: Move it somewhere else.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void RoundAndDownscaleBasic()
internal void RoundAndDownscalePreAvx2()
{
ref Vector<float> a = ref Unsafe.As<Vector4, Vector<float>>(ref this.A);
a = a.FastRound();
@ -56,7 +57,8 @@ namespace SixLabors.ImageSharp.Common.Tuples
}
/// <summary>
/// AVX2-only color-conversion specific downscale method.
/// AVX2-only Downscale method, specific to Jpeg color conversion.
/// TODO: Move it somewhere else.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void RoundAndDownscaleAvx2()

89
src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs

@ -96,51 +96,56 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// <summary>
/// Level shift by +128, clip to [0, 255]
/// </summary>
/// <param name="d">The destination block</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void NormalizeColorsInto(ref Block8x8F d)
internal void NormalizeColorsInplace()
{
d.V0L = Vector4.Clamp(V0L + COff4, CMin4, CMax4);
d.V0R = Vector4.Clamp(V0R + COff4, CMin4, CMax4);
d.V1L = Vector4.Clamp(V1L + COff4, CMin4, CMax4);
d.V1R = Vector4.Clamp(V1R + COff4, CMin4, CMax4);
d.V2L = Vector4.Clamp(V2L + COff4, CMin4, CMax4);
d.V2R = Vector4.Clamp(V2R + COff4, CMin4, CMax4);
d.V3L = Vector4.Clamp(V3L + COff4, CMin4, CMax4);
d.V3R = Vector4.Clamp(V3R + COff4, CMin4, CMax4);
d.V4L = Vector4.Clamp(V4L + COff4, CMin4, CMax4);
d.V4R = Vector4.Clamp(V4R + COff4, CMin4, CMax4);
d.V5L = Vector4.Clamp(V5L + COff4, CMin4, CMax4);
d.V5R = Vector4.Clamp(V5R + COff4, CMin4, CMax4);
d.V6L = Vector4.Clamp(V6L + COff4, CMin4, CMax4);
d.V6R = Vector4.Clamp(V6R + COff4, CMin4, CMax4);
d.V7L = Vector4.Clamp(V7L + COff4, CMin4, CMax4);
d.V7R = Vector4.Clamp(V7R + COff4, CMin4, CMax4);
this.V0L = Vector4.Clamp(this.V0L + COff4, CMin4, CMax4);
this.V0R = Vector4.Clamp(this.V0R + COff4, CMin4, CMax4);
this.V1L = Vector4.Clamp(this.V1L + COff4, CMin4, CMax4);
this.V1R = Vector4.Clamp(this.V1R + COff4, CMin4, CMax4);
this.V2L = Vector4.Clamp(this.V2L + COff4, CMin4, CMax4);
this.V2R = Vector4.Clamp(this.V2R + COff4, CMin4, CMax4);
this.V3L = Vector4.Clamp(this.V3L + COff4, CMin4, CMax4);
this.V3R = Vector4.Clamp(this.V3R + COff4, CMin4, CMax4);
this.V4L = Vector4.Clamp(this.V4L + COff4, CMin4, CMax4);
this.V4R = Vector4.Clamp(this.V4R + COff4, CMin4, CMax4);
this.V5L = Vector4.Clamp(this.V5L + COff4, CMin4, CMax4);
this.V5R = Vector4.Clamp(this.V5R + COff4, CMin4, CMax4);
this.V6L = Vector4.Clamp(this.V6L + COff4, CMin4, CMax4);
this.V6R = Vector4.Clamp(this.V6R + COff4, CMin4, CMax4);
this.V7L = Vector4.Clamp(this.V7L + COff4, CMin4, CMax4);
this.V7R = Vector4.Clamp(this.V7R + COff4, CMin4, CMax4);
}
/// <summary>
/// Level shift by +128, clip to [0, 255]
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void NormalizeColorsInplace()
public void NormalizeColorsAndRoundInplaceAvx2()
{
this.V0L = Vector4.Clamp(V0L + COff4, CMin4, CMax4);
this.V0R = Vector4.Clamp(V0R + COff4, CMin4, CMax4);
this.V1L = Vector4.Clamp(V1L + COff4, CMin4, CMax4);
this.V1R = Vector4.Clamp(V1R + COff4, CMin4, CMax4);
this.V2L = Vector4.Clamp(V2L + COff4, CMin4, CMax4);
this.V2R = Vector4.Clamp(V2R + COff4, CMin4, CMax4);
this.V3L = Vector4.Clamp(V3L + COff4, CMin4, CMax4);
this.V3R = Vector4.Clamp(V3R + COff4, CMin4, CMax4);
this.V4L = Vector4.Clamp(V4L + COff4, CMin4, CMax4);
this.V4R = Vector4.Clamp(V4R + COff4, CMin4, CMax4);
this.V5L = Vector4.Clamp(V5L + COff4, CMin4, CMax4);
this.V5R = Vector4.Clamp(V5R + COff4, CMin4, CMax4);
this.V6L = Vector4.Clamp(V6L + COff4, CMin4, CMax4);
this.V6R = Vector4.Clamp(V6R + COff4, CMin4, CMax4);
this.V7L = Vector4.Clamp(V7L + COff4, CMin4, CMax4);
this.V7R = Vector4.Clamp(V7R + COff4, CMin4, CMax4);
}
}
Vector<float> off = new Vector<float>(128f);
Vector<float> max = new Vector<float>(255F);
ref Vector<float> row0 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V0L);
row0 = NormalizeAndRound(row0, off, max);
ref Vector<float> row1 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V1L);
row1 = NormalizeAndRound(row1, off, max);
ref Vector<float> row2 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V2L);
row2 = NormalizeAndRound(row2, off, max);
ref Vector<float> row3 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V3L);
row3 = NormalizeAndRound(row3, off, max);
ref Vector<float> row4 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V4L);
row4 = NormalizeAndRound(row4, off, max);
ref Vector<float> row5 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V5L);
row5 = NormalizeAndRound(row5, off, max);
ref Vector<float> row6 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V6L);
row6 = NormalizeAndRound(row6, off, max);
ref Vector<float> row7 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V7L);
row7 = NormalizeAndRound(row7, off, max);
}
}
}

23
src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt

@ -61,9 +61,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// <summary>
/// Level shift by +128, clip to [0, 255]
/// </summary>
/// <param name="d">The destination block</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void TransformByteConvetibleColorValuesInto(ref Block8x8F d)
internal void NormalizeColorsInplace()
{
<#
@ -74,11 +73,29 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
for (int j = 0; j < 2; j++)
{
char side = j == 0 ? 'L' : 'R';
Write($"d.V{i}{side} = Vector4.Clamp(V{i}{side} + COff4, CMin4, CMax4);\r\n");
Write($"this.V{i}{side} = Vector4.Clamp(this.V{i}{side} + COff4, CMin4, CMax4);\r\n");
}
}
PopIndent();
#>
}
public void NormalizeColorsAndRoundInplaceAvx2()
{
Vector<float> off = new Vector<float>(128f);
Vector<float> max = new Vector<float>(255F);
<#
for (int i = 0; i < 8; i++)
{
#>
ref Vector<float> row<#=i#> = ref Unsafe.As<Vector4, Vector<float>>(ref this.V<#=i#>L);
row<#=i#> = NormalizeAndRound(row<#=i#>, off, max);
<#
}
#>
}
}
}

91
src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs

@ -315,28 +315,31 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// <summary>
/// Multiply all elements of the block.
/// </summary>
/// <param name="scaleVec">Vector to multiply by</param>
/// <param name="value">The value to multiply by</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyInplace(float scaleVec)
{
this.V0L *= scaleVec;
this.V0R *= scaleVec;
this.V1L *= scaleVec;
this.V1R *= scaleVec;
this.V2L *= scaleVec;
this.V2R *= scaleVec;
this.V3L *= scaleVec;
this.V3R *= scaleVec;
this.V4L *= scaleVec;
this.V4R *= scaleVec;
this.V5L *= scaleVec;
this.V5R *= scaleVec;
this.V6L *= scaleVec;
this.V6R *= scaleVec;
this.V7L *= scaleVec;
this.V7R *= scaleVec;
public void MultiplyInplace(float value)
{
this.V0L *= value;
this.V0R *= value;
this.V1L *= value;
this.V1R *= value;
this.V2L *= value;
this.V2R *= value;
this.V3L *= value;
this.V3R *= value;
this.V4L *= value;
this.V4R *= value;
this.V5L *= value;
this.V5R *= value;
this.V6L *= value;
this.V6R *= value;
this.V7L *= value;
this.V7R *= value;
}
/// <summary>
/// Multiply all elements of the block by the corresponding elements of 'other'
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyInplace(ref Block8x8F other)
{
@ -405,33 +408,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
}
}
/// <summary>
/// Level shift by +128, clip to [0, 255], and write to buffer.
/// </summary>
/// <param name="destinationBuffer">Color buffer</param>
/// <param name="stride">Stride offset</param>
/// <param name="tempBlockPtr">Temp Block pointer</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void CopyColorsTo(Span<byte> destinationBuffer, int stride, Block8x8F* tempBlockPtr)
{
this.NormalizeColorsInto(ref *tempBlockPtr);
ref byte d = ref destinationBuffer.DangerousGetPinnableReference();
float* src = (float*)tempBlockPtr;
for (int i = 0; i < 8; i++)
{
ref byte dRow = ref Unsafe.Add(ref d, i * stride);
Unsafe.Add(ref dRow, 0) = (byte)src[0];
Unsafe.Add(ref dRow, 1) = (byte)src[1];
Unsafe.Add(ref dRow, 2) = (byte)src[2];
Unsafe.Add(ref dRow, 3) = (byte)src[3];
Unsafe.Add(ref dRow, 4) = (byte)src[4];
Unsafe.Add(ref dRow, 5) = (byte)src[5];
Unsafe.Add(ref dRow, 6) = (byte)src[6];
Unsafe.Add(ref dRow, 7) = (byte)src[7];
src += 8;
}
}
/// <summary>
/// Unzig the elements of block into dest, while dividing them by elements of qt and "pre-rounding" the values.
/// To finish the rounding it's enough to (int)-cast these values.
@ -529,29 +505,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
return result;
}
public void NormalizeColorsAndRoundInplaceAvx2()
{
Vector<float> off = new Vector<float>(128f);
Vector<float> max = new Vector<float>(255F);
ref Vector<float> row0 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V0L);
row0 = NormalizeAndRound(row0, off, max);
ref Vector<float> row1 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V1L);
row1 = NormalizeAndRound(row1, off, max);
ref Vector<float> row2 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V2L);
row2 = NormalizeAndRound(row2, off, max);
ref Vector<float> row3 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V3L);
row3 = NormalizeAndRound(row3, off, max);
ref Vector<float> row4 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V4L);
row4 = NormalizeAndRound(row4, off, max);
ref Vector<float> row5 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V5L);
row5 = NormalizeAndRound(row5, off, max);
ref Vector<float> row6 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V6L);
row6 = NormalizeAndRound(row6, off, max);
ref Vector<float> row7 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V7L);
row7 = NormalizeAndRound(row7, off, max);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> NormalizeAndRound(Vector<float> row, Vector<float> off, Vector<float> max)
{

22
src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs

@ -33,18 +33,32 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
/// </summary>
public Block8x8F DequantiazationTable;
/// <summary>
/// Defines the horizontal and vertical scale we need to apply to the 8x8 sized block.
/// </summary>
private Size subSamplingDivisors;
/// <summary>
/// Initialize the <see cref="JpegBlockPostProcessor"/> instance on the stack.
/// Initializes a new instance of the <see cref="JpegBlockPostProcessor"/> struct.
/// </summary>
public static void Init(JpegBlockPostProcessor* postProcessor, IRawJpegData decoder, IJpegComponent component)
public JpegBlockPostProcessor(IRawJpegData decoder, IJpegComponent component)
{
int qtIndex = component.QuantizationTableIndex;
postProcessor->DequantiazationTable = ZigZag.CreateDequantizationTable(ref decoder.QuantizationTables[qtIndex]);
postProcessor->subSamplingDivisors = component.SubSamplingDivisors;
this.DequantiazationTable = ZigZag.CreateDequantizationTable(ref decoder.QuantizationTables[qtIndex]);
this.subSamplingDivisors = component.SubSamplingDivisors;
this.SourceBlock = default(Block8x8F);
this.WorkspaceBlock1 = default(Block8x8F);
this.WorkspaceBlock2 = default(Block8x8F);
}
/// <summary>
/// Processes 'sourceBlock' producing Jpeg color channel values from spectral values:
/// - Dequantize
/// - Applying IDCT
/// - Level shift by +128, clip to [0, 255]
/// - Copy the resultin color values into 'destArea' scaling up the block by amount defined in <see cref="subSamplingDivisors"/>
/// </summary>
public void ProcessBlockColorsInto(
ref Block8x8 sourceBlock,
BufferArea<float> destArea)

5
src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs

@ -66,10 +66,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
/// <summary>
/// Invoke <see cref="JpegBlockPostProcessor"/> for <see cref="BlockRowsPerStep"/> block rows, copy the result into <see cref="ColorBuffer"/>.
/// </summary>
public unsafe void CopyBlocksToColorBuffer()
public void CopyBlocksToColorBuffer()
{
var blockPp = default(JpegBlockPostProcessor);
JpegBlockPostProcessor.Init(&blockPp, this.ImagePostProcessor.RawJpeg, this.Component);
var blockPp = new JpegBlockPostProcessor(this.ImagePostProcessor.RawJpeg, this.Component);
for (int y = 0; y < this.BlockRowsPerStep; y++)
{

47
tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs

@ -222,33 +222,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms");
}
[Fact]
public unsafe void CopyColorsTo()
{
float[] data = Create8x8FloatData();
var block = new Block8x8F();
block.LoadFrom(data);
block.MultiplyInplace(5);
int stride = 256;
int height = 42;
int offset = height * 10 + 20;
byte[] colorsExpected = new byte[stride * height];
byte[] colorsActual = new byte[stride * height];
var temp = new Block8x8F();
ReferenceImplementations.CopyColorsTo(ref block, new Span<byte>(colorsExpected, offset), stride);
block.CopyColorsTo(new Span<byte>(colorsActual, offset), stride, &temp);
// Output.WriteLine("******* EXPECTED: *********");
// PrintLinearData(colorsExpected);
// Output.WriteLine("******** ACTUAL: **********");
Assert.Equal(colorsExpected, colorsActual);
}
private static float[] Create8x8ColorCropTestData()
{
float[] result = new float[64];
@ -263,30 +236,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
return result;
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void NormalizeColors(bool inplace)
[Fact]
public void NormalizeColors()
{
var block = default(Block8x8F);
float[] input = Create8x8ColorCropTestData();
block.LoadFrom(input);
this.Output.WriteLine("Input:");
this.PrintLinearData(input);
var dest = default(Block8x8F);
if (inplace)
{
dest = block;
dest.NormalizeColorsInplace();
}
else
{
block.NormalizeColorsInto(ref dest);
}
Block8x8F dest = block;
dest.NormalizeColorsInplace();
float[] array = new float[64];
dest.CopyTo(array);
this.Output.WriteLine("Result:");

Loading…
Cancel
Save