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);
                }
            }
Example #2
0
            /// <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);
            }
Example #4
0
            /// <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));
            }
Example #5
0
            /// <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);
            }
Example #9
0
        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);
            }
Example #11
0
        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);
                }
            }
        }
Example #12
0
            /// <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);
            }
Example #13
0
        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);
        }
Example #14
0
        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);
                }
            }
Example #17
0
 public static void ToBgr24(ReadOnlySpan <byte> source, Span <byte> dest)
 => SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(0, 1, 2, 3));
Example #18
0
 public void Shuffle3()
 {
     SimdUtils.Shuffle3(this.source, this.destination, Control);
 }
Example #19
0
 public static void ToArgb32(ReadOnlySpan <byte> source, Span <byte> dest)
 => SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(0, 1, 2, 3));
Example #20
0
 public static void ToRgba32(ReadOnlySpan <byte> source, Span <byte> dest)
 => SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(3, 0, 1, 2));
Example #21
0
 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);
 }
Example #23
0
 public void BulkConvertByteToNormalizedFloat(int count)
 {
     TestImpl_BulkConvertByteToNormalizedFloat(
         count,
         (s, d) => SimdUtils.BulkConvertByteToNormalizedFloat(s.Span, d.Span));
 }
Example #24
0
 public static void ToArgb32(ReadOnlySpan <byte> source, Span <byte> dest)
 => SimdUtils.Shuffle4Channel <WXYZShuffle4>(source, dest, default);
Example #25
0
 public static void ToRgba32(ReadOnlySpan <byte> source, Span <byte> dest)
 => SimdUtils.Pad3Shuffle4 <XYZWPad3Shuffle4>(source, dest, default);
Example #26
0
 public static void ToRgba32(ReadOnlySpan <byte> source, Span <byte> dest)
 => SimdUtils.Shuffle4Channel <ZYXWShuffle4>(source, dest, default);
Example #27
0
 public void Shuffle4Channel()
 {
     SimdUtils.Shuffle4(this.source, this.destination, Control);
 }
Example #28
0
 public static void ToBgra32(ReadOnlySpan <byte> source, Span <byte> dest)
 => SimdUtils.Shuffle4 <WZYXShuffle4>(source, dest, default);
Example #29
0
 public void Shuffle4Channel()
 {
     SimdUtils.Shuffle4 <WXYZShuffle4>(this.source, this.destination, default);
 }
 public void Pad3Shuffle4FastFallback()
 {
     SimdUtils.Pad3Shuffle4(this.source, this.destination, ControlFast);
 }