Răsfoiți Sursa

dispatcher wip

flabbet 1 an în urmă
părinte
comite
b3b23d7858

+ 57 - 0
src/PixiEditor.Engine.AvaloniaPlatform/AvaloniaHost.cs

@@ -0,0 +1,57 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Platform;
+using PixiEditor.Engine.AvaloniaPlatform.Exceptions;
+using PixiEditor.Numerics;
+using SkiaSharp;
+
+namespace PixiEditor.Engine.AvaloniaPlatform;
+
+public class AvaloniaHost
+{
+    public VecI Size { get; }
+    
+    private PixiEngineTopLevel _topLevel;
+    public AvaloniaHost(VecI size, Control control)
+    {
+        Size = size;
+        
+        var locator = AvaloniaLocator.Current;
+        
+        if(locator.GetService<IPlatformGraphics>() is not PixiEngineGraphics graphics)
+        {
+            throw new PlatformNotInitializedException($"No PixiEngine grapics fround. Did you call UsePixiEngine()?.");
+        }
+        
+        PixiEngineTopLevel topLevel = new PixiEngineTopLevel(new PixiEngineTopLevelImpl(PixiEnginePlatform.Compositor, graphics))
+        {
+            Background = null
+        };
+        topLevel.Content = control;
+        
+        topLevel.Impl.SetRenderSize(new PixelSize(size.X, size.Y), 1);
+        
+        topLevel.Prepare();
+        topLevel.StartRendering();
+        
+        _topLevel = topLevel;
+    }
+
+    public void Update(double dt)
+    {
+        PixiEnginePlatform.TriggerRenderTick();
+
+        _topLevel.Impl.OnDraw(new Rect(0, 0, Size.X, Size.Y));
+    }
+
+    public void Render(SKSurface targetSurface, double dt)
+    {
+        var surface = _topLevel.Impl.Surface;
+        targetSurface.Canvas.DrawSurface(surface.Surface, new SKPoint(0, 0));
+    }
+    
+    public void Resize(VecI newSize)
+    {
+        _topLevel.Impl.SetRenderSize(new PixelSize(newSize.X, newSize.Y), 1);
+    }
+}

+ 15 - 0
src/PixiEditor.Engine.AvaloniaPlatform/ManualRenderTimer.cs

@@ -0,0 +1,15 @@
+using Avalonia.Rendering;
+
+namespace PixiEditor.Engine.AvaloniaPlatform;
+
+/// <summary>A <see cref="IRenderTimer"/> implementation that is only triggered manually.</summary>
+internal sealed class ManualRenderTimer : IRenderTimer
+{
+    public event Action<TimeSpan>? Tick;
+
+    bool IRenderTimer.RunsInBackground
+        => false;
+
+    public void TriggerTick(TimeSpan elapsed)
+        => Tick?.Invoke(elapsed);
+}

+ 26 - 0
src/PixiEditor.Engine.AvaloniaPlatform/PixiEngineDispatcher.cs

@@ -0,0 +1,26 @@
+using Avalonia.Threading;
+
+namespace PixiEditor.Engine.AvaloniaPlatform;
+
+public class PixiEngineDispatcher : IDispatcherImpl
+{
+    private readonly Thread _mainThread;
+    private readonly SysTimer _timer;
+    private readonly SendOrPostCallback _invokeSignaled; // cached delegate
+    private readonly SendOrPostCallback _invokeTimer;  // cached delegate
+    
+    public void Signal()
+    {
+        throw new NotImplementedException();
+    }
+
+    public void UpdateTimer(long? dueTimeInMs)
+    {
+        throw new NotImplementedException();
+    }
+
+    public bool CurrentThreadIsLoopThread => _mainThread == Thread.CurrentThread;
+    public long Now { get; }
+    public event Action? Signaled;
+    public event Action? Timer;
+}

+ 1 - 1
src/PixiEditor.Engine.AvaloniaPlatform/PixiEngineGpuRenderSession.cs

