Browse Source

PR feedback

pull/2401/head
Günther Foidl 3 years ago
parent
commit
e234b003ef
  1. 20
      src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
  2. 8
      src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs
  3. 2
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  4. 2
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  5. 20
      src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
  6. 4
      src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs
  7. 4
      src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs
  8. 4
      src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs
  9. 12
      src/ImageSharp/Formats/Webp/Lossless/PredictorEncoder.cs
  10. 10
      src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
  11. 12
      src/ImageSharp/Formats/Webp/Lossless/Vp8LHashChain.cs
  12. 6
      src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs
  13. 2
      src/ImageSharp/Formats/Webp/Lossy/PassStats.cs
  14. 6
      src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs
  15. 8
      src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
  16. 2
      src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs
  17. 4
      src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
  18. 48
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs
  19. 16
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DState.cs
  20. 32
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
  21. 16
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionState.cs
  22. 14
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
  23. 18
      src/ImageSharp/Processing/Processors/Convolution/ReadOnlyKernel.cs

20
src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs

@ -84,9 +84,9 @@ internal readonly struct WXYZShuffle4 : IShuffle4
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = (int)((uint)source.Length / 4);
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < (uint)n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
@ -108,9 +108,9 @@ internal readonly struct WZYXShuffle4 : IShuffle4
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = (int)((uint)source.Length / 4);
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < (uint)n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
@ -132,9 +132,9 @@ internal readonly struct YZWXShuffle4 : IShuffle4
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = (int)((uint)source.Length / 4);
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < (uint)n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
@ -156,9 +156,9 @@ internal readonly struct ZYXWShuffle4 : IShuffle4
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = (int)((uint)source.Length / 4);
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < (uint)n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
@ -187,9 +187,9 @@ internal readonly struct XWZYShuffle4 : IShuffle4
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = (int)((uint)source.Length / 4);
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < (uint)n; i++)
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);

8
src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs

@ -71,7 +71,7 @@ internal static partial class SimdUtils
{
VerifySpanInput(source, dest, 4);
int count = (int)((uint)dest.Length / 4);
uint count = (uint)dest.Length / 4;
if (count == 0)
{
return;
@ -83,7 +83,7 @@ internal static partial class SimdUtils
const float scale = 1f / 255f;
Vector4 d = default;
for (nuint i = 0; i < (uint)count; i++)
for (nuint i = 0; i < count; i++)
{
ref ByteVector4 s = ref Unsafe.Add(ref sBase, i);
d.X = s.X;
@ -105,7 +105,7 @@ internal static partial class SimdUtils
{
VerifySpanInput(source, dest, 4);
int count = (int)((uint)source.Length / 4);
uint count = (uint)source.Length / 4;
if (count == 0)
{
return;
@ -117,7 +117,7 @@ internal static partial class SimdUtils
var half = new Vector4(0.5f);
var maxBytes = new Vector4(255f);
for (nuint i = 0; i < (uint)count; i++)
for (nuint i = 0; i < count; i++)
{
Vector4 s = Unsafe.Add(ref sBase, i);
s *= maxBytes;

2
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -1361,7 +1361,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
this.metadata.VerticalResolution = Math.Round(UnitConverter.InchToMeter(ImageMetadata.DefaultVerticalResolution));
}
short bitsPerPixel = this.infoHeader.BitsPerPixel;
ushort bitsPerPixel = this.infoHeader.BitsPerPixel;
this.bmpMetadata = this.metadata.GetBmpMetadata();
this.bmpMetadata.InfoHeaderType = infoHeaderType;
this.bmpMetadata.BitsPerPixel = (BmpBitsPerPixel)bitsPerPixel;

2
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -212,7 +212,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals
width: width,
height: height,
planes: 1,
bitsPerPixel: (short)bpp,
bitsPerPixel: bpp,
imageSize: height * bytesPerLine,
xPelsPerMeter: hResolution,
yPelsPerMeter: vResolution,

20
src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs

@ -70,7 +70,7 @@ internal struct BmpInfoHeader
int width,
int height,
short planes,
short bitsPerPixel,
ushort bitsPerPixel,
BmpCompression compression = default,
int imageSize = 0,
int xPelsPerMeter = 0,
@ -157,7 +157,7 @@ internal struct BmpInfoHeader
/// Gets or sets the number of bits per pixel, which is the color depth of the image.
/// Typical values are 1, 4, 8, 16, 24 and 32.
/// </summary>
public short BitsPerPixel { get; set; }
public ushort BitsPerPixel { get; set; }
/// <summary>
/// Gets or sets the compression method being used.
@ -311,7 +311,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(4, 2)),
height: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(6, 2)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(8, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(10, 2)));
bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(10, 2)));
/// <summary>
/// Parses a short variant of the OS22XBITMAPHEADER. It is identical to the BITMAPCOREHEADER, except that the width and height
@ -325,7 +325,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)));
bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)));
/// <summary>
/// Parses the full BMP Version 3 BITMAPINFOHEADER header (40 bytes).
@ -338,7 +338,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)),
bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)),
compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
@ -359,7 +359,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)),
bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)),
compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
@ -386,7 +386,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)));
bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)));
// The compression value in OS/2 bitmap has a different meaning than in windows bitmaps.
// Map the OS/2 value to the windows values.
@ -431,7 +431,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)),
bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)),
compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
@ -484,7 +484,7 @@ internal struct BmpInfoHeader
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(14, 2), this.BitsPerPixel);
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(14, 2), this.BitsPerPixel);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(16, 4), (int)this.Compression);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(20, 4), this.ImageSize);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(24, 4), this.XPelsPerMeter);
@ -504,7 +504,7 @@ internal struct BmpInfoHeader
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(14, 2), this.BitsPerPixel);
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(14, 2), this.BitsPerPixel);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(16, 4), (int)this.Compression);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(20, 4), this.ImageSize);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(24, 4), this.XPelsPerMeter);

