From 5faf9025a6aa8f1a2f5a66d81d84c64723d820ac Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Fri, 2 Nov 2018 17:08:20 -0500 Subject: [PATCH 1/9] ImageSharp-762: Added methods to pre-seed AoT compiler on iOS --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 19 +++++++++++++++++++ .../OctreeFrameQuantizer{TPixel}.cs | 2 ++ 2 files changed, 21 insertions(+) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 8ddd4247e1..b226201082 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -5,6 +5,7 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp { @@ -35,5 +36,23 @@ namespace SixLabors.ImageSharp public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); + + /// + /// 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 excepion: + /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." + /// The reason this happens is the SaveAsGif method makes haevy 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. + public static void AotCompileOctreeQuantizer() + where TPixel : struct, IPixel + { + var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); + test.AotGetPalette(); + } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 1eeb0be410..8f688e8387 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -136,6 +136,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + internal TPixel[] AotGetPalette() => this.octree.Palletize(this.colors); + /// protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors); From 83eeca9246bfa0f5360c8aa321cb31a4297a7b06 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Sat, 3 Nov 2018 19:24:30 -0500 Subject: [PATCH 2/9] 762: added AoT method to pre-seed dithering engine --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index b226201082..2c5496f528 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -5,6 +5,8 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp @@ -54,5 +56,17 @@ namespace SixLabors.ImageSharp var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); test.AotGetPalette(); } + + /// + /// This method pre-seeds the default FloydSteinbergDiffuser in the AoT compiler for iOS. + /// + /// The pixel format. + public static void AotCompileDithering() + where TPixel : struct, IPixel + { + var test = new FloydSteinbergDiffuser(); + TPixel pixel = default; + test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); + } } } From 9c14fc5b372db657f2946b0a11c920564f7857c8 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Sat, 3 Nov 2018 19:36:47 -0500 Subject: [PATCH 3/9] 762: added AoT method to pre-seed WuQuantizer --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 14 +++++++++++++- .../Quantization/WuFrameQuantizer{TPixel}.cs | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 2c5496f528..f1c2ae5fb5 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -58,7 +58,19 @@ namespace SixLabors.ImageSharp } /// - /// This method pre-seeds the default FloydSteinbergDiffuser in the AoT compiler for iOS. + /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. + /// + /// The pixel format. + public static void AotCompileWuQuantizer() + where TPixel : struct, IPixel + { + var test = new WuFrameQuantizer(new WuQuantizer(false)); + test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. /// /// The pixel format. public static void AotCompileDithering() diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 43d22597df..44df226cfd 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -173,6 +173,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + internal TPixel[] AotGetPalette() => this.GetPalette(); + /// protected override TPixel[] GetPalette() { From 23142318827e9f949d0018179495ed9c024bf172 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 5 Nov 2018 13:27:08 -0600 Subject: [PATCH 4/9] ImageSharp-762_Aot-compiling: moved AoT methods to AotCompiler static class --- src/ImageSharp/Advanced/AotCompiler.cs | 103 ++++++++++++++++++ src/ImageSharp/Formats/Gif/ImageExtensions.cs | 42 ------- 2 files changed, 103 insertions(+), 42 deletions(-) create mode 100644 src/ImageSharp/Advanced/AotCompiler.cs diff --git a/src/ImageSharp/Advanced/AotCompiler.cs b/src/ImageSharp/Advanced/AotCompiler.cs new file mode 100644 index 0000000000..1c7f12ef7b --- /dev/null +++ b/src/ImageSharp/Advanced/AotCompiler.cs @@ -0,0 +1,103 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; +using SixLabors.ImageSharp.Processing.Processors.Quantization; + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Unlike traditional Mono/.NET, code on the iPhone is statically compiled ahead of time instead of being + /// compiled on demand by a JIT compiler. This means there are a few limitations with respect to generics, + /// these are caused because not every possible generic instantiation can be determined up front at compile time. + /// The Aot Compiler is designed to overcome the limitations of this compiler. + /// + public static class AotCompiler + { + /// + /// Seeds the compiler using the given pixel format. + /// + /// The pixel format. + public static void Seed() + where TPixel : struct, IPixel + { + // This is we actually call all the individual methods you need to seed. + AotCompileOctreeQuantizer(); + AotCompileWuQuantizer(); + AotCompileDithering(); + + // TODO: Do the discovery work to figure out what works and what doesn't. + } + + /// + /// Seeds the compiler using the given pixel formats. + /// + /// The first pixel format. + /// The second pixel format. + public static void Seed() + where TPixel : struct, IPixel + where TPixel2 : struct, IPixel + { + Seed(); + Seed(); + } + + /// + /// Seeds the compiler using the given pixel formats. + /// + /// The first pixel format. + /// The second pixel format. + /// The third pixel format. + public static void Seed() + where TPixel : struct, IPixel + where TPixel2 : struct, IPixel + where TPixel3 : struct, IPixel + { + Seed(); + Seed(); + } + + /// + /// 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 excepion: + /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." + /// The reason this happens is the SaveAsGif method makes haevy 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 : struct, IPixel + { + var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. + /// + /// The pixel format. + private static void AotCompileWuQuantizer() + where TPixel : struct, IPixel + { + var test = new WuFrameQuantizer(new WuQuantizer(false)); + test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. + /// + /// The pixel format. + private static void AotCompileDithering() + where TPixel : struct, IPixel + { + var test = new FloydSteinbergDiffuser(); + TPixel pixel = default; + test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index f1c2ae5fb5..3939299e90 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -38,47 +38,5 @@ namespace SixLabors.ImageSharp public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); - - /// - /// 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 excepion: - /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." - /// The reason this happens is the SaveAsGif method makes haevy 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. - public static void AotCompileOctreeQuantizer() - where TPixel : struct, IPixel - { - var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); - test.AotGetPalette(); - } - - /// - /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. - /// - /// The pixel format. - public static void AotCompileWuQuantizer() - where TPixel : struct, IPixel - { - var test = new WuFrameQuantizer(new WuQuantizer(false)); - test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); - test.AotGetPalette(); - } - - /// - /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. - /// - /// The pixel format. - public static void AotCompileDithering() - where TPixel : struct, IPixel - { - var test = new FloydSteinbergDiffuser(); - TPixel pixel = default; - test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); - } } } From c80d8f604bb9d54e72cb8ccc5fdb3e4735a4ea1b Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 5 Nov 2018 13:28:17 -0600 Subject: [PATCH 5/9] ImageSharp-762_Aot-compiling: namespace cleanup --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 3939299e90..8ddd4247e1 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -5,9 +5,6 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Primitives; -using SixLabors.ImageSharp.Processing.Processors.Dithering; -using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp { From e80ba75efd51c09943cf1558b29e3b623ac4ba3e Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 5 Nov 2018 16:55:48 -0600 Subject: [PATCH 6/9] ImageSharp-762_Aot-compiling: whitespace cleanup --- src/ImageSharp/Advanced/AotCompiler.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Advanced/AotCompiler.cs b/src/ImageSharp/Advanced/AotCompiler.cs index 1c7f12ef7b..406c162ad5 100644 --- a/src/ImageSharp/Advanced/AotCompiler.cs +++ b/src/ImageSharp/Advanced/AotCompiler.cs @@ -63,9 +63,9 @@ namespace SixLabors.ImageSharp.Advanced /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." /// The reason this happens is the SaveAsGif method makes haevy 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 + /// 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. From 71285affda077b6a68a2c0f5711ba710aaf61280 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Tue, 6 Nov 2018 09:46:14 -0600 Subject: [PATCH 7/9] ImageSharp-762_Aot-compiling: clean up AotGetPalette method --- .../Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 8f688e8387..dd56375f63 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } - internal TPixel[] AotGetPalette() => this.octree.Palletize(this.colors); + internal TPixel[] AotGetPalette() => this.GetPalette(); /// protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors); From f4fbe8d3c1dd0a1ff2f3d1bfe2486b249cd701e6 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Sat, 10 Nov 2018 17:25:39 -0600 Subject: [PATCH 8/9] ImageSharp-762_Aot-compiling: added simple unit test to check no exceptions are thrown by AotCompiler --- .../Advanced/AotCompilerTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs new file mode 100644 index 0000000000..3d6faa27ec --- /dev/null +++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs @@ -0,0 +1,18 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Advanced +{ + public class AotCompilerTests + { + [Fact] + public void AotCompiler_NoExceptions() + { + AotCompiler.Seed(); + } + } +} From 3f2953f61118bbdd2b6322ff55c282d57997de61 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 12 Nov 2018 13:34:17 -0600 Subject: [PATCH 9/9] ImageSharp-762_Aot-compiling: renamed to AotCompilerTools --- src/ImageSharp/Advanced/{AotCompiler.cs => AotCompilerTools.cs} | 2 +- tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/ImageSharp/Advanced/{AotCompiler.cs => AotCompilerTools.cs} (99%) diff --git a/src/ImageSharp/Advanced/AotCompiler.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs similarity index 99% rename from src/ImageSharp/Advanced/AotCompiler.cs rename to src/ImageSharp/Advanced/AotCompilerTools.cs index 406c162ad5..9e7624480d 100644 --- a/src/ImageSharp/Advanced/AotCompiler.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Advanced /// these are caused because not every possible generic instantiation can be determined up front at compile time. /// The Aot Compiler is designed to overcome the limitations of this compiler. /// - public static class AotCompiler + public static class AotCompilerTools { /// /// Seeds the compiler using the given pixel format. diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs index 3d6faa27ec..5c1dd4bb08 100644 --- a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs +++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced [Fact] public void AotCompiler_NoExceptions() { - AotCompiler.Seed(); + AotCompilerTools.Seed(); } } }