1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-12 21:38:38 +00:00

Change surface manager SKTexture handling

This commit is contained in:
Robert 2023-10-09 20:04:23 +02:00
parent 543b62a715
commit 3e88aa37ff

View File

@ -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<ArtemisDevice> _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<ArtemisDevice> 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<ArtemisDevice> 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();
}
}
/// <inheritdoc />
public void Dispose()
{
SetPaused(true);
Surface.UnregisterUpdateTrigger(_updateTrigger);
lock (_renderLock)
{
_updateTrigger.Dispose();
_texture?.Dispose();
Surface.Dispose();
}
}
private void UpdateLedGroup()
{
List<Led> 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<ArtemisDevice> 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<ArtemisDevice> 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<Led> 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;
/// <inheritdoc />
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();
}
}