Skip to content

Commit d617907

Browse files
Merge branch 'main' into vector-constants
2 parents 97ac149 + b6736b0 commit d617907

File tree

75 files changed

+1378
-803
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1378
-803
lines changed

src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public static float Compress(float channel)
167167
[MethodImpl(MethodImplOptions.AggressiveInlining)]
168168
private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
169169
{
170-
fixed (float* tablePointer = &table[0])
170+
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
171171
{
172172
var scale = Vector256.Create((float)Scale);
173173
Vector256<float> zero = Vector256<float>.Zero;
@@ -199,7 +199,7 @@ private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
199199
[MethodImpl(MethodImplOptions.AggressiveInlining)]
200200
private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table)
201201
{
202-
fixed (float* tablePointer = &table[0])
202+
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
203203
{
204204
Vector4 zero = Vector4.Zero;
205205
var scale = new Vector4(Scale);

src/ImageSharp/Common/Helpers/Numerics.cs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,4 +949,94 @@ public static int EvenReduceSum(Vector256<int> accumulator)
949949
[MethodImpl(MethodImplOptions.AggressiveInlining)]
950950
public static bool IsOutOfRange(int value, int min, int max)
951951
=> (uint)(value - min) > (uint)(max - min);
952+
953+
/// <summary>
954+
/// Gets the count of vectors that safely fit into the given span.
955+
/// </summary>
956+
/// <typeparam name="TVector">The type of the vector.</typeparam>
957+
/// <param name="span">The given span.</param>
958+
/// <returns>Count of vectors that safely fit into the span.</returns>
959+
public static nuint VectorCount<TVector>(this Span<byte> span)
960+
where TVector : struct
961+
=> (uint)span.Length / (uint)Vector<TVector>.Count;
962+
963+
/// <summary>
964+
/// Gets the count of vectors that safely fit into the given span.
965+
/// </summary>
966+
/// <typeparam name="TVector">The type of the vector.</typeparam>
967+
/// <param name="span">The given span.</param>
968+
/// <returns>Count of vectors that safely fit into the span.</returns>
969+
public static nuint Vector128Count<TVector>(this Span<byte> span)
970+
where TVector : struct
971+
=> (uint)span.Length / (uint)Vector128<TVector>.Count;
972+
973+
/// <summary>
974+
/// Gets the count of vectors that safely fit into the given span.
975+
/// </summary>
976+
/// <typeparam name="TVector">The type of the vector.</typeparam>
977+
/// <param name="span">The given span.</param>
978+
/// <returns>Count of vectors that safely fit into the span.</returns>
979+
public static nuint Vector128Count<TVector>(this ReadOnlySpan<byte> span)
980+
where TVector : struct
981+
=> (uint)span.Length / (uint)Vector128<TVector>.Count;
982+
983+
/// <summary>
984+
/// Gets the count of vectors that safely fit into the given span.
985+
/// </summary>
986+
/// <typeparam name="TVector">The type of the vector.</typeparam>
987+
/// <param name="span">The given span.</param>
988+
/// <returns>Count of vectors that safely fit into the span.</returns>
989+
public static nuint Vector256Count<TVector>(this Span<byte> span)
990+
where TVector : struct
991+
=> (uint)span.Length / (uint)Vector256<TVector>.Count;
992+
993+
/// <summary>
994+
/// Gets the count of vectors that safely fit into the given span.
995+
/// </summary>
996+
/// <typeparam name="TVector">The type of the vector.</typeparam>
997+
/// <param name="span">The given span.</param>
998+
/// <returns>Count of vectors that safely fit into the span.</returns>
999+
public static nuint Vector256Count<TVector>(this ReadOnlySpan<byte> span)
1000+
where TVector : struct
1001+
=> (uint)span.Length / (uint)Vector256<TVector>.Count;
1002+
1003+
/// <summary>
1004+
/// Gets the count of vectors that safely fit into the given span.
1005+
/// </summary>
1006+
/// <typeparam name="TVector">The type of the vector.</typeparam>
1007+
/// <param name="span">The given span.</param>
1008+
/// <returns>Count of vectors that safely fit into the span.</returns>
1009+
public static nuint VectorCount<TVector>(this Span<float> span)
1010+
where TVector : struct
1011+
=> (uint)span.Length / (uint)Vector<TVector>.Count;
1012+
1013+
/// <summary>
1014+
/// Gets the count of vectors that safely fit into the given span.
1015+
/// </summary>
1016+
/// <typeparam name="TVector">The type of the vector.</typeparam>
1017+
/// <param name="span">The given span.</param>
1018+
/// <returns>Count of vectors that safely fit into the span.</returns>
1019+
public static nuint Vector128Count<TVector>(this Span<float> span)
1020+
where TVector : struct
1021+
=> (uint)span.Length / (uint)Vector128<TVector>.Count;
1022+
1023+
/// <summary>
1024+
/// Gets the count of vectors that safely fit into the given span.
1025+
/// </summary>
1026+
/// <typeparam name="TVector">The type of the vector.</typeparam>
1027+
/// <param name="span">The given span.</param>
1028+
/// <returns>Count of vectors that safely fit into the span.</returns>
1029+
public static nuint Vector256Count<TVector>(this Span<float> span)
1030+
where TVector : struct
1031+
=> (uint)span.Length / (uint)Vector256<TVector>.Count;
1032+
1033+
/// <summary>
1034+
/// Gets the count of vectors that safely fit into length.
1035+
/// </summary>
1036+
/// <typeparam name="TVector">The type of the vector.</typeparam>
1037+
/// <param name="length">The given length.</param>
1038+
/// <returns>Count of vectors that safely fit into the length.</returns>
1039+
public static nuint Vector256Count<TVector>(int length)
1040+
where TVector : struct
1041+
=> (uint)length / (uint)Vector256<TVector>.Count;
9521042
}

src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ internal static void ByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float
9797
{
9898
VerifySpanInput(source, dest, Vector<byte>.Count);
9999

100-
nuint n = (uint)dest.Length / (uint)Vector<byte>.Count;
100+
nuint n = dest.VectorCount<byte>();
101101

102102
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(source));
103103
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dest));
@@ -132,7 +132,7 @@ internal static void NormalizedFloatToByteSaturate(
132132
{
133133
VerifySpanInput(source, dest, Vector<byte>.Count);
134134

135-
nuint n = (uint)dest.Length / (uint)Vector<byte>.Count;
135+
nuint n = dest.VectorCount<byte>();
136136

137137
ref Vector<float> sourceBase =
138138
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));