4
src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs

@ -157,7 +157,7 @@ internal class ComponentProcessor : IDisposable
// Ideally we need to use log2: Numerics.Log2((uint)factor)
// but division by 2 works just fine in this case
int haddIterationsCount = (int)((uint)factor / 2);
uint haddIterationsCount = (uint)factor / 2;
// Transform spans so that it only contains 'remainder'
// values for the scalar fallback code
@ -168,7 +168,7 @@ internal class ComponentProcessor : IDisposable
nuint length = (uint)(touchedCount / Vector256<float>.Count);
for (int i = 0; i < haddIterationsCount; i++)
for (uint i = 0; i < haddIterationsCount; i++)
{
length /= 2;

4
src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs

@ -38,7 +38,7 @@ internal static class BackwardReferenceEncoder
int width,
int height,
ReadOnlySpan<uint> bgra,
int quality,
uint quality,
int lz77TypesToTry,
ref int cacheBits,
MemoryAllocator memoryAllocator,
@ -123,7 +123,7 @@ internal static class BackwardReferenceEncoder
/// The local color cache is also disabled for the lower (smaller then 25) quality.
/// </summary>
/// <returns>Best cache size.</returns>
private static int CalculateBestCacheSize(ReadOnlySpan<uint> bgra, int quality, Vp8LBackwardRefs refs, int bestCacheBits)
private static int CalculateBestCacheSize(ReadOnlySpan<uint> bgra, uint quality, Vp8LBackwardRefs refs, int bestCacheBits)
{
int cacheBitsMax = quality <= 25 ? 0 : bestCacheBits;
if (cacheBitsMax == 0)

4
src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs

@ -27,7 +27,7 @@ internal class HistogramEncoder
private const ushort InvalidHistogramSymbol = ushort.MaxValue;
public static void GetHistoImageSymbols(int xSize, int ySize, Vp8LBackwardRefs refs, int quality, int histoBits, int cacheBits, List<Vp8LHistogram> imageHisto, Vp8LHistogram tmpHisto, ushort[] histogramSymbols)
public static void GetHistoImageSymbols(int xSize, int ySize, Vp8LBackwardRefs refs, uint quality, int histoBits, int cacheBits, List<Vp8LHistogram> imageHisto, Vp8LHistogram tmpHisto, ushort[] histogramSymbols)
{
int histoXSize = histoBits > 0 ? LosslessUtils.SubSampleSize(xSize, histoBits) : 1;
int histoYSize = histoBits > 0 ? LosslessUtils.SubSampleSize(ySize, histoBits) : 1;
@ -660,7 +660,7 @@ internal class HistogramEncoder
output.TrivialSymbol = a.TrivialSymbol == b.TrivialSymbol ? a.TrivialSymbol : NonTrivialSym;
}
private static double GetCombineCostFactor(int histoSize, int quality)
private static double GetCombineCostFactor(int histoSize, uint quality)
{
double combineCostFactor = 0.16d;
if (quality < 90)

12
src/ImageSharp/Formats/Webp/Lossless/PredictorEncoder.cs

@ -113,7 +113,7 @@ internal static unsafe class PredictorEncoder
lowEffort);
}
public static void ColorSpaceTransform(int width, int height, int bits, int quality, Span<uint> bgra, Span<uint> image, Span<int> scratch)
public static void ColorSpaceTransform(int width, int height, int bits, uint quality, Span<uint> bgra, Span<uint> image, Span<int> scratch)
{
int maxTileSize = 1 << bits;
int tileXSize = LosslessUtils.SubSampleSize(width, bits);
@ -837,7 +837,7 @@ internal static unsafe class PredictorEncoder
int bits,
Vp8LMultipliers prevX,
Vp8LMultipliers prevY,
int quality,
uint quality,
int xSize,
int ySize,
int[] accumulatedRedHisto,
@ -871,14 +871,14 @@ internal static unsafe class PredictorEncoder
int tileHeight,
Vp8LMultipliers prevX,
Vp8LMultipliers prevY,
int quality,
uint quality,
int[] accumulatedRedHisto,
ref Vp8LMultipliers bestTx)
{
int maxIters = 4 + ((7 * quality) >> 8); // in range [4..6]
uint maxIters = 4 + ((7 * quality) / 256); // in range [4..6]
int greenToRedBest = 0;
double bestDiff = GetPredictionCostCrossColorRed(argb, stride, scratch, tileWidth, tileHeight, prevX, prevY, greenToRedBest, accumulatedRedHisto);
for (int iter = 0; iter < maxIters; iter++)
for (int iter = 0; iter < (int)maxIters; iter++)
{
// ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to
// one in color computation. Having initial delta here as 1 is sufficient
@ -901,7 +901,7 @@ internal static unsafe class PredictorEncoder
bestTx.GreenToRed = (byte)(greenToRedBest & 0xff);
}
private static void GetBestGreenRedToBlue(Span<uint> argb, int stride, Span<int> scratch, int tileWidth, int tileHeight, Vp8LMultipliers prevX, Vp8LMultipliers prevY, int quality, int[] accumulatedBlueHisto, ref Vp8LMultipliers bestTx)
private static void GetBestGreenRedToBlue(Span<uint> argb, int stride, Span<int> scratch, int tileWidth, int tileHeight, Vp8LMultipliers prevX, Vp8LMultipliers prevY, uint quality, int[] accumulatedBlueHisto, ref Vp8LMultipliers bestTx)
{
int iters = (quality < 25) ? 1 : (quality > 50) ? GreenRedToBlueMaxIters : 4;
int greenToBlueBest = 0;

10
src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs

@ -57,7 +57,7 @@ internal class Vp8LEncoder : IDisposable
/// <summary>
/// The quality, that will be used to encode the image.
/// </summary>
private readonly int quality;
private readonly uint quality;
/// <summary>
/// Quality/speed trade-off (0=fast, 6=slower-better).
@ -110,7 +110,7 @@ internal class Vp8LEncoder : IDisposable
Configuration configuration,
int width,
int height,
int quality,
uint quality,
bool skipMetadata,
WebpEncodingMethod method,
WebpTransparentColorMode transparentColorMode,
@ -122,7 +122,7 @@ internal class Vp8LEncoder : IDisposable
this.memoryAllocator = memoryAllocator;
this.configuration = configuration;
this.quality = Numerics.Clamp(quality, 0, 100);
this.quality = Math.Min(quality, 100u);
this.skipMetadata = skipMetadata;
this.method = method;
this.transparentColorMode = transparentColorMode;
@ -772,7 +772,7 @@ internal class Vp8LEncoder : IDisposable
this.EncodeImageNoHuffman(this.TransformData.GetSpan(), this.HashChain, this.Refs[0], this.Refs[1], transformWidth, transformHeight, this.quality, lowEffort);
}
private void EncodeImageNoHuffman(Span<uint> bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs refsTmp1, Vp8LBackwardRefs refsTmp2, int width, int height, int quality, bool lowEffort)
private void EncodeImageNoHuffman(Span<uint> bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs refsTmp1, Vp8LBackwardRefs refsTmp2, int width, int height, uint quality, bool lowEffort)
{
int cacheBits = 0;
ushort[] histogramSymbols = new ushort[1]; // Only one tree, one symbol.
@ -1820,7 +1820,7 @@ internal class Vp8LEncoder : IDisposable
{
// VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
// pixel in each, plus 2 regular scanlines of bytes.
int bgraScratchSize = this.UsePredictorTransform ? (int)((((uint)width + 1) * 2) + ((((uint)width * 2) + 4 - 1) / 4)) : 0;
int bgraScratchSize = this.UsePredictorTransform ? ((width + 1) * 2) + (((width * 2) + 4 - 1) / 4) : 0;
int transformDataSize = this.UsePredictorTransform || this.UseCrossColorTransform ? LosslessUtils.SubSampleSize(width, this.TransformBits) * LosslessUtils.SubSampleSize(height, this.TransformBits) : 0;
this.BgraScratch = this.memoryAllocator.Allocate<uint>(bgraScratchSize);

12
src/ImageSharp/Formats/Webp/Lossless/Vp8LHashChain.cs

@ -56,10 +56,10 @@ internal sealed class Vp8LHashChain : IDisposable
/// </summary>
public int Size { get; }
public void Fill(ReadOnlySpan<uint> bgra, int quality, int xSize, int ySize, bool lowEffort)
public void Fill(ReadOnlySpan<uint> bgra, uint quality, int xSize, int ySize, bool lowEffort)
{
int size = xSize * ySize;
int iterMax = GetMaxItersForQuality((uint)quality);
int iterMax = GetMaxItersForQuality(quality);
int windowSize = GetWindowSizeForHashChain(quality, xSize);
int pos;
@ -275,11 +275,11 @@ internal sealed class Vp8LHashChain : IDisposable
private static int GetMaxItersForQuality(uint quality) => (int)(8 + (quality * quality / 128));
[MethodImpl(InliningOptions.ShortMethod)]
private static int GetWindowSizeForHashChain(int quality, int xSize)
private static int GetWindowSizeForHashChain(uint quality, int xSize)
{
int maxWindowSize = quality > 75 ? WindowSize
: quality > 50 ? xSize << 8
: quality > 25 ? xSize << 6
int maxWindowSize = quality > 75u ? WindowSize
: quality > 50u ? xSize << 8
: quality > 25u ? xSize << 6
: xSize << 4;
return maxWindowSize > WindowSize ? WindowSize : maxWindowSize;

6
src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs

@ -523,18 +523,18 @@ internal sealed class Vp8LHistogram : IDeepCloneable
do
{
// Load values.
Vector256<uint> a0 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref aRef, idx));
Vector256<uint> a0 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref aRef, idx + 0));
Vector256<uint> a1 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref aRef, idx + 8));
Vector256<uint> a2 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref aRef, idx + 16));
Vector256<uint> a3 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref aRef, idx + 24));
Vector256<uint> b0 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref bRef, idx));
Vector256<uint> b0 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref bRef, idx + 0));
Vector256<uint> b1 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref bRef, idx + 8));
Vector256<uint> b2 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref bRef, idx + 16));
Vector256<uint> b3 = Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref bRef, idx + 24));
// Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But
// that's ok since the histogram values are less than 1<<28 (max picture count).
Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref outputRef, idx)) = Avx2.Add(a0, b0);
Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref outputRef, idx + 0)) = Avx2.Add(a0, b0);
Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref outputRef, idx + 8)) = Avx2.Add(a1, b1);
Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref outputRef, idx + 16)) = Avx2.Add(a2, b2);
Unsafe.As<uint, Vector256<uint>>(ref Unsafe.Add(ref outputRef, idx + 24)) = Avx2.Add(a3, b3);

