Browse Source

[GLX] Resize the platform render target to compositor-provided size (#17779)

We should be doing that for other platforms later as well, since only compositor knows what scene size it's planning to draw
pull/17446/head
Nikita Tsukanov 2 years ago
committed by GitHub
parent
commit
eada7ba983
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 23
      src/Avalonia.Base/Platform/IRenderTarget.cs
  2. 5
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
  3. 8
      src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs
  4. 2
      src/Avalonia.X11/Glx/GlxDisplay.cs
  5. 33
      src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
  6. 11
      src/Avalonia.X11/X11Window.cs
  7. 13
      src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
  8. 8
      src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderTarget.cs
  9. 13
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs
  10. 21
      src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs

23
src/Avalonia.Base/Platform/IRenderTarget.cs

@ -25,30 +25,39 @@ namespace Avalonia.Platform
public bool IsCorrupted { get; } public bool IsCorrupted { get; }
} }
[PrivateApi] [PrivateApi, Obsolete("Use IRenderTarget2", true)]
// TODO12: Remove
public interface IRenderTargetWithProperties : IRenderTarget public interface IRenderTargetWithProperties : IRenderTarget
{
RenderTargetProperties Properties { get; }
}
[PrivateApi]
// TODO12: Merge into IRenderTarget
public interface IRenderTarget2 : IRenderTarget
{ {
RenderTargetProperties Properties { get; } RenderTargetProperties Properties { get; }
/// <summary> /// <summary>
/// Creates an <see cref="IDrawingContextImpl"/> for a rendering session. /// Creates an <see cref="IDrawingContextImpl"/> for a rendering session.
/// </summary> /// </summary>
/// <param name="useScaledDrawing">Apply DPI reported by the render target as a hidden transform matrix</param> /// <param name="expectedPixelSize">The pixel size of the surface</param>
/// <param name="properties">Returns various properties about the returned drawing context</param> /// <param name="properties">Returns various properties about the returned drawing context</param>
IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing, out RenderTargetDrawingContextProperties properties); IDrawingContextImpl CreateDrawingContext(PixelSize expectedPixelSize,
out RenderTargetDrawingContextProperties properties);
} }
internal static class RenderTargetExtensions internal static class RenderTargetExtensions
{ {
public static IDrawingContextImpl CreateDrawingContextWithProperties( public static IDrawingContextImpl CreateDrawingContextWithProperties(
this IRenderTarget renderTarget, this IRenderTarget renderTarget,
bool useScaledDrawing, PixelSize expectedPixelSize,
out RenderTargetDrawingContextProperties properties) out RenderTargetDrawingContextProperties properties)
{ {
if (renderTarget is IRenderTargetWithProperties target) if (renderTarget is IRenderTarget2 target)
return target.CreateDrawingContext(useScaledDrawing, out properties); return target.CreateDrawingContext(expectedPixelSize, out properties);
properties = default; properties = default;
return renderTarget.CreateDrawingContext(useScaledDrawing); return renderTarget.CreateDrawingContext(false);
} }
} }
} }

5
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs

@ -141,7 +141,7 @@ namespace Avalonia.Rendering.Composition.Server
if (!_redrawRequested) if (!_redrawRequested)
return; return;
var renderTargetWithProperties = _renderTarget as IRenderTargetWithProperties; var renderTargetWithProperties = _renderTarget as IRenderTarget2;
var needLayer = _overlays.RequireLayer // Check if we don't need overlays var needLayer = _overlays.RequireLayer // Check if we don't need overlays
@ -149,7 +149,8 @@ namespace Avalonia.Rendering.Composition.Server
|| !(renderTargetWithProperties?.Properties.RetainsPreviousFrameContents == true || !(renderTargetWithProperties?.Properties.RetainsPreviousFrameContents == true
&& renderTargetWithProperties?.Properties.IsSuitableForDirectRendering == 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)) if(needLayer && (PixelSize != _layerSize || _layer == null || _layer.IsCorrupted))
{ {

8
src/Avalonia.OpenGL/Surfaces/IGlPlatformSurfaceRenderTarget.cs

@ -1,4 +1,5 @@
using System; using System;
using Avalonia.Metadata;
namespace Avalonia.OpenGL.Surfaces namespace Avalonia.OpenGL.Surfaces
{ {
@ -11,4 +12,11 @@ namespace Avalonia.OpenGL.Surfaces
{ {
bool IsCorrupted { get; } bool IsCorrupted { get; }
} }
[PrivateApi]
public interface IGlPlatformSurfaceRenderTarget2 : IGlPlatformSurfaceRenderTargetWithCorruptionInfo
{
IGlPlatformSurfaceRenderingSession BeginDraw(PixelSize expectedPixelSize);
}
} }

2
src/Avalonia.X11/Glx/GlxDisplay.cs

@ -18,6 +18,8 @@ namespace Avalonia.X11.Glx
public XVisualInfo* VisualInfo => _visual; public XVisualInfo* VisualInfo => _visual;
public GlxContext DeferredContext { get; } public GlxContext DeferredContext { get; }
public GlxInterface Glx { get; } = new GlxInterface(); public GlxInterface Glx { get; } = new GlxInterface();
public X11Info X11Info => _x11;
public IntPtr FbConfig => _fbconfig;
public GlxDisplay(X11Info x11, IList<GlVersion> probeProfiles) public GlxDisplay(X11Info x11, IList<GlVersion> probeProfiles)
{ {
_x11 = x11; _x11 = x11;

33
src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs

@ -21,10 +21,11 @@ namespace Avalonia.X11.Glx
return new RenderTarget((GlxContext)context, _info); return new RenderTarget((GlxContext)context, _info);
} }
private class RenderTarget : IGlPlatformSurfaceRenderTarget private class RenderTarget : IGlPlatformSurfaceRenderTarget2
{ {
private readonly GlxContext _context; private readonly GlxContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info; private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
private PixelSize? _lastSize;
public RenderTarget(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info) public RenderTarget(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info)
{ {
@ -36,29 +37,51 @@ namespace Avalonia.X11.Glx
{ {
// No-op // 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); var oldContext = _context.MakeCurrent(_info.Handle);
// Reset to default FBO first // Reset to default FBO first
_context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, 0); _context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, 0);
return new Session(_context, _info, oldContext); return new Session(_context, _info, size, oldContext);
} }
private class Session : IGlPlatformSurfaceRenderingSession private class Session : IGlPlatformSurfaceRenderingSession
{ {
private readonly GlxContext _context; private readonly GlxContext _context;
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info; private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info;
private readonly PixelSize? _size;
private readonly IDisposable _clearContext; private readonly IDisposable _clearContext;
public IGlContext Context => _context; public IGlContext Context => _context;
public Session(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info, public Session(GlxContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info,
PixelSize? size,
IDisposable clearContext) IDisposable clearContext)
{ {
_context = context; _context = context;
_info = info; _info = info;
_size = size;
_clearContext = clearContext; _clearContext = clearContext;
} }
@ -71,7 +94,7 @@ namespace Avalonia.X11.Glx
_clearContext.Dispose(); _clearContext.Dispose();
} }
public PixelSize Size => _info.Size; public PixelSize Size => _size ?? _info.Size;
public double Scaling => _info.Scaling; public double Scaling => _info.Scaling;
public bool IsYFlipped { get; } public bool IsYFlipped { get; }
} }

11
src/Avalonia.X11/X11Window.cs

@ -67,6 +67,7 @@ namespace Avalonia.X11
private TransparencyHelper? _transparencyHelper; private TransparencyHelper? _transparencyHelper;
private RawEventGrouper? _rawEventGrouper; private RawEventGrouper? _rawEventGrouper;
private bool _useRenderWindow = false; private bool _useRenderWindow = false;
private bool _useCompositorDrivenRenderWindowResize = false;
private bool _usePositioningFlags = false; private bool _usePositioningFlags = false;
private X11FocusProxy? _focusProxy; private X11FocusProxy? _focusProxy;
@ -111,7 +112,12 @@ namespace Avalonia.X11
var glx = glfeature as GlxPlatformGraphics; var glx = glfeature as GlxPlatformGraphics;
if (glx != null) if (glx != null)
{
visualInfo = *glx.Display.VisualInfo; 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) else if (glfeature == null)
visualInfo = _x11.TransparentVisualInfo; visualInfo = _x11.TransparentVisualInfo;
@ -569,7 +575,8 @@ namespace Avalonia.X11
Resized?.Invoke(ClientSize, WindowResizeReason.Unspecified); Resized?.Invoke(ClientSize, WindowResizeReason.Unspecified);
}, DispatcherPriority.AsyncRenderTargetResize); }, DispatcherPriority.AsyncRenderTargetResize);
if (_useRenderWindow)
if (_useRenderWindow && !_useCompositorDrivenRenderWindowResize)
XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width, XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width,
ev.ConfigureEvent.height); ev.ConfigureEvent.height);
if (_xSyncState == XSyncState.WaitConfigure) if (_xSyncState == XSyncState.WaitConfigure)
@ -1081,7 +1088,7 @@ namespace Avalonia.X11
var pixelSize = ToPixelSize(clientSize); var pixelSize = ToPixelSize(clientSize);
UpdateSizeHints(pixelSize); UpdateSizeHints(pixelSize);
XConfigureResizeWindow(_x11.Display, _handle, pixelSize); XConfigureResizeWindow(_x11.Display, _handle, pixelSize);
if (_useRenderWindow) if (_useRenderWindow && !_useCompositorDrivenRenderWindowResize)
XConfigureResizeWindow(_x11.Display, _renderHandle, pixelSize); XConfigureResizeWindow(_x11.Display, _renderHandle, pixelSize);
XFlush(_x11.Display); XFlush(_x11.Display);

