Skip to content

Commit

Permalink
[GLX] Resize the platform render target to compositor-provided size (#…
Browse files Browse the repository at this point in the history
…17779)

We should be doing that for other platforms later as well, since only compositor knows what scene size it's planning to draw
  • Loading branch information
kekekeks authored Dec 16, 2024
1 parent 6cd1cb4 commit eada7ba
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 25 deletions.
23 changes: 16 additions & 7 deletions src/Avalonia.Base/Platform/IRenderTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

/// <summary>
/// Creates an <see cref="IDrawingContextImpl"/> for a rendering session.
/// </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>
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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,16 @@ 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
// Check if render target can be rendered to directly and preserves the previous frame
|| !(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))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Avalonia.Metadata;

namespace Avalonia.OpenGL.Surfaces
{
Expand All @@ -11,4 +12,11 @@ public interface IGlPlatformSurfaceRenderTargetWithCorruptionInfo : IGlPlatformS
{
bool IsCorrupted { get; }
}

[PrivateApi]
public interface IGlPlatformSurfaceRenderTarget2 : IGlPlatformSurfaceRenderTargetWithCorruptionInfo
{
IGlPlatformSurfaceRenderingSession BeginDraw(PixelSize expectedPixelSize);
}

}
2 changes: 2 additions & 0 deletions src/Avalonia.X11/Glx/GlxDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<GlVersion> probeProfiles)
{
_x11 = x11;
Expand Down
33 changes: 28 additions & 5 deletions src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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;
}

Expand All @@ -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; }
}
Expand Down
11 changes: 9 additions & 2 deletions src/Avalonia.X11/X11Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);

Expand Down
13 changes: 9 additions & 4 deletions src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Avalonia.Skia
/// <summary>
/// Skia render target that renders to a framebuffer surface. No gpu acceleration available.
/// </summary>
internal class FramebufferRenderTarget : IRenderTargetWithProperties
internal class FramebufferRenderTarget : IRenderTarget2
{
private SKImageInfo _currentImageInfo;
private IntPtr _currentFramebufferAddress;
Expand Down Expand Up @@ -50,10 +50,15 @@ public void Dispose()

/// <inheritdoc />
public IDrawingContextImpl CreateDrawingContext(bool scaleDrawingToDpi) =>
CreateDrawingContext(scaleDrawingToDpi, out _);
CreateDrawingContextCore(scaleDrawingToDpi, out _);

/// <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)
throw new ObjectDisposedException(nameof(FramebufferRenderTarget));
Expand All @@ -77,7 +82,7 @@ public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing, out Rende
{
Surface = _framebufferSurface,
Dpi = framebuffer.Dpi,
ScaleDrawingToDpi = useScaledDrawing
ScaleDrawingToDpi = scaleDrawingToDpi
};

properties = new()
Expand Down
8 changes: 8 additions & 0 deletions src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderTarget.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Avalonia.Metadata;
using SkiaSharp;

namespace Avalonia.Skia
Expand All @@ -16,4 +17,11 @@ public interface ISkiaGpuRenderTarget : IDisposable

bool IsCorrupted { get; }
}

[PrivateApi]
//TODO12: Merge with ISkiaGpuRenderTarget
public interface ISkiaGpuRenderTarget2 : ISkiaGpuRenderTarget
{
ISkiaGpuRenderSession BeginRenderingSession(PixelSize pixelSize);
}
}
13 changes: 10 additions & 3 deletions src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Avalonia.Skia
{
internal class GlRenderTarget : ISkiaGpuRenderTarget
internal class GlRenderTarget : ISkiaGpuRenderTarget2
{
private readonly GRContext _grContext;
private IGlPlatformSurfaceRenderTarget _surface;
Expand Down Expand Up @@ -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
{
Expand Down
21 changes: 19 additions & 2 deletions src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Avalonia.Skia
/// <summary>
/// Adapts <see cref="ISkiaGpuRenderTarget"/> to be used within our rendering pipeline.
/// </summary>
internal class SkiaGpuRenderTarget : IRenderTarget
internal class SkiaGpuRenderTarget : IRenderTarget2
{
private readonly ISkiaGpu _skiaGpu;
private readonly ISkiaGpuRenderTarget _renderTarget;
Expand All @@ -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
{
Expand All @@ -39,5 +53,8 @@ public IDrawingContextImpl CreateDrawingContext(bool useScaledDrawing)
}

public bool IsCorrupted => _renderTarget.IsCorrupted;
public RenderTargetProperties Properties { get; }


}
}

0 comments on commit eada7ba

Please sign in to comment.