2
src/ImageSharp/Formats/Webp/Lossy/PassStats.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy;
/// </summary>
internal class PassStats
{
public PassStats(long targetSize, float targetPsnr, int qMin, int qMax, int quality)
public PassStats(long targetSize, float targetPsnr, int qMin, int qMax, uint quality)
{
bool doSizeSearch = targetSize != 0;

6
src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs

@ -347,12 +347,12 @@ internal class Vp8EncIterator
}
}
public int FastMbAnalyze(int quality)
public int FastMbAnalyze(uint quality)
{
// Empirical cut-off value, should be around 16 (~=block size). We use the
// [8-17] range and favor intra4 at high quality, intra16 for low quality.
int q = quality;
int kThreshold = 8 + ((17 - 8) * q / 100);
uint q = quality;
uint kThreshold = 8 + ((17 - 8) * q / 100);
int k;
Span<uint> dc = stackalloc uint[16];
uint m;

8
src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs

@ -31,7 +31,7 @@ internal class Vp8Encoder : IDisposable
/// <summary>
/// The quality, that will be used to encode the image.
/// </summary>
private readonly int quality;
private readonly uint quality;
/// <summary>
/// Quality/speed trade-off (0=fast, 6=slower-better).
@ -113,7 +113,7 @@ internal class Vp8Encoder : IDisposable
Configuration configuration,
int width,
int height,
int quality,
uint quality,
bool skipMetadata,
WebpEncodingMethod method,
int entropyPasses,
@ -125,7 +125,7 @@ internal class Vp8Encoder : IDisposable
this.configuration = configuration;
this.Width = width;
this.Height = height;
this.quality = Numerics.Clamp(quality, 0, 100);
this.quality = Math.Min(quality, 100);
this.skipMetadata = skipMetadata;
this.method = method;
this.entropyPasses = Numerics.Clamp(entropyPasses, 1, 10);
@ -1177,6 +1177,6 @@ internal class Vp8Encoder : IDisposable
{
int total = a + b;
return total == 0 ? 255 // that's the default probability.
: ((255 * a) + (int)((uint)total / 2)) / total; // rounded proba
: ((255 * a) + (total >> 1)) / total; // rounded proba
}
}

