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> /// <summary>
/// Contains value type tuples of 8 elements. /// 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> /// </summary>
internal static class Tuple8 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}]"; 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) public void LoadFrom(ref OfUInt32 i)
{ {
this.V0 = (byte)i.V0; this.V0 = (byte)i.V0;

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

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

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

@ -96,51 +96,56 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// <summary> /// <summary>
/// Level shift by +128, clip to [0, 255] /// Level shift by +128, clip to [0, 255]
/// </summary> /// </summary>
/// <param name="d">The destination block</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void NormalizeColorsInto(ref Block8x8F d) internal void NormalizeColorsInplace()
{ {
d.V0L = Vector4.Clamp(V0L + COff4, CMin4, CMax4); this.V0L = Vector4.Clamp(this.V0L + COff4, CMin4, CMax4);
d.V0R = Vector4.Clamp(V0R + COff4, CMin4, CMax4); this.V0R = Vector4.Clamp(this.V0R + COff4, CMin4, CMax4);
d.V1L = Vector4.Clamp(V1L + COff4, CMin4, CMax4); this.V1L = Vector4.Clamp(this.V1L + COff4, CMin4, CMax4);
d.V1R = Vector4.Clamp(V1R + COff4, CMin4, CMax4); this.V1R = Vector4.Clamp(this.V1R + COff4, CMin4, CMax4);
d.V2L = Vector4.Clamp(V2L + COff4, CMin4, CMax4); this.V2L = Vector4.Clamp(this.V2L + COff4, CMin4, CMax4);
d.V2R = Vector4.Clamp(V2R + COff4, CMin4, CMax4); this.V2R = Vector4.Clamp(this.V2R + COff4, CMin4, CMax4);
d.V3L = Vector4.Clamp(V3L + COff4, CMin4, CMax4); this.V3L = Vector4.Clamp(this.V3L + COff4, CMin4, CMax4);
d.V3R = Vector4.Clamp(V3R + COff4, CMin4, CMax4); this.V3R = Vector4.Clamp(this.V3R + COff4, CMin4, CMax4);
d.V4L = Vector4.Clamp(V4L + COff4, CMin4, CMax4); this.V4L = Vector4.Clamp(this.V4L + COff4, CMin4, CMax4);
d.V4R = Vector4.Clamp(V4R + COff4, CMin4, CMax4); this.V4R = Vector4.Clamp(this.V4R + COff4, CMin4, CMax4);
d.V5L = Vector4.Clamp(V5L + COff4, CMin4, CMax4); this.V5L = Vector4.Clamp(this.V5L + COff4, CMin4, CMax4);
d.V5R = Vector4.Clamp(V5R + COff4, CMin4, CMax4); this.V5R = Vector4.Clamp(this.V5R + COff4, CMin4, CMax4);
d.V6L = Vector4.Clamp(V6L + COff4, CMin4, CMax4); this.V6L = Vector4.Clamp(this.V6L + COff4, CMin4, CMax4);
d.V6R = Vector4.Clamp(V6R + COff4, CMin4, CMax4); this.V6R = Vector4.Clamp(this.V6R + COff4, CMin4, CMax4);
d.V7L = Vector4.Clamp(V7L + COff4, CMin4, CMax4); this.V7L = Vector4.Clamp(this.V7L + COff4, CMin4, CMax4);
d.V7R = Vector4.Clamp(V7R + COff4, CMin4, CMax4); this.V7R = Vector4.Clamp(this.V7R + COff4, CMin4, CMax4);
} }
public void NormalizeColorsAndRoundInplaceAvx2()
/// <summary>
/// Level shift by +128, clip to [0, 255]
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void NormalizeColorsInplace()
{ {
this.V0L = Vector4.Clamp(V0L + COff4, CMin4, CMax4); Vector<float> off = new Vector<float>(128f);
this.V0R = Vector4.Clamp(V0R + COff4, CMin4, CMax4); Vector<float> max = new Vector<float>(255F);
this.V1L = Vector4.Clamp(V1L + COff4, CMin4, CMax4);
this.V1R = Vector4.Clamp(V1R + COff4, CMin4, CMax4);
this.V2L = Vector4.Clamp(V2L + COff4, CMin4, CMax4); ref Vector<float> row0 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V0L);
this.V2R = Vector4.Clamp(V2R + COff4, CMin4, CMax4); row0 = NormalizeAndRound(row0, off, max);
this.V3L = Vector4.Clamp(V3L + COff4, CMin4, CMax4);
this.V3R = Vector4.Clamp(V3R + COff4, CMin4, CMax4); ref Vector<float> row1 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V1L);
this.V4L = Vector4.Clamp(V4L + COff4, CMin4, CMax4); row1 = NormalizeAndRound(row1, off, max);
this.V4R = Vector4.Clamp(V4R + COff4, CMin4, CMax4);
this.V5L = Vector4.Clamp(V5L + COff4, CMin4, CMax4); ref Vector<float> row2 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V2L);
this.V5R = Vector4.Clamp(V5R + COff4, CMin4, CMax4); row2 = NormalizeAndRound(row2, off, max);
this.V6L = Vector4.Clamp(V6L + COff4, CMin4, CMax4);
this.V6R = Vector4.Clamp(V6R + COff4, CMin4, CMax4); ref Vector<float> row3 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V3L);
this.V7L = Vector4.Clamp(V7L + COff4, CMin4, CMax4); row3 = NormalizeAndRound(row3, off, max);
this.V7R = Vector4.Clamp(V7R + COff4, CMin4, CMax4);
} 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> /// <summary>
/// Level shift by +128, clip to [0, 255] /// Level shift by +128, clip to [0, 255]
/// </summary> /// </summary>
/// <param name="d">The destination block</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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++) for (int j = 0; j < 2; j++)
{ {
char side = j == 0 ? 'L' : 'R'; 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(); 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> /// <summary>
/// Multiply all elements of the block. /// Multiply all elements of the block.
/// </summary> /// </summary>
/// <param name="scaleVec">Vector to multiply by</param> /// <param name="value">The value to multiply by</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyInplace(float scaleVec) public void MultiplyInplace(float value)
{ {
this.V0L *= scaleVec; this.V0L *= value;
this.V0R *= scaleVec; this.V0R *= value;
this.V1L *= scaleVec; this.V1L *= value;
this.V1R *= scaleVec; this.V1R *= value;
this.V2L *= scaleVec; this.V2L *= value;
this.V2R *= scaleVec; this.V2R *= value;
this.V3L *= scaleVec; this.V3L *= value;
this.V3R *= scaleVec; this.V3R *= value;
this.V4L *= scaleVec; this.V4L *= value;
this.V4R *= scaleVec; this.V4R *= value;
this.V5L *= scaleVec; this.V5L *= value;
this.V5R *= scaleVec; this.V5R *= value;
this.V6L *= scaleVec; this.V6L *= value;
this.V6R *= scaleVec; this.V6R *= value;
this.V7L *= scaleVec; this.V7L *= value;
this.V7R *= scaleVec; this.V7R *= value;
} }
/// <summary>
/// Multiply all elements of the block by the corresponding elements of 'other'
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyInplace(ref Block8x8F other) 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> /// <summary>
/// Unzig the elements of block into dest, while dividing them by elements of qt and "pre-rounding" the values. /// 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. /// To finish the rounding it's enough to (int)-cast these values.
@ -529,29 +505,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
return result; 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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> NormalizeAndRound(Vector<float> row, Vector<float> off, Vector<float> max) 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> /// </summary>
public Block8x8F DequantiazationTable; public Block8x8F DequantiazationTable;
/// <summary>
/// Defines the horizontal and vertical scale we need to apply to the 8x8 sized block.
/// </summary>
private Size subSamplingDivisors; private Size subSamplingDivisors;
/// <summary> /// <summary>
/// Initialize the <see cref="JpegBlockPostProcessor"/> instance on the stack. /// Initializes a new instance of the <see cref="JpegBlockPostProcessor"/> struct.
/// </summary> /// </summary>
public static void Init(JpegBlockPostProcessor* postProcessor, IRawJpegData decoder, IJpegComponent component) public JpegBlockPostProcessor(IRawJpegData decoder, IJpegComponent component)
{ {
int qtIndex = component.QuantizationTableIndex; int qtIndex = component.QuantizationTableIndex;
postProcessor->DequantiazationTable = ZigZag.CreateDequantizationTable(ref decoder.QuantizationTables[qtIndex]); this.DequantiazationTable = ZigZag.CreateDequantizationTable(ref decoder.QuantizationTables[qtIndex]);
postProcessor->subSamplingDivisors = component.SubSamplingDivisors; 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( public void ProcessBlockColorsInto(
ref Block8x8 sourceBlock, ref Block8x8 sourceBlock,
BufferArea<float> destArea) BufferArea<float> destArea)

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

@ -66,10 +66,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
/// <summary> /// <summary>
/// Invoke <see cref="JpegBlockPostProcessor"/> for <see cref="BlockRowsPerStep"/> block rows, copy the result into <see cref="ColorBuffer"/>. /// Invoke <see cref="JpegBlockPostProcessor"/> for <see cref="BlockRowsPerStep"/> block rows, copy the result into <see cref="ColorBuffer"/>.
/// </summary> /// </summary>
public unsafe void CopyBlocksToColorBuffer() public void CopyBlocksToColorBuffer()
{ {
var blockPp = default(JpegBlockPostProcessor); var blockPp = new JpegBlockPostProcessor(this.ImagePostProcessor.RawJpeg, this.Component);
JpegBlockPostProcessor.Init(&blockPp, this.ImagePostProcessor.RawJpeg, this.Component);
for (int y = 0; y < this.BlockRowsPerStep; y++) 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"); 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() private static float[] Create8x8ColorCropTestData()
{ {
float[] result = new float[64]; float[] result = new float[64];
@ -263,30 +236,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
return result; return result;
} }
[Theory] [Fact]
[InlineData(false)] public void NormalizeColors()
[InlineData(true)]
public void NormalizeColors(bool inplace)
{ {
var block = default(Block8x8F); var block = default(Block8x8F);
float[] input = Create8x8ColorCropTestData(); float[] input = Create8x8ColorCropTestData();
block.LoadFrom(input); block.LoadFrom(input);
this.Output.WriteLine("Input:"); this.Output.WriteLine("Input:");
this.PrintLinearData(input); this.PrintLinearData(input);
var dest = default(Block8x8F);
if (inplace) Block8x8F dest = block;
{ dest.NormalizeColorsInplace();
dest = block;
dest.NormalizeColorsInplace();
}
else
{
block.NormalizeColorsInto(ref dest);
}
float[] array = new float[64]; float[] array = new float[64];
dest.CopyTo(array); dest.CopyTo(array);
this.Output.WriteLine("Result:"); this.Output.WriteLine("Result:");

Loading…
Cancel
Save