internal static void FromVector4 <TPixel>( Configuration configuration, PixelOperations <TPixel> pixelOperations, ReadOnlySpan <Vector4> sourceVectors, Span <TPixel> destPixels, bool scaled) where TPixel : struct, IPixel <TPixel> { Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); int count = sourceVectors.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { FromVector4Fallback(sourceVectors, destPixels, scaled); return; } // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, // so let's allocate a temporary buffer as usually: using (IMemoryOwner <Rgba32> tempBuffer = configuration.MemoryAllocator.Allocate <Rgba32>(count)) { Span <Rgba32> tempSpan = tempBuffer.Memory.Span; SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( MemoryMarshal.Cast <Vector4, float>(sourceVectors), MemoryMarshal.Cast <Rgba32, byte>(tempSpan)); pixelOperations.FromRgba32(configuration, tempSpan, destPixels); } }
/// <inheritdoc /> internal override void PackFromVector4(ReadOnlySpan <Vector4> sourceVectors, Span <Rgba32> destinationColors, int count) { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); sourceVectors = sourceVectors.Slice(0, count); destinationColors = destinationColors.Slice(0, count); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( MemoryMarshal.Cast <Vector4, float>(sourceVectors), MemoryMarshal.Cast <Rgba32, byte>(destinationColors)); }
static void RunTest(string serialized) { // No need to test multiple shuffle controls as the // pipeline is always the same. int size = FeatureTestRunner.Deserialize <int>(serialized); byte control = default(WZYXShuffle4).Control; TestShuffleFloat4Channel( size, (s, d) => SimdUtils.Shuffle4Channel(s.Span, d.Span, control), control); }
/// <inheritdoc /> internal override void ToVector4(ReadOnlySpan <Rgba32> sourceColors, Span <Vector4> destinationVectors, int count) { Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); sourceColors = sourceColors.Slice(0, count); destinationVectors = destinationVectors.Slice(0, count); SimdUtils.BulkConvertByteToNormalizedFloat( MemoryMarshal.Cast <Rgba32, byte>(sourceColors), MemoryMarshal.Cast <Vector4, float>(destinationVectors)); }
/// <inheritdoc /> internal override void FromVector4( Configuration configuration, ReadOnlySpan <Vector4> sourceVectors, Span <Rgba32> destPixels) { Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); destPixels = destPixels.Slice(0, sourceVectors.Length); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( MemoryMarshal.Cast <Vector4, float>(sourceVectors), MemoryMarshal.Cast <Rgba32, byte>(destPixels)); }
/// <inheritdoc /> public override void ToVector4( Configuration configuration, ReadOnlySpan <Rgba32> sourcePixels, Span <Vector4> destinationVectors, PixelConversionModifiers modifiers) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationVectors, nameof(destinationVectors)); destinationVectors = destinationVectors.Slice(0, sourcePixels.Length); SimdUtils.ByteToNormalizedFloat( MemoryMarshal.Cast <Rgba32, byte>(sourcePixels), MemoryMarshal.Cast <Vector4, float>(destinationVectors)); Vector4Converters.ApplyForwardConversionModifiers(destinationVectors, modifiers); }
/// <inheritdoc /> public override void FromVector4Destructive( Configuration configuration, Span <Vector4> sourceVectors, Span <Rgba32> destinationPixels, PixelConversionModifiers modifiers) { Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationPixels, nameof(destinationPixels)); destinationPixels = destinationPixels.Slice(0, sourceVectors.Length); Vector4Converters.ApplyBackwardConversionModifiers(sourceVectors, modifiers); SimdUtils.NormalizedFloatToByteSaturate( MemoryMarshal.Cast <Vector4, float>(sourceVectors), MemoryMarshal.Cast <Rgba32, byte>(destinationPixels)); }
/// <inheritdoc /> internal override void PackFromRgbPlanes( Configuration configuration, ReadOnlySpan <byte> redChannel, ReadOnlySpan <byte> greenChannel, ReadOnlySpan <byte> blueChannel, Span <Rgb24> destination) { Guard.NotNull(configuration, nameof(configuration)); int count = redChannel.Length; GuardPackFromRgbPlanes(greenChannel, blueChannel, destination, count); SimdUtils.PackFromRgbPlanes(configuration, redChannel, greenChannel, blueChannel, destination); }
private void ConvertNextStride(int spectralStep) { int maxY = Math.Min(this.pixelBuffer.Height, this.pixelRowCounter + this.pixelRowsPerStep); var buffers = new Buffer2D <float> [this.componentProcessors.Length]; for (int i = 0; i < this.componentProcessors.Length; i++) { this.componentProcessors[i].CopyBlocksToColorBuffer(spectralStep); buffers[i] = this.componentProcessors[i].ColorBuffer; } int width = this.pixelBuffer.Width; for (int yy = this.pixelRowCounter; yy < maxY; yy++) { int y = yy - this.pixelRowCounter; var values = new JpegColorConverter.ComponentValues(buffers, y); this.colorConverter.ConvertToRgbInplace(values); values = values.Slice(0, width); // slice away Jpeg padding Span <byte> r = this.rgbBuffer.Slice(0, width); Span <byte> g = this.rgbBuffer.Slice(width, width); Span <byte> b = this.rgbBuffer.Slice(width * 2, width); SimdUtils.NormalizedFloatToByteSaturate(values.Component0, r); SimdUtils.NormalizedFloatToByteSaturate(values.Component1, g); SimdUtils.NormalizedFloatToByteSaturate(values.Component2, b); // PackFromRgbPlanes expects the destination to be padded, so try to get padded span containing extra elements from the next row. // If we can't get such a padded row because we are on a MemoryGroup boundary or at the last row, // pack pixels to a temporary, padded proxy buffer, then copy the relevant values to the destination row. if (this.pixelBuffer.TryGetPaddedRowSpan(yy, 3, out Span <TPixel> destRow)) { PixelOperations <TPixel> .Instance.PackFromRgbPlanes(this.configuration, r, g, b, destRow); } else { Span <TPixel> proxyRow = this.paddedProxyPixelRow.GetSpan(); PixelOperations <TPixel> .Instance.PackFromRgbPlanes(this.configuration, r, g, b, proxyRow); proxyRow.Slice(0, width).CopyTo(this.pixelBuffer.GetRowSpan(yy)); } } this.pixelRowCounter += this.pixelRowsPerStep; }
/// <inheritdoc /> internal override void PackFromRgbPlanes( Configuration configuration, ReadOnlySpan <byte> redChannel, ReadOnlySpan <byte> greenChannel, ReadOnlySpan <byte> blueChannel, Span <Rgba32> destination) { Guard.NotNull(configuration, nameof(configuration)); int count = redChannel.Length; Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!"); Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!"); Guard.IsTrue(destination.Length > count, nameof(destination), "'destination' span should not be shorter than the source channels!"); SimdUtils.PackFromRgbPlanes(configuration, redChannel, greenChannel, blueChannel, destination); }
public void BulkConvertNormalizedFloatToByteClampOverflows(int count) { TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span)); // For small values, let's stress test the implementation a bit: if (count > 0 && count < 10) { for (int i = 0; i < 20; i++) { TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( count, (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span), i + 42); } } }
/// <inheritdoc /> internal override void PackFromRgbPlanes( Configuration configuration, ReadOnlySpan <byte> redChannel, ReadOnlySpan <byte> greenChannel, ReadOnlySpan <byte> blueChannel, Span <Rgb24> destination) { Guard.NotNull(configuration, nameof(configuration)); int count = redChannel.Length; Guard.IsTrue(greenChannel.Length == count, nameof(greenChannel), "Channels must be of same size!"); Guard.IsTrue(blueChannel.Length == count, nameof(blueChannel), "Channels must be of same size!"); Guard.IsTrue(destination.Length > count + 2, nameof(destination), "'destination' must contain a padding of 3 elements!"); SimdUtils.PackFromRgbPlanes(configuration, redChannel, greenChannel, blueChannel, destination); }
public void BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { return; } float[] source = new Random(seed).GenerateRandomFloatArray(count, 0, 1f); byte[] dest = new byte[count]; SimdUtils.BulkConvertNormalizedFloatToByte(source, dest); byte[] expected = source.Select(f => (byte)Math.Round(f * 255f)).ToArray(); Assert.Equal(expected, dest); }
public void BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count) { if (this.SkipOnNonAvx2()) { return; } float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444); float[] normalized = orig.Select(f => f / 255f).ToArray(); byte[] dest = new byte[count]; SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest); byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray(); Assert.Equal(expected, dest); }
internal static void ToVector4 <TPixel>( Configuration configuration, PixelOperations <TPixel> pixelOperations, ReadOnlySpan <TPixel> sourcePixels, Span <Vector4> destVectors, PixelConversionModifiers modifiers) where TPixel : struct, IPixel <TPixel> { Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); int count = sourcePixels.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { Default.UnsafeToVector4(sourcePixels, destVectors, modifiers); return; } // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: int countWithoutLastItem = count - 1; ReadOnlySpan <TPixel> reducedSource = sourcePixels.Slice(0, countWithoutLastItem); Span <Rgba32> lastQuarterOfDestBuffer = MemoryMarshal.Cast <Vector4, Rgba32>(destVectors).Slice((3 * count) + 1, countWithoutLastItem); pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); // 'destVectors' and 'lastQuarterOfDestBuffer' are overlapping buffers, // but we are always reading/writing at different positions: SimdUtils.BulkConvertByteToNormalizedFloat( MemoryMarshal.Cast <Rgba32, byte>(lastQuarterOfDestBuffer), MemoryMarshal.Cast <Vector4, float>(destVectors.Slice(0, countWithoutLastItem))); destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); // TODO: Investigate optimized 1-pass approach! ApplyForwardConversionModifiers(destVectors, modifiers); }
internal static void FromVector4 <TPixel>( Configuration configuration, PixelOperations <TPixel> pixelOperations, Span <Vector4> sourceVectors, Span <TPixel> destPixels, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel <TPixel> { Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); int count = sourceVectors.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { Default.UnsafeFromVector4(sourceVectors, destPixels, modifiers); return; } // TODO: Investigate optimized 1-pass approach! ApplyBackwardConversionModifiers(sourceVectors, modifiers); // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, // so let's allocate a temporary buffer as usually: using (IMemoryOwner <Rgba32> tempBuffer = configuration.MemoryAllocator.Allocate <Rgba32>(count)) { Span <Rgba32> tempSpan = tempBuffer.Memory.Span; SimdUtils.NormalizedFloatToByteSaturate( MemoryMarshal.Cast <Vector4, float>(sourceVectors), MemoryMarshal.Cast <Rgba32, byte>(tempSpan)); pixelOperations.FromRgba32(configuration, tempSpan, destPixels); } }
public static void ToBgr24(ReadOnlySpan <byte> source, Span <byte> dest) => SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(0, 1, 2, 3));
public void Shuffle3() { SimdUtils.Shuffle3(this.source, this.destination, Control); }
public static void ToArgb32(ReadOnlySpan <byte> source, Span <byte> dest) => SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(0, 1, 2, 3));
public static void ToRgba32(ReadOnlySpan <byte> source, Span <byte> dest) => SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(3, 0, 1, 2));
public static void ToRgb24(ReadOnlySpan <byte> source, Span <byte> dest) => SimdUtils.Shuffle4Slice3 <XYZWShuffle4Slice3>(source, dest, default);
public void Pad3Shuffle4() { SimdUtils.Pad3Shuffle4(this.source, this.destination, Control); }
public void BulkConvertByteToNormalizedFloat(int count) { TestImpl_BulkConvertByteToNormalizedFloat( count, (s, d) => SimdUtils.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); }
public static void ToArgb32(ReadOnlySpan <byte> source, Span <byte> dest) => SimdUtils.Shuffle4Channel <WXYZShuffle4>(source, dest, default);
public static void ToRgba32(ReadOnlySpan <byte> source, Span <byte> dest) => SimdUtils.Pad3Shuffle4 <XYZWPad3Shuffle4>(source, dest, default);
public static void ToRgba32(ReadOnlySpan <byte> source, Span <byte> dest) => SimdUtils.Shuffle4Channel <ZYXWShuffle4>(source, dest, default);
public void Shuffle4Channel() { SimdUtils.Shuffle4(this.source, this.destination, Control); }
public static void ToBgra32(ReadOnlySpan <byte> source, Span <byte> dest) => SimdUtils.Shuffle4 <WZYXShuffle4>(source, dest, default);
public void Shuffle4Channel() { SimdUtils.Shuffle4 <WXYZShuffle4>(this.source, this.destination, default); }
public void Pad3Shuffle4FastFallback() { SimdUtils.Pad3Shuffle4(this.source, this.destination, ControlFast); }