13
src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs

@ -10,7 +10,7 @@ namespace Avalonia.Skia
/// <summary> /// <summary>
/// Skia render target that renders to a framebuffer surface. No gpu acceleration available. /// Skia render target that renders to a framebuffer surface. No gpu acceleration available.
/// </summary> /// </summary>
internal class FramebufferRenderTarget : IRenderTargetWithProperties internal class FramebufferRenderTarget : IRenderTarget2
{ {
private SKImageInfo _currentImageInfo; private SKImageInfo _currentImageInfo;
private IntPtr _currentFramebufferAddress; private IntPtr _currentFramebufferAddress;
@ -50,10 +50,15 @@ namespace Avalonia.Skia
/// <inheritdoc /> /// <inheritdoc />
public IDrawingContextImpl CreateDrawingContext(bool scaleDrawingToDpi) => public IDrawingContextImpl CreateDrawingContext(bool scaleDrawingToDpi) =>
CreateDrawingContext(scaleDrawingToDpi, out _); CreateDrawingContextCore(scaleDrawingToDpi, out _);
/// <inheritdoc /> /// <inheritdoc />
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) if (_renderTarget == null)
throw new ObjectDisposedException(nameof(FramebufferRenderTarget)); throw new ObjectDisposedException(nameof(FramebufferRenderTarget));
@ -77,7 +82,7 @@ namespace Avalonia.Skia
{ {
Surface = _framebufferSurface, Surface = _framebufferSurface,
Dpi = framebuffer.Dpi, Dpi = framebuffer.Dpi,
ScaleDrawingToDpi = useScaledDrawing ScaleDrawingToDpi = scaleDrawingToDpi
}; };
properties = new() properties = new()

8
src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderTarget.cs

@ -1,4 +1,5 @@
using System; using System;
using Avalonia.Metadata;
using SkiaSharp; using SkiaSharp;
namespace Avalonia.Skia namespace Avalonia.Skia
@ -16,4 +17,11 @@ namespace Avalonia.Skia
bool IsCorrupted { get; } bool IsCorrupted { get; }
} }
[PrivateApi]
//TODO12: Merge with ISkiaGpuRenderTarget
public interface ISkiaGpuRenderTarget2 : ISkiaGpuRenderTarget
{
ISkiaGpuRenderSession BeginRenderingSession(PixelSize pixelSize);
}
} }

13
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs

@ -9,7 +9,7 @@ using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.Skia namespace Avalonia.Skia
{ {
internal class GlRenderTarget : ISkiaGpuRenderTarget internal class GlRenderTarget : ISkiaGpuRenderTarget2
{ {
private readonly GRContext _grContext; private readonly GRContext _grContext;
private IGlPlatformSurfaceRenderTarget _surface; private IGlPlatformSurfaceRenderTarget _surface;
@ -59,9 +59,16 @@ namespace Avalonia.Skia
public double ScaleFactor => _glSession.Scaling; 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; bool success = false;
try try
{ {

21
src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs

@ -5,7 +5,7 @@ namespace Avalonia.Skia
/// <summary> /// <summary>
/// Adapts <see cref="ISkiaGpuRenderTarget"/> to be used within our rendering pipeline. /// Adapts <see cref="ISkiaGpuRenderTarget"/> to be used within our rendering pipeline.
/// </summary> /// </summary>
internal class SkiaGpuRenderTarget : IRenderTarget internal class SkiaGpuRenderTarget : IRenderTarget2
{ {
private readonly ISkiaGpu _skiaGpu; private readonly ISkiaGpu _skiaGpu;
private readonly ISkiaGpuRenderTarget _renderTarget; private readonly ISkiaGpuRenderTarget _renderTarget;
@ -21,9 +21,23 @@ namespace Avalonia.Skia
_renderTarget.Dispose(); _renderTarget.Dispose();
} }
public IDrawingContextImpl CreateDrawingContext(PixelSize expectedPixelSize,
out RenderTargetDrawingContextProperties properties) =>
CreateDrawingContextCore(expectedPixelSize, false, out properties);
public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing) 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 var nfo = new DrawingContextImpl.CreateInfo
{ {
@ -39,5 +53,8 @@ namespace Avalonia.Skia
} }
public bool IsCorrupted => _renderTarget.IsCorrupted; public bool IsCorrupted => _renderTarget.IsCorrupted;
public RenderTargetProperties Properties { get; }
} }
} }

Loading…
Cancel
Save