src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ private static void Shuffle4(
227227
ref Vector256<float> destBase =
228228
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(dest));
229229

230-
nint n = (nint)((uint)dest.Length / (uint)Vector256<float>.Count);
230+
nint n = (nint)dest.Vector256Count<float>();
231231
nint m = Numerics.Modulo4(n);
232232
nint u = n - m;
233233

@@ -395,7 +395,7 @@ private static void Shuffle3(
395395
ref Vector128<byte> destBase =
396396
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
397397

398-
nuint n = (uint)source.Length / (uint)Vector128<byte>.Count;
398+
nuint n = source.Vector128Count<byte>();
399399

400400
for (nuint i = 0; i < n; i += 3)
401401
{
@@ -457,7 +457,7 @@ private static void Pad3Shuffle4(
457457
ref Vector128<byte> destBase =
458458
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
459459

460-
nuint n = (uint)source.Length / (uint)Vector128<byte>.Count;
460+
nuint n = source.Vector128Count<byte>();
461461

462462
for (nuint i = 0, j = 0; i < n; i += 3, j += 4)
463463
{
@@ -500,7 +500,7 @@ private static void Shuffle4Slice3(
500500
ref Vector128<byte> destBase =
501501
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
502502

503-
nuint n = (uint)source.Length / (uint)Vector128<byte>.Count;
503+
nuint n = source.Vector128Count<byte>();
504504

505505
for (nuint i = 0, j = 0; i < n; i += 4, j += 3)
506506
{
@@ -680,7 +680,7 @@ internal static unsafe void ByteToNormalizedFloat(
680680
{
681681
VerifySpanInput(source, dest, Vector256<byte>.Count);
682682

683-
nuint n = (uint)dest.Length / (uint)Vector256<byte>.Count;
683+
nuint n = dest.Vector256Count<byte>();
684684

685685
ref Vector256<float> destBase =
686686
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(dest));
@@ -713,7 +713,7 @@ internal static unsafe void ByteToNormalizedFloat(
713713
// Sse
714714
VerifySpanInput(source, dest, Vector128<byte>.Count);
715715

716-
nuint n = (uint)dest.Length / (uint)Vector128<byte>.Count;
716+
nuint n = dest.Vector128Count<byte>();
717717

718718
ref Vector128<float> destBase =
719719
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(dest));
@@ -812,7 +812,7 @@ internal static void NormalizedFloatToByteSaturate(
812812
{
813813
VerifySpanInput(source, dest, Vector256<byte>.Count);
814814

815-
nuint n = (uint)dest.Length / (uint)Vector256<byte>.Count;
815+
nuint n = dest.Vector256Count<byte>();
816816

817817
ref Vector256<float> sourceBase =
818818
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(source));
@@ -850,7 +850,7 @@ internal static void NormalizedFloatToByteSaturate(
850850
// Sse
851851
VerifySpanInput(source, dest, Vector128<byte>.Count);
852852

853-
nuint n = (uint)dest.Length / (uint)Vector128<byte>.Count;
853+
nuint n = dest.Vector128Count<byte>();
854854

855855
ref Vector128<float> sourceBase =
856856
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(source));
@@ -893,7 +893,7 @@ internal static void PackFromRgbPlanesAvx2Reduce(
893893
ref Vector256<byte> bBase = ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(blueChannel));
894894
ref byte dBase = ref Unsafe.As<Rgb24, byte>(ref MemoryMarshal.GetReference(destination));
895895

896-
nuint count = (uint)redChannel.Length / (uint)Vector256<byte>.Count;
896+
nuint count = redChannel.Vector256Count<byte>();
897897

898898
Vector256<uint> control1 = PermuteMaskEvenOdd8x32();
899899

@@ -963,7 +963,7 @@ internal static void PackFromRgbPlanesAvx2Reduce(
963963
ref Vector256<byte> bBase = ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(blueChannel));
964964
ref Vector256<byte> dBase = ref Unsafe.As<Rgba32, Vector256<byte>>(ref MemoryMarshal.GetReference(destination));
965965

966-
nuint count = (uint)redChannel.Length / (uint)Vector256<byte>.Count;
966+
nuint count = redChannel.Vector256Count<byte>();
967967
Vector256<uint> control1 = PermuteMaskEvenOdd8x32();
968968
Vector256<byte> a = Vector256.Create((byte)255);
969969

src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ private void ReadRle24<TPixel>(BufferedReadStream stream, Buffer2D<TPixel> pixel
453453
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
454454
private void UncompressRle4(BufferedReadStream stream, int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
455455
{
456+
Span<byte> scratchBuffer = stackalloc byte[128];
456457
Span<byte> cmd = stackalloc byte[2];
457458
int count = 0;
458459

@@ -491,9 +492,9 @@ private void UncompressRle4(BufferedReadStream stream, int w, Span<byte> buffer,
491492
int max = cmd[1];
492493
int bytesToRead = (int)(((uint)max + 1) / 2);
493494

494-
byte[] run = new byte[bytesToRead];
495+
Span<byte> run = bytesToRead <= 128 ? scratchBuffer.Slice(0, bytesToRead) : new byte[bytesToRead];
495496

496-
stream.Read(run, 0, run.Length);
497+
stream.Read(run);
497498

498499
int idx = 0;
499500
for (int i = 0; i < max; i++)
@@ -559,6 +560,7 @@ private void UncompressRle4(BufferedReadStream stream, int w, Span<byte> buffer,
559560
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
560561
private void UncompressRle8(BufferedReadStream stream, int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
561562
{
563+
Span<byte> scratchBuffer = stackalloc byte[128];
562564
Span<byte> cmd = stackalloc byte[2];
563565
int count = 0;
564566

@@ -596,13 +598,13 @@ private void UncompressRle8(BufferedReadStream stream, int w, Span<byte> buffer,
596598
// Take this number of bytes from the stream as uncompressed data.
597599
int length = cmd[1];
598600

599-
byte[] run = new byte[length];
601+
Span<byte> run = length <= 128 ? scratchBuffer.Slice(0, length) : new byte[length];
600602

601-
stream.Read(run, 0, run.Length);
603+
stream.Read(run);
602604

603-
run.AsSpan().CopyTo(buffer[count..]);
605+
run.CopyTo(buffer[count..]);
604606

605-
count += run.Length;
607+
count += length;
606608

607609
// Absolute mode data is aligned to two-byte word-boundary.
608610
int padding = length & 1;
@@ -639,6 +641,7 @@ private void UncompressRle8(BufferedReadStream stream, int w, Span<byte> buffer,
639641
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
640642
private void UncompressRle24(BufferedReadStream stream, int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
641643
{
644+
Span<byte> scratchBuffer = stackalloc byte[128];
642645
Span<byte> cmd = stackalloc byte[2];
643646
int uncompressedPixels = 0;
644647

@@ -675,17 +678,18 @@ private void UncompressRle24(BufferedReadStream stream, int w, Span<byte> buffer
675678
// If the second byte > 2, we are in 'absolute mode'.
676679
// Take this number of bytes from the stream as uncompressed data.
677680
int length = cmd[1];
681+
int length3 = length * 3;
678682

679-
byte[] run = new byte[length * 3];
683+
Span<byte> run = length3 <= 128 ? scratchBuffer.Slice(0, length3) : new byte[length3];
680684

681-
stream.Read(run, 0, run.Length);
685+
stream.Read(run);
682686

683-
run.AsSpan().CopyTo(buffer[(uncompressedPixels * 3)..]);
687+
run.CopyTo(buffer[(uncompressedPixels * 3)..]);
684688

685689
uncompressedPixels += length;
686690

687691
// Absolute mode data is aligned to two-byte word-boundary.
688-
int padding = run.Length & 1;
692+
int padding = length3 & 1;
689693

690694
stream.Skip(padding);
691695

@@ -1286,18 +1290,18 @@ private void ReadInfoHeader(BufferedReadStream stream)
12861290
// color masks for each color channel follow the info header.
12871291
if (this.infoHeader.Compression == BmpCompression.BitFields)
12881292
{
1289-
byte[] bitfieldsBuffer = new byte[12];
1290-
stream.Read(bitfieldsBuffer, 0, 12);
1291-
Span<byte> data = bitfieldsBuffer.AsSpan();
1293+
Span<byte> bitfieldsBuffer = stackalloc byte[12];
1294+
stream.Read(bitfieldsBuffer);
1295+
Span<byte> data = bitfieldsBuffer;
12921296
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
12931297
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
12941298
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
12951299
}
12961300
else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS)
12971301
{
1298-
byte[] bitfieldsBuffer = new byte[16];
1299-
stream.Read(bitfieldsBuffer, 0, 16);
1300-
Span<byte> data = bitfieldsBuffer.AsSpan();
1302+
Span<byte> bitfieldsBuffer = stackalloc byte[16];
1303+
stream.Read(bitfieldsBuffer);
1304+
Span<byte> data = bitfieldsBuffer;
13011305
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
13021306
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
13031307
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
@@ -1470,7 +1474,7 @@ private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out b
14701474
{
14711475
// Usually the color palette is 1024 byte (256 colors * 4), but the documentation does not mention a size limit.
14721476
// Make sure, that we will not read pass the bitmap offset (starting position of image data).
1473-
if ((stream.Position + colorMapSizeBytes) > this.fileHeader.Offset)
1477+
if (stream.Position > this.fileHeader.Offset - colorMapSizeBytes)
14741478
{
14751479
BmpThrowHelper.ThrowInvalidImageContentException(
14761480
$"Reading the color map would read beyond the bitmap offset. Either the color map size of '{colorMapSizeBytes}' is invalid or the bitmap offset.");

0 commit comments

Comments
 (0)