Skip to content

Commit

Permalink
feat: 2-layer skia for GTK
Browse files Browse the repository at this point in the history
  • Loading branch information
ramezgerges committed May 17, 2024
1 parent 2c3f532 commit d6493e7
Show file tree
Hide file tree
Showing 16 changed files with 64 additions and 36 deletions.
7 changes: 7 additions & 0 deletions src/Uno.UI.Composition/Composition/Visual.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,20 @@ public partial class Visual : CompositionObject, I3DTransformableObject
private CompositionCompositeMode _compositeMode;
private ICompositionTarget? _compositionTarget;

// a visual is a flyout visual if it's directly set by SetAsFlyoutVisual or is a child of a flyout visual
// This doesn't yet handle the case of a child visual changing parents. As in: once a flyout visual, always a flyout visual.
private bool _isFlyoutVisual;

internal Visual(Compositor compositor) : base(compositor)
{
InitializePartial();
}

partial void InitializePartial();

internal void SetAsFlyoutVisual() => _isFlyoutVisual = true;
protected bool IsFlyoutVisual() => _isFlyoutVisual || (Parent?.IsFlyoutVisual() ?? false);

internal VisualInteractionSource? VisualInteractionSource { get; set; }

internal bool IsTranslationEnabled { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI.Composition/Composition/Visual.skia.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ internal int ZIndex
/// </summary>
/// <param name="surface">The surface on which this visual should be rendered.</param>
/// <param name="offsetOverride">The offset (from the origin) to render the Visual at. If null, the offset properties on the Visual like <see cref="Offset"/> and <see cref="AnchorPoint"/> are used.</param>
internal void RenderRootVisual(SKSurface surface, Vector2? offsetOverride = null)
internal void RenderRootVisual(SKSurface surface, Vector2? offsetOverride = null, bool isFlyoutSurface = false)
{
if (this is { Opacity: 0 } or { IsVisible: false })
{
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public void Run()

public void TakeScreenshot(string filePath)
{
InitialWindow?.Host.Renderer?.TakeScreenshot(filePath);
InitialWindow?.Host.TakeScreenshot(filePath);
}

private void InitializeDispatcher()
Expand Down
6 changes: 4 additions & 2 deletions src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ internal abstract partial class GLRenderSurfaceBase : GLArea, IGtkRenderer
private GRContext? _grContext;
private GRBackendRenderTarget? _renderTarget;
private SKSurface? _surface;
private bool _isFlyoutSurface;

/// <summary>
/// This field determines if OpenGL ES shouls be used or not.
Expand All @@ -51,7 +52,7 @@ internal abstract partial class GLRenderSurfaceBase : GLArea, IGtkRenderer

public SKColor BackgroundColor { get; set; }

public GLRenderSurfaceBase(IGtkXamlRootHost host)
public GLRenderSurfaceBase(IGtkXamlRootHost host, bool isFlyoutSurface)
{
_xamlRoot = GtkManager.XamlRootMap.GetRootForHost(host) ?? throw new InvalidOperationException("XamlRoot must not be null when renderer is initialized");
_xamlRoot.Changed += OnXamlRootChanged;
Expand All @@ -70,6 +71,7 @@ public GLRenderSurfaceBase(IGtkXamlRootHost host)
// and arranged properly.
AutoRender = false;
_host = host;
_isFlyoutSurface = isFlyoutSurface;
}

public Widget Widget => this;
Expand Down Expand Up @@ -142,7 +144,7 @@ private void UnoGLDrawingArea_Render(object o, RenderArgs args)

if (_host.RootElement?.Visual is { } rootVisual)
{
Compositor.GetSharedCompositor().RenderRootVisual(_surface, rootVisual);
Compositor.GetSharedCompositor().RenderRootVisual(_surface, rootVisual, _isFlyoutSurface);
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/Uno.UI.Runtime.Skia.Gtk/Rendering/GtkRendererProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Uno.UI.Runtime.Skia.Gtk.Rendering;

internal static class GtkRendererProvider
{
public static async Task<IGtkRenderer> CreateForHostAsync(IGtkXamlRootHost host)
public static async Task<IGtkRenderer> CreateForHostAsync(IGtkXamlRootHost host, bool isFlyoutSurface)
{
RenderSurfaceType? renderSurfaceType = host.RenderSurfaceType;
if (TryReadRenderSurfaceTypeEnvironment(out var overridenSurfaceType))
Expand Down Expand Up @@ -83,15 +83,15 @@ async void ValidateSurface()
}
}

return BuildRenderSurfaceType(renderSurfaceType.Value, host);
return BuildRenderSurfaceType(renderSurfaceType.Value, host, isFlyoutSurface);
}

private static IGtkRenderer BuildRenderSurfaceType(RenderSurfaceType renderSurfaceType, IGtkXamlRootHost host)
private static IGtkRenderer BuildRenderSurfaceType(RenderSurfaceType renderSurfaceType, IGtkXamlRootHost host, bool isFlyoutSurface)
=> renderSurfaceType switch
{
RenderSurfaceType.OpenGLES => new OpenGLESRenderSurface(host),
RenderSurfaceType.OpenGL => new OpenGLRenderSurface(host),
RenderSurfaceType.Software => new SoftwareRenderSurface(host),
RenderSurfaceType.OpenGLES => new OpenGLESRenderSurface(host, isFlyoutSurface),
RenderSurfaceType.OpenGL => new OpenGLRenderSurface(host, isFlyoutSurface),
RenderSurfaceType.Software => new SoftwareRenderSurface(host, isFlyoutSurface),
_ => throw new InvalidOperationException($"Unsupported RenderSurfaceType {GtkHost.Current!.RenderSurfaceType}")
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal class OpenGLESRenderSurface : GLRenderSurfaceBase
private static DefaultNativeContext NativeContext
=> _nativeContext ??= new Silk.NET.Core.Contexts.DefaultNativeContext(new OpenGLESLibraryNameContainer().GetLibraryName());

public OpenGLESRenderSurface(IGtkXamlRootHost host) : base(host)
public OpenGLESRenderSurface(IGtkXamlRootHost host, bool isFlyoutSurface) : base(host, isFlyoutSurface)
{
_glES = new GL(NativeContext);
_isGLES = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal class OpenGLRenderSurface : GLRenderSurfaceBase
private static DefaultNativeContext NativeContext
=> _nativeContext ??= new Silk.NET.Core.Contexts.DefaultNativeContext(new GLCoreLibraryNameContainer().GetLibraryName());

public OpenGLRenderSurface(IGtkXamlRootHost host) : base(host)
public OpenGLRenderSurface(IGtkXamlRootHost host, bool isFlyoutSurface) : base(host, isFlyoutSurface)
{
SetRequiredVersion(3, 3);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ internal class SoftwareRenderSurface : DrawingArea, IGtkRenderer
private int _bheight, _bwidth;
private ImageSurface? _gtkSurface;
private int renderCount;
private bool _isFlyoutSurface;

private float _scale = 1;
private XamlRoot _xamlRoot;
Expand All @@ -35,7 +36,7 @@ internal class SoftwareRenderSurface : DrawingArea, IGtkRenderer
public SKColor BackgroundColor { get; set; }
= SKColors.White;

public SoftwareRenderSurface(IGtkXamlRootHost host)
public SoftwareRenderSurface(IGtkXamlRootHost host, bool isFlyoutSurface)
{
_xamlRoot = GtkManager.XamlRootMap.GetRootForHost(host) ?? throw new InvalidOperationException("XamlRoot must not be null when renderer is initialized");
_xamlRoot.Changed += OnXamlRootChanged;
Expand All @@ -51,6 +52,7 @@ public SoftwareRenderSurface(IGtkXamlRootHost host)
}
}
_host = host;
_isFlyoutSurface = isFlyoutSurface;
}

public Widget Widget => this;
Expand Down Expand Up @@ -96,7 +98,7 @@ protected override bool OnDrawn(Context cr)
if (_host.RootElement?.Visual is { } rootVisual)
{
var compositor = Compositor.GetSharedCompositor();
compositor.RenderRootVisual(_surface, rootVisual);
compositor.RenderRootVisual(_surface, rootVisual, _isFlyoutSurface);

if (compositor.IsSoftwareRenderer is null)
{
Expand Down
48 changes: 32 additions & 16 deletions src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindowHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
using Uno.UI.Hosting;
using Uno.UI.Runtime.Skia.Gtk.Hosting;
using Uno.UI.Runtime.Skia.Gtk.Rendering;
using Uno.UI.Xaml.Core;
using Windows.Graphics.Display;
using Windows.Foundation;
using SkiaSharp;
using WinUI = Microsoft.UI.Xaml;
using WinUIWindow = Microsoft.UI.Xaml.Window;
using GtkWindow = Gtk.Window;
Expand All @@ -26,9 +26,9 @@ internal class UnoGtkWindowHost : IGtkXamlRootHost
private readonly Fixed _nativeOverlayLayer = new();
private readonly CompositeDisposable _disposables = new();

private Widget? _area;
private XamlRoot? _xamlRoot;
private IGtkRenderer? _renderer;
private IGtkRenderer? _bottomRenderer;
private IGtkRenderer? _topRenderer;

public UnoGtkWindowHost(GtkWindow gtkWindow, WinUIWindow winUIWindow)
{
Expand All @@ -50,16 +50,15 @@ public UnoGtkWindowHost(GtkWindow gtkWindow, WinUIWindow winUIWindow)

public Fixed? NativeOverlayLayer => _nativeOverlayLayer;

public IGtkRenderer? Renderer => _renderer;

public async Task InitializeAsync()
{
_renderer = await GtkRendererProvider.CreateForHostAsync(this);
_bottomRenderer = await GtkRendererProvider.CreateForHostAsync(this, isFlyoutSurface: false);
_topRenderer = await GtkRendererProvider.CreateForHostAsync(this, isFlyoutSurface: true);
UpdateRendererBackground();
_topRenderer.BackgroundColor = SKColors.Transparent;

var overlay = new Overlay();

_area = (Widget)_renderer;
var area = (Widget)_bottomRenderer;
var area2 = (Widget)_topRenderer;

_xamlRoot = GtkManager.XamlRootMap.GetRootForHost(this);
_xamlRoot!.Changed += OnXamlRootChanged;
Expand All @@ -69,18 +68,32 @@ public async Task InitializeAsync()
// Either way, make sure to match the subscription with the size, i.e. either use
// _area.Realized/SizeAllocated and _area.AllocatedXX or _gtkWindow.Realized/SizeAllocation
// and _gtkWindow.AllocatedXX
_area.Realized += (s, e) =>
area.Realized += (s, e) =>
{
UpdateWindowSize(area.AllocatedWidth, area.AllocatedHeight);
};
area2.Realized += (s, e) =>
{
UpdateWindowSize(_area.AllocatedWidth, _area.AllocatedHeight);
area2.Window.PassThrough = true;
};

_area.SizeAllocated += (s, e) =>
// PassThrough makes it so that any pointer event will fall through.
// We can't selectively pass certain events through, so we keep it off.
// area2.Realized += (s, e) =>
// {
// area2.Window.PassThrough = true;
// };

area.SizeAllocated += (s, e) =>
{
UpdateWindowSize(e.Allocation.Width, e.Allocation.Height);
};

overlay.Add(_area);
var overlay = new Overlay();
overlay.Add(area);
overlay.AddOverlay(_nativeOverlayLayer);
overlay.AddOverlay(area2);
overlay.SetOverlayPassThrough(area2, true);
_eventBox.Add(overlay);
_gtkWindow.Add(_eventBox);
}
Expand All @@ -107,9 +120,9 @@ private void UpdateRendererBackground()
{
if (_winUIWindow.Background is WinUI.Media.SolidColorBrush brush)
{
if (_renderer is not null)
if (_bottomRenderer is not null)
{
_renderer.BackgroundColor = brush.Color;
_bottomRenderer.BackgroundColor = brush.Color;
}
}
else
Expand All @@ -125,6 +138,9 @@ void IXamlRootHost.InvalidateRender()
{
_winUIWindow.RootElement?.XamlRoot?.InvalidateOverlays();

_renderer?.InvalidateRender();
_bottomRenderer?.InvalidateRender();
_topRenderer?.InvalidateRender();
}

public void TakeScreenshot(string filePath) => _bottomRenderer?.TakeScreenshot(filePath);
}
2 changes: 1 addition & 1 deletion src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ void Invalidate()

if (_host.RootElement?.Visual is { } rootVisual)
{
_host.RootElement.XamlRoot!.Compositor.RenderRootVisual(surface, rootVisual);
_host.RootElement.XamlRoot!.Compositor.RenderRootVisual(surface, rootVisual, false);
}

_fbDev.VSync();
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI.Runtime.Skia.MacOS/MacOSWindowHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private void Draw(SKSurface surface)

if (RootElement?.Visual is { } rootVisual)
{
RootElement.XamlRoot?.Compositor.RenderRootVisual(surface, rootVisual);
RootElement.XamlRoot?.Compositor.RenderRootVisual(surface, rootVisual, false);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public void Render(DrawingContext drawingContext)

if (_host.RootElement?.Visual is { } rootVisual)
{
rootVisual.Compositor.RenderRootVisual(_surface, rootVisual);
rootVisual.Compositor.RenderRootVisual(_surface, rootVisual, false);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public void Render(DrawingContext drawingContext)
surface.Canvas.SetMatrix(SKMatrix.CreateScale((float)dpiScaleX, (float)dpiScaleY));
if (_host.RootElement?.Visual is { } rootVisual)
{
rootVisual.Compositor.RenderRootVisual(surface, rootVisual);
rootVisual.Compositor.RenderRootVisual(surface, rootVisual, false);

if (rootVisual.Compositor.IsSoftwareRenderer is null)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI.Runtime.Skia.X11/X11OpenGLRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void IX11Renderer.InvalidateRender()

if (_host.RootElement?.Visual is { } rootVisual)
{
_host.RootElement.XamlRoot!.Compositor.RenderRootVisual(_surface, rootVisual);
_host.RootElement.XamlRoot!.Compositor.RenderRootVisual(_surface, rootVisual, false);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI.Runtime.Skia.X11/X11SoftwareRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void IX11Renderer.InvalidateRender()

if (host.RootElement?.Visual is { } rootVisual)
{
host.RootElement.XamlRoot!.Compositor.RenderRootVisual(_surface, rootVisual);
host.RootElement.XamlRoot!.Compositor.RenderRootVisual(_surface, rootVisual, false);
}

canvas.Flush();
Expand Down
1 change: 1 addition & 0 deletions src/Uno.UI/UI/Xaml/Controls/Popup/PopupRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal partial class PopupRoot : Panel

public PopupRoot()
{
Visual.SetAsFlyoutVisual();
KeyDown += OnKeyDown;
Loaded += OnRootLoaded;
Unloaded += OnRootUnloaded;
Expand Down

0 comments on commit d6493e7

Please sign in to comment.