Skip to content

Commit 3c3479e

Browse files
committed
Reduced intermediate allocations: Tga
1 parent 1d3ae0e commit 3c3479e

File tree

2 files changed

+25
-30
lines changed

2 files changed

+25
-30
lines changed

src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ namespace SixLabors.ImageSharp.Formats.Tga;
1717
/// </summary>
1818
internal sealed class TgaDecoderCore : IImageDecoderInternals
1919
{
20-
/// <summary>
21-
/// A scratch buffer to reduce allocations.
22-
/// </summary>
23-
private readonly byte[] scratchBuffer = new byte[4];
24-
2520
/// <summary>
2621
/// General configuration options.
2722
/// </summary>
@@ -407,6 +402,7 @@ private void ReadBgra16<TPixel>(BufferedReadStream stream, int width, int height
407402
bool invertX = InvertX(origin);
408403
using IMemoryOwner<byte> row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0);
409404
Span<byte> rowSpan = row.GetSpan();
405+
Span<byte> scratchBuffer = stackalloc byte[2];
410406

411407
for (int y = 0; y < height; y++)
412408
{
@@ -417,24 +413,24 @@ private void ReadBgra16<TPixel>(BufferedReadStream stream, int width, int height
417413
{
418414
for (int x = width - 1; x >= 0; x--)
419415
{
420-
int bytesRead = stream.Read(this.scratchBuffer, 0, 2);
416+
int bytesRead = stream.Read(scratchBuffer);
421417
if (bytesRead != 2)
422418
{
423419
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel row");
424420
}
425421

426422
if (!this.hasAlpha)
427423
{
428-
this.scratchBuffer[1] |= 1 << 7;
424+
scratchBuffer[1] |= 1 << 7;
429425
}
430426

431427
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
432428
{
433-
color.FromLa16(Unsafe.As<byte, La16>(ref MemoryMarshal.GetArrayDataReference(this.scratchBuffer)));
429+
color.FromLa16(Unsafe.As<byte, La16>(ref MemoryMarshal.GetReference(scratchBuffer)));
434430
}
435431
else
436432
{
437-
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref MemoryMarshal.GetArrayDataReference(this.scratchBuffer)));
433+
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref MemoryMarshal.GetReference(scratchBuffer)));
438434
}
439435

440436
pixelSpan[x] = color;
@@ -484,14 +480,15 @@ private void ReadBgr24<TPixel>(BufferedReadStream stream, int width, int height,
484480
bool invertX = InvertX(origin);
485481
if (invertX)
486482
{
483+
Span<byte> scratchBuffer = stackalloc byte[4];
487484
TPixel color = default;
488485
for (int y = 0; y < height; y++)
489486
{
490487
int newY = InvertY(y, height, origin);
491488
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
492489
for (int x = width - 1; x >= 0; x--)
493490
{
494-
this.ReadBgr24Pixel(stream, color, x, pixelSpan);
491+
ReadBgr24Pixel(stream, color, x, pixelSpan, scratchBuffer);
495492
}
496493
}
497494

@@ -558,6 +555,8 @@ private void ReadBgra32<TPixel>(BufferedReadStream stream, int width, int height
558555
return;
559556
}
560557

558+
Span<byte> scratchBuffer = stackalloc byte[4];
559+
561560
for (int y = 0; y < height; y++)
562561
{
563562
int newY = InvertY(y, height, origin);
@@ -566,14 +565,14 @@ private void ReadBgra32<TPixel>(BufferedReadStream stream, int width, int height
566565
{
567566
for (int x = width - 1; x >= 0; x--)
568567
{
569-
this.ReadBgra32Pixel(stream, x, color, pixelRow);
568+
this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer);
570569
}
571570
}
572571
else
573572
{
574573
for (int x = 0; x < width; x++)
575574
{
576-
this.ReadBgra32Pixel(stream, x, color, pixelRow);
575+
this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer);
577576
}
578577
}
579578
}
@@ -687,16 +686,16 @@ private static void ReadL8Pixel<TPixel>(BufferedReadStream stream, TPixel color,
687686
}
688687

689688
[MethodImpl(MethodImplOptions.AggressiveInlining)]
690-
private void ReadBgr24Pixel<TPixel>(BufferedReadStream stream, TPixel color, int x, Span<TPixel> pixelSpan)
689+
private static void ReadBgr24Pixel<TPixel>(BufferedReadStream stream, TPixel color, int x, Span<TPixel> pixelSpan, Span<byte> scratchBuffer)
691690
where TPixel : unmanaged, IPixel<TPixel>
692691
{
693-
int bytesRead = stream.Read(this.scratchBuffer, 0, 3);
692+
int bytesRead = stream.Read(scratchBuffer, 0, 3);
694693
if (bytesRead != 3)
695694
{
696695
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgr pixel");
697696
}
698697

699-
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref MemoryMarshal.GetArrayDataReference(this.scratchBuffer)));
698+
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref MemoryMarshal.GetReference(scratchBuffer)));
700699
pixelSpan[x] = color;
701700
}
702701

