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/Gpu/ISkiaGpu.cs b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs index ebb0cb3a1b..f394fe7ac1 100644 --- a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs +++ b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs @@ -28,7 +28,9 @@ namespace Avalonia.Skia { SKSurface WriteSurface { get; } SKSurface ReadSurface { get; } - + bool CanBlit { get; } + void Blit(); + } 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 93afd14286..45572ca40b 100644 --- a/src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs +++ b/src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs @@ -97,15 +97,16 @@ namespace Avalonia.Skia new GRGlFramebufferInfo((uint)_fbo, SKColorType.Rgba8888.ToGlSizedFormat())); WriteSurface = SKSurface.Create(_grContext, target, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888); + CanBlit = gl.BlitFramebuffer != null; } public void Dispose() { using (_glContext.EnsureCurrent()) { - WriteSurface.Dispose(); + WriteSurface?.Dispose(); WriteSurface = null; - ReadSurface.Dispose(); + ReadSurface?.Dispose(); ReadSurface = null; var gl = _glContext.GlInterface; if (_fbo != 0) @@ -120,5 +121,15 @@ namespace Avalonia.Skia public SKSurface WriteSurface { get; private set; } public SKSurface ReadSurface { get; private set; } + public bool CanBlit { get; } + public void Blit() + { + var gl = _glContext.GlInterface; + gl.GetIntegerv(GL_READ_FRAMEBUFFER_BINDING, out var oldRead); + gl.BindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); + gl.BlitFramebuffer(0, 0, _pixelSize.Width, _pixelSize.Height, 0, 0, _pixelSize.Width, _pixelSize.Height, + GL_COLOR_BUFFER_BIT, GL_LINEAR); + gl.BindFramebuffer(GL_READ_FRAMEBUFFER, oldRead); + } } } diff --git a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs index d6ea229089..9cf0642e99 100644 --- a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs @@ -23,6 +23,8 @@ namespace Avalonia.Skia { public SKSurface WriteSurface { get; private set; } public SKSurface ReadSurface { get; private set; } + public bool CanBlit => false; + public void Blit() => throw new NotSupportedException(); public SkiaSurfaceWrapper(SKSurface surface) { @@ -136,8 +138,12 @@ namespace Avalonia.Skia { if (sourceRect.Left == 0 && sourceRect.Top == 0 && sourceRect.Size == destRect.Size) { - _surface.ReadSurface.Canvas.Flush(); - _surface.ReadSurface.Draw(context.Canvas, destRect.Left, destRect.Top, paint); + _surface.WriteSurface.Canvas.Flush(); + if (context.Canvas.TotalMatrix.IsIdentity && _surface.CanBlit && destRect.Top == 0 && + destRect.Left == 0) + _surface.Blit(); + else + _surface.ReadSurface.Draw(context.Canvas, destRect.Left, destRect.Top, paint); } else using (var image = SnapshotImage())