1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Software rendering - Fixed memory leak

Rendering - Swap back and forth between software and GPU without crash
This commit is contained in:
Robert 2021-03-22 21:00:37 +01:00
parent 97668ee932
commit c444ff4e59
8 changed files with 105 additions and 79 deletions

View File

@ -9,6 +9,7 @@ namespace Artemis.Core
private bool _disposed;
private SKRect _lastBounds;
private SKRect _lastParentBounds;
private GRContext? _lastGraphicsContext;
public SKSurface? Surface { get; private set; }
public SKPaint? Paint { get; private set; }
public SKPath? Path { get; private set; }
@ -27,7 +28,7 @@ namespace Artemis.Core
if (IsOpen)
throw new ArtemisCoreException("Cannot open render context because it is already open");
if (path.Bounds != _lastBounds || (parent != null && parent.Bounds != _lastParentBounds))
if (path.Bounds != _lastBounds || (parent != null && parent.Bounds != _lastParentBounds) || _lastGraphicsContext != Constants.ManagedGraphicsContext?.GraphicsContext)
Invalidate();
if (!_valid || Surface == null)
@ -53,6 +54,7 @@ namespace Artemis.Core
_lastParentBounds = parent?.Bounds ?? new SKRect();
_lastBounds = path.Bounds;
_lastGraphicsContext = Constants.ManagedGraphicsContext?.GraphicsContext;
_valid = true;
}
@ -70,7 +72,14 @@ namespace Artemis.Core
throw new ObjectDisposedException("Renderer");
Surface?.Canvas.Restore();
// Looks like every part of the paint needs to be disposed :(
Paint?.ColorFilter?.Dispose();
Paint?.ImageFilter?.Dispose();
Paint?.MaskFilter?.Dispose();
Paint?.PathEffect?.Dispose();
Paint?.Dispose();
Paint = null;
IsOpen = false;

View File

@ -51,6 +51,8 @@ namespace Artemis.Core.Services
UpdateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value};
Surface.RegisterUpdateTrigger(UpdateTrigger);
Utilities.ShutdownRequested += UtilitiesOnShutdownRequested;
}
public TimerUpdateTrigger UpdateTrigger { get; }
@ -66,6 +68,11 @@ namespace Artemis.Core.Services
_texture?.Invalidate();
}
private void UtilitiesOnShutdownRequested(object? sender, EventArgs e)
{
IsRenderPaused = true;
}
private void SurfaceOnLayoutChanged(SurfaceLayoutChangedEventArgs args)
{
UpdateLedGroup();
@ -115,6 +122,11 @@ namespace Artemis.Core.Services
DeviceAdded?.Invoke(this, e);
}
private void RenderScaleSettingOnSettingChanged(object? sender, EventArgs e)
{
_texture?.Invalidate();
}
public IReadOnlyCollection<ArtemisDevice> EnabledDevices => _enabledDevices.AsReadOnly();
public IReadOnlyCollection<ArtemisDevice> Devices => _devices.AsReadOnly();
public IReadOnlyDictionary<Led, ArtemisLed> LedMap => new ReadOnlyDictionary<Led, ArtemisLed>(_ledMap);
@ -195,11 +207,6 @@ namespace Artemis.Core.Services
}
}
private void RenderScaleSettingOnSettingChanged(object? sender, EventArgs e)
{
_texture?.Invalidate();
}
public void Dispose()
{
Surface.UnregisterUpdateTrigger(UpdateTrigger);

View File

@ -2,7 +2,7 @@
"profiles": {
"Artemis.UI": {
"commandName": "Project",
"commandLineArgs": "--force-elevation"
"commandLineArgs": "--force-elevation --pcmr"
}
}
}

View File

@ -32,11 +32,9 @@
<TextBlock Grid.Column="1" HorizontalAlignment="Right" Margin="0,0,5,0">
<Run Text="FPS: " />
<Run FontWeight="Bold" Text="{Binding CurrentFps}" />
<Run Text=" at " />
<Run Text="{Binding RenderWidth}" /><Run Text="x" />
<Run Text="{Binding RenderHeight}" />
<Run Text=" - Renderer: "></Run>
<Run Text="at" />
<Run Text="{Binding RenderWidth}" /><Run Text="x" /><Run Text="{Binding RenderHeight}" />
<Run Text="- Renderer:"></Run>
<Run Text="{Binding Renderer}"></Run>
</TextBlock>
</Grid>

View File