2
src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs

@ -731,7 +731,7 @@ internal sealed class WebpLossyDecoder
Span<byte> dst = buf[dstStartIdx..];
int yEnd = io.MbY + io.MbH;
int mbw = io.MbW;
int uvw = (int)(((uint)mbw + 1) / 2);
int uvw = (mbw + 1) >> 1; // >> 1 is bit-hack for / 2
int y = io.MbY;
byte[] uvBuffer = new byte[(14 * 32) + 15];

4
src/ImageSharp/Formats/Webp/WebpEncoderCore.cs

@ -27,7 +27,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
/// <summary>
/// Compression quality. Between 0 and 100.
/// </summary>
private readonly int quality;
private readonly uint quality;
/// <summary>
/// Quality/speed trade-off (0=fast, 6=slower-better).
@ -92,7 +92,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
this.memoryAllocator = configuration.MemoryAllocator;
this.alphaCompression = encoder.UseAlphaCompression;
this.fileFormat = encoder.FileFormat;
this.quality = encoder.Quality;
this.quality = (uint)encoder.Quality;
this.method = encoder.Method;
this.entropyPasses = encoder.EntropyPasses;
this.spatialNoiseShaping = encoder.SpatialNoiseShaping;

48
src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs

@ -76,7 +76,7 @@ internal readonly struct Convolution2DRowOperation<TPixel> : IRowOperation<Vecto
Span<Vector4> targetXBuffer = span.Slice(boundsWidth * 2, boundsWidth);
var state = new Convolution2DState(in this.kernelMatrixY, in this.kernelMatrixX, this.map);
ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y);
ref int sampleRowBase = ref state.GetSampleRow((uint)(y - this.bounds.Y));
// Clear the target buffers for each row run.
targetYBuffer.Clear();
@ -87,24 +87,24 @@ internal readonly struct Convolution2DRowOperation<TPixel> : IRowOperation<Vecto
ReadOnlyKernel kernelY = state.KernelY;
ReadOnlyKernel kernelX = state.KernelX;
Span<TPixel> sourceRow;
for (int kY = 0; kY < kernelY.Rows; kY++)
for (uint kY = 0; kY < kernelY.Rows; kY++)
{
// Get the precalculated source sample row for this kernel row and copy to our buffer.
int sampleY = Unsafe.Add(ref sampleRowBase, (uint)kY);
int sampleY = Unsafe.Add(ref sampleRowBase, kY);
sourceRow = this.sourcePixels.DangerousGetRowSpan(sampleY).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer);
for (int x = 0; x < sourceBuffer.Length; x++)
for (uint x = 0; x < (uint)sourceBuffer.Length; x++)
{
ref int sampleColumnBase = ref state.GetSampleColumn(x);
ref Vector4 targetY = ref Unsafe.Add(ref targetBaseY, (uint)x);
ref Vector4 targetX = ref Unsafe.Add(ref targetBaseX, (uint)x);
ref Vector4 targetY = ref Unsafe.Add(ref targetBaseY, x);
ref Vector4 targetX = ref Unsafe.Add(ref targetBaseX, x);
for (int kX = 0; kX < kernelY.Columns; kX++)
for (uint kX = 0; kX < kernelY.Columns; kX++)
{
int sampleX = Unsafe.Add(ref sampleColumnBase, (uint)kX) - boundsX;
int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
Vector4 sample = Unsafe.Add(ref sourceBase, (uint)sampleX);
targetY += kernelX[kY, kX] * sample;
targetX += kernelY[kY, kX] * sample;
@ -117,14 +117,14 @@ internal readonly struct Convolution2DRowOperation<TPixel> : IRowOperation<Vecto
sourceRow = this.sourcePixels.DangerousGetRowSpan(y).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
for (int x = 0; x < sourceRow.Length; x++)
for (nuint x = 0; x < (uint)sourceRow.Length; x++)
{
ref Vector4 target = ref Unsafe.Add(ref targetBaseY, (uint)x);
ref Vector4 target = ref Unsafe.Add(ref targetBaseY, x);
Vector4 vectorY = target;
Vector4 vectorX = Unsafe.Add(ref targetBaseX, (uint)x);
Vector4 vectorX = Unsafe.Add(ref targetBaseX, x);
target = Vector4.SquareRoot((vectorX * vectorX) + (vectorY * vectorY));
target.W = Unsafe.Add(ref MemoryMarshal.GetReference(sourceBuffer), (uint)x).W;
target.W = Unsafe.Add(ref MemoryMarshal.GetReference(sourceBuffer), x).W;
}
Span<TPixel> targetRowSpan = this.targetPixels.DangerousGetRowSpan(y).Slice(boundsX, boundsWidth);
@ -142,7 +142,7 @@ internal readonly struct Convolution2DRowOperation<TPixel> : IRowOperation<Vecto
Span<Vector4> targetXBuffer = span.Slice(boundsWidth * 2, boundsWidth);
var state = new Convolution2DState(in this.kernelMatrixY, in this.kernelMatrixX, this.map);
ref int sampleRowBase = ref state.GetSampleRow(y - this.bounds.Y);
ref int sampleRowBase = ref state.GetSampleRow((uint)(y - this.bounds.Y));
// Clear the target buffers for each row run.
targetYBuffer.Clear();
@ -152,26 +152,26 @@ internal readonly struct Convolution2DRowOperation<TPixel> : IRowOperation<Vecto
ReadOnlyKernel kernelY = state.KernelY;
ReadOnlyKernel kernelX = state.KernelX;
for (int kY = 0; kY < kernelY.Rows; kY++)
for (uint kY = 0; kY < kernelY.Rows; kY++)
{
// Get the precalculated source sample row for this kernel row and copy to our buffer.
int sampleY = Unsafe.Add(ref sampleRowBase, (uint)kY);
int sampleY = Unsafe.Add(ref sampleRowBase, kY);
Span<TPixel> sourceRow = this.sourcePixels.DangerousGetRowSpan(sampleY).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
Numerics.Premultiply(sourceBuffer);
ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer);
for (int x = 0; x < sourceBuffer.Length; x++)
for (uint x = 0; x < (uint)sourceBuffer.Length; x++)
{
ref int sampleColumnBase = ref state.GetSampleColumn(x);
ref Vector4 targetY = ref Unsafe.Add(ref targetBaseY, (uint)x);
ref Vector4 targetX = ref Unsafe.Add(ref targetBaseX, (uint)x);
ref Vector4 targetY = ref Unsafe.Add(ref targetBaseY, x);
ref Vector4 targetX = ref Unsafe.Add(ref targetBaseX, x);
for (int kX = 0; kX < kernelY.Columns; kX++)
for (uint kX = 0; kX < kernelY.Columns; kX++)
{
int sampleX = Unsafe.Add(ref sampleColumnBase, (uint)kX) - boundsX;
Vector4 sample = Unsafe.Add(ref sourceBase, (uint)sampleX);
int sampleX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
Vector4 sample = Unsafe.Add(ref sourceBase, sampleX);
targetY += kernelX[kY, kX] * sample;
targetX += kernelY[kY, kX] * sample;
}
@ -179,11 +179,11 @@ internal readonly struct Convolution2DRowOperation<TPixel> : IRowOperation<Vecto
}
// Now we need to combine the values
for (int x = 0; x < targetYBuffer.Length; x++)
for (nuint x = 0; x < (uint)targetYBuffer.Length; x++)
{
ref Vector4 target = ref Unsafe.Add(ref targetBaseY, (uint)x);
ref Vector4 target = ref Unsafe.Add(ref targetBaseY, x);
Vector4 vectorY = target;
Vector4 vectorX = Unsafe.Add(ref targetBaseX, (uint)x);
Vector4 vectorX = Unsafe.Add(ref targetBaseX, x);
target = Vector4.SquareRoot((vectorX * vectorX) + (vectorY * vectorY));
}

16
src/ImageSharp/Processing/Processors/Convolution/Convolution2DState.cs

@ -13,8 +13,8 @@ internal readonly ref struct Convolution2DState
{
private readonly Span<int> rowOffsetMap;
private readonly Span<int> columnOffsetMap;
private readonly int kernelHeight;
private readonly int kernelWidth;
private readonly uint kernelHeight;
private readonly uint kernelWidth;
public Convolution2DState(
in DenseMatrix<float> kernelY,
@ -24,8 +24,8 @@ internal readonly ref struct Convolution2DState
// We check the kernels are the same size upstream.
this.KernelY = new ReadOnlyKernel(kernelY);
this.KernelX = new ReadOnlyKernel(kernelX);
this.kernelHeight = kernelY.Rows;
this.kernelWidth = kernelY.Columns;
this.kernelHeight = (uint)kernelY.Rows;
this.kernelWidth = (uint)kernelY.Columns;
this.rowOffsetMap = map.GetRowOffsetSpan();
this.columnOffsetMap = map.GetColumnOffsetSpan();
}
@ -43,10 +43,10 @@ internal readonly ref struct Convolution2DState
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ref int GetSampleRow(int row)
=> ref Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), (uint)(row * this.kernelHeight));
public readonly ref int GetSampleRow(uint row)
=> ref Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), row * this.kernelHeight);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ref int GetSampleColumn(int column)
=> ref Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), (uint)(column * this.kernelWidth));
public readonly ref int GetSampleColumn(uint column)
=> ref Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), column * this.kernelWidth);
}

