diff --git a/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs index 31fa0238bf..6009fdfbc0 100644 --- a/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs +++ b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Compression.Zlib; @@ -426,8 +427,8 @@ internal sealed unsafe class DeflaterEngine : IDisposable private void SlideWindow() { Unsafe.CopyBlockUnaligned( - ref this.window.Span[0], - ref this.window.Span[DeflaterConstants.WSIZE], + ref MemoryMarshal.GetReference(this.window.Span), + ref Unsafe.Add(ref MemoryMarshal.GetReference(this.window.Span), DeflaterConstants.WSIZE), DeflaterConstants.WSIZE); this.matchStart -= DeflaterConstants.WSIZE; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs index 59789dcd25..1b043b68f2 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs @@ -53,7 +53,8 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder private ArithmeticDecodingTable[] acDecodingTables; - private readonly byte[] fixedBin = { 113, 0, 0, 0 }; + // Use C#'s optimization to refer to assembly's data segment, no allocation occurs. + private ReadOnlySpan fixedBin => new byte[] { 113, 0, 0, 0 }; private readonly CancellationToken cancellationToken; @@ -231,7 +232,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder } } - private ref byte GetFixedBinReference() => ref this.fixedBin[0]; + private ref byte GetFixedBinReference() => ref MemoryMarshal.GetReference(fixedBin); /// /// Decodes the entropy coded data. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticStatistics.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticStatistics.cs index 1e890d8269..9bd4110d07 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticStatistics.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticStatistics.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Runtime.InteropServices; + namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; internal class ArithmeticStatistics @@ -18,7 +20,7 @@ internal class ArithmeticStatistics public int Identifier { get; private set; } - public ref byte GetReference() => ref this.statistics[0]; + public ref byte GetReference() => ref MemoryMarshal.GetArrayDataReference(this.statistics); public ref byte GetReference(int offset) => ref this.statistics[offset]; diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 25c4a0d700..51b23242c8 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -255,7 +255,7 @@ internal static class PngScanlineProcessor // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha // channel and we should try to read it. Rgba32 rgba = default; - ref byte paletteAlphaRef = ref paletteAlpha[0]; + ref byte paletteAlphaRef = ref MemoryMarshal.GetArrayDataReference(paletteAlpha); for (int x = 0; x < header.Width; x++) { @@ -301,7 +301,7 @@ internal static class PngScanlineProcessor // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha // channel and we should try to read it. Rgba32 rgba = default; - ref byte paletteAlphaRef = ref paletteAlpha[0]; + ref byte paletteAlphaRef = ref MemoryMarshal.GetArrayDataReference(paletteAlpha); for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) { int index = Unsafe.Add(ref scanlineSpanRef, (uint)o); diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index ce4f566b87..e7dca00f79 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; @@ -429,11 +430,11 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite) { - color.FromLa16(Unsafe.As(ref this.scratchBuffer[0])); + color.FromLa16(Unsafe.As(ref MemoryMarshal.GetArrayDataReference(this.scratchBuffer))); } else { - color.FromBgra5551(Unsafe.As(ref this.scratchBuffer[0])); + color.FromBgra5551(Unsafe.As(ref MemoryMarshal.GetArrayDataReference(this.scratchBuffer))); } pixelSpan[x] = color; @@ -695,7 +696,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgr pixel"); } - color.FromBgr24(Unsafe.As(ref this.scratchBuffer[0])); + color.FromBgr24(Unsafe.As(ref MemoryMarshal.GetArrayDataReference(this.scratchBuffer))); pixelSpan[x] = color; } diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs index 04653bd6ec..bc023ec450 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs @@ -133,7 +133,7 @@ public sealed class BokehBlurProcessor : IImageProcessor // The target buffer is zeroed initially and then it accumulates the results // of each partial convolution, so we don't have to clear it here as well ref Vector4 targetBase = ref this.targetValues.GetElementUnsafe(boundsX, y); - ref Complex64 kernelStart = ref this.kernel[0]; + ref Complex64 kernelStart = ref MemoryMarshal.GetArrayDataReference(this.kernel); ref Complex64 kernelEnd = ref Unsafe.Add(ref kernelStart, (uint)kernelSize); while (Unsafe.IsAddressLessThan(ref kernelStart, ref kernelEnd)) diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index 2508a7da25..e4b0a60ab0 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -244,7 +244,7 @@ internal class BokehBlurProcessor : ImageProcessor ref Vector4 sourceBase = ref MemoryMarshal.GetReference(span); ref ComplexVector4 targetStart = ref MemoryMarshal.GetReference(targetBuffer); ref ComplexVector4 targetEnd = ref Unsafe.Add(ref targetStart, (uint)span.Length); - ref Complex64 kernelBase = ref this.kernel[0]; + ref Complex64 kernelBase = ref MemoryMarshal.GetArrayDataReference(this.kernel); ref Complex64 kernelEnd = ref Unsafe.Add(ref kernelBase, (uint)kernelSize); ref int sampleColumnBase = ref MemoryMarshal.GetReference(this.map.GetColumnOffsetSpan()); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs index b09db9fa05..cc6e1e5fb2 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs @@ -179,7 +179,7 @@ internal class Convolution2PassProcessor : ImageProcessor ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer); ref Vector4 targetStart = ref MemoryMarshal.GetReference(targetBuffer); ref Vector4 targetEnd = ref Unsafe.Add(ref targetStart, (uint)sourceBuffer.Length); - ref float kernelBase = ref this.kernel[0]; + ref float kernelBase = ref MemoryMarshal.GetArrayDataReference(this.kernel); ref float kernelEnd = ref Unsafe.Add(ref kernelBase, (uint)kernelSize); ref int sampleColumnBase = ref MemoryMarshal.GetReference(this.map.GetColumnOffsetSpan()); @@ -243,7 +243,7 @@ internal class Convolution2PassProcessor : ImageProcessor ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer); ref Vector4 targetStart = ref MemoryMarshal.GetReference(targetBuffer); ref Vector4 targetEnd = ref Unsafe.Add(ref targetStart, (uint)sourceBuffer.Length); - ref float kernelBase = ref this.kernel[0]; + ref float kernelBase = ref MemoryMarshal.GetArrayDataReference(this.kernel); ref float kernelEnd = ref Unsafe.Add(ref kernelBase, (uint)kernelSize); ref int sampleColumnBase = ref MemoryMarshal.GetReference(this.map.GetColumnOffsetSpan()); @@ -341,7 +341,7 @@ internal class Convolution2PassProcessor : ImageProcessor targetBuffer.Clear(); ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); - ref float kernelStart = ref this.kernel[0]; + ref float kernelStart = ref MemoryMarshal.GetArrayDataReference(this.kernel); ref float kernelEnd = ref Unsafe.Add(ref kernelStart, (uint)kernelSize); Span sourceRow; @@ -406,7 +406,7 @@ internal class Convolution2PassProcessor : ImageProcessor targetBuffer.Clear(); ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer); - ref float kernelStart = ref this.kernel[0]; + ref float kernelStart = ref MemoryMarshal.GetArrayDataReference(this.kernel); ref float kernelEnd = ref Unsafe.Add(ref kernelStart, (uint)kernelSize); Span sourceRow; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelDataProvider.cs b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelDataProvider.cs index 8f501da23e..a680393c8c 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelDataProvider.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelDataProvider.cs @@ -192,7 +192,7 @@ internal static class BokehBlurKernelDataProvider { ref Complex64[] kernelRef = ref Unsafe.Add(ref baseKernelsRef, (uint)i); int length = kernelRef.Length; - ref Complex64 valueRef = ref kernelRef[0]; + ref Complex64 valueRef = ref MemoryMarshal.GetArrayDataReference(kernelRef); ref Vector4 paramsRef = ref Unsafe.Add(ref baseParamsRef, (uint)i); for (int j = 0; j < length; j++) @@ -214,7 +214,7 @@ internal static class BokehBlurKernelDataProvider { ref Complex64[] kernelsRef = ref Unsafe.Add(ref baseKernelsRef, (uint)i); int length = kernelsRef.Length; - ref Complex64 valueRef = ref kernelsRef[0]; + ref Complex64 valueRef = ref MemoryMarshal.GetArrayDataReference(kernelsRef); for (int j = 0; j < length; j++) { diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index edf293d39e..a231d6dee7 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -684,7 +684,7 @@ internal struct WuQuantizer : IQuantizer using IMemoryOwner vvOwner = this.Configuration.MemoryAllocator.Allocate(this.maxColors); Span vv = vvOwner.GetSpan(); - ref Box cube = ref this.colorCube[0]; + ref Box cube = ref MemoryMarshal.GetArrayDataReference(this.colorCube); cube.RMin = cube.GMin = cube.BMin = cube.AMin = 0; cube.RMax = cube.GMax = cube.BMax = IndexCount - 1; cube.AMax = IndexAlphaCount - 1;