Skip to content

Commit 6619809

Browse files
committed
Merge remote-tracking branch 'upstream/master' into pgm-support
2 parents efece70 + ee83e99 commit 6619809

File tree

188 files changed

+5885
-1794
lines changed

Some content is hidden

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

188 files changed

+5885
-1794
lines changed

Directory.Build.props

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
<PropertyGroup>
1414
<!-- This MUST be defined before importing props. -->
1515
<SixLaborsSolutionDirectory>$(MSBuildThisFileDirectory)</SixLaborsSolutionDirectory>
16+
17+
<!-- For some reason Debug-InnerLoop doesn't define DEBUG by default. -->
18+
<DefineConstants Condition="'$(Configuration)' == 'Debug-InnerLoop'">$(DefineConstants);DEBUG</DefineConstants>
1619
</PropertyGroup>
1720

1821
<!-- Import the shared global .props file -->
@@ -30,5 +33,4 @@
3033
<PropertyGroup Condition="$(Configuration.StartsWith('Release')) == true">
3134
<Optimize>true</Optimize>
3235
</PropertyGroup>
33-
3436
</Project>

src/ImageSharp/Advanced/AdvancedImageExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public static IMemoryGroup<TPixel> GetPixelMemoryGroup<TPixel>(this Image<TPixel
143143
/// <param name="source">The source.</param>
144144
/// <param name="rowIndex">The row.</param>
145145
/// <returns>The <see cref="Span{TPixel}"/></returns>
146-
public static Memory<TPixel> GetPixelRowMemory<TPixel>(this ImageFrame<TPixel> source, int rowIndex)
146+
public static Memory<TPixel> DangerousGetPixelRowMemory<TPixel>(this ImageFrame<TPixel> source, int rowIndex)
147147
where TPixel : unmanaged, IPixel<TPixel>
148148
{
149149
Guard.NotNull(source, nameof(source));
@@ -161,7 +161,7 @@ public static Memory<TPixel> GetPixelRowMemory<TPixel>(this ImageFrame<TPixel> s
161161
/// <param name="source">The source.</param>
162162
/// <param name="rowIndex">The row.</param>
163163
/// <returns>The <see cref="Span{TPixel}"/></returns>
164-
public static Memory<TPixel> GetPixelRowMemory<TPixel>(this Image<TPixel> source, int rowIndex)
164+
public static Memory<TPixel> DangerousGetPixelRowMemory<TPixel>(this Image<TPixel> source, int rowIndex)
165165
where TPixel : unmanaged, IPixel<TPixel>
166166
{
167167
Guard.NotNull(source, nameof(source));

src/ImageSharp/Advanced/AotCompilerTools.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ private static void AotCompileDither<TPixel, TDither>()
534534
private static void AotCompileMemoryManagers<TPixel>()
535535
where TPixel : unmanaged, IPixel<TPixel>
536536
{
537-
AotCompileMemoryManager<TPixel, ArrayPoolMemoryAllocator>();
537+
AotCompileMemoryManager<TPixel, UniformUnmanagedMemoryPoolMemoryAllocator>();
538538
AotCompileMemoryManager<TPixel, SimpleGcMemoryAllocator>();
539539
}
540540

src/ImageSharp/Common/Helpers/DebugGuard.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ public static void IsTrue(bool target, string message)
2626
}
2727
}
2828

29+
/// <summary>
30+
/// Verifies whether a condition (indicating disposed state) is met, throwing an ObjectDisposedException if it's true.
31+
/// </summary>
32+
/// <param name="isDisposed">Whether the object is disposed.</param>
33+
/// <param name="objectName">The name of the object.</param>
34+
[Conditional("DEBUG")]
35+
public static void NotDisposed(bool isDisposed, string objectName)
36+
{
37+
if (isDisposed)
38+
{
39+
throw new ObjectDisposedException(objectName);
40+
}
41+
}
42+
2943
/// <summary>
3044
/// Verifies, that the target span is of same size than the 'other' span.
3145
/// </summary>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ internal interface IComponentShuffle
2828
/// </summary>
2929
/// <param name="source">The source span of bytes.</param>
3030
/// <param name="dest">The destination span of bytes.</param>
31+
/// <remarks>
32+
/// Implementation can assume that source.Length is less or equal than dest.Length.
33+
/// Loops should iterate using source.Length.
34+
/// </remarks>
3135
void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest);
3236
}
3337

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public static void Shuffle3<TShuffle>(
7777
TShuffle shuffle)
7878
where TShuffle : struct, IShuffle3
7979
{
80+
// Source length should be smaller than dest length, and divisible by 3.
8081
VerifyShuffle3SpanInput(source, dest);
8182

8283
#if SUPPORTS_RUNTIME_INTRINSICS
@@ -182,9 +183,9 @@ private static void VerifyShuffle3SpanInput<T>(ReadOnlySpan<T> source, Span<T> d
182183
where T : struct
183184
{
184185
DebugGuard.IsTrue(
185-
source.Length == dest.Length,
186+
source.Length <= dest.Length,
186187
nameof(source),
187-
"Input spans must be of same length!");
188+
"Source should fit into dest!");
188189

189190
DebugGuard.IsTrue(
190191
source.Length % 3 == 0,

src/ImageSharp/Configuration.cs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ public sealed class Configuration
2727
/// <summary>
2828
/// A lazily initialized configuration default instance.
2929
/// </summary>
30-
private static readonly Lazy<Configuration> Lazy = new Lazy<Configuration>(CreateDefaultInstance);
30+
private static readonly Lazy<Configuration> Lazy = new(CreateDefaultInstance);
3131
private const int DefaultStreamProcessingBufferSize = 8096;
3232
private int streamProcessingBufferSize = DefaultStreamProcessingBufferSize;
3333
private int maxDegreeOfParallelism = Environment.ProcessorCount;
34+
private MemoryAllocator memoryAllocator = MemoryAllocator.Default;
3435

3536
/// <summary>
3637
/// Initializes a new instance of the <see cref="Configuration" /> class.
@@ -96,6 +97,14 @@ public int StreamProcessingBufferSize
9697
}
9798
}
9899

100+
/// <summary>
101+
/// Gets or sets a value indicating whether to force image buffers to be contiguous whenever possible.
102+
/// </summary>
103+
/// <remarks>
104+
/// Contiguous allocations are not possible, if the image needs a buffer larger than <see cref="int.MaxValue"/>.
105+
/// </remarks>
106+
public bool PreferContiguousImageBuffers { get; set; }
107+
99108
/// <summary>
100109
/// Gets a set of properties for the Configuration.
101110
/// </summary>
@@ -118,9 +127,31 @@ public int StreamProcessingBufferSize
118127
public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager();
119128

120129
/// <summary>
121-
/// Gets or sets the <see cref="MemoryAllocator"/> that is currently in use.
130+
/// Gets or sets the <see cref="ImageSharp.Memory.MemoryAllocator"/> that is currently in use.
131+
/// Defaults to <see cref="ImageSharp.Memory.MemoryAllocator.Default"/>.
132+
/// <para />
133+
/// Allocators are expensive, so it is strongly recommended to use only one busy instance per process.
134+
/// In case you need to customize it, you can ensure this by changing
122135
/// </summary>
123-
public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault();
136+
/// <remarks>
137+
/// It's possible to reduce allocator footprint by assigning a custom instance created with
138+
/// <see cref="Memory.MemoryAllocator.Create(MemoryAllocatorOptions)"/>, but note that since the default pooling
139+
/// allocators are expensive, it is strictly recommended to use a single process-wide allocator.
140+
/// You can ensure this by altering the allocator of <see cref="Default"/>, or by implementing custom application logic that
141+
/// manages allocator lifetime.
142+
/// <para />
143+
/// If an allocator has to be dropped for some reason, <see cref="Memory.MemoryAllocator.ReleaseRetainedResources"/>
144+
/// shall be invoked after disposing all associated <see cref="Image"/> instances.
145+
/// </remarks>
146+
public MemoryAllocator MemoryAllocator
147+
{
148+
get => this.memoryAllocator;
149+
set
150+
{
151+
Guard.NotNull(value, nameof(this.MemoryAllocator));
152+
this.memoryAllocator = value;
153+
}
154+
}
124155

125156
/// <summary>
126157
/// Gets the maximum header size of all the formats.
@@ -166,7 +197,7 @@ public void Configure(IConfigurationModule configuration)
166197
MaxDegreeOfParallelism = this.MaxDegreeOfParallelism,
167198
StreamProcessingBufferSize = this.StreamProcessingBufferSize,
168199
ImageFormatsManager = this.ImageFormatsManager,
169-
MemoryAllocator = this.MemoryAllocator,
200+
memoryAllocator = this.memoryAllocator,
170201
ImageOperationsProvider = this.ImageOperationsProvider,
171202
ReadOrigin = this.ReadOrigin,
172203
FileSystem = this.FileSystem,

src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ private void ReadRle<TPixel>(BmpCompression compression, Buffer2D<TPixel> pixels
306306
int newY = Invert(y, height, inverted);
307307
int rowStartIdx = y * width;
308308
Span<byte> bufferRow = bufferSpan.Slice(rowStartIdx, width);
309-
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
309+
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(newY);
310310

311311
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
312312
if (rowHasUndefinedPixels)
@@ -377,7 +377,7 @@ private void ReadRle24<TPixel>(Buffer2D<TPixel> pixels, int width, int height, b
377377
for (int y = 0; y < height; y++)
378378
{
379379
int newY = Invert(y, height, inverted);
380-
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
380+
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(newY);
381381
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
382382
if (rowHasUndefinedPixels)
383383
{
@@ -826,7 +826,7 @@ private void ReadRgbPalette<TPixel>(Buffer2D<TPixel> pixels, byte[] colors, int
826826
int newY = Invert(y, height, inverted);
827827
this.stream.Read(rowSpan);
828828
int offset = 0;
829-
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
829+
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(newY);
830830

831831
for (int x = 0; x < arrayWidth; x++)
832832
{
@@ -878,7 +878,7 @@ private void ReadRgb16<TPixel>(Buffer2D<TPixel> pixels, int width, int height, b
878878
{
879879
this.stream.Read(bufferSpan);
880880
int newY = Invert(y, height, inverted);
881-
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
881+
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(newY);
882882

883883
int offset = 0;
884884
for (int x = 0; x < width; x++)
@@ -933,7 +933,7 @@ private void ReadRgb24<TPixel>(Buffer2D<TPixel> pixels, int width, int height, b
933933
{
934934
this.stream.Read(rowSpan);
935935
int newY = Invert(y, height, inverted);
936-
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
936+
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
937937
PixelOperations<TPixel>.Instance.FromBgr24Bytes(
938938
this.Configuration,
939939
rowSpan,
@@ -961,7 +961,7 @@ private void ReadRgb32Fast<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
961961
{
962962
this.stream.Read(rowSpan);
963963
int newY = Invert(y, height, inverted);
964-
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
964+
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
965965
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
966966
this.Configuration,
967967
rowSpan,
@@ -1031,7 +1031,7 @@ private void ReadRgb32Slow<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
10311031
this.stream.Read(rowSpan);
10321032

10331033
int newY = Invert(y, height, inverted);
1034-
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
1034+
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
10351035

10361036
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
10371037
this.Configuration,
@@ -1054,7 +1054,7 @@ private void ReadRgb32Slow<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
10541054
width);
10551055

10561056
int newY = Invert(y, height, inverted);
1057-
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
1057+
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
10581058

10591059
for (int x = 0; x < width; x++)
10601060
{
@@ -1109,7 +1109,7 @@ private void ReadRgb32BitFields<TPixel>(Buffer2D<TPixel> pixels, int width, int
11091109
{
11101110
this.stream.Read(bufferSpan);
11111111
int newY = Invert(y, height, inverted);
1112-
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
1112+
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(newY);
11131113

11141114
int offset = 0;
11151115
for (int x = 0; x < width; x++)

src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ private void Write32Bit<TPixel>(Stream stream, Buffer2D<TPixel> pixels)
274274

275275
for (int y = pixels.Height - 1; y >= 0; y--)
276276
{
277-
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
277+
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(y);
278278
PixelOperations<TPixel>.Instance.ToBgra32Bytes(
279279
this.configuration,
280280
pixelSpan,
@@ -300,7 +300,7 @@ private void Write24Bit<TPixel>(Stream stream, Buffer2D<TPixel> pixels)
300300

301301
for (int y = pixels.Height - 1; y >= 0; y--)
302302
{
303-
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
303+
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(y);
304304
PixelOperations<TPixel>.Instance.ToBgr24Bytes(
305305
this.configuration,
306306
pixelSpan,
@@ -326,7 +326,7 @@ private void Write16Bit<TPixel>(Stream stream, Buffer2D<TPixel> pixels)
326326

327327
for (int y = pixels.Height - 1; y >= 0; y--)
328328
{
329-
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
329+
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(y);
330330

331331
PixelOperations<TPixel>.Instance.ToBgra5551Bytes(
332332
this.configuration,
@@ -379,7 +379,7 @@ private void Write8BitColor<TPixel>(Stream stream, ImageFrame<TPixel> image, Spa
379379

380380
for (int y = image.Height - 1; y >= 0; y--)
381381
{
382-
ReadOnlySpan<byte> pixelSpan = quantized.GetPixelRowSpan(y);
382+
ReadOnlySpan<byte> pixelSpan = quantized.DangerousGetRowSpan(y);
383383
stream.Write(pixelSpan);
384384

385385
for (int i = 0; i < this.padding; i++)
@@ -413,10 +413,10 @@ private void Write8BitGray<TPixel>(Stream stream, ImageFrame<TPixel> image, Span
413413
}
414414

415415
stream.Write(colorPalette);
416-
416+
Buffer2D<TPixel> imageBuffer = image.PixelBuffer;
417417
for (int y = image.Height - 1; y >= 0; y--)
418418
{
419-
ReadOnlySpan<TPixel> inputPixelRow = image.GetPixelRowSpan(y);
419+
ReadOnlySpan<TPixel> inputPixelRow = imageBuffer.DangerousGetRowSpan(y);
420420
ReadOnlySpan<byte> outputPixelRow = MemoryMarshal.AsBytes(inputPixelRow);
421421
stream.Write(outputPixelRow);
422422

@@ -447,11 +447,11 @@ private void Write4BitColor<TPixel>(Stream stream, ImageFrame<TPixel> image)
447447
ReadOnlySpan<TPixel> quantizedColorPalette = quantized.Palette.Span;
448448
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
449449

450-
ReadOnlySpan<byte> pixelRowSpan = quantized.GetPixelRowSpan(0);
450+
ReadOnlySpan<byte> pixelRowSpan = quantized.DangerousGetRowSpan(0);
451451
int rowPadding = pixelRowSpan.Length % 2 != 0 ? this.padding - 1 : this.padding;
452452
for (int y = image.Height - 1; y >= 0; y--)
453453
{
454-
pixelRowSpan = quantized.GetPixelRowSpan(y);
454+
pixelRowSpan = quantized.DangerousGetRowSpan(y);
455455

456456
int endIdx = pixelRowSpan.Length % 2 == 0 ? pixelRowSpan.Length : pixelRowSpan.Length - 1;
457457
for (int i = 0; i < endIdx; i += 2)
@@ -491,11 +491,11 @@ private void Write1BitColor<TPixel>(Stream stream, ImageFrame<TPixel> image)
491491
ReadOnlySpan<TPixel> quantizedColorPalette = quantized.Palette.Span;
492492
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
493493

494-
ReadOnlySpan<byte> quantizedPixelRow = quantized.GetPixelRowSpan(0);
494+
ReadOnlySpan<byte> quantizedPixelRow = quantized.DangerousGetRowSpan(0);
495495
int rowPadding = quantizedPixelRow.Length % 8 != 0 ? this.padding - 1 : this.padding;
496496
for (int y = image.Height - 1; y >= 0; y--)
497497
{
498-
quantizedPixelRow = quantized.GetPixelRowSpan(y);
498+
quantizedPixelRow = quantized.DangerousGetRowSpan(y);
499499

500500
int endIdx = quantizedPixelRow.Length % 8 == 0 ? quantizedPixelRow.Length : quantizedPixelRow.Length - 8;
501501
for (int i = 0; i < endIdx; i += 8)

src/ImageSharp/Formats/Gif/GifDecoderCore.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPi
445445

446446
for (int y = descriptorTop; y < descriptorBottom && y < imageHeight; y++)
447447
{
448-
ref byte indicesRowRef = ref MemoryMarshal.GetReference(indices.GetRowSpan(y - descriptorTop));
448+
ref byte indicesRowRef = ref MemoryMarshal.GetReference(indices.DangerousGetRowSpan(y - descriptorTop));
449449

450450
// Check if this image is interlaced.
451451
int writeY; // the target y offset to write to
@@ -481,7 +481,7 @@ private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPi
481481
writeY = y;
482482
}
483483

484-
ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY));
484+
ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.PixelBuffer.DangerousGetRowSpan(writeY));
485485

486486
if (!transFlag)
487487
{

0 commit comments

Comments
 (0)