/// <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));
            }
Esempio n. 2
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;
        }
Esempio n. 3
0
        public void BulkConvertNormalizedFloatToByteClampOverflows(int count)
        {
            TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, (s, d) => SimdUtils.NormalizedFloatToByteSaturate(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.NormalizedFloatToByteSaturate(s.Span, d.Span),
                        i + 42);
                }
            }
        }
            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);
                }
            }