32
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs

@ -123,7 +123,7 @@ internal class ConvolutionProcessor<TPixel> : ImageProcessor<TPixel>
var state = new ConvolutionState(in this.kernel, this.map);
int row = y - this.bounds.Y;
ref int sampleRowBase = ref state.GetSampleRow(row);
ref int sampleRowBase = ref state.GetSampleRow((uint)row);
if (this.preserveAlpha)
{
@ -132,23 +132,23 @@ internal class ConvolutionProcessor<TPixel> : ImageProcessor<TPixel>
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
Span<TPixel> sourceRow;
for (int kY = 0; kY < state.Kernel.Rows; kY++)
for (uint kY = 0; kY < state.Kernel.Rows; kY++)
{
// Get the precalculated source sample row for this kernel row and copy to our buffer.
int offsetY = Unsafe.Add(ref sampleRowBase, (uint)kY);
int offsetY = Unsafe.Add(ref sampleRowBase, kY);
sourceRow = this.sourcePixels.DangerousGetRowSpan(offsetY).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer);
for (int x = 0; x < sourceBuffer.Length; x++)
for (uint x = 0; x < (uint)sourceBuffer.Length; x++)
{
ref int sampleColumnBase = ref state.GetSampleColumn(x);
ref Vector4 target = ref Unsafe.Add(ref targetBase, (uint)x);
ref Vector4 target = ref Unsafe.Add(ref targetBase, x);
for (int kX = 0; kX < state.Kernel.Columns; kX++)
for (uint kX = 0; kX < state.Kernel.Columns; kX++)
{
int offsetX = Unsafe.Add(ref sampleColumnBase, (uint)kX) - boundsX;
int offsetX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
Vector4 sample = Unsafe.Add(ref sourceBase, (uint)offsetX);
target += state.Kernel[kY, kX] * sample;
}
@ -159,10 +159,10 @@ internal class ConvolutionProcessor<TPixel> : ImageProcessor<TPixel>
sourceRow = this.sourcePixels.DangerousGetRowSpan(y).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
for (int x = 0; x < sourceRow.Length; x++)
for (nuint x = 0; x < (uint)sourceRow.Length; x++)
{
ref Vector4 target = ref Unsafe.Add(ref targetBase, (uint)x);
target.W = Unsafe.Add(ref MemoryMarshal.GetReference(sourceBuffer), (uint)x).W;
ref Vector4 target = ref Unsafe.Add(ref targetBase, x);
target.W = Unsafe.Add(ref MemoryMarshal.GetReference(sourceBuffer), x).W;
}
}
else
@ -171,24 +171,24 @@ internal class ConvolutionProcessor<TPixel> : ImageProcessor<TPixel>
targetBuffer.Clear();
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
for (int kY = 0; kY < state.Kernel.Rows; kY++)
for (uint kY = 0; kY < state.Kernel.Rows; kY++)
{
// Get the precalculated source sample row for this kernel row and copy to our buffer.
int offsetY = Unsafe.Add(ref sampleRowBase, (uint)kY);
int offsetY = Unsafe.Add(ref sampleRowBase, kY);
Span<TPixel> sourceRow = this.sourcePixels.DangerousGetRowSpan(offsetY).Slice(boundsX, boundsWidth);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, sourceRow, sourceBuffer);
Numerics.Premultiply(sourceBuffer);
ref Vector4 sourceBase = ref MemoryMarshal.GetReference(sourceBuffer);
for (int x = 0; x < sourceBuffer.Length; x++)
for (uint x = 0; x < (uint)sourceBuffer.Length; x++)
{
ref int sampleColumnBase = ref state.GetSampleColumn(x);
ref Vector4 target = ref Unsafe.Add(ref targetBase, (uint)x);
ref Vector4 target = ref Unsafe.Add(ref targetBase, x);
for (int kX = 0; kX < state.Kernel.Columns; kX++)
for (uint kX = 0; kX < state.Kernel.Columns; kX++)
{
int offsetX = Unsafe.Add(ref sampleColumnBase, (uint)kX) - boundsX;
int offsetX = Unsafe.Add(ref sampleColumnBase, kX) - boundsX;
Vector4 sample = Unsafe.Add(ref sourceBase, (uint)offsetX);
target += state.Kernel[kY, kX] * sample;
}

16
src/ImageSharp/Processing/Processors/Convolution/ConvolutionState.cs

@ -13,16 +13,16 @@ internal readonly ref struct ConvolutionState
{
private readonly Span<int> rowOffsetMap;
private readonly Span<int> columnOffsetMap;
private readonly int kernelHeight;
private readonly int kernelWidth;
private readonly uint kernelHeight;
private readonly uint kernelWidth;
public ConvolutionState(
in DenseMatrix<float> kernel,
KernelSamplingMap map)
{
this.Kernel = new ReadOnlyKernel(kernel);
this.kernelHeight = kernel.Rows;
this.kernelWidth = kernel.Columns;
this.kernelHeight = (uint)kernel.Rows;
this.kernelWidth = (uint)kernel.Columns;
this.rowOffsetMap = map.GetRowOffsetSpan();
this.columnOffsetMap = map.GetColumnOffsetSpan();
}
@ -34,10 +34,10 @@ internal readonly ref struct ConvolutionState
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ref int GetSampleRow(int row)
=> ref Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), (uint)(row * this.kernelHeight));
public readonly ref int GetSampleRow(uint row)
=> ref Unsafe.Add(ref MemoryMarshal.GetReference(this.rowOffsetMap), row * this.kernelHeight);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ref int GetSampleColumn(int column)
=> ref Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), (uint)(column * this.kernelWidth));
public readonly ref int GetSampleColumn(uint column)
=> ref Unsafe.Add(ref MemoryMarshal.GetReference(this.columnOffsetMap), column * this.kernelWidth);
}

