From 731974b04146d4ffcb1a972cfd623f6f6bb57a0b Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 3 Oct 2020 18:42:03 +0300 Subject: [PATCH] Only do manual layer fbo management on Windows --- .../HeadlessPlatformRenderInterface.cs | 2 ++ .../Platform/IDrawingContextImpl.cs | 5 +++++ .../Rendering/DeferredRenderer.cs | 2 +- src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs | 3 +-- .../Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs | 7 ++++++- src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs | 9 +++++++++ src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs | 16 ++++++---------- .../Media/Imaging/D2DRenderTargetBitmapImpl.cs | 12 +++++------- 8 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs index 246610b897..f88310a390 100644 --- a/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs +++ b/src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs @@ -272,6 +272,8 @@ namespace Avalonia.Headless } + public bool CanBlit => false; + public Vector Dpi { get; } public PixelSize PixelSize { get; } public int Version { get; set; } diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index 9eaef0c616..17571cb1dd 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -164,5 +164,10 @@ namespace Avalonia.Platform /// /// void Blit(IDrawingContextImpl context); + + /// + /// Returns true if layer supports optimized blit + /// + bool CanBlit { get; } } } diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index 71b9553256..15e14935ca 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -502,7 +502,7 @@ namespace Avalonia.Rendering if (layer.OpacityMask == null) { - if (firstLayer) + if (firstLayer && bitmap.Item.CanBlit) bitmap.Item.Blit(context); else context.DrawBitmap(bitmap, layer.Opacity, sourceRect, clientRect); diff --git a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs index c06b4af52f..869c261f1b 100644 --- a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs +++ b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs @@ -28,8 +28,7 @@ namespace Avalonia.Skia { SKSurface Surface { get; } bool CanBlit { get; } - void Blit(); - + void Blit(SKCanvas canvas); } public interface IOpenGlAwareSkiaGpu : ISkiaGpu diff --git a/src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs b/src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs index a1fbba3b2e..9ee8d698ba 100644 --- a/src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs +++ b/src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs @@ -116,8 +116,13 @@ namespace Avalonia.Skia public SKSurface Surface { get; private set; } public bool CanBlit { get; } - public void Blit() + public void Blit(SKCanvas canvas) { + // This should set the render target as the current FBO + // which is definitely not the best method, but it works + canvas.Clear(); + canvas.Flush(); + var gl = _glContext.GlInterface; gl.GetIntegerv(GL_READ_FRAMEBUFFER_BINDING, out var oldRead); gl.BindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); diff --git a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs index 961b6bb284..c02d813e24 100644 --- a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs +++ b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using Avalonia.Logging; using Avalonia.OpenGL; using Avalonia.OpenGL.Imaging; @@ -48,6 +49,14 @@ namespace Avalonia.Skia public ISkiaSurface TryCreateSurface(PixelSize size) { + // Only windows platform needs our FBO trickery + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return null; + + // Blit feature requires glBlitFramebuffer + if (_glContext.GlInterface.BlitFramebuffer == null) + return null; + size = new PixelSize(Math.Max(size.Width, 1), Math.Max(size.Height, 1)); if (_canCreateSurfaces == false) return null; diff --git a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs index 314a3604e9..61b599a731 100644 --- a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs @@ -23,20 +23,18 @@ namespace Avalonia.Skia class SkiaSurfaceWrapper : ISkiaSurface { public SKSurface Surface { get; private set; } - public SKSurface ReadSurface { get; private set; } public bool CanBlit => false; - public void Blit() => throw new NotSupportedException(); + public void Blit(SKCanvas canvas) => throw new NotSupportedException(); public SkiaSurfaceWrapper(SKSurface surface) { - Surface = ReadSurface = surface; + Surface = surface; } public void Dispose() { Surface?.Dispose(); Surface = null; - ReadSurface = null; } } @@ -141,11 +139,7 @@ namespace Avalonia.Skia if (_surface.CanBlit) { _surface.Surface.Canvas.Flush(); - - // This should set the render target as the current FBO - context.Canvas.Clear(); - context.Canvas.Flush(); - _surface.Blit(); + _surface.Blit(context.Canvas); } else { @@ -155,7 +149,9 @@ namespace Avalonia.Skia context.Canvas.SetMatrix(oldMatrix); } } - + + public bool CanBlit => true; + /// public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint) { diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs index fa56ffb4a7..9a0e2ec00c 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Utilities; @@ -34,12 +35,9 @@ namespace Avalonia.Direct2D1.Media.Imaging return new DrawingContextImpl(visualBrushRenderer, this, _renderTarget, null, () => Version++); } - public void Blit(IDrawingContextImpl context) - { - var rc = new Rect(0, 0, PixelSize.Width, PixelSize.Height); - context.DrawBitmap(RefCountable.CreateUnownedNotClonable(this), - 1, rc, rc); - } + public void Blit(IDrawingContextImpl context) => throw new NotSupportedException(); + + public bool CanBlit => false; public IDrawingContextLayerImpl CreateLayer(Size size) {