diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs index ef29c01f7..a7f4eebbb 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs @@ -22,8 +22,8 @@ public class ArtemisDevice : CorePropertyChanged internal ArtemisDevice(IRGBDevice rgbDevice, DeviceProvider deviceProvider) { - _originalLeds = new List(rgbDevice.Select(l => new OriginalLed(l))); Rectangle ledRectangle = new(rgbDevice.Select(x => x.Boundary)); + _originalLeds = new List(rgbDevice.Select(l => new OriginalLed(l))); _originalSize = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y); Identifier = rgbDevice.GetDeviceIdentifier(); @@ -54,10 +54,10 @@ public class ArtemisDevice : CorePropertyChanged internal ArtemisDevice(IRGBDevice rgbDevice, DeviceProvider deviceProvider, DeviceEntity deviceEntity) { - _originalLeds = new List(rgbDevice.Select(l => new OriginalLed(l))); Rectangle ledRectangle = new(rgbDevice.Select(x => x.Boundary)); + _originalLeds = new List(rgbDevice.Select(l => new OriginalLed(l))); _originalSize = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y); - + Identifier = rgbDevice.GetDeviceIdentifier(); DeviceEntity = deviceEntity; RgbDevice = rgbDevice; diff --git a/src/Artemis.Core/Services/Core/SurfaceManager.cs b/src/Artemis.Core/Services/Core/SurfaceManager.cs index 8630186ca..7fb7a044c 100644 --- a/src/Artemis.Core/Services/Core/SurfaceManager.cs +++ b/src/Artemis.Core/Services/Core/SurfaceManager.cs @@ -16,7 +16,6 @@ internal sealed class SurfaceManager : IDisposable private readonly TimerUpdateTrigger _updateTrigger; 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; @@ -24,7 +23,7 @@ internal sealed class SurfaceManager : IDisposable public SurfaceManager(IRenderer renderer, IManagedGraphicsContext? graphicsContext, int targetFrameRate, float renderScale) { _renderer = renderer; - _updateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / targetFrameRate}; + _updateTrigger = new TimerUpdateTrigger(false) {UpdateFrequency = 1.0 / targetFrameRate}; GraphicsContext = graphicsContext; TargetFrameRate = targetFrameRate; @@ -45,34 +44,46 @@ internal sealed class SurfaceManager : IDisposable public void AddDevices(IEnumerable devices) { - lock (_renderLock) + List newDevices = new(); + lock (_devices) { foreach (ArtemisDevice artemisDevice in devices) { if (_devices.Contains(artemisDevice)) continue; _devices.Add(artemisDevice); - Surface.Attach(artemisDevice.RgbDevice); + newDevices.Add(artemisDevice.RgbDevice); artemisDevice.DeviceUpdated += ArtemisDeviceOnDeviceUpdated; } - - _texture?.Invalidate(); } + + if (!newDevices.Any()) + return; + + Surface.Attach(newDevices); + _texture?.Invalidate(); } public void RemoveDevices(IEnumerable devices) { - lock (_renderLock) + List removedDevices = new(); + lock (_devices) { foreach (ArtemisDevice artemisDevice in devices) { + if (!_devices.Remove(artemisDevice)) + continue; artemisDevice.DeviceUpdated -= ArtemisDeviceOnDeviceUpdated; - Surface.Detach(artemisDevice.RgbDevice); + removedDevices.Add(artemisDevice.RgbDevice); _devices.Remove(artemisDevice); } - - _texture?.Invalidate(); } + + if (!removedDevices.Any()) + return; + + Surface.Detach(removedDevices); + _texture?.Invalidate(); } public bool SetPaused(bool paused) @@ -97,20 +108,14 @@ internal sealed class SurfaceManager : IDisposable public void UpdateRenderScale(float renderScale) { - lock (_renderLock) - { - RenderScale = renderScale; - _texture?.Invalidate(); - } + RenderScale = renderScale; + _texture?.Invalidate(); } public void UpdateGraphicsContext(IManagedGraphicsContext? graphicsContext) { - lock (_renderLock) - { - GraphicsContext = graphicsContext; - _texture?.Invalidate(); - } + GraphicsContext = graphicsContext; + _texture?.Invalidate(); } /// @@ -118,29 +123,10 @@ internal sealed class SurfaceManager : IDisposable { 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}; + _updateTrigger.Dispose(); + _texture?.Dispose(); + Surface.Dispose(); } private SKTexture CreateTexture() @@ -155,53 +141,54 @@ internal sealed class SurfaceManager : IDisposable 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; + lock (_devices) + { + _texture?.Dispose(); + _texture = new SKTexture(GraphicsContext, width, height, RenderScale, _devices); + _textureBrush.Texture = _texture; + + _surfaceLedGroup?.Detach(); + _surfaceLedGroup = new ListLedGroup(Surface, _devices.SelectMany(d => d.Leds).Select(l => l.RgbLed)) {Brush = _textureBrush}; + } - UpdateLedGroup(); - return _texture; } private void SurfaceOnUpdating(UpdatingEventArgs args) { - lock (_renderLock) + SKTexture? texture = _texture; + if (texture == null || texture.IsInvalid) + texture = CreateTexture(); + + // Prepare a canvas + SKCanvas canvas = texture.Surface.Canvas; + canvas.Save(); + + // Apply scaling if necessary + if (Math.Abs(texture.RenderScale - 1) > 0.001) + canvas.Scale(texture.RenderScale); + + // Fresh start! + canvas.Clear(new SKColor(0, 0, 0)); + + try { - SKTexture? texture = _texture; - if (texture == null || texture.IsInvalid) - texture = CreateTexture(); + _renderer.Render(canvas, args.DeltaTime); + } + finally + { + canvas.RestoreToCount(-1); + canvas.Flush(); + texture.CopyPixelData(); + } - // Prepare a canvas - SKCanvas canvas = texture.Surface.Canvas; - canvas.Save(); - - // Apply scaling if necessary - if (Math.Abs(texture.RenderScale - 1) > 0.001) - canvas.Scale(texture.RenderScale); - - // Fresh start! - canvas.Clear(new SKColor(0, 0, 0)); - - try - { - _renderer.Render(canvas, args.DeltaTime); - } - finally - { - canvas.RestoreToCount(-1); - canvas.Flush(); - texture.CopyPixelData(); - } - - try - { - _renderer.PostRender(texture); - } - catch - { - // ignored - } + try + { + _renderer.PostRender(texture); + } + catch + { + // ignored } } diff --git a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs index 84e4be2c2..dab8dacc4 100644 --- a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs +++ b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs @@ -153,9 +153,9 @@ public class DeviceVisualizer : Control private Rect MeasureDevice() { - if (Device == null) + if (Device == null || float.IsNaN(Device.RgbDevice.ActualSize.Width) || float.IsNaN(Device.RgbDevice.ActualSize.Height)) return new Rect(); - + Rect deviceRect = new(0, 0, Device.RgbDevice.ActualSize.Width, Device.RgbDevice.ActualSize.Height); Geometry geometry = new RectangleGeometry(deviceRect); geometry.Transform = new RotateTransform(Device.Rotation); diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceLogicalLayoutDialogView.axaml.cs b/src/Artemis.UI/Screens/Device/Tabs/DeviceLogicalLayoutDialogView.axaml.cs index c90b51c67..d4dace819 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/DeviceLogicalLayoutDialogView.axaml.cs +++ b/src/Artemis.UI/Screens/Device/Tabs/DeviceLogicalLayoutDialogView.axaml.cs @@ -10,8 +10,6 @@ namespace Artemis.UI.Screens.Device; public partial class DeviceLogicalLayoutDialogView : ReactiveUserControl { - private readonly AutoCompleteBox _autoCompleteBox; - public DeviceLogicalLayoutDialogView() { InitializeComponent(); @@ -23,8 +21,8 @@ public partial class DeviceLogicalLayoutDialogView : ReactiveUserControl