@ -21,6 +21,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
private int _renderHeight;
private string _frameTargetPath;
private string _renderer;
private int _frames;
private DateTime _frameCountStart;
public RenderDebugViewModel(ICoreService coreService)
{
@ -76,8 +78,6 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
{
_coreService.FrameRendered += CoreServiceOnFrameRendered;
_coreService.FrameRendering += CoreServiceOnFrameRendering;
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
base.OnActivate();
}
@ -132,7 +132,15 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e)
{
CurrentFps = Math.Round(1.0 / e.DeltaTime, 2);
if (DateTime.Now - _frameCountStart >= TimeSpan.FromSeconds(1))
{
CurrentFps = _frames;
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
_frames = 0;
_frameCountStart = DateTime.Now;
}
_frames++;
}
}
}

View File

@ -28,6 +28,7 @@ namespace Artemis.UI.Services
private bool _registeredBuiltInDataModelDisplays;
private bool _registeredBuiltInDataModelInputs;
private bool _registeredBuiltInPropertyEditors;
private VulkanContext _vulkanContext;
public RegistrationService(ILogger logger,
ICoreService coreService,
@ -128,7 +129,8 @@ namespace Artemis.UI.Services
_rgbService.UpdateGraphicsContext(null);
break;
case "Vulkan":
_rgbService.UpdateGraphicsContext(new VulkanContext());
_vulkanContext ??= new VulkanContext();
_rgbService.UpdateGraphicsContext(_vulkanContext);
break;
default:
throw new ArgumentOutOfRangeException();

View File

@ -8,27 +8,24 @@ namespace Artemis.UI.SkiaSharp.Vulkan
{
internal sealed class Win32VkContext : VkContext
{
private static readonly NativeWindow window = new NativeWindow();
public NativeWindow Window { get; }
public Win32VkContext()
{
Instance = Instance.Create(null, new[] { "VK_KHR_surface", "VK_KHR_win32_surface" });
Window = new NativeWindow();
Instance = Instance.Create(null, new[] {"VK_KHR_surface", "VK_KHR_win32_surface"});
PhysicalDevice = Instance.EnumeratePhysicalDevices().First();
Surface = Instance.CreateWin32Surface(Kernel32.CurrentModuleHandle, window.Handle);
Surface = Instance.CreateWin32Surface(Kernel32.CurrentModuleHandle, Window.Handle);
(GraphicsFamily, PresentFamily) = FindQueueFamilies();
DeviceQueueCreateInfo[]? queueInfos = new[]
DeviceQueueCreateInfo[] queueInfos =
{
new DeviceQueueCreateInfo { QueueFamilyIndex = GraphicsFamily, QueuePriorities = new[] { 1f } },
new DeviceQueueCreateInfo { QueueFamilyIndex = PresentFamily, QueuePriorities = new[] { 1f } },
new() {QueueFamilyIndex = GraphicsFamily, QueuePriorities = new[] {1f}},
new() {QueueFamilyIndex = PresentFamily, QueuePriorities = new[] {1f}}
};
Device = PhysicalDevice.CreateDevice(queueInfos, null, null);
GraphicsQueue = Device.GetQueue(GraphicsFamily, 0);
PresentQueue = Device.GetQueue(PresentFamily, 0);
GetProc = (name, instanceHandle, deviceHandle) =>
@ -54,12 +51,18 @@ namespace Artemis.UI.SkiaSharp.Vulkan
};
}
public override void Dispose()
{
base.Dispose();
Window.DestroyHandle();
}
private (uint, uint) FindQueueFamilies()
{
QueueFamilyProperties[]? queueFamilyProperties = PhysicalDevice.GetQueueFamilyProperties();
QueueFamilyProperties[] queueFamilyProperties = PhysicalDevice.GetQueueFamilyProperties();
var graphicsFamily = queueFamilyProperties
.Select((properties, index) => new { properties, index })
.Select((properties, index) => new {properties, index})
.SkipWhile(pair => !pair.properties.QueueFlags.HasFlag(QueueFlags.Graphics))
.FirstOrDefault();
@ -77,7 +80,7 @@ namespace Artemis.UI.SkiaSharp.Vulkan
if (!presentFamily.HasValue)
throw new Exception("Unable to find present queue");
return ((uint)graphicsFamily.index, presentFamily.Value);
return ((uint) graphicsFamily.index, presentFamily.Value);
}
}
}

View File

@ -50,14 +50,13 @@ namespace Artemis.UI.SkiaSharp
{
throw new ArtemisGraphicsContextException("Failed to create Vulkan graphics context", e);
}
GraphicsContext.Flush();
}
/// <inheritdoc />
public void Dispose()
{
_vulkanBackendContext?.Dispose();
_vulkanContext?.Dispose();
GraphicsContext?.Dispose();
}
public GRContext GraphicsContext { get; }