From 347dd15ea261d640e2834f9b8e31aa92dd4d18e5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 17 Sep 2017 16:26:18 +0200 Subject: [PATCH] cleanup and docs --- src/ImageSharp/Common/Tuples/Tuple8.cs | 5 +- src/ImageSharp/Common/Tuples/Vector4Pair.cs | 8 +- .../Jpeg/Common/Block8x8F.Generated.cs | 89 +++++++++--------- .../Jpeg/Common/Block8x8F.Generated.tt | 23 ++++- .../Formats/Jpeg/Common/Block8x8F.cs | 91 +++++-------------- .../Common/Decoder/JpegBlockPostProcessor.cs | 22 ++++- .../Decoder/JpegComponentPostProcessor.cs | 5 +- .../Formats/Jpg/Block8x8FTests.cs | 47 +--------- 8 files changed, 122 insertions(+), 168 deletions(-) diff --git a/src/ImageSharp/Common/Tuples/Tuple8.cs b/src/ImageSharp/Common/Tuples/Tuple8.cs index 590a3f5c9..3335e6e37 100644 --- a/src/ImageSharp/Common/Tuples/Tuple8.cs +++ b/src/ImageSharp/Common/Tuples/Tuple8.cs @@ -4,7 +4,7 @@ namespace SixLabors.ImageSharp.Common.Tuples { /// /// Contains value type tuples of 8 elements. - /// TODO: Should T4 this stuff to be DRY + /// TODO: We should T4 this stuff to be DRY /// 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}]"; } + /// + /// Sets the values of this tuple by casting all elements of the given tuple to . + /// public void LoadFrom(ref OfUInt32 i) { this.V0 = (byte)i.V0; diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index 1be936b30..4f43c9811 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -39,10 +39,11 @@ namespace SixLabors.ImageSharp.Common.Tuples } /// - /// Color-conversion specific downscale method. + /// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4! + /// TODO: Move it somewhere else. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void RoundAndDownscaleBasic() + internal void RoundAndDownscalePreAvx2() { ref Vector a = ref Unsafe.As>(ref this.A); a = a.FastRound(); @@ -56,7 +57,8 @@ namespace SixLabors.ImageSharp.Common.Tuples } /// - /// AVX2-only color-conversion specific downscale method. + /// AVX2-only Downscale method, specific to Jpeg color conversion. + /// TODO: Move it somewhere else. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void RoundAndDownscaleAvx2() diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs index 4c1b4f4d1..e8614205c 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs @@ -96,51 +96,56 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common /// /// Level shift by +128, clip to [0, 255] /// - /// The destination block [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); } - - /// - /// Level shift by +128, clip to [0, 255] - /// - [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 off = new Vector(128f); + Vector max = new Vector(255F); + + + ref Vector row0 = ref Unsafe.As>(ref this.V0L); + row0 = NormalizeAndRound(row0, off, max); + + ref Vector row1 = ref Unsafe.As>(ref this.V1L); + row1 = NormalizeAndRound(row1, off, max); + + ref Vector row2 = ref Unsafe.As>(ref this.V2L); + row2 = NormalizeAndRound(row2, off, max); + + ref Vector row3 = ref Unsafe.As>(ref this.V3L); + row3 = NormalizeAndRound(row3, off, max); + + ref Vector row4 = ref Unsafe.As>(ref this.V4L); + row4 = NormalizeAndRound(row4, off, max); + + ref Vector row5 = ref Unsafe.As>(ref this.V5L); + row5 = NormalizeAndRound(row5, off, max); + + ref Vector row6 = ref Unsafe.As>(ref this.V6L); + row6 = NormalizeAndRound(row6, off, max); + + ref Vector row7 = ref Unsafe.As>(ref this.V7L); + row7 = NormalizeAndRound(row7, off, max); + } + } } diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt index bef3e4914..9ab3ee12c 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt @@ -61,9 +61,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common /// /// Level shift by +128, clip to [0, 255] /// - /// The destination block [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 off = new Vector(128f); + Vector max = new Vector(255F); + + <# + + for (int i = 0; i < 8; i++) + { + #> + + ref Vector row<#=i#> = ref Unsafe.As>(ref this.V<#=i#>L); + row<#=i#> = NormalizeAndRound(row<#=i#>, off, max); + <# + } + #> + } } } diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs index 6ba69bec4..ff9db6ab9 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs @@ -315,28 +315,31 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common /// /// Multiply all elements of the block. /// - /// Vector to multiply by + /// The value to multiply by [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; } + /// + /// Multiply all elements of the block by the corresponding elements of 'other' + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MultiplyInplace(ref Block8x8F other) { @@ -405,33 +408,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common } } - /// - /// Level shift by +128, clip to [0, 255], and write to buffer. - /// - /// Color buffer - /// Stride offset - /// Temp Block pointer - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe void CopyColorsTo(Span 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; - } - } - /// /// 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 off = new Vector(128f); - Vector max = new Vector(255F); - - ref Vector row0 = ref Unsafe.As>(ref this.V0L); - row0 = NormalizeAndRound(row0, off, max); - ref Vector row1 = ref Unsafe.As>(ref this.V1L); - row1 = NormalizeAndRound(row1, off, max); - ref Vector row2 = ref Unsafe.As>(ref this.V2L); - row2 = NormalizeAndRound(row2, off, max); - ref Vector row3 = ref Unsafe.As>(ref this.V3L); - row3 = NormalizeAndRound(row3, off, max); - ref Vector row4 = ref Unsafe.As>(ref this.V4L); - row4 = NormalizeAndRound(row4, off, max); - ref Vector row5 = ref Unsafe.As>(ref this.V5L); - row5 = NormalizeAndRound(row5, off, max); - ref Vector row6 = ref Unsafe.As>(ref this.V6L); - row6 = NormalizeAndRound(row6, off, max); - ref Vector row7 = ref Unsafe.As>(ref this.V7L); - row7 = NormalizeAndRound(row7, off, max); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector NormalizeAndRound(Vector row, Vector off, Vector max) { diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs index 0459a5df0..d0f2b8817 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs @@ -33,18 +33,32 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder /// public Block8x8F DequantiazationTable; + /// + /// Defines the horizontal and vertical scale we need to apply to the 8x8 sized block. + /// private Size subSamplingDivisors; /// - /// Initialize the instance on the stack. + /// Initializes a new instance of the struct. /// - 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); } + /// + /// 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 + /// public void ProcessBlockColorsInto( ref Block8x8 sourceBlock, BufferArea destArea) diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs index 53aafed01..87c1431e0 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs @@ -66,10 +66,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder /// /// Invoke for block rows, copy the result into . /// - 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++) { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs index 1398b2f89..8d1e585db 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs +++ b/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(colorsExpected, offset), stride); - - block.CopyColorsTo(new Span(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:");