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)
{