From 2e6ac845ed3f5c290c4590c966614bd1a272724b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Aug 2020 15:14:08 +0100 Subject: [PATCH 1/5] Encode then decode. --- src/ImageSharp/Advanced/AotCompilerTools.cs | 73 +++++++++------------ 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index 2ea456286f..dc0c59e7bf 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -3,12 +3,12 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -27,14 +27,14 @@ internal static class AotCompilerTools { static AotCompilerTools() { - System.Runtime.CompilerServices.Unsafe.SizeOf(); - System.Runtime.CompilerServices.Unsafe.SizeOf(); - System.Runtime.CompilerServices.Unsafe.SizeOf(); - System.Runtime.CompilerServices.Unsafe.SizeOf(); - System.Runtime.CompilerServices.Unsafe.SizeOf(); - System.Runtime.CompilerServices.Unsafe.SizeOf(); - System.Runtime.CompilerServices.Unsafe.SizeOf(); - System.Runtime.CompilerServices.Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); } /// @@ -90,10 +90,7 @@ private static void Seed() Unsafe.SizeOf(); - AotCodec(new Formats.Png.PngDecoder(), new Formats.Png.PngEncoder()); - AotCodec(new Formats.Bmp.BmpDecoder(), new Formats.Bmp.BmpEncoder()); - AotCodec(new Formats.Gif.GifDecoder(), new Formats.Gif.GifEncoder()); - AotCodec(new Formats.Jpeg.JpegDecoder(), new Formats.Jpeg.JpegEncoder()); + AotCodecs(); // TODO: Do the discovery work to figure out what works and what doesn't. } @@ -112,11 +109,9 @@ private static void Seed() private static void AotCompileOctreeQuantizer() where TPixel : unmanaged, IPixel { - using (var test = new OctreeQuantizer(Configuration.Default, new OctreeQuantizer().Options)) - { - var frame = new ImageFrame(Configuration.Default, 1, 1); - test.QuantizeFrame(frame, frame.Bounds()); - } + using var test = new OctreeQuantizer(Configuration.Default, new OctreeQuantizer().Options); + var frame = new ImageFrame(Configuration.Default, 1, 1); + test.QuantizeFrame(frame, frame.Bounds()); } /// @@ -126,11 +121,9 @@ private static void AotCompileOctreeQuantizer() private static void AotCompileWuQuantizer() where TPixel : unmanaged, IPixel { - using (var test = new WuQuantizer(Configuration.Default, new WuQuantizer().Options)) - { - var frame = new ImageFrame(Configuration.Default, 1, 1); - test.QuantizeFrame(frame, frame.Bounds()); - } + using var test = new WuQuantizer(Configuration.Default, new WuQuantizer().Options); + var frame = new ImageFrame(Configuration.Default, 1, 1); + test.QuantizeFrame(frame, frame.Bounds()); } /// @@ -140,11 +133,9 @@ private static void AotCompileWuQuantizer() private static void AotCompilePaletteQuantizer() where TPixel : unmanaged, IPixel { - using (var test = (PaletteQuantizer)new PaletteQuantizer(Array.Empty()).CreatePixelSpecificQuantizer(Configuration.Default)) - { - var frame = new ImageFrame(Configuration.Default, 1, 1); - test.QuantizeFrame(frame, frame.Bounds()); - } + using var test = (PaletteQuantizer)new PaletteQuantizer(Array.Empty()).CreatePixelSpecificQuantizer(Configuration.Default); + var frame = new ImageFrame(Configuration.Default, 1, 1); + test.QuantizeFrame(frame, frame.Bounds()); } /// @@ -167,26 +158,22 @@ private static void AotCompileDithering() /// /// This method pre-seeds the decoder and encoder for a given pixel format in the AoT compiler for iOS. /// - /// The image decoder to seed. - /// The image encoder to seed. /// The pixel format. - private static void AotCodec(IImageDecoder decoder, IImageEncoder encoder) + private static void AotCodecs() where TPixel : unmanaged, IPixel { - try + Configuration configuration = Configuration.Default; + ImageFormatManager formatsManager = configuration.ImageFormatsManager; + foreach (IImageFormat imageFormat in configuration.ImageFormats) { - decoder.Decode(Configuration.Default, null); - } - catch - { - } + using var ms = new MemoryStream(); + using (var encoded = new Image(1, 1)) + { + encoded.Save(ms, formatsManager.FindEncoder(imageFormat)); + ms.Position = 0; + } - try - { - encoder.Encode(null, null); - } - catch - { + using var decoded = Image.Load(ms); } } From 0fa3921de620b49778e250d2a6b88a6a8a6dd9be Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 7 Sep 2020 12:36:18 +0100 Subject: [PATCH 2/5] Add all IPixel interface methods. --- src/ImageSharp/Advanced/AotCompilerTools.cs | 27 ++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index dc0c59e7bf..666eb513f1 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -82,6 +82,7 @@ private static void Seed() where TPixel : unmanaged, IPixel { // This is we actually call all the individual methods you need to seed. + AotPixelInterface(); AotCompileOctreeQuantizer(); AotCompileWuQuantizer(); AotCompilePaletteQuantizer(); @@ -95,6 +96,30 @@ private static void Seed() // TODO: Do the discovery work to figure out what works and what doesn't. } + private static void AotPixelInterface() + where TPixel : unmanaged, IPixel + { + TPixel pixel = default; + Rgba32 rgba32 = default; + pixel.ToRgba32(ref rgba32); + pixel.FromRgba32(rgba32); + pixel.FromScaledVector4(pixel.ToScaledVector4()); + pixel.FromVector4(pixel.ToVector4()); + + pixel.FromArgb32(default); + pixel.FromBgr24(default); + pixel.FromBgra32(default); + pixel.FromBgra5551(default); + pixel.FromL16(default); + pixel.FromL8(default); + pixel.FromLa16(default); + pixel.FromLa32(default); + pixel.FromRgb24(default); + pixel.FromRgb48(default); + pixel.FromRgba64(default); + pixel.FromRgb24(default); + } + /// /// This method doesn't actually do anything but serves an important purpose... /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an exception: @@ -107,7 +132,7 @@ private static void Seed() /// /// The pixel format. private static void AotCompileOctreeQuantizer() - where TPixel : unmanaged, IPixel + where TPixel : unmanaged, IPixel { using var test = new OctreeQuantizer(Configuration.Default, new OctreeQuantizer().Options); var frame = new ImageFrame(Configuration.Default, 1, 1); From 65d103ed65f99b8ce1ef52d0f1164cfa8de4a810 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 8 Sep 2020 08:53:50 +0100 Subject: [PATCH 3/5] Update AotCompilerTools.cs --- src/ImageSharp/Advanced/AotCompilerTools.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index 666eb513f1..ed23cd445a 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -198,7 +198,8 @@ private static void AotCodecs() ms.Position = 0; } - using var decoded = Image.Load(ms); + using var decoded = Image.Load(ms); + Span span = decoded.GetPixelRowSpan(0); } } From 10739590ce81ed37e63dd05dabbff7e96ba48944 Mon Sep 17 00:00:00 2001 From: UltraNamahage <60680748+UltraNamahage@users.noreply.github.com> Date: Wed, 10 Mar 2021 18:46:49 +0900 Subject: [PATCH 4/5] Have AotCompilerTools cache additional methods. --- src/ImageSharp/Advanced/AotCompilerTools.cs | 348 ++++++++++++++++++++ 1 file changed, 348 insertions(+) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index ed23cd445a..666b459e42 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -7,10 +7,25 @@ using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.ImageSharp.Processing.Processors.Binarization; +using SixLabors.ImageSharp.Processing.Processors.Convolution; using SixLabors.ImageSharp.Processing.Processors.Dithering; +using SixLabors.ImageSharp.Processing.Processors.Drawing; +using SixLabors.ImageSharp.Processing.Processors.Effects; +using SixLabors.ImageSharp.Processing.Processors.Filters; +using SixLabors.ImageSharp.Processing.Processors.Normalization; +using SixLabors.ImageSharp.Processing.Processors.Overlays; using SixLabors.ImageSharp.Processing.Processors.Quantization; +using SixLabors.ImageSharp.Processing.Processors.Transforms; namespace SixLabors.ImageSharp.Advanced { @@ -89,6 +104,18 @@ private static void Seed() AotCompileDithering(); AotCompilePixelOperations(); + AotCompileImage(); + AotCompileImageProcessingContextFactory(); + AotCompileImageEncoderInternals(); + AotCompileImageDecoderInternals(); + AotCompileImageEncoders(); + AotCompileImageDecoders(); + AotCompileImageProcessors(); + AotCompileGenericImageProcessors(); + AotCompileResamplers(); + AotCompileQuantizers(); + AotCompilePixelSamplingStrategys(); + Unsafe.SizeOf(); AotCodecs(); @@ -213,5 +240,326 @@ private static void AotCompilePixelOperations() var pixelOp = new PixelOperations(); pixelOp.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.Clear); } + + /// + /// This method pre-seeds the for a given pixel format in the AoT compiler. + /// + /// The pixel format. + private static unsafe void AotCompileImage() + where TPixel : unmanaged, IPixel + { + Image img = default; + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + img.CloneAs(default); + + ImageFrame.LoadPixelData(default, default(ReadOnlySpan), default, default); + ImageFrame.LoadPixelData(default, default(ReadOnlySpan), default, default); + } + + private static void AotCompileImageProcessingContextFactory() + where TPixel : unmanaged, IPixel + => default(DefaultImageOperationsProviderFactory).CreateImageProcessingContext(default, default, default); + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// The pixel format. + private static void AotCompileImageEncoderInternals() + where TPixel : unmanaged, IPixel + { + default(BmpEncoderCore).Encode(default, default, default); + default(GifEncoderCore).Encode(default, default, default); + default(JpegEncoderCore).Encode(default, default, default); + default(PngEncoderCore).Encode(default, default, default); + default(TgaEncoderCore).Encode(default, default, default); + } + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// The pixel format. + private static void AotCompileImageDecoderInternals() + where TPixel : unmanaged, IPixel + { + default(BmpDecoderCore).Decode(default, default, default); + default(GifDecoderCore).Decode(default, default, default); + default(JpegDecoderCore).Decode(default, default, default); + default(PngDecoderCore).Decode(default, default, default); + default(TgaDecoderCore).Decode(default, default, default); + } + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// The pixel format. + private static void AotCompileImageEncoders() + where TPixel : unmanaged, IPixel + { + AotCompileImageEncoder(); + AotCompileImageEncoder(); + AotCompileImageEncoder(); + AotCompileImageEncoder(); + AotCompileImageEncoder(); + } + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// The pixel format. + private static void AotCompileImageDecoders() + where TPixel : unmanaged, IPixel + { + AotCompileImageDecoder(); + AotCompileImageDecoder(); + AotCompileImageDecoder(); + AotCompileImageDecoder(); + AotCompileImageDecoder(); + } + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + /// The encoder. + private static void AotCompileImageEncoder() + where TPixel : unmanaged, IPixel + where TEncoder : class, IImageEncoder + { + default(TEncoder).Encode(default, default); + default(TEncoder).EncodeAsync(default, default, default); + } + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + /// The decoder. + private static void AotCompileImageDecoder() + where TPixel : unmanaged, IPixel + where TDecoder : class, IImageDecoder + { + default(TDecoder).Decode(default, default); + default(TDecoder).DecodeAsync(default, default, default); + } + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// + /// There is no structure that implements ISwizzler. + /// + /// The pixel format. + private static void AotCompileImageProcessors() + where TPixel : unmanaged, IPixel + { + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + AotCompileImageProcessor(); + + AotCompilerCloningImageProcessor(); + AotCompilerCloningImageProcessor(); + AotCompilerCloningImageProcessor(); + AotCompilerCloningImageProcessor(); + AotCompilerCloningImageProcessor(); + AotCompilerCloningImageProcessor(); + AotCompilerCloningImageProcessor(); + } + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + /// The processor type + private static void AotCompileImageProcessor() + where TPixel : unmanaged, IPixel + where TProc : class, IImageProcessor + => default(TProc).CreatePixelSpecificProcessor(default, default, default); + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + /// The processor type + private static void AotCompilerCloningImageProcessor() + where TPixel : unmanaged, IPixel + where TProc : class, ICloningImageProcessor + => default(TProc).CreatePixelSpecificCloningProcessor(default, default, default); + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// + /// There is no structure that implements ISwizzler. + /// + /// The pixel format. + private static void AotCompileGenericImageProcessors() + where TPixel : unmanaged, IPixel + { + AotCompileGenericCloningImageProcessor>(); + AotCompileGenericCloningImageProcessor>(); + AotCompileGenericCloningImageProcessor>(); + AotCompileGenericCloningImageProcessor>(); + AotCompileGenericCloningImageProcessor>(); + } + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + /// The processor type + private static void AotCompileGenericCloningImageProcessor() + where TPixel : unmanaged, IPixel + where TProc : class, ICloningImageProcessor + => default(TProc).CloneAndExecute(); + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// The pixel format. + private static void AotCompileResamplers() + where TPixel : unmanaged, IPixel + { + AotCompileResampler(); + AotCompileResampler(); + AotCompileResampler(); + AotCompileResampler(); + AotCompileResampler(); + AotCompileResampler(); + AotCompileResampler(); + } + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + /// The processor type + private static void AotCompileResampler() + where TPixel : unmanaged, IPixel + where TResampler : struct, IResampler + { + default(TResampler).ApplyTransform(default); + + default(AffineTransformProcessor).ApplyTransform(default); + default(ProjectiveTransformProcessor).ApplyTransform(default); + default(ResizeProcessor).ApplyTransform(default); + default(RotateProcessor).ApplyTransform(default); + } + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// The pixel format. + private static void AotCompileQuantizers() + where TPixel : unmanaged, IPixel + { + AotCompileQuantizer(); + AotCompileQuantizer(); + AotCompileQuantizer(); + AotCompileQuantizer(); + AotCompileQuantizer(); + } + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + /// The quantizer type + private static void AotCompileQuantizer() + where TPixel : unmanaged, IPixel + + where TQuantizer : class, IQuantizer + { + default(TQuantizer).CreatePixelSpecificQuantizer(default); + default(TQuantizer).CreatePixelSpecificQuantizer(default, default); + } + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + private static void AotCompilePixelSamplingStrategys() + where TPixel : unmanaged, IPixel + { + default(DefaultPixelSamplingStrategy).EnumeratePixelRegions(default); + default(ExtensivePixelSamplingStrategy).EnumeratePixelRegions(default); + } } } From ece070705369bd3bc8329813aef57d0d1d2edaf9 Mon Sep 17 00:00:00 2001 From: UltraNamahage <60680748+UltraNamahage@users.noreply.github.com> Date: Sun, 14 Mar 2021 04:10:01 +0900 Subject: [PATCH 5/5] Organize Seed and solve the problem of more Seed and code strips with the Preserve attribute. --- src/ImageSharp/Advanced/AotCompilerTools.cs | 320 +++++++++--------- src/ImageSharp/Advanced/PreserveAttribute.cs | 14 + .../PaletteDitherProcessor{TPixel}.cs | 3 +- 3 files changed, 168 insertions(+), 169 deletions(-) create mode 100644 src/ImageSharp/Advanced/PreserveAttribute.cs diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index 666b459e42..ea4cd1c8c4 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -3,7 +3,6 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Formats; @@ -13,6 +12,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Tga; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors; @@ -40,70 +40,82 @@ namespace SixLabors.ImageSharp.Advanced [ExcludeFromCodeCoverage] internal static class AotCompilerTools { - static AotCompilerTools() - { - Unsafe.SizeOf(); - Unsafe.SizeOf(); - Unsafe.SizeOf(); - Unsafe.SizeOf(); - Unsafe.SizeOf(); - Unsafe.SizeOf(); - Unsafe.SizeOf(); - Unsafe.SizeOf(); - } - /// /// This is the method that seeds the AoT compiler. /// None of these seed methods needs to actually be called to seed the compiler. /// The calls just need to be present when the code is compiled, and each implementation will be built. /// + /// + /// This method doesn't actually do anything but serves an important purpose... + /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an exception: + /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." + /// The reason this happens is the SaveAsGif method makes heavy use of generics, which are too confusing for the AoT + /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on + /// iOS so it bombs out. + /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the + /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! + /// + [Preserve] private static void SeedEverything() { - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); - Seed(); + try + { + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + Unsafe.SizeOf(); + + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + Seed(); + } + catch + { + // nop + } + + throw new InvalidOperationException("This method is used for AOT code generation only. Do not call it at runtime."); } /// /// Seeds the compiler using the given pixel format. /// /// The pixel format. + [Preserve] private static void Seed() where TPixel : unmanaged, IPixel { // This is we actually call all the individual methods you need to seed. - AotPixelInterface(); - AotCompileOctreeQuantizer(); - AotCompileWuQuantizer(); - AotCompilePaletteQuantizer(); - AotCompileDithering(); - AotCompilePixelOperations(); - AotCompileImage(); AotCompileImageProcessingContextFactory(); AotCompileImageEncoderInternals(); @@ -115,136 +127,19 @@ private static void Seed() AotCompileResamplers(); AotCompileQuantizers(); AotCompilePixelSamplingStrategys(); + AotCompileDithers(); + AotCompileMemoryManagers(); Unsafe.SizeOf(); - AotCodecs(); - // TODO: Do the discovery work to figure out what works and what doesn't. } - private static void AotPixelInterface() - where TPixel : unmanaged, IPixel - { - TPixel pixel = default; - Rgba32 rgba32 = default; - pixel.ToRgba32(ref rgba32); - pixel.FromRgba32(rgba32); - pixel.FromScaledVector4(pixel.ToScaledVector4()); - pixel.FromVector4(pixel.ToVector4()); - - pixel.FromArgb32(default); - pixel.FromBgr24(default); - pixel.FromBgra32(default); - pixel.FromBgra5551(default); - pixel.FromL16(default); - pixel.FromL8(default); - pixel.FromLa16(default); - pixel.FromLa32(default); - pixel.FromRgb24(default); - pixel.FromRgb48(default); - pixel.FromRgba64(default); - pixel.FromRgb24(default); - } - - /// - /// This method doesn't actually do anything but serves an important purpose... - /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an exception: - /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." - /// The reason this happens is the SaveAsGif method makes heavy use of generics, which are too confusing for the AoT - /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on - /// iOS so it bombs out. - /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the - /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! - /// - /// The pixel format. - private static void AotCompileOctreeQuantizer() - where TPixel : unmanaged, IPixel - { - using var test = new OctreeQuantizer(Configuration.Default, new OctreeQuantizer().Options); - var frame = new ImageFrame(Configuration.Default, 1, 1); - test.QuantizeFrame(frame, frame.Bounds()); - } - - /// - /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. - /// - /// The pixel format. - private static void AotCompileWuQuantizer() - where TPixel : unmanaged, IPixel - { - using var test = new WuQuantizer(Configuration.Default, new WuQuantizer().Options); - var frame = new ImageFrame(Configuration.Default, 1, 1); - test.QuantizeFrame(frame, frame.Bounds()); - } - - /// - /// This method pre-seeds the PaletteQuantizer in the AoT compiler for iOS. - /// - /// The pixel format. - private static void AotCompilePaletteQuantizer() - where TPixel : unmanaged, IPixel - { - using var test = (PaletteQuantizer)new PaletteQuantizer(Array.Empty()).CreatePixelSpecificQuantizer(Configuration.Default); - var frame = new ImageFrame(Configuration.Default, 1, 1); - test.QuantizeFrame(frame, frame.Bounds()); - } - - /// - /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. - /// - /// The pixel format. - private static void AotCompileDithering() - where TPixel : unmanaged, IPixel - { - ErrorDither errorDither = ErrorDither.FloydSteinberg; - OrderedDither orderedDither = OrderedDither.Bayer2x2; - TPixel pixel = default; - using (var image = new ImageFrame(Configuration.Default, 1, 1)) - { - errorDither.Dither(image, image.Bounds(), pixel, pixel, 0, 0, 0); - orderedDither.Dither(pixel, 0, 0, 0, 0); - } - } - - /// - /// This method pre-seeds the decoder and encoder for a given pixel format in the AoT compiler for iOS. - /// - /// The pixel format. - private static void AotCodecs() - where TPixel : unmanaged, IPixel - { - Configuration configuration = Configuration.Default; - ImageFormatManager formatsManager = configuration.ImageFormatsManager; - foreach (IImageFormat imageFormat in configuration.ImageFormats) - { - using var ms = new MemoryStream(); - using (var encoded = new Image(1, 1)) - { - encoded.Save(ms, formatsManager.FindEncoder(imageFormat)); - ms.Position = 0; - } - - using var decoded = Image.Load(ms); - Span span = decoded.GetPixelRowSpan(0); - } - } - - /// - /// This method pre-seeds the PixelOperations engine for the AoT compiler on iOS. - /// - /// The pixel format. - private static void AotCompilePixelOperations() - where TPixel : unmanaged, IPixel - { - var pixelOp = new PixelOperations(); - pixelOp.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.Clear); - } - /// /// This method pre-seeds the for a given pixel format in the AoT compiler. /// /// The pixel format. + [Preserve] private static unsafe void AotCompileImage() where TPixel : unmanaged, IPixel { @@ -282,6 +177,11 @@ private static unsafe void AotCompileImage() ImageFrame.LoadPixelData(default, default(ReadOnlySpan), default, default); } + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// The pixel format. + [Preserve] private static void AotCompileImageProcessingContextFactory() where TPixel : unmanaged, IPixel => default(DefaultImageOperationsProviderFactory).CreateImageProcessingContext(default, default, default); @@ -290,6 +190,7 @@ private static void AotCompileImageProcessingContextFactory() /// This method pre-seeds the all in the AoT compiler. /// /// The pixel format. + [Preserve] private static void AotCompileImageEncoderInternals() where TPixel : unmanaged, IPixel { @@ -304,6 +205,7 @@ private static void AotCompileImageEncoderInternals() /// This method pre-seeds the all in the AoT compiler. /// /// The pixel format. + [Preserve] private static void AotCompileImageDecoderInternals() where TPixel : unmanaged, IPixel { @@ -318,6 +220,7 @@ private static void AotCompileImageDecoderInternals() /// This method pre-seeds the all in the AoT compiler. /// /// The pixel format. + [Preserve] private static void AotCompileImageEncoders() where TPixel : unmanaged, IPixel { @@ -332,6 +235,7 @@ private static void AotCompileImageEncoders() /// This method pre-seeds the all in the AoT compiler. /// /// The pixel format. + [Preserve] private static void AotCompileImageDecoders() where TPixel : unmanaged, IPixel { @@ -347,6 +251,7 @@ private static void AotCompileImageDecoders() /// /// The pixel format. /// The encoder. + [Preserve] private static void AotCompileImageEncoder() where TPixel : unmanaged, IPixel where TEncoder : class, IImageEncoder @@ -360,6 +265,7 @@ private static void AotCompileImageEncoder() /// /// The pixel format. /// The decoder. + [Preserve] private static void AotCompileImageDecoder() where TPixel : unmanaged, IPixel where TDecoder : class, IImageDecoder @@ -375,6 +281,7 @@ private static void AotCompileImageDecoder() /// There is no structure that implements ISwizzler. /// /// The pixel format. + [Preserve] private static void AotCompileImageProcessors() where TPixel : unmanaged, IPixel { @@ -448,6 +355,7 @@ private static void AotCompileImageProcessors() /// /// The pixel format. /// The processor type + [Preserve] private static void AotCompileImageProcessor() where TPixel : unmanaged, IPixel where TProc : class, IImageProcessor @@ -458,6 +366,7 @@ private static void AotCompileImageProcessor() /// /// The pixel format. /// The processor type + [Preserve] private static void AotCompilerCloningImageProcessor() where TPixel : unmanaged, IPixel where TProc : class, ICloningImageProcessor @@ -470,6 +379,7 @@ private static void AotCompilerCloningImageProcessor() /// There is no structure that implements ISwizzler. /// /// The pixel format. + [Preserve] private static void AotCompileGenericImageProcessors() where TPixel : unmanaged, IPixel { @@ -485,6 +395,7 @@ private static void AotCompileGenericImageProcessors() /// /// The pixel format. /// The processor type + [Preserve] private static void AotCompileGenericCloningImageProcessor() where TPixel : unmanaged, IPixel where TProc : class, ICloningImageProcessor @@ -494,6 +405,7 @@ private static void AotCompileGenericCloningImageProcessor() /// This method pre-seeds the all in the AoT compiler. /// /// The pixel format. + [Preserve] private static void AotCompileResamplers() where TPixel : unmanaged, IPixel { @@ -511,6 +423,7 @@ private static void AotCompileResamplers() /// /// The pixel format. /// The processor type + [Preserve] private static void AotCompileResampler() where TPixel : unmanaged, IPixel where TResampler : struct, IResampler @@ -527,6 +440,7 @@ private static void AotCompileResampler() /// This method pre-seeds the all in the AoT compiler. /// /// The pixel format. + [Preserve] private static void AotCompileQuantizers() where TPixel : unmanaged, IPixel { @@ -542,6 +456,7 @@ private static void AotCompileQuantizers() /// /// The pixel format. /// The quantizer type + [Preserve] private static void AotCompileQuantizer() where TPixel : unmanaged, IPixel @@ -555,11 +470,80 @@ private static void AotCompileQuantizer() /// This method pre-seeds the in the AoT compiler. /// /// The pixel format. + [Preserve] private static void AotCompilePixelSamplingStrategys() where TPixel : unmanaged, IPixel { default(DefaultPixelSamplingStrategy).EnumeratePixelRegions(default); default(ExtensivePixelSamplingStrategy).EnumeratePixelRegions(default); } + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// The pixel format. + [Preserve] + private static void AotCompileDithers() + where TPixel : unmanaged, IPixel + { + AotCompileDither(); + AotCompileDither(); + } + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + /// The dither. + [Preserve] + private static void AotCompileDither() + where TPixel : unmanaged, IPixel + where TDither : struct, IDither + { + var octree = default(OctreeQuantizer); + default(TDither).ApplyQuantizationDither, TPixel>(ref octree, default, default, default); + + var palette = default(PaletteQuantizer); + default(TDither).ApplyQuantizationDither, TPixel>(ref palette, default, default, default); + + var wu = default(WuQuantizer); + default(TDither).ApplyQuantizationDither, TPixel>(ref wu, default, default, default); + default(TDither).ApplyPaletteDither.DitherProcessor, TPixel>(default, default, default); + } + + /// + /// This method pre-seeds the all in the AoT compiler. + /// + /// The pixel format. + [Preserve] + private static void AotCompileMemoryManagers() + where TPixel : unmanaged, IPixel + { + AotCompileMemoryManager(); + AotCompileMemoryManager(); + } + + /// + /// This method pre-seeds the in the AoT compiler. + /// + /// The pixel format. + /// The buffer. + [Preserve] + private static void AotCompileMemoryManager() + where TPixel : unmanaged, IPixel + where TBuffer : MemoryAllocator + { + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + default(TBuffer).Allocate(default, default); + } } } diff --git a/src/ImageSharp/Advanced/PreserveAttribute.cs b/src/ImageSharp/Advanced/PreserveAttribute.cs new file mode 100644 index 0000000000..a16b30e235 --- /dev/null +++ b/src/ImageSharp/Advanced/PreserveAttribute.cs @@ -0,0 +1,14 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// This is necessary to avoid being excluded from compilation in environments that do AOT builds, such as Unity's IL2CPP and Xamarin. + /// The only thing that matters is the class name. + /// There is no need to use or inherit from the PreserveAttribute class in each environment. + /// + internal sealed class PreserveAttribute : System.Attribute + { + } +} diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index 789d02046e..4631cd4229 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -72,7 +72,8 @@ protected override void Dispose(bool disposing) /// Used to allow inlining of calls to /// . /// - private readonly struct DitherProcessor : IPaletteDitherImageProcessor + /// Internal for AOT + internal readonly struct DitherProcessor : IPaletteDitherImageProcessor { private readonly EuclideanPixelMap pixelMap;