A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

140 lines
4.1 KiB

using System;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.LogicalTree;
using Avalonia.Rendering.Composition;
using Avalonia.VisualTree;
namespace GpuInterop;
public abstract class DrawingSurfaceDemoBase : Control, IGpuDemo
{
private CompositionSurfaceVisual? _visual;
private Compositor? _compositor;
private readonly Action _update;
private string _info = string.Empty;
private bool _updateQueued;
private bool _initialized;
protected CompositionDrawingSurface? Surface { get; private set; }
public DrawingSurfaceDemoBase()
{
_update = UpdateFrame;
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
Initialize();
}
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
if (_initialized)
FreeGraphicsResources();
_initialized = false;
base.OnDetachedFromLogicalTree(e);
}
async void Initialize()
{
try
{
var selfVisual = ElementComposition.GetElementVisual(this)!;
_compositor = selfVisual.Compositor;
Surface = _compositor.CreateDrawingSurface();
_visual = _compositor.CreateSurfaceVisual();
_visual.Size = new (Bounds.Width, Bounds.Height);
_visual.Surface = Surface;
ElementComposition.SetElementChildVisual(this, _visual);
var (res, info) = await DoInitialize(_compositor, Surface);
_info = info;
if (ParentControl != null)
ParentControl.Info = info;
_initialized = res;
QueueNextFrame();
}
catch (Exception e)
{
if (ParentControl != null)
ParentControl.Info = e.ToString();
}
}
void UpdateFrame()
{
_updateQueued = false;
var root = this.GetVisualRoot();
if (root == null)
return;
_visual!.Size = new (Bounds.Width, Bounds.Height);
var size = PixelSize.FromSize(Bounds.Size, root.RenderScaling);
RenderFrame(size);
if (SupportsDisco && Disco > 0)
QueueNextFrame();
}
void QueueNextFrame()
{
if (_initialized && !_updateQueued && _compositor != null)
{
_updateQueued = true;
_compositor?.RequestCompositionUpdate(_update);
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
if(change.Property == BoundsProperty)
QueueNextFrame();
base.OnPropertyChanged(change);
}
async Task<(bool success, string info)> DoInitialize(Compositor compositor,
CompositionDrawingSurface compositionDrawingSurface)
{
var interop = await compositor.TryGetCompositionGpuInterop();
if (interop == null)
return (false, "Compositor doesn't support interop for the current backend");
return InitializeGraphicsResources(compositor, compositionDrawingSurface, interop);
}
protected abstract (bool success, string info) InitializeGraphicsResources(Compositor compositor,
CompositionDrawingSurface compositionDrawingSurface, ICompositionGpuInterop gpuInterop);
protected abstract void FreeGraphicsResources();
protected abstract void RenderFrame(PixelSize pixelSize);
protected virtual bool SupportsDisco => false;
public void Update(GpuDemo? parent, float yaw, float pitch, float roll, float disco)
{
ParentControl = parent;
if (ParentControl != null)
{
ParentControl.Info = _info;
ParentControl.DiscoVisible = true;
}
Yaw = yaw;
Pitch = pitch;
Roll = roll;
Disco = disco;
QueueNextFrame();
}
public GpuDemo? ParentControl { get; private set; }
public float Disco { get; private set; }
public float Roll { get; private set; }
public float Pitch { get; private set; }
public float Yaw { get; private set; }
}