@@ -20,6 +20,6 @@ public class PixiEngineGpuRenderSession : ISkiaGpuRenderSession
     
     
     public void Dispose()
     public void Dispose()
     {
     {
-        //Surface.Surface?.Flush(true);
+        Surface.Surface?.Flush(true);
     }
     }
 }
 }

+ 15 - 4
src/PixiEditor.Engine.AvaloniaPlatform/PixiEnginePlatform.cs

@@ -11,17 +11,28 @@ namespace PixiEditor.Engine.AvaloniaPlatform;
 internal class PixiEnginePlatform
 internal class PixiEnginePlatform
 {
 {
     private static Compositor? _compositor;
     private static Compositor? _compositor;
+    private static ManualRenderTimer? _renderTimer;
     public static Compositor Compositor => _compositor ?? throw new PlatformNotInitializedException($"({nameof(PixiEnginePlatform)})was not initialized.");
     public static Compositor Compositor => _compositor ?? throw new PlatformNotInitializedException($"({nameof(PixiEnginePlatform)})was not initialized.");
     public static void Initialize()
     public static void Initialize()
     {
     {
-        SkiaPixiEngine engine = SkiaPixiEngine.Create();
-        var graphics = new PixiEngineGraphics(engine);
+        var graphics = new PixiEngineGraphics((SkiaPixiEngine)PixiEngine.ActiveEngine);
         
         
         AvaloniaLocator.CurrentMutable
         AvaloniaLocator.CurrentMutable
             .Bind<IPlatformGraphics>().ToConstant(graphics)
             .Bind<IPlatformGraphics>().ToConstant(graphics)
-            .Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
-            .Bind<IWindowingPlatform>().ToConstant(new PixiEngineWindowingPlatform());
+            .Bind<IRenderTimer>().ToConstant(new ManualRenderTimer())
+            .Bind<IWindowingPlatform>().ToConstant(new PixiEngineWindowingPlatform(graphics));
 
 
         _compositor = new Compositor(graphics);
         _compositor = new Compositor(graphics);
+        _renderTimer = new ManualRenderTimer();
+    }
+    
+    public static void TriggerRenderTick()
+    {
+        if (_renderTimer is null)
+        {
+            return;
+        }
+        
+        _renderTimer.TriggerTick(new TimeSpan((long) (PixiEngine.ActiveEngine.Ticks * 10UL)));
     }
     }
 }
 }

+ 6 - 2
src/PixiEditor.Engine.AvaloniaPlatform/PixiEngineSkiaGpu.cs

@@ -17,7 +17,6 @@ public class PixiEngineSkiaGpu : ISkiaGpu
 
 
     public PixiEngineSkiaGpu(SkiaPixiEngine engine)
     public PixiEngineSkiaGpu(SkiaPixiEngine engine)
     {
     {
-        engine.SetupBackendWindowLess();
         context = engine.GrContext;
         context = engine.GrContext;
         glContext = engine.GlContext;
         glContext = engine.GlContext;
     }
     }
@@ -43,9 +42,14 @@ public class PixiEngineSkiaGpu : ISkiaGpu
         if(size.Width <= 0 || size.Height <= 0)
         if(size.Width <= 0 || size.Height <= 0)
             return null;
             return null;
         
         
-        return new PixiEngineSkiaSurface(DrawingSurface.Create(new ImageInfo(size.Width, size.Height)), session?.ScaleFactor ?? 1);
+        return new PixiEngineSkiaSurface(CreateSurface(size.Width, size.Height), session?.ScaleFactor ?? 1);
     }
     }
 
 