@@ -715,19 +714,19 @@ private void ReadBgr24Row<TPixel>(BufferedReadStream stream, int width, Buffer2D
715714
}
716715

717716
[MethodImpl(MethodImplOptions.AggressiveInlining)]
718-
private void ReadBgra32Pixel<TPixel>(BufferedReadStream stream, int x, TPixel color, Span<TPixel> pixelRow)
717+
private void ReadBgra32Pixel<TPixel>(BufferedReadStream stream, int x, TPixel color, Span<TPixel> pixelRow, Span<byte> scratchBuffer)
719718
where TPixel : unmanaged, IPixel<TPixel>
720719
{
721-
int bytesRead = stream.Read(this.scratchBuffer, 0, 4);
720+
int bytesRead = stream.Read(scratchBuffer, 0, 4);
722721
if (bytesRead != 4)
723722
{
724723
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgra pixel");
725724
}
726725

727726
Guard.NotNull(this.tgaMetadata);
728727

729-
byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : this.scratchBuffer[3];
730-
color.FromBgra32(new Bgra32(this.scratchBuffer[2], this.scratchBuffer[1], this.scratchBuffer[0], alpha));
728+
byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : scratchBuffer[3];
729+
color.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha));
731730
pixelRow[x] = color;
732731
}
733732

@@ -814,7 +813,7 @@ private static void ReadPalettedBgra32Pixel<TPixel>(BufferedReadStream stream, S
814813
private void UncompressRle(BufferedReadStream stream, int width, int height, Span<byte> buffer, int bytesPerPixel)
815814
{
816815
int uncompressedPixels = 0;
817-
Span<byte> pixel = this.scratchBuffer.AsSpan(0, bytesPerPixel);
816+
Span<byte> pixel = stackalloc byte[bytesPerPixel];
818817
int totalPixels = width * height;
819818
while (uncompressedPixels < totalPixels)
820819
{
@@ -825,7 +824,7 @@ private void UncompressRle(BufferedReadStream stream, int width, int height, Spa
825824
if (highBit == 1)
826825
{
827826
int runLength = runLengthByte & 127;
828-
int bytesRead = stream.Read(pixel, 0, bytesPerPixel);
827+
int bytesRead = stream.Read(pixel);
829828
if (bytesRead != bytesPerPixel)
830829
{
831830
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel from the stream");
@@ -845,7 +844,7 @@ private void UncompressRle(BufferedReadStream stream, int width, int height, Spa
845844
int bufferIdx = uncompressedPixels * bytesPerPixel;
846845
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
847846
{
848-
int bytesRead = stream.Read(pixel, 0, bytesPerPixel);
847+
int bytesRead = stream.Read(pixel);
849848
if (bytesRead != bytesPerPixel)
850849
{
851850
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel from the stream");

src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals
2222
/// </summary>
2323
private readonly MemoryAllocator memoryAllocator;
2424

25-
/// <summary>
26-
/// Reusable buffer for writing data.
27-
/// </summary>
28-
private readonly byte[] buffer = new byte[2];
29-
3025
/// <summary>
3126
/// The color depth, in number of bits per pixel.
3227
/// </summary>
@@ -221,9 +216,10 @@ private void WritePixel<TPixel>(Stream stream, TPixel currentPixel, Rgba32 color
221216

222217
case TgaBitsPerPixel.Pixel16:
223218
Bgra5551 bgra5551 = new(color.ToVector4());
224-
BinaryPrimitives.WriteInt16LittleEndian(this.buffer, (short)bgra5551.PackedValue);
225-
stream.WriteByte(this.buffer[0]);
226-
stream.WriteByte(this.buffer[1]);
219+
Span<byte> buffer = stackalloc byte[2];
220+
BinaryPrimitives.WriteInt16LittleEndian(buffer, (short)bgra5551.PackedValue);
221+
stream.WriteByte(buffer[0]);
222+
stream.WriteByte(buffer[1]);
227223

228224
break;
229225

0 commit comments

Comments
 (0)