From 3e88aa37ffb4165e819a7a4810e0117b10be63d4 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 9 Oct 2023 20:04:23 +0200 Subject: [PATCH] Change surface manager SKTexture handling --- .../Services/Core/SurfaceManager.cs | 271 +++++++++--------- 1 file changed, 131 insertions(+), 140 deletions(-) diff --git a/src/Artemis.Core/Services/Core/SurfaceManager.cs b/src/Artemis.Core/Services/Core/SurfaceManager.cs index fb3845e3c..2a3b895aa 100644 --- a/src/Artemis.Core/Services/Core/SurfaceManager.cs +++ b/src/Artemis.Core/Services/Core/SurfaceManager.cs @@ -14,9 +14,9 @@ internal sealed class SurfaceManager : IDisposable { private readonly IRenderer _renderer; private readonly TimerUpdateTrigger _updateTrigger; - private readonly object _renderLock = new(); private readonly List _devices = new(); private readonly SKTextureBrush _textureBrush = new(null) {CalculationMode = RenderMode.Absolute}; + private readonly object _renderLock = new(); private ListLedGroup? _surfaceLedGroup; private SKTexture? _texture; @@ -36,13 +36,142 @@ internal sealed class SurfaceManager : IDisposable SetPaused(true); } + public IManagedGraphicsContext? GraphicsContext { get; private set; } + public int TargetFrameRate { get; private set; } + public float RenderScale { get; private set; } + public RGBSurface Surface { get; } + + public bool IsPaused { get; private set; } + + public void AddDevices(IEnumerable devices) + { + lock (_renderLock) + { + foreach (ArtemisDevice artemisDevice in devices) + { + if (_devices.Contains(artemisDevice)) + continue; + _devices.Add(artemisDevice); + Surface.Attach(artemisDevice.RgbDevice); + artemisDevice.DeviceUpdated += ArtemisDeviceOnDeviceUpdated; + } + + _texture?.Invalidate(); + } + } + + public void RemoveDevices(IEnumerable devices) + { + lock (_renderLock) + { + foreach (ArtemisDevice artemisDevice in devices) + { + artemisDevice.DeviceUpdated -= ArtemisDeviceOnDeviceUpdated; + Surface.Detach(artemisDevice.RgbDevice); + _devices.Remove(artemisDevice); + } + + _texture?.Invalidate(); + } + } + + public bool SetPaused(bool paused) + { + if (IsPaused == paused) + return false; + + if (paused) + _updateTrigger.Stop(); + else + _updateTrigger.Start(); + + IsPaused = paused; + return true; + } + + public void UpdateTargetFrameRate(int targetFrameRate) + { + TargetFrameRate = targetFrameRate; + _updateTrigger.UpdateFrequency = 1.0 / TargetFrameRate; + } + + public void UpdateRenderScale(float renderScale) + { + lock (_renderLock) + { + RenderScale = renderScale; + _texture?.Invalidate(); + } + } + + public void UpdateGraphicsContext(IManagedGraphicsContext? graphicsContext) + { + lock (_renderLock) + { + GraphicsContext = graphicsContext; + _texture?.Invalidate(); + } + } + + /// + public void Dispose() + { + SetPaused(true); + Surface.UnregisterUpdateTrigger(_updateTrigger); + lock (_renderLock) + { + _updateTrigger.Dispose(); + _texture?.Dispose(); + Surface.Dispose(); + } + } + + private void UpdateLedGroup() + { + List leds = _devices.SelectMany(d => d.Leds).Select(l => l.RgbLed).ToList(); + + if (_surfaceLedGroup == null) + { + _surfaceLedGroup = new ListLedGroup(Surface, leds) {Brush = _textureBrush}; + return; + } + + // Clean up the old background + _surfaceLedGroup.Detach(); + + // Apply the application wide brush and decorator + _surfaceLedGroup = new ListLedGroup(Surface, leds) {Brush = _textureBrush}; + } + + private SKTexture CreateTexture() + { + float evenWidth = Surface.Boundary.Size.Width; + if (evenWidth % 2 != 0) + evenWidth++; + float evenHeight = Surface.Boundary.Size.Height; + if (evenHeight % 2 != 0) + evenHeight++; + + int width = Math.Max(1, MathF.Min(evenWidth * RenderScale, 4096).RoundToInt()); + int height = Math.Max(1, MathF.Min(evenHeight * RenderScale, 4096).RoundToInt()); + + _texture?.Dispose(); + _texture = new SKTexture(GraphicsContext, width, height, RenderScale, _devices); + _textureBrush.Texture = _texture; + + return _texture; + } + private void SurfaceOnUpdating(UpdatingEventArgs args) { lock (_renderLock) { SKTexture? texture = _texture; if (texture == null || texture.IsInvalid) + { texture = CreateTexture(); + UpdateLedGroup(); + } // Prepare a canvas SKCanvas canvas = texture.Surface.Canvas; @@ -77,146 +206,8 @@ internal sealed class SurfaceManager : IDisposable } } - public IManagedGraphicsContext? GraphicsContext { get; private set; } - public int TargetFrameRate { get; private set; } - public float RenderScale { get; private set; } - public RGBSurface Surface { get; } - - public bool IsPaused { get; private set; } - - public void AddDevices(IEnumerable devices) - { - lock (_renderLock) - { - foreach (ArtemisDevice artemisDevice in devices) - { - if (_devices.Contains(artemisDevice)) - continue; - _devices.Add(artemisDevice); - Surface.Attach(artemisDevice.RgbDevice); - artemisDevice.DeviceUpdated += ArtemisDeviceOnDeviceUpdated; - } - - Update(); - } - } - - public void RemoveDevices(IEnumerable devices) - { - lock (_renderLock) - { - foreach (ArtemisDevice artemisDevice in devices) - { - artemisDevice.DeviceUpdated -= ArtemisDeviceOnDeviceUpdated; - Surface.Detach(artemisDevice.RgbDevice); - _devices.Remove(artemisDevice); - } - - Update(); - } - } - - public bool SetPaused(bool paused) - { - if (IsPaused == paused) - return false; - - if (paused) - _updateTrigger.Stop(); - else - _updateTrigger.Start(); - - IsPaused = paused; - return true; - } - - private void Update() - { - lock (_renderLock) - { - UpdateLedGroup(); - CreateTexture(); - } - } - - private void UpdateLedGroup() - { - List leds = _devices.SelectMany(d => d.Leds).Select(l => l.RgbLed).ToList(); - - if (_surfaceLedGroup == null) - { - _surfaceLedGroup = new ListLedGroup(Surface, leds) {Brush = _textureBrush}; - LedsChanged?.Invoke(this, EventArgs.Empty); - return; - } - - // Clean up the old background - _surfaceLedGroup.Detach(); - - // Apply the application wide brush and decorator - _surfaceLedGroup = new ListLedGroup(Surface, leds) {Brush = _textureBrush}; - LedsChanged?.Invoke(this, EventArgs.Empty); - } - - private SKTexture CreateTexture() - { - float evenWidth = Surface.Boundary.Size.Width; - if (evenWidth % 2 != 0) - evenWidth++; - float evenHeight = Surface.Boundary.Size.Height; - if (evenHeight % 2 != 0) - evenHeight++; - - int width = Math.Max(1, MathF.Min(evenWidth * RenderScale, 4096).RoundToInt()); - int height = Math.Max(1, MathF.Min(evenHeight * RenderScale, 4096).RoundToInt()); - - _texture?.Dispose(); - _texture = new SKTexture(GraphicsContext, width, height, RenderScale, _devices); - _textureBrush.Texture = _texture; - - return _texture; - } - private void ArtemisDeviceOnDeviceUpdated(object? sender, EventArgs e) { - Update(); - } - - public event EventHandler? LedsChanged; - - /// - public void Dispose() - { - SetPaused(true); - - Surface.UnregisterUpdateTrigger(_updateTrigger); - _updateTrigger.Dispose(); - _texture?.Dispose(); - Surface.Dispose(); - } - - public void UpdateTargetFrameRate(int targetFrameRate) - { - TargetFrameRate = targetFrameRate; - _updateTrigger.UpdateFrequency = 1.0 / TargetFrameRate; - } - - public void UpdateRenderScale(float renderScale) - { - lock (_renderLock) - { - RenderScale = renderScale; - _texture?.Invalidate(); - } - } - - public void UpdateGraphicsContext(IManagedGraphicsContext? graphicsContext) - { - lock (_renderLock) - { - GraphicsContext = graphicsContext; - _texture?.Dispose(); - _texture = null; - } + _texture?.Invalidate(); } } \ No newline at end of file