+    public DrawingSurface CreateSurface(int sizeX, int sizeY)
+    {
+        return DrawingSurface.Create(new ImageInfo(sizeX, sizeY));
+    }
+    
     public void Dispose()
     public void Dispose()
     {
     {
         context.Dispose();
         context.Dispose();

+ 2 - 15
src/PixiEditor.Engine.AvaloniaPlatform/PixiEngineSkiaSurface.cs

@@ -8,24 +8,17 @@ public class PixiEngineSkiaSurface : ISkiaSurface
 {
 {
     public DrawingSurface BackendSurface { get; }
     public DrawingSurface BackendSurface { get; }
 
 
-    public SKSurface Surface => nonDrawingSurface ?? BackendSurface?.Native as SKSurface;
+    public SKSurface Surface => BackendSurface?.Native as SKSurface;
     public bool CanBlit => false;
     public bool CanBlit => false;
     public bool IsDisposed
     public bool IsDisposed
     {
     {
         get
         get
         {
         {
-            if (nonDrawingSurface != null)
-            {
-                return false;
-            }
-            
             return BackendSurface.IsDisposed;
             return BackendSurface.IsDisposed;
         }
         }
     }
     }
 
 
-    public double RenderScaling { get; }
-
-    private SKSurface? nonDrawingSurface;
+    public double RenderScaling { get; set; }
 
 
     public PixiEngineSkiaSurface(DrawingSurface surface, double renderScaling)
     public PixiEngineSkiaSurface(DrawingSurface surface, double renderScaling)
     {
     {
@@ -33,12 +26,6 @@ public class PixiEngineSkiaSurface : ISkiaSurface
         RenderScaling = renderScaling;
         RenderScaling = renderScaling;
     }
     }
 
 
-    public PixiEngineSkiaSurface(SKSurface surface, double scaling)
-    {
-       nonDrawingSurface = surface;
-       RenderScaling = scaling;
-    }
-
     public void Blit(SKCanvas canvas)
     public void Blit(SKCanvas canvas)
     {
     {
         throw new NotSupportedException();
         throw new NotSupportedException();

+ 60 - 5
src/PixiEditor.Engine.AvaloniaPlatform/PixiEngineTopLevelImpl.cs

@@ -11,7 +11,7 @@ internal sealed class PixiEngineTopLevelImpl : ITopLevelImpl
 {
 {
     public Size ClientSize { get; private set; }
     public Size ClientSize { get; private set; }
     public Size? FrameSize { get; private set; }
     public Size? FrameSize { get; private set; }
-    public double RenderScaling { get; } = 1;
+    public double RenderScaling { get; private set; } = 1;
     public IEnumerable<object> Surfaces { get; private set; }
     public IEnumerable<object> Surfaces { get; private set; }
     public Action<RawInputEventArgs>? Input { get; set; }
     public Action<RawInputEventArgs>? Input { get; set; }
     public Action<Rect>? Paint { get; set; }
     public Action<Rect>? Paint { get; set; }
@@ -38,23 +38,78 @@ internal sealed class PixiEngineTopLevelImpl : ITopLevelImpl
         }
         }
     }
     }
 
 
+    public PixiEngineSkiaSurface Surface
+    {
+        get => _surface;
+        set
+        {
+            _surface = value;
+            Surfaces = new[] { _surface };
+        }
+    }
+    
+    public PixiEngineGraphics Graphics { get; }
+
     private PixiEngineSkiaSurface _surface;
     private PixiEngineSkiaSurface _surface;
 
 
     private IInputRoot? _inputRoot;
     private IInputRoot? _inputRoot;
     private ICursorImpl _cursor;
     private ICursorImpl _cursor;
     private WindowTransparencyLevel _transparencyLevel;
     private WindowTransparencyLevel _transparencyLevel;
+    private PixelSize _renderSize;
 
 
-    public PixiEngineTopLevelImpl(Compositor compositor)
+    public PixiEngineTopLevelImpl(Compositor compositor, PixiEngineGraphics graphics)
     {
     {
         Compositor = compositor;
         Compositor = compositor;
+        Graphics = graphics;
     }
     }
     
     
-    public void SetRenderSize(Size size)
+    public void OnDraw(Rect rect)
     {
     {
-        ClientSize = size;
-        FrameSize = size;
+        Paint?.Invoke(rect);
+    }
+    
+    public void SetRenderSize(PixelSize renderSize, double renderScaling)
+    {
+        var hasScalingChanged = RenderScaling != renderScaling;
+        if (_renderSize == renderSize && !hasScalingChanged)
+            return;
+
+        var oldClientSize = ClientSize;
+        var unclampedClientSize = renderSize.ToSize(renderScaling);
+
+        ClientSize = new Size(Math.Max(unclampedClientSize.Width, 0.0), Math.Max(unclampedClientSize.Height, 0.0));
+        RenderScaling = renderScaling;
+
+        if (_renderSize != renderSize) 
+        {
+            _renderSize = renderSize;
+
+            if (_surface is not null) 
+            {
+                _surface.Dispose();
+                _surface = null;
+            }
+
+            _surface = CreateSurface();
+        }
+
+        if (hasScalingChanged) 
+        {
+            if (_surface != null)
+                _surface.RenderScaling = RenderScaling;
+            
+            ScalingChanged?.Invoke(RenderScaling);
+        }
+
+        if (oldClientSize != ClientSize)
+            Resized?.Invoke(ClientSize, hasScalingChanged ? WindowResizeReason.DpiChange : WindowResizeReason.Unspecified);
     }
     }
 
 
+    private PixiEngineSkiaSurface CreateSurface()
+    {
+        return new PixiEngineSkiaSurface(Graphics.GetSharedContext().CreateSurface(_renderSize.Width, _renderSize.Height), RenderScaling);
+    }
+    
     public object? TryGetFeature(Type featureType)
     public object? TryGetFeature(Type featureType)
     {
     {
         return null;
         return null;

+ 4 - 3
src/PixiEditor.Engine.AvaloniaPlatform/PixiEngineWindowingPlatform.cs

@@ -3,13 +3,14 @@ using PixiEditor.Engine.AvaloniaPlatform.Windowing;
 
 
 namespace PixiEditor.Engine.AvaloniaPlatform;
 namespace PixiEditor.Engine.AvaloniaPlatform;
 
 
-public class PixiEngineWindowingPlatform() : IWindowingPlatform
+public class PixiEngineWindowingPlatform(PixiEngineGraphics graphics) : IWindowingPlatform
 {
 {
+    private PixiEngineGraphics _graphics = graphics;
+    
     public IWindowImpl CreateWindow()
     public IWindowImpl CreateWindow()
     {
     {
-        PixiEngineTopLevel topLevel = new PixiEngineTopLevel(new PixiEngineTopLevelImpl(PixiEnginePlatform.Compositor));
         Window window = new Window();
         Window window = new Window();
-        return new PixiEngineWindowImpl(window, topLevel);
+        return new PixiEngineWindowImpl(window);
     }
     }
 
 
     public IWindowImpl CreateEmbeddableWindow()
     public IWindowImpl CreateEmbeddableWindow()

+ 10 - 5
src/PixiEditor.Engine.AvaloniaPlatform/Windowing/PixiEngineWindowImpl.cs

@@ -64,19 +64,24 @@ public class PixiEngineWindowImpl : IWindowImpl
     private WindowTransparencyLevel _transparencyLevel;
     private WindowTransparencyLevel _transparencyLevel;
     private Window _underlyingWindow;
     private Window _underlyingWindow;
 
 
-    public PixiEngineWindowImpl(Window underlyingWindow, PixiEngineTopLevel topLevel)
+    public PixiEngineWindowImpl(Window underlyingWindow)
     {
     {
         _underlyingWindow = underlyingWindow;
         _underlyingWindow = underlyingWindow;
         Compositor = PixiEnginePlatform.Compositor;
         Compositor = PixiEnginePlatform.Compositor;
-        
-        topLevel.Impl.Surface = new PixiEngineSkiaSurface(underlyingWindow.FramebufferSurface, topLevel.RenderScaling);
-        topLevel.Impl.SetRenderSize(new Size(underlyingWindow.Size.X, underlyingWindow.Size.Y));
+
+        //topLevel.Impl.Surface = new PixiEngineSkiaSurface(topLevel.Impl.Graphics.GetSharedContext().CreateSurface(underlyingWindow.Size.X, underlyingWindow.Size.Y, RenderScaling), RenderScaling);
+        /*topLevel.Impl.SetRenderSize(new Size(underlyingWindow.Size.X, underlyingWindow.Size.Y));
         ClientSize = new Size(underlyingWindow.Size.X, underlyingWindow.Size.Y);
         ClientSize = new Size(underlyingWindow.Size.X, underlyingWindow.Size.Y);
         
         
         topLevel.Prepare();
         topLevel.Prepare();
         topLevel.StartRendering();
         topLevel.StartRendering();
         
         
-        topLevel.Content = underlyingWindow;
+        _underlyingWindow.Render += (surface, d) =>
+        {
+            //Paint?.Invoke(new Rect(0, 0, underlyingWindow.Size.X, underlyingWindow.Size.Y));  
+        };
+        
+        topLevel.Content = underlyingWindow;*/
     }
     }
 
 
     object? IOptionalFeatureProvider.TryGetFeature(Type featureType) { return null; }
     object? IOptionalFeatureProvider.TryGetFeature(Type featureType) { return null; }

+ 7 - 5
src/PixiEditor.Engine/PixiEngine.cs

@@ -12,6 +12,8 @@ public abstract class PixiEngine
     
     
     public GRContext GrContext { get; protected set; }
     public GRContext GrContext { get; protected set; }
     public IGLContext GlContext { get; protected set; }
     public IGLContext GlContext { get; protected set; }
+    public ulong Ticks { get; private set; }
+
     private IDrawingBackend _drawingBackend;
     private IDrawingBackend _drawingBackend;
     
     
     internal PixiEngine(IDrawingBackend drawingBackend)
     internal PixiEngine(IDrawingBackend drawingBackend)
@@ -20,13 +22,13 @@ public abstract class PixiEngine
         ActiveEngine = this;
         ActiveEngine = this;
     }
     }
 
 
-    public virtual IWindow GetWindow(WindowOptions options)
-    {
-        return Silk.NET.Windowing.Window.Create(options);   
-    }
-
     protected void SetBackendActive()
     protected void SetBackendActive()
     {
     {
         DrawingBackendApi.SetupBackend(_drawingBackend);
         DrawingBackendApi.SetupBackend(_drawingBackend);
     }
     }
+    
+    protected void Tick(double deltaTime)
+    {
+        Ticks += (ulong)deltaTime;
+    }
 }
 }

+ 3 - 0
src/PixiEditor.Engine/SkiaPixiEngine.cs

@@ -36,6 +36,8 @@ public sealed class SkiaPixiEngine : PixiEngine
             GlContext = _mainWindow.GLContext;
             GlContext = _mainWindow.GLContext;
             Setup(GrContext);
             Setup(GrContext);
         };
         };
+        
+        _mainWindow.Update += Tick;
 
 
         _mainWindow.Initialize();
         _mainWindow.Initialize();
     }
     }