14
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs

@ -98,8 +98,8 @@ internal class EdgeDetectorCompassProcessor<TPixel> : ImageProcessor<TPixel>
{
private readonly Buffer2D<TPixel> targetPixels;
private readonly Buffer2D<TPixel> passPixels;
private readonly int minX;
private readonly int maxX;
private readonly uint minX;
private readonly uint maxX;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperation(
@ -109,8 +109,8 @@ internal class EdgeDetectorCompassProcessor<TPixel> : ImageProcessor<TPixel>
{
this.targetPixels = targetPixels;
this.passPixels = passPixels;
this.minX = bounds.X;
this.maxX = bounds.Right;
this.minX = (uint)bounds.X;
this.maxX = (uint)bounds.Right;
}
/// <inheritdoc/>
@ -120,11 +120,11 @@ internal class EdgeDetectorCompassProcessor<TPixel> : ImageProcessor<TPixel>
ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.DangerousGetRowSpan(y));
ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.DangerousGetRowSpan(y));
for (int x = this.minX; x < this.maxX; x++)
for (nuint x = this.minX; x < this.maxX; x++)
{
// Grab the max components of the two pixels
ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, (uint)x);
ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, (uint)x);
ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, x);
ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, x);
var pixelValue = Vector4.Max(currentPassPixel.ToVector4(), currentTargetPixel.ToVector4());

