diff --git a/src/Avalonia.OpenGL/GlInterface.cs b/src/Avalonia.OpenGL/GlInterface.cs
index ea2fe0a99c..28b62136da 100644
--- a/src/Avalonia.OpenGL/GlInterface.cs
+++ b/src/Avalonia.OpenGL/GlInterface.cs
@@ -117,6 +117,19 @@ namespace Avalonia.OpenGL
public delegate int GlCheckFramebufferStatus(int target);
[GlEntryPoint("glCheckFramebufferStatus")]
public GlCheckFramebufferStatus CheckFramebufferStatus { get; }
+
+ public delegate void GlBlitFramebuffer(int srcX0,
+ int srcY0,
+ int srcX1,
+ int srcY1,
+ int dstX0,
+ int dstY0,
+ int dstX1,
+ int dstY1,
+ int mask,
+ int filter);
+ [GlMinVersionEntryPoint("glBlitFramebuffer", 3, 0)]
+ public GlBlitFramebuffer BlitFramebuffer { get; }
public delegate void GlGenRenderbuffers(int count, int[] res);
[GlEntryPoint("glGenRenderbuffers")]
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index a155fd863b..669da8d03c 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -31,6 +31,7 @@ namespace Avalonia.Skia
private bool _disposed;
private GRContext _grContext;
public GRContext GrContext => _grContext;
+ private ISkiaGpu _gpu;
private readonly SKPaint _strokePaint = new SKPaint();
private readonly SKPaint _fillPaint = new SKPaint();
private readonly SKPaint _boxShadowPaint = new SKPaint();
@@ -65,6 +66,11 @@ namespace Avalonia.Skia
/// GPU-accelerated context (optional)
///
public GRContext GrContext;
+
+ ///
+ /// Skia GPU provider context (optional)
+ ///
+ public ISkiaGpu Gpu;
}
///
@@ -79,6 +85,7 @@ namespace Avalonia.Skia
_disposables = disposables;
_canTextUseLcdRendering = !createInfo.DisableTextLcdRendering;
_grContext = createInfo.GrContext;
+ _gpu = createInfo.Gpu;
if (_grContext != null)
Monitor.Enter(_grContext);
Surface = createInfo.Surface;
@@ -417,7 +424,7 @@ namespace Avalonia.Skia
///
public IRenderTargetBitmapImpl CreateLayer(Size size)
{
- return CreateRenderTarget(size);
+ return CreateRenderTarget( size);
}
///
@@ -925,7 +932,8 @@ namespace Avalonia.Skia
Dpi = _dpi,
Format = format,
DisableTextLcdRendering = !_canTextUseLcdRendering,
- GrContext = _grContext
+ GrContext = _grContext,
+ Gpu = _gpu
};
return new SurfaceRenderTarget(createInfo);
diff --git a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs
index 1a7a9b75cf..c06b4af52f 100644
--- a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs
+++ b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using Avalonia.OpenGL.Imaging;
using SkiaSharp;
@@ -15,6 +16,20 @@ namespace Avalonia.Skia
/// Surfaces.
/// Created render target or if it fails.
ISkiaGpuRenderTarget TryCreateRenderTarget(IEnumerable
internal class SkiaGpuRenderTarget : IRenderTargetWithCorruptionInfo
{
+ private readonly ISkiaGpu _skiaGpu;
private readonly ISkiaGpuRenderTarget _renderTarget;
- public SkiaGpuRenderTarget(ISkiaGpuRenderTarget renderTarget)
+ public SkiaGpuRenderTarget(ISkiaGpu skiaGpu, ISkiaGpuRenderTarget renderTarget)
{
+ _skiaGpu = skiaGpu;
_renderTarget = renderTarget;
}
@@ -30,7 +32,8 @@ namespace Avalonia.Skia
Surface = session.SkSurface,
Dpi = SkiaPlatform.DefaultDpi * session.ScaleFactor,
VisualBrushRenderer = visualBrushRenderer,
- DisableTextLcdRendering = true
+ DisableTextLcdRendering = true,
+ Gpu = _skiaGpu
};
return new DrawingContextImpl(nfo, session);
diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
index b9c1cbc673..d6f76a2c20 100644
--- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
+++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
@@ -138,7 +138,7 @@ namespace Avalonia.Skia
var gpuRenderTarget = _skiaGpu?.TryCreateRenderTarget(surfaces);
if (gpuRenderTarget != null)
{
- return new SkiaGpuRenderTarget(gpuRenderTarget);
+ return new SkiaGpuRenderTarget(_skiaGpu, gpuRenderTarget);
}
foreach (var surface in surfaces)
diff --git a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
index 27b29c6e1e..fb765cac7f 100644
--- a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
+++ b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
@@ -13,10 +13,31 @@ namespace Avalonia.Skia
///
internal class SurfaceRenderTarget : IRenderTargetBitmapImpl, IDrawableBitmapImpl
{
- private readonly SKSurface _surface;
+ private readonly ISkiaSurface _surface;
private readonly SKCanvas _canvas;
private readonly bool _disableLcdRendering;
private readonly GRContext _grContext;
+ private readonly ISkiaGpu _gpu;
+
+ 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 SkiaSurfaceWrapper(SKSurface surface)
+ {
+ Surface = ReadSurface = surface;
+ }
+
+ public void Dispose()
+ {
+ Surface?.Dispose();
+ Surface = null;
+ ReadSurface = null;
+ }
+ }
///
/// Create new surface render target.
@@ -29,9 +50,14 @@ namespace Avalonia.Skia
_disableLcdRendering = createInfo.DisableTextLcdRendering;
_grContext = createInfo.GrContext;
- _surface = CreateSurface(createInfo.GrContext, PixelSize.Width, PixelSize.Height, createInfo.Format);
+ _gpu = createInfo.Gpu;
- _canvas = _surface?.Canvas;
+ _surface = _gpu?.TryCreateSurface(PixelSize);
+ if (_surface == null)
+ _surface = new SkiaSurfaceWrapper(CreateSurface(createInfo.GrContext, PixelSize.Width, PixelSize.Height,
+ createInfo.Format));
+
+ _canvas = _surface?.Surface.Canvas;
if (_surface == null || _canvas == null)
{
@@ -70,11 +96,12 @@ namespace Avalonia.Skia
var createInfo = new DrawingContextImpl.CreateInfo
{
- Surface = _surface,
+ Surface = _surface.Surface,
Dpi = Dpi,
VisualBrushRenderer = visualBrushRenderer,
DisableTextLcdRendering = _disableLcdRendering,
- GrContext = _grContext
+ GrContext = _grContext,
+ Gpu = _gpu
};
return new DrawingContextImpl(createInfo, Disposable.Create(() => Version++));
@@ -111,7 +138,12 @@ namespace Avalonia.Skia
{
using (var image = SnapshotImage())
{
- context.Canvas.DrawImage(image, sourceRect, destRect, paint);
+ _surface.Surface.Canvas.Flush();
+ if (context.Canvas.TotalMatrix.IsIdentity && _surface.CanBlit && destRect.Top == 0 &&
+ destRect.Left == 0)
+ _surface.Blit();
+ else
+ _surface.Surface.Draw(context.Canvas, destRect.Left, destRect.Top, paint);
}
}
@@ -121,7 +153,7 @@ namespace Avalonia.Skia
/// Image snapshot.
public SKImage SnapshotImage()
{
- return _surface.Snapshot();
+ return _surface.Surface.Snapshot();
}
///
@@ -172,6 +204,8 @@ namespace Avalonia.Skia
/// GPU-accelerated context (optional)
///
public GRContext GrContext;
+
+ public ISkiaGpu Gpu;
}
}
}