From 1db8031b02578e250707893c497ff8e4b0d0deed Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 14 Mar 2019 15:16:30 +0100 Subject: [PATCH 1/4] Custom skia gpu support. --- src/Skia/Avalonia.Skia/CustomRenderTarget.cs | 39 +++++++++++++++++++ src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs | 23 +++++++++++ .../Avalonia.Skia/ICustomSkiaRenderSession.cs | 26 +++++++++++++ .../Avalonia.Skia/ICustomSkiaRenderTarget.cs | 16 ++++++++ .../Avalonia.Skia/PlatformRenderInterface.cs | 32 ++++++++++++--- .../SkiaApplicationExtensions.cs | 7 +++- src/Skia/Avalonia.Skia/SkiaPlatform.cs | 6 +-- 7 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 src/Skia/Avalonia.Skia/CustomRenderTarget.cs create mode 100644 src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs create mode 100644 src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs create mode 100644 src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs diff --git a/src/Skia/Avalonia.Skia/CustomRenderTarget.cs b/src/Skia/Avalonia.Skia/CustomRenderTarget.cs new file mode 100644 index 00000000000..dd62237b0c6 --- /dev/null +++ b/src/Skia/Avalonia.Skia/CustomRenderTarget.cs @@ -0,0 +1,39 @@ +using Avalonia.Platform; +using Avalonia.Rendering; + +namespace Avalonia.Skia +{ + /// + /// Adapts to be used within Skia rendering pipeline. + /// + internal class CustomRenderTarget : IRenderTarget + { + private readonly ICustomSkiaRenderTarget _renderTarget; + + public CustomRenderTarget(ICustomSkiaRenderTarget renderTarget) + { + _renderTarget = renderTarget; + } + + public void Dispose() + { + _renderTarget.Dispose(); + } + + public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer) + { + ICustomSkiaRenderSession session = _renderTarget.BeginRendering(); + + var nfo = new DrawingContextImpl.CreateInfo + { + GrContext = session.GrContext, + Canvas = session.Canvas, + Dpi = SkiaPlatform.DefaultDpi * session.ScaleFactor, + VisualBrushRenderer = visualBrushRenderer, + DisableTextLcdRendering = true + }; + + return new DrawingContextImpl(nfo, session); + } + } +} diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs b/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs new file mode 100644 index 00000000000..0cd2e346ffb --- /dev/null +++ b/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using SkiaSharp; + +namespace Avalonia.Skia +{ + /// + /// Custom Skia gpu instance. + /// + public interface ICustomSkiaGpu + { + /// + /// Skia GrContext used. + /// + GRContext GrContext { get; } + + /// + /// Attempts to create custom render target from given surfaces. + /// + /// Surfaces. + /// Created render target or if it fails. + ICustomSkiaRenderTarget TryCreateRenderTarget(IEnumerable surfaces); + } +} diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs b/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs new file mode 100644 index 00000000000..70b3a49bcf7 --- /dev/null +++ b/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs @@ -0,0 +1,26 @@ +using System; +using SkiaSharp; + +namespace Avalonia.Skia +{ + /// + /// Custom render session for Skia render target. + /// + public interface ICustomSkiaRenderSession : IDisposable + { + /// + /// GrContext used by this session. + /// + GRContext GrContext { get; } + + /// + /// Canvas that will be used to render. + /// + SKCanvas Canvas { get; } + + /// + /// Scaling factor. + /// + double ScaleFactor { get; } + } +} diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs b/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs new file mode 100644 index 00000000000..1609eaf7fe0 --- /dev/null +++ b/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs @@ -0,0 +1,16 @@ +using System; + +namespace Avalonia.Skia +{ + /// + /// Custom Skia render target. + /// + public interface ICustomSkiaRenderTarget : IDisposable + { + /// + /// Start rendering to this render target. + /// + /// + ICustomSkiaRenderSession BeginRendering(); + } +} diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index c6e68b1c8b3..ec162f9767c 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -15,14 +15,25 @@ namespace Avalonia.Skia /// /// Skia platform render interface. /// - public class PlatformRenderInterface : IPlatformRenderInterface + internal class PlatformRenderInterface : IPlatformRenderInterface { + private readonly ICustomSkiaGpu _customSkiaGpu; + private GRContext GrContext { get; } public IEnumerable InstalledFontNames => SKFontManager.Default.FontFamilies; - public PlatformRenderInterface() + public PlatformRenderInterface(ICustomSkiaGpu customSkiaGpu) { + if (customSkiaGpu != null) + { + _customSkiaGpu = customSkiaGpu; + + GrContext = _customSkiaGpu.GrContext; + + return; + } + var gl = AvaloniaLocator.Current.GetService(); if (gl != null) { @@ -32,12 +43,11 @@ public PlatformRenderInterface() ? GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc)) : GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc))) { - GrContext = GRContext.Create(GRBackend.OpenGL, iface); } } } - + /// public IFormattedTextImpl CreateFormattedText( string text, @@ -98,13 +108,23 @@ public IRenderTargetBitmapImpl CreateRenderTargetBitmap(PixelSize size, Vector d DisableTextLcdRendering = false, GrContext = GrContext }; - + return new SurfaceRenderTarget(createInfo); } /// - public virtual IRenderTarget CreateRenderTarget(IEnumerable surfaces) + public IRenderTarget CreateRenderTarget(IEnumerable surfaces) { + if (_customSkiaGpu != null) + { + ICustomSkiaRenderTarget customRenderTarget = _customSkiaGpu.TryCreateRenderTarget(surfaces); + + if (customRenderTarget != null) + { + return new CustomRenderTarget(customRenderTarget); + } + } + foreach (var surface in surfaces) { if (surface is IGlPlatformSurface glSurface && GrContext != null) diff --git a/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs b/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs index f4412df4735..0778c647360 100644 --- a/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; using Avalonia.Controls; using Avalonia.Skia; @@ -18,9 +19,11 @@ public static class SkiaApplicationExtensions /// Builder type. /// Builder. /// Configure builder. - public static T UseSkia(this T builder) where T : AppBuilderBase, new() + public static T UseSkia(this T builder, Func gpuFactory = null) where T : AppBuilderBase, new() { - builder.UseRenderingSubsystem(() => SkiaPlatform.Initialize(), "Skia"); + var customGpu = gpuFactory?.Invoke(); + + builder.UseRenderingSubsystem(() => SkiaPlatform.Initialize(customGpu), "Skia"); return builder; } } diff --git a/src/Skia/Avalonia.Skia/SkiaPlatform.cs b/src/Skia/Avalonia.Skia/SkiaPlatform.cs index a9d69aea31f..f287f58685d 100644 --- a/src/Skia/Avalonia.Skia/SkiaPlatform.cs +++ b/src/Skia/Avalonia.Skia/SkiaPlatform.cs @@ -13,10 +13,10 @@ public static class SkiaPlatform /// /// Initialize Skia platform. /// - public static void Initialize() + public static void Initialize(ICustomSkiaGpu customGpu) { - var renderInterface = new PlatformRenderInterface(); - + var renderInterface = new PlatformRenderInterface(customGpu); + AvaloniaLocator.CurrentMutable .Bind().ToConstant(renderInterface); } From 0f414d839177d34317fb4d87d9b12332ab45a8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Komosi=C5=84ski?= Date: Sun, 17 Mar 2019 17:43:23 +0100 Subject: [PATCH 2/4] Fix unit tests. --- src/Skia/Avalonia.Skia/SkiaPlatform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Skia/Avalonia.Skia/SkiaPlatform.cs b/src/Skia/Avalonia.Skia/SkiaPlatform.cs index f287f58685d..e4185c43a23 100644 --- a/src/Skia/Avalonia.Skia/SkiaPlatform.cs +++ b/src/Skia/Avalonia.Skia/SkiaPlatform.cs @@ -13,7 +13,7 @@ public static class SkiaPlatform /// /// Initialize Skia platform. /// - public static void Initialize(ICustomSkiaGpu customGpu) + public static void Initialize(ICustomSkiaGpu customGpu = null) { var renderInterface = new PlatformRenderInterface(customGpu); From adf92d2ecb3ba3111fd3cf3efddd58b0250e129a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Komosi=C5=84ski?= Date: Sun, 17 Mar 2019 17:57:15 +0100 Subject: [PATCH 3/4] Add license headers. --- src/Skia/Avalonia.Skia/CustomRenderTarget.cs | 3 +++ src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs | 3 +++ src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs | 3 +++ src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs | 3 +++ 4 files changed, 12 insertions(+) diff --git a/src/Skia/Avalonia.Skia/CustomRenderTarget.cs b/src/Skia/Avalonia.Skia/CustomRenderTarget.cs index dd62237b0c6..23a509a2a46 100644 --- a/src/Skia/Avalonia.Skia/CustomRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/CustomRenderTarget.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using Avalonia.Platform; using Avalonia.Rendering; diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs b/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs index 0cd2e346ffb..751dd3c1e79 100644 --- a/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs +++ b/src/Skia/Avalonia.Skia/ICustomSkiaGpu.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using System.Collections.Generic; using SkiaSharp; diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs b/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs index 70b3a49bcf7..6a4591921e4 100644 --- a/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs +++ b/src/Skia/Avalonia.Skia/ICustomSkiaRenderSession.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using System; using SkiaSharp; diff --git a/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs b/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs index 1609eaf7fe0..f67b28b77ba 100644 --- a/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/ICustomSkiaRenderTarget.cs @@ -1,3 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + using System; namespace Avalonia.Skia From 9209c9be421f18e20ebf95647ffdf3dedf99120b Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Mon, 8 Apr 2019 14:49:53 +0200 Subject: [PATCH 4/4] Implement platform options for Skia. --- .../SkiaApplicationExtensions.cs | 10 ++++------ src/Skia/Avalonia.Skia/SkiaOptions.cs | 19 +++++++++++++++++++ src/Skia/Avalonia.Skia/SkiaPlatform.cs | 8 +++++++- 3 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 src/Skia/Avalonia.Skia/SkiaOptions.cs diff --git a/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs b/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs index 0778c647360..102f1f92aa9 100644 --- a/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaApplicationExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using System; using Avalonia.Controls; using Avalonia.Skia; @@ -19,12 +18,11 @@ public static class SkiaApplicationExtensions /// Builder type. /// Builder. /// Configure builder. - public static T UseSkia(this T builder, Func gpuFactory = null) where T : AppBuilderBase, new() + public static T UseSkia(this T builder) where T : AppBuilderBase, new() { - var customGpu = gpuFactory?.Invoke(); - - builder.UseRenderingSubsystem(() => SkiaPlatform.Initialize(customGpu), "Skia"); - return builder; + return builder.UseRenderingSubsystem(() => SkiaPlatform.Initialize( + AvaloniaLocator.Current.GetService() ?? new SkiaOptions()), + "Skia"); } } } diff --git a/src/Skia/Avalonia.Skia/SkiaOptions.cs b/src/Skia/Avalonia.Skia/SkiaOptions.cs new file mode 100644 index 00000000000..bac1849be8f --- /dev/null +++ b/src/Skia/Avalonia.Skia/SkiaOptions.cs @@ -0,0 +1,19 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Skia; + +namespace Avalonia +{ + /// + /// Options for Skia rendering subsystem. + /// + public class SkiaOptions + { + /// + /// Custom gpu factory to use. Can be used to customize behavior of Skia renderer. + /// + public Func CustomGpuFactory { get; set; } + } +} diff --git a/src/Skia/Avalonia.Skia/SkiaPlatform.cs b/src/Skia/Avalonia.Skia/SkiaPlatform.cs index e4185c43a23..f16e967f42e 100644 --- a/src/Skia/Avalonia.Skia/SkiaPlatform.cs +++ b/src/Skia/Avalonia.Skia/SkiaPlatform.cs @@ -13,8 +13,14 @@ public static class SkiaPlatform /// /// Initialize Skia platform. /// - public static void Initialize(ICustomSkiaGpu customGpu = null) + public static void Initialize() { + Initialize(new SkiaOptions()); + } + + public static void Initialize(SkiaOptions options) + { + var customGpu = options.CustomGpuFactory?.Invoke(); var renderInterface = new PlatformRenderInterface(customGpu); AvaloniaLocator.CurrentMutable