/// <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)); }
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; }
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); } }