18
src/ImageSharp/Processing/Processors/Convolution/ReadOnlyKernel.cs

@ -17,43 +17,43 @@ internal readonly ref struct ReadOnlyKernel
public ReadOnlyKernel(DenseMatrix<float> matrix)
{
this.Columns = matrix.Columns;
this.Rows = matrix.Rows;
this.Columns = (uint)matrix.Columns;
this.Rows = (uint)matrix.Rows;
this.values = matrix.Span;
}
public int Columns
public uint Columns
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public int Rows
public uint Rows
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public float this[int row, int column]
public float this[uint row, uint column]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
this.CheckCoordinates(row, column);
ref float vBase = ref MemoryMarshal.GetReference(this.values);
return Unsafe.Add(ref vBase, (uint)((row * this.Columns) + column));
return Unsafe.Add(ref vBase, (row * this.Columns) + column);
}
}
[Conditional("DEBUG")]
private void CheckCoordinates(int row, int column)
private void CheckCoordinates(uint row, uint column)
{
if (row < 0 || row >= this.Rows)
if (row >= this.Rows)
{
throw new ArgumentOutOfRangeException(nameof(row), row, $"{row} is outwith the matrix bounds.");
}
if (column < 0 || column >= this.Columns)
if (column >= this.Columns)
{
throw new ArgumentOutOfRangeException(nameof(column), column, $"{column} is outwith the matrix bounds.");
}

Loading…
Cancel
Save