mirror of https://github.com/SixLabors/ImageSharp
Browse Source
# Conflicts: # src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs # src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs # src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs # tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs # tests/ImageSharp.Tests/Formats/Tiff/Compression/PackBitsTiffCompressionTests.cs # tests/ImageSharp.Tests/Image/ImageFrameTests.cs # tests/ImageSharp.Tests/Image/ImageTests.cs # tests/ImageSharp.Tests/Memory/Allocators/ArrayPoolMemoryAllocatorTests.cs # tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs # tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs # tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.csaf/UniformUnmanagedMemoryPoolMemoryAllocator-02-MemoryGuards
599 changed files with 7026 additions and 3748 deletions
@ -1 +1 @@ |
|||
Subproject commit 9b94ebc4be9b7a8d7620c257e6ee485455973332 |
|||
Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3 |
|||
@ -0,0 +1,149 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
#if SUPPORTS_RUNTIME_INTRINSICS
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using System.Runtime.Intrinsics; |
|||
using System.Runtime.Intrinsics.X86; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components |
|||
{ |
|||
internal partial struct Block8x8F |
|||
{ |
|||
/// <summary>
|
|||
/// A number of rows of 8 scalar coefficients each in <see cref="Block8x8F"/>
|
|||
/// </summary>
|
|||
public const int RowCount = 8; |
|||
|
|||
[FieldOffset(0)] |
|||
public Vector256<float> V0; |
|||
[FieldOffset(32)] |
|||
public Vector256<float> V1; |
|||
[FieldOffset(64)] |
|||
public Vector256<float> V2; |
|||
[FieldOffset(96)] |
|||
public Vector256<float> V3; |
|||
[FieldOffset(128)] |
|||
public Vector256<float> V4; |
|||
[FieldOffset(160)] |
|||
public Vector256<float> V5; |
|||
[FieldOffset(192)] |
|||
public Vector256<float> V6; |
|||
[FieldOffset(224)] |
|||
public Vector256<float> V7; |
|||
|
|||
private static readonly Vector256<int> MultiplyIntoInt16ShuffleMask = Vector256.Create(0, 1, 4, 5, 2, 3, 6, 7); |
|||
|
|||
private static unsafe void MultiplyIntoInt16_Avx2(ref Block8x8F a, ref Block8x8F b, ref Block8x8 dest) |
|||
{ |
|||
DebugGuard.IsTrue(Avx2.IsSupported, "Avx2 support is required to run this operation!"); |
|||
|
|||
ref Vector256<float> aBase = ref a.V0; |
|||
ref Vector256<float> bBase = ref b.V0; |
|||
|
|||
ref Vector256<short> destRef = ref dest.V01; |
|||
|
|||
for (nint i = 0; i < 8; i += 2) |
|||
{ |
|||
Vector256<int> row0 = Avx.ConvertToVector256Int32(Avx.Multiply(Unsafe.Add(ref aBase, i + 0), Unsafe.Add(ref bBase, i + 0))); |
|||
Vector256<int> row1 = Avx.ConvertToVector256Int32(Avx.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1))); |
|||
|
|||
Vector256<short> row = Avx2.PackSignedSaturate(row0, row1); |
|||
row = Avx2.PermuteVar8x32(row.AsInt32(), MultiplyIntoInt16ShuffleMask).AsInt16(); |
|||
|
|||
Unsafe.Add(ref destRef, (IntPtr)((uint)i / 2)) = row; |
|||
} |
|||
} |
|||
|
|||
private static void MultiplyIntoInt16_Sse2(ref Block8x8F a, ref Block8x8F b, ref Block8x8 dest) |
|||
{ |
|||
DebugGuard.IsTrue(Sse2.IsSupported, "Sse2 support is required to run this operation!"); |
|||
|
|||
ref Vector128<float> aBase = ref Unsafe.As<Block8x8F, Vector128<float>>(ref a); |
|||
ref Vector128<float> bBase = ref Unsafe.As<Block8x8F, Vector128<float>>(ref b); |
|||
|
|||
ref Vector128<short> destBase = ref Unsafe.As<Block8x8, Vector128<short>>(ref dest); |
|||
|
|||
for (int i = 0; i < 16; i += 2) |
|||
{ |
|||
Vector128<int> left = Sse2.ConvertToVector128Int32(Sse.Multiply(Unsafe.Add(ref aBase, i + 0), Unsafe.Add(ref bBase, i + 0))); |
|||
Vector128<int> right = Sse2.ConvertToVector128Int32(Sse.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1))); |
|||
|
|||
Vector128<short> row = Sse2.PackSignedSaturate(left, right); |
|||
Unsafe.Add(ref destBase, (IntPtr)((uint)i / 2)) = row; |
|||
} |
|||
} |
|||
|
|||
private void TransposeInplace_Avx() |
|||
{ |
|||
// https://stackoverflow.com/questions/25622745/transpose-an-8x8-float-using-avx-avx2/25627536#25627536
|
|||
Vector256<float> r0 = Avx.InsertVector128( |
|||
this.V0, |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V4L), |
|||
1); |
|||
|
|||
Vector256<float> r1 = Avx.InsertVector128( |
|||
this.V1, |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V5L), |
|||
1); |
|||
|
|||
Vector256<float> r2 = Avx.InsertVector128( |
|||
this.V2, |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V6L), |
|||
1); |
|||
|
|||
Vector256<float> r3 = Avx.InsertVector128( |
|||
this.V3, |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V7L), |
|||
1); |
|||
|
|||
Vector256<float> r4 = Avx.InsertVector128( |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V0R).ToVector256(), |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V4R), |
|||
1); |
|||
|
|||
Vector256<float> r5 = Avx.InsertVector128( |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V1R).ToVector256(), |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V5R), |
|||
1); |
|||
|
|||
Vector256<float> r6 = Avx.InsertVector128( |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V2R).ToVector256(), |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V6R), |
|||
1); |
|||
|
|||
Vector256<float> r7 = Avx.InsertVector128( |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V3R).ToVector256(), |
|||
Unsafe.As<Vector4, Vector128<float>>(ref this.V7R), |
|||
1); |
|||
|
|||
Vector256<float> t0 = Avx.UnpackLow(r0, r1); |
|||
Vector256<float> t2 = Avx.UnpackLow(r2, r3); |
|||
Vector256<float> v = Avx.Shuffle(t0, t2, 0x4E); |
|||
this.V0 = Avx.Blend(t0, v, 0xCC); |
|||
this.V1 = Avx.Blend(t2, v, 0x33); |
|||
|
|||
Vector256<float> t4 = Avx.UnpackLow(r4, r5); |
|||
Vector256<float> t6 = Avx.UnpackLow(r6, r7); |
|||
v = Avx.Shuffle(t4, t6, 0x4E); |
|||
this.V4 = Avx.Blend(t4, v, 0xCC); |
|||
this.V5 = Avx.Blend(t6, v, 0x33); |
|||
|
|||
Vector256<float> t1 = Avx.UnpackHigh(r0, r1); |
|||
Vector256<float> t3 = Avx.UnpackHigh(r2, r3); |
|||
v = Avx.Shuffle(t1, t3, 0x4E); |
|||
this.V2 = Avx.Blend(t1, v, 0xCC); |
|||
this.V3 = Avx.Blend(t3, v, 0x33); |
|||
|
|||
Vector256<float> t5 = Avx.UnpackHigh(r4, r5); |
|||
Vector256<float> t7 = Avx.UnpackHigh(r6, r7); |
|||
v = Avx.Shuffle(t5, t7, 0x4E); |
|||
this.V6 = Avx.Blend(t5, v, 0xCC); |
|||
this.V7 = Avx.Blend(t7, v, 0x33); |
|||
} |
|||
} |
|||
} |
|||
#endif
|
|||
@ -1,21 +1,21 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder |
|||
{ |
|||
/// <summary>
|
|||
/// Enumerates the quantization tables
|
|||
/// Enumerates the quantization tables.
|
|||
/// </summary>
|
|||
internal enum QuantIndex |
|||
{ |
|||
/// <summary>
|
|||
/// The luminance quantization table index
|
|||
/// The luminance quantization table index.
|
|||
/// </summary>
|
|||
Luminance = 0, |
|||
|
|||
/// <summary>
|
|||
/// The chrominance quantization table index
|
|||
/// The chrominance quantization table index.
|
|||
/// </summary>
|
|||
Chrominance = 1, |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,114 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder |
|||
{ |
|||
/// <summary>
|
|||
/// On-stack worker struct to convert TPixel -> Rgb24 of 8x8 pixel blocks.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel type to work on.</typeparam>
|
|||
internal ref struct RgbForwardConverter<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Number of pixels processed per single <see cref="Convert(int, int, ref RowOctet{TPixel})"/> call
|
|||
/// </summary>
|
|||
private const int PixelsPerSample = 8 * 8; |
|||
|
|||
/// <summary>
|
|||
/// Total byte size of processed pixels converted from TPixel to <see cref="Rgb24"/>
|
|||
/// </summary>
|
|||
private const int RgbSpanByteSize = PixelsPerSample * 3; |
|||
|
|||
/// <summary>
|
|||
/// <see cref="Size"/> of sampling area from given frame pixel buffer.
|
|||
/// </summary>
|
|||
private static readonly Size SampleSize = new Size(8, 8); |
|||
|
|||
/// <summary>
|
|||
/// The Red component.
|
|||
/// </summary>
|
|||
public Block8x8F R; |
|||
|
|||
/// <summary>
|
|||
/// The Green component.
|
|||
/// </summary>
|
|||
public Block8x8F G; |
|||
|
|||
/// <summary>
|
|||
/// The Blue component.
|
|||
/// </summary>
|
|||
public Block8x8F B; |
|||
|
|||
/// <summary>
|
|||
/// Temporal 64-byte span to hold unconverted TPixel data.
|
|||
/// </summary>
|
|||
private readonly Span<TPixel> pixelSpan; |
|||
|
|||
/// <summary>
|
|||
/// Temporal 64-byte span to hold converted Rgb24 data.
|
|||
/// </summary>
|
|||
private readonly Span<Rgb24> rgbSpan; |
|||
|
|||
/// <summary>
|
|||
/// Sampled pixel buffer size.
|
|||
/// </summary>
|
|||
private readonly Size samplingAreaSize; |
|||
|
|||
/// <summary>
|
|||
/// <see cref="Configuration"/> for internal operations.
|
|||
/// </summary>
|
|||
private readonly Configuration config; |
|||
|
|||
public RgbForwardConverter(ImageFrame<TPixel> frame) |
|||
{ |
|||
this.R = default; |
|||
this.G = default; |
|||
this.B = default; |
|||
|
|||
// temporal pixel buffers
|
|||
this.pixelSpan = new TPixel[PixelsPerSample].AsSpan(); |
|||
this.rgbSpan = MemoryMarshal.Cast<byte, Rgb24>(new byte[RgbSpanByteSize + RgbToYCbCrConverterVectorized.AvxCompatibilityPadding].AsSpan()); |
|||
|
|||
// frame data
|
|||
this.samplingAreaSize = new Size(frame.Width, frame.Height); |
|||
this.config = frame.GetConfiguration(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a 8x8 image area inside 'pixels' at position (x, y) to Rgb24.
|
|||
/// </summary>
|
|||
public void Convert(int x, int y, ref RowOctet<TPixel> currentRows) |
|||
{ |
|||
YCbCrForwardConverter<TPixel>.LoadAndStretchEdges(currentRows, this.pixelSpan, new Point(x, y), SampleSize, this.samplingAreaSize); |
|||
|
|||
PixelOperations<TPixel>.Instance.ToRgb24(this.config, this.pixelSpan, this.rgbSpan); |
|||
|
|||
ref Block8x8F redBlock = ref this.R; |
|||
ref Block8x8F greenBlock = ref this.G; |
|||
ref Block8x8F blueBlock = ref this.B; |
|||
|
|||
CopyToBlock(this.rgbSpan, ref redBlock, ref greenBlock, ref blueBlock); |
|||
} |
|||
|
|||
private static void CopyToBlock(Span<Rgb24> rgbSpan, ref Block8x8F redBlock, ref Block8x8F greenBlock, ref Block8x8F blueBlock) |
|||
{ |
|||
ref Rgb24 rgbStart = ref MemoryMarshal.GetReference(rgbSpan); |
|||
|
|||
for (int i = 0; i < Block8x8F.Size; i++) |
|||
{ |
|||
Rgb24 c = Unsafe.Add(ref rgbStart, (nint)(uint)i); |
|||
|
|||
redBlock[i] = c.R; |
|||
greenBlock[i] = c.G; |
|||
blueBlock[i] = c.B; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue