diff --git a/src/Avalonia.Base/Platform/IRenderTarget.cs b/src/Avalonia.Base/Platform/IRenderTarget.cs
index 39504ac9fbe..1a46b376acd 100644
--- a/src/Avalonia.Base/Platform/IRenderTarget.cs
+++ b/src/Avalonia.Base/Platform/IRenderTarget.cs
@@ -25,30 +25,39 @@ public interface IRenderTarget : IDisposable
public bool IsCorrupted { get; }
}
- [PrivateApi]
+ [PrivateApi, Obsolete("Use IRenderTarget2", true)]
+ // TODO12: Remove
public interface IRenderTargetWithProperties : IRenderTarget
+ {
+ RenderTargetProperties Properties { get; }
+ }
+
+ [PrivateApi]
+ // TODO12: Merge into IRenderTarget
+ public interface IRenderTarget2 : IRenderTarget
{
RenderTargetProperties Properties { get; }
///
/// Creates an for a rendering session.
///
- /// Apply DPI reported by the render target as a hidden transform matrix
+ /// The pixel size of the surface
/// Returns various properties about the returned drawing context
- IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing, out RenderTargetDrawingContextProperties properties);
+ IDrawingContextImpl CreateDrawingContext(PixelSize expectedPixelSize,
+ out RenderTargetDrawingContextProperties properties);
}
internal static class RenderTargetExtensions
{
public static IDrawingContextImpl CreateDrawingContextWithProperties(
this IRenderTarget renderTarget,
- bool useScaledDrawing,
+ PixelSize expectedPixelSize,
out RenderTargetDrawingContextProperties properties)
{
- if (renderTarget is IRenderTargetWithProperties target)
- return target.CreateDrawingContext(useScaledDrawing, out properties);
+ if (renderTarget is IRenderTarget2 target)
+ return target.CreateDrawingContext(expectedPixelSize, out properties);
properties = default;
- return renderTarget.CreateDrawingContext(useScaledDrawing);
+ return renderTarget.CreateDrawingContext(false);
}
}
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
index e5b5e0e6c26..e942761fcf0 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
@@ -141,7 +141,7 @@ public void Render()
if (!_redrawRequested)
return;
- var renderTargetWithProperties = _renderTarget as IRenderTargetWithProperties;
+ var renderTargetWithProperties = _renderTarget as IRenderTarget2;
var needLayer = _overlays.RequireLayer // Check if we don't need overlays
@@ -149,7 +149,8 @@ public void Render()
|| !(renderTargetWithProperties?.Properties.RetainsPreviousFrameContents == true
&& renderTargetWithProperties?.Properties.IsSuitableForDirectRendering == true);
- using (var renderTargetContext = _renderTarget.CreateDrawingContextWithProperties(false, out var properties))
+ using (var renderTargetContext = _renderTarget.CreateDrawingContextWithProperties(
+ this.PixelSize, out var properties))
{
if(needLayer && (PixelSize != _layerSize || _layer == null || _layer.IsCorrupted))
{
diff --git a/src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs b/src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs
index f89b6f04f5c..13e89e95508 100644
--- a/src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs
+++ b/src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs
@@ -1,4 +1,5 @@
using System;
+using Avalonia.Metadata;
namespace Avalonia.OpenGL.Surfaces
{
@@ -11,4 +12,11 @@ public interface IGlPlatformSurfaceRenderTargetWithCorruptionInfo : IGlPlatformS
{
bool IsCorrupted { get; }
}
+
+ [PrivateApi]
+ public interface IGlPlatformSurfaceRenderTarget2 : IGlPlatformSurfaceRenderTargetWithCorruptionInfo
+ {
+ IGlPlatformSurfaceRenderingSession BeginDraw(PixelSize expectedPixelSize);
+ }
+
}
diff --git a/src/Avalonia.X11/Glx/GlxDisplay.cs b/src/Avalonia.X11/Glx/GlxDisplay.cs
index 190677074a8..9ce34ec7c41 100644
--- a/src/Avalonia.X11/Glx/GlxDisplay.cs
+++ b/src/Avalonia.X11/Glx/GlxDisplay.cs
@@ -18,6 +18,8 @@ internal unsafe class GlxDisplay
public XVisualInfo* VisualInfo => _visual;
public GlxContext DeferredContext { get; }
public GlxInterface Glx { get; } = new GlxInterface();
+ public X11Info X11Info => _x11;
+ public IntPtr FbConfig => _fbconfig;
public GlxDisplay(X11Info x11, IList probeProfiles)
{
_x11 = x11;
diff --git a/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs b/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
index 17c5909a39a..0c7c7d21659 100644
--- a/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
+++ b/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
@@ -21,10 +21,11 @@ public IGlPlatformSurfaceRenderTarget CreateGlRenderTarget(IGlContext context)
return new RenderTarget((GlxContext)context, _info);
}
- private class RenderTarget : IGlPlatformSurfaceRenderTarget
+ private class RenderTarget : IGlPlatformSurfaceRenderTarget2
{
private readonly GlxContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
+ private PixelSize? _lastSize;
public RenderTarget(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info)
{
@@ -36,29 +37,51 @@ public void Dispose()
{
// No-op
}
-
- public IGlPlatformSurfaceRenderingSession BeginDraw()
+
+ public bool IsCorrupted => false;
+ public IGlPlatformSurfaceRenderingSession BeginDraw(PixelSize size) => BeginDrawCore(size);
+ public IGlPlatformSurfaceRenderingSession BeginDraw() => BeginDrawCore(null);
+ public IGlPlatformSurfaceRenderingSession BeginDrawCore(PixelSize? expectedSize)
{
+ var size = expectedSize ?? _info.Size;
+ if (expectedSize.HasValue)
+ {
+ XLib.XConfigureResizeWindow(_context.Display.X11Info.DeferredDisplay,
+ _info.Handle, size.Width, size.Height);
+ XLib.XFlush(_context.Display.X11Info.DeferredDisplay);
+
+ if (_lastSize != size)
+ {
+ XLib.XSync(_context.Display.X11Info.DeferredDisplay, true);
+ _lastSize = size;
+ }
+ _context.Glx.WaitX();
+ }
+
+
var oldContext = _context.MakeCurrent(_info.Handle);
// Reset to default FBO first
_context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, 0);
- return new Session(_context, _info, oldContext);
+ return new Session(_context, _info, size, oldContext);
}
private class Session : IGlPlatformSurfaceRenderingSession
{
private readonly GlxContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
+ private readonly PixelSize? _size;
private readonly IDisposable _clearContext;
public IGlContext Context => _context;
public Session(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info,
+ PixelSize? size,
IDisposable clearContext)
{
_context = context;
_info = info;
+ _size = size;
_clearContext = clearContext;
}
@@ -71,7 +94,7 @@ public void Dispose()
_clearContext.Dispose();
}
- public PixelSize Size => _info.Size;
+ public PixelSize Size => _size ?? _info.Size;
public double Scaling => _info.Scaling;
public bool IsYFlipped { get; }
}
diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs
index 0a254b6b2b3..7ad0cd44615 100644
--- a/src/Avalonia.X11/X11Window.cs
+++ b/src/Avalonia.X11/X11Window.cs
@@ -67,6 +67,7 @@ internal unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client,
private TransparencyHelper? _transparencyHelper;
private RawEventGrouper? _rawEventGrouper;
private bool _useRenderWindow = false;
+ private bool _useCompositorDrivenRenderWindowResize = false;
private bool _usePositioningFlags = false;
private X11FocusProxy? _focusProxy;
@@ -111,7 +112,12 @@ public X11Window(AvaloniaX11Platform platform, IWindowImpl? popupParent, bool ov
var glx = glfeature as GlxPlatformGraphics;
if (glx != null)
+ {
visualInfo = *glx.Display.VisualInfo;
+ // TODO: We should query this from the active render surface, however we don't actually track what
+ // the target sufrace currently is
+ _useCompositorDrivenRenderWindowResize = true;
+ }
else if (glfeature == null)
visualInfo = _x11.TransparentVisualInfo;
@@ -569,7 +575,8 @@ private void OnEvent(ref XEvent ev)
Resized?.Invoke(ClientSize, WindowResizeReason.Unspecified);
}, DispatcherPriority.AsyncRenderTargetResize);
- if (_useRenderWindow)
+
+ if (_useRenderWindow && !_useCompositorDrivenRenderWindowResize)
XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width,
ev.ConfigureEvent.height);
if (_xSyncState == XSyncState.WaitConfigure)
@@ -1081,7 +1088,7 @@ private void Resize(Size clientSize, bool force, WindowResizeReason reason)
var pixelSize = ToPixelSize(clientSize);
UpdateSizeHints(pixelSize);
XConfigureResizeWindow(_x11.Display, _handle, pixelSize);
- if (_useRenderWindow)
+ if (_useRenderWindow && !_useCompositorDrivenRenderWindowResize)
XConfigureResizeWindow(_x11.Display, _renderHandle, pixelSize);
XFlush(_x11.Display);
diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
index 4b8f1791842..318cdac22c0 100644
--- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
+++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
@@ -10,7 +10,7 @@ namespace Avalonia.Skia
///
/// Skia render target that renders to a framebuffer surface. No gpu acceleration available.
///
- internal class FramebufferRenderTarget : IRenderTargetWithProperties
+ internal class FramebufferRenderTarget : IRenderTarget2
{
private SKImageInfo _currentImageInfo;
private IntPtr _currentFramebufferAddress;
@@ -50,10 +50,15 @@ public void Dispose()
///
public IDrawingContextImpl CreateDrawingContext(bool scaleDrawingToDpi) =>
- CreateDrawingContext(scaleDrawingToDpi, out _);
+ CreateDrawingContextCore(scaleDrawingToDpi, out _);
///
- public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing, out RenderTargetDrawingContextProperties properties)
+ public IDrawingContextImpl CreateDrawingContext(PixelSize expectedPixelSize,
+ out RenderTargetDrawingContextProperties properties)
+ => CreateDrawingContextCore(false, out properties);
+
+ IDrawingContextImpl CreateDrawingContextCore(bool scaleDrawingToDpi,
+ out RenderTargetDrawingContextProperties properties)
{
if (_renderTarget == null)
throw new ObjectDisposedException(nameof(FramebufferRenderTarget));
@@ -77,7 +82,7 @@ public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing, out Rende
{
Surface = _framebufferSurface,
Dpi = framebuffer.Dpi,
- ScaleDrawingToDpi = useScaledDrawing
+ ScaleDrawingToDpi = scaleDrawingToDpi
};
properties = new()
diff --git a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderTarget.cs b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderTarget.cs
index bd5b170a688..f8be7dc66f0 100644
--- a/src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderTarget.cs
+++ b/src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderTarget.cs
@@ -1,4 +1,5 @@
using System;
+using Avalonia.Metadata;
using SkiaSharp;
namespace Avalonia.Skia
@@ -16,4 +17,11 @@ public interface ISkiaGpuRenderTarget : IDisposable
bool IsCorrupted { get; }
}
+
+ [PrivateApi]
+ //TODO12: Merge with ISkiaGpuRenderTarget
+ public interface ISkiaGpuRenderTarget2 : ISkiaGpuRenderTarget
+ {
+ ISkiaGpuRenderSession BeginRenderingSession(PixelSize pixelSize);
+ }
}
diff --git a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs
index 25e004f4efe..56ce4a71945 100644
--- a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs
+++ b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs
@@ -9,7 +9,7 @@
namespace Avalonia.Skia
{
- internal class GlRenderTarget : ISkiaGpuRenderTarget
+ internal class GlRenderTarget : ISkiaGpuRenderTarget2
{
private readonly GRContext _grContext;
private IGlPlatformSurfaceRenderTarget _surface;
@@ -59,9 +59,16 @@ public void Dispose()
public double ScaleFactor => _glSession.Scaling;
}
- public ISkiaGpuRenderSession BeginRenderingSession()
+ public ISkiaGpuRenderSession BeginRenderingSession(PixelSize size) => BeginRenderingSessionCore(size);
+ public ISkiaGpuRenderSession BeginRenderingSession() => BeginRenderingSessionCore(null);
+
+ ISkiaGpuRenderSession BeginRenderingSessionCore(PixelSize? expectedSize)
{
- var glSession = _surface.BeginDraw();
+ var glSession =
+ expectedSize != null && _surface is IGlPlatformSurfaceRenderTarget2 surface2
+ ? surface2.BeginDraw(expectedSize.Value)
+ : _surface.BeginDraw();
+
bool success = false;
try
{
diff --git a/src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs b/src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs
index 8cc7ed68688..8d231a57849 100644
--- a/src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs
+++ b/src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs
@@ -5,7 +5,7 @@ namespace Avalonia.Skia
///
/// Adapts to be used within our rendering pipeline.
///
- internal class SkiaGpuRenderTarget : IRenderTarget
+ internal class SkiaGpuRenderTarget : IRenderTarget2
{
private readonly ISkiaGpu _skiaGpu;
private readonly ISkiaGpuRenderTarget _renderTarget;
@@ -21,9 +21,23 @@ public void Dispose()
_renderTarget.Dispose();
}
+ public IDrawingContextImpl CreateDrawingContext(PixelSize expectedPixelSize,
+ out RenderTargetDrawingContextProperties properties) =>
+ CreateDrawingContextCore(expectedPixelSize, false, out properties);
+
public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing)
+ => CreateDrawingContextCore(null, useScaledDrawing, out _);
+
+
+ IDrawingContextImpl CreateDrawingContextCore(PixelSize? expectedPixelSize,
+ bool useScaledDrawing,
+ out RenderTargetDrawingContextProperties properties)
{
- var session = _renderTarget.BeginRenderingSession();
+ properties = default;
+ var session =
+ expectedPixelSize.HasValue && _renderTarget is ISkiaGpuRenderTarget2 target2
+ ? target2.BeginRenderingSession(expectedPixelSize.Value)
+ : _renderTarget.BeginRenderingSession();
var nfo = new DrawingContextImpl.CreateInfo
{
@@ -39,5 +53,8 @@ public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing)
}
public bool IsCorrupted => _renderTarget.IsCorrupted;
+ public RenderTargetProperties Properties { get; }
+
+
}
}