@@ -51,6 +53,7 @@ public sealed class SkiaPixiEngine : PixiEngine
     public void RunWithWindow(Window window)
     public void RunWithWindow(Window window)
     {
     {
         window.InitWithGrContext += Setup;
         window.InitWithGrContext += Setup;
+        window.Update += Tick;
         window.Run();
         window.Run();
     }
     }
     
     

+ 25 - 13
src/PixiEditor.Engine/Window.cs

@@ -38,9 +38,11 @@ public class Window
     }
     }
 
 
     public SKSurface FramebufferSurface => frontBufferSurface;
     public SKSurface FramebufferSurface => frontBufferSurface;
+    public event Action<double> Update;
 
 
     public event Action<SKSurface, double> Render;
     public event Action<SKSurface, double> Render;
     public event Action Init;
     public event Action Init;
+    public event Action<VecI> Resize;
     internal event Action<GRContext> InitWithGrContext;
     internal event Action<GRContext> InitWithGrContext;
 
 
     private bool ran = false;
     private bool ran = false;
@@ -52,24 +54,34 @@ public class Window
             Title = title, Size = size == default ? new Vector2D<int>(600, 600) : size.ToVector2D()
             Title = title, Size = size == default ? new Vector2D<int>(600, 600) : size.ToVector2D()
         };
         };
 
 
-        if (PixiEngine.ActiveEngine == null)
-            throw new InvalidOperationException("PixiEngine is not initialized.");
-
-        _window = PixiEngine.ActiveEngine.GetWindow(options);
+        _window = Silk.NET.Windowing.Window.Create(options);
         
         
         if (!_window.IsInitialized)
         if (!_window.IsInitialized)
         {
         {
             _window.Load += () =>
             _window.Load += () =>
             {
             {
                 gl = GL.GetApi(_window);
                 gl = GL.GetApi(_window);
-                frontBufferSurface = SKSurface.Create(new SKImageInfo(1200, 600));
+                
+                _grContext = PixiEngine.ActiveEngine.GrContext;
 
 
-                InitSkiaSurface(_window.FramebufferSize);
+                if (_grContext == null)
+                {
+                    GRGlGetProcedureAddressDelegate proc = Glfw.GetApi().GetProcAddress;
+                    _grContext = GRContext.CreateGl(GRGlInterface.Create(proc));
 
 
-                InitWithGrContext?.Invoke(_grContext);
+                    InitWithGrContext?.Invoke(_grContext);
+                }
+
+                frontBufferSurface = SKSurface.Create(new SKImageInfo(1200, 600));
+                InitSkiaSurface(_window.FramebufferSize);
                 Init?.Invoke();
                 Init?.Invoke();
             };
             };
         }
         }
+        
+        _window.Update += (deltaTime) =>
+        {
+            Update?.Invoke(deltaTime);
+        };
 
 
         _window.FramebufferResize += (newSize) =>
         _window.FramebufferResize += (newSize) =>
         {
         {
@@ -78,6 +90,7 @@ public class Window
         };
         };
 
 
         _window.Render += OnRender;
         _window.Render += OnRender;
+        _window.Resize += (newSize) => Resize?.Invoke(newSize.ToVecI());
     }
     }
 
 
     public void Run()
     public void Run()
@@ -103,17 +116,16 @@ public class Window
 
 
     private void OnRender(double deltaTime)
     private void OnRender(double deltaTime)
     {
     {
-        frontBufferSurface.Canvas.Clear(SKColors.White);
+        frontBufferSurface.Canvas.Clear(SKColors.Transparent);
         Render?.Invoke(frontBufferSurface, deltaTime);
         Render?.Invoke(frontBufferSurface, deltaTime);
-        frontBufferSurface.Canvas.Flush();
+        frontBufferSurface.Flush(true);
     }
     }
 
 
     private void InitSkiaSurface(Vector2D<int> size)
     private void InitSkiaSurface(Vector2D<int> size)
-    {
-        _grContext = PixiEngine.ActiveEngine.GrContext;
-        var frameBuffer = new GRGlFramebufferInfo(0, SKColorType.RgbaF16.ToGlSizedFormat());
+    { ;
+        var frameBuffer = new GRGlFramebufferInfo(0, SKColorType.Rgba8888.ToGlSizedFormat());
         GRBackendRenderTarget target = new GRBackendRenderTarget(size.X, size.Y, 4, 0, frameBuffer);
         GRBackendRenderTarget target = new GRBackendRenderTarget(size.X, size.Y, 4, 0, frameBuffer);
-        frontBufferSurface = SKSurface.Create(_grContext, target, GRSurfaceOrigin.BottomLeft, SKColorType.RgbaF16);
+        frontBufferSurface = SKSurface.Create(_grContext, target, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888);
     }
     }
 
 
     public void Show()
     public void Show()

+ 0 - 10
src/PixiEngineAvaloniaApp/App.axaml.cs

@@ -10,14 +10,4 @@ public partial class App : Application
     {
     {
         AvaloniaXamlLoader.Load(this);
         AvaloniaXamlLoader.Load(this);
     }
     }
-
-    public override void OnFrameworkInitializationCompleted()
-    {
-        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
-        {
-            desktop.MainWindow = new MainWindow();
-        }
-
-        base.OnFrameworkInitializationCompleted();
-    }
 }
 }

+ 21 - 7
src/PixiEngineAvaloniaApp/Program.cs

@@ -1,20 +1,34 @@
 using Avalonia;
 using Avalonia;
 using System;
 using System;
+using PixiEditor.Engine;
 using PixiEditor.Engine.AvaloniaPlatform;
 using PixiEditor.Engine.AvaloniaPlatform;
+using PixiEditor.Numerics;
+using SkiaSharp;
 
 
 namespace PixiEngineAvaloniaApp;
 namespace PixiEngineAvaloniaApp;
 
 
 class Program
 class Program
 {
 {
-    // Initialization code. Don't use any Avalonia, third-party APIs or any
-    // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
-    // yet and stuff might break.
-    [STAThread]
-    public static void Main(string[] args) => BuildAvaloniaApp()
-        .StartWithClassicDesktopLifetime(args);
+    public static void Main(string[] args)
+    {
+        Window mainWindow = new Window("PixiEngine Avalonia App", new VecI(600, 600));
+        AvaloniaHost host = null;
+        mainWindow.Init += () =>
+        {
+            BuildAvaloniaApp();
+            host = new AvaloniaHost(mainWindow.Size, new SampleView());
+        };
+        
+        mainWindow.Render += (surface, dt) => host.Render(surface, dt);
+        mainWindow.Update += dt => host.Update(dt);
+        mainWindow.Resize += size => host.Resize(size);
+        
+        SkiaPixiEngine.CreateAndRun(mainWindow);
+    }
 
 
     // Avalonia configuration, don't remove; also used by visual designer.
     // Avalonia configuration, don't remove; also used by visual designer.
     public static AppBuilder BuildAvaloniaApp()
     public static AppBuilder BuildAvaloniaApp()
         => AppBuilder.Configure<App>()
         => AppBuilder.Configure<App>()
-            .UsePixiEngine();
+            .UsePixiEngine()
+            .SetupWithoutStarting();
 }
 }

+ 4 - 5
src/PixiEngineAvaloniaApp/MainWindow.axaml → src/PixiEngineAvaloniaApp/SampleView.axaml

@@ -1,9 +1,8 @@
-<Window xmlns="https://github.com/avaloniaui"
+<UserControl xmlns="https://github.com/avaloniaui"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
         mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
-        x:Class="PixiEngineAvaloniaApp.MainWindow"
-        Title="PixiEngineAvaloniaApp">
-    Welcome to Avalonia!
-</Window>
+        x:Class="PixiEngineAvaloniaApp.SampleView" Height="100" Width="100">
+    <TextBlock Foreground="Red"/>
+</UserControl>

+ 2 - 2
src/PixiEngineAvaloniaApp/MainWindow.axaml.cs → src/PixiEngineAvaloniaApp/SampleView.axaml.cs

@@ -2,9 +2,9 @@ using Avalonia.Controls;
 
 
 namespace PixiEngineAvaloniaApp;
 namespace PixiEngineAvaloniaApp;
 
 
-public partial class MainWindow : Window
+public partial class SampleView : UserControl
 {
 {
-    public MainWindow()
+    public SampleView()
     {
     {
         InitializeComponent();
         InitializeComponent();
     }
     }