From 34407aaeecc72f609c0c2e2efa94ce9e744b9401 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 6 May 2022 18:19:02 +0200 Subject: [PATCH] Core - Made graphics context providable by UI Windows - Implemented Vulkan graphics context Splash screen - Tweaked design --- src/.idea/.idea.Artemis/.idea/avalonia.xml | 3 + src/Artemis.Core/Services/CoreService.cs | 1 + .../Interfaces/IGraphicsContextProvider.cs | 10 +++ .../Services/Interfaces/IRgbService.cs | 12 ++- src/Artemis.Core/Services/RgbService.cs | 53 ++++++++++- .../Artemis.UI.Windows.csproj | 1 + .../Ninject/WindowsModule.cs | 4 +- .../Providers/GraphicsContextProvider.cs | 26 ++++++ .../SkiaSharp/Vulkan/Kernel32.cs | 21 +++++ .../SkiaSharp/Vulkan/VkContext.cs | 34 ++++++++ .../SkiaSharp/Vulkan/Win32VkContext.cs | 87 +++++++++++++++++++ .../SkiaSharp/VulkanContext.cs | 64 ++++++++++++++ src/Artemis.UI.Windows/packages.lock.json | 19 ++++ src/Artemis.UI/Screens/Root/SplashView.axaml | 5 +- .../Screens/Root/SplashViewModel.cs | 2 +- .../Settings/Tabs/GeneralTabViewModel.cs | 22 ++--- .../Interfaces/IRegistrationService.cs | 1 - .../Services/RegistrationService.cs | 6 +- 18 files changed, 346 insertions(+), 25 deletions(-) create mode 100644 src/Artemis.Core/Services/Interfaces/IGraphicsContextProvider.cs create mode 100644 src/Artemis.UI.Windows/Providers/GraphicsContextProvider.cs create mode 100644 src/Artemis.UI.Windows/SkiaSharp/Vulkan/Kernel32.cs create mode 100644 src/Artemis.UI.Windows/SkiaSharp/Vulkan/VkContext.cs create mode 100644 src/Artemis.UI.Windows/SkiaSharp/Vulkan/Win32VkContext.cs create mode 100644 src/Artemis.UI.Windows/SkiaSharp/VulkanContext.cs diff --git a/src/.idea/.idea.Artemis/.idea/avalonia.xml b/src/.idea/.idea.Artemis/.idea/avalonia.xml index e69cb94fc..6eb6336ba 100644 --- a/src/.idea/.idea.Artemis/.idea/avalonia.xml +++ b/src/.idea/.idea.Artemis/.idea/avalonia.xml @@ -18,6 +18,8 @@ + + @@ -26,6 +28,7 @@ + diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index ed00c54fe..4f868785b 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -232,6 +232,7 @@ namespace Artemis.Core.Services _pluginManagementService.CopyBuiltInPlugins(); _pluginManagementService.LoadPlugins(StartupArguments, IsElevated); + _rgbService.ApplyPreferredGraphicsContext(StartupArguments.Contains("--force-software-render")); _rgbService.SetRenderPaused(false); OnInitialized(); } diff --git a/src/Artemis.Core/Services/Interfaces/IGraphicsContextProvider.cs b/src/Artemis.Core/Services/Interfaces/IGraphicsContextProvider.cs new file mode 100644 index 000000000..26361fbe2 --- /dev/null +++ b/src/Artemis.Core/Services/Interfaces/IGraphicsContextProvider.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Artemis.Core.SkiaSharp; + +namespace Artemis.Core.Services; + +public interface IGraphicsContextProvider +{ + IReadOnlyCollection GraphicsContextNames { get; } + IManagedGraphicsContext? GetGraphicsContext(string name); +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Interfaces/IRgbService.cs b/src/Artemis.Core/Services/Interfaces/IRgbService.cs index c9bed101a..adefcba3f 100644 --- a/src/Artemis.Core/Services/Interfaces/IRgbService.cs +++ b/src/Artemis.Core/Services/Interfaces/IRgbService.cs @@ -40,7 +40,7 @@ namespace Artemis.Core.Services /// Gets a boolean indicating whether the render pipeline is open /// bool RenderOpen { get; } - + /// /// Gets or sets a boolean indicating whether to flush the RGB.NET LEDs during next update /// @@ -56,6 +56,12 @@ namespace Artemis.Core.Services /// void CloseRender(); + /// + /// Applies the current value of the Core.PreferredGraphicsContext setting to the graphics context. + /// + /// A boolean to indicate whether or not to force the graphics context to software mode. + void ApplyPreferredGraphicsContext(bool forceSoftware); + /// /// Updates the graphics context to the provided . /// Note: The old graphics context will be used until the next frame starts rendering and is disposed afterwards. @@ -139,10 +145,10 @@ namespace Artemis.Core.Services void DisableDevice(ArtemisDevice device); /// - /// Pauses or resumes rendering, method won't return until the current frame finished rendering + /// Pauses or resumes rendering, method won't return until the current frame finished rendering /// /// - /// if the pause state was changed; otherwise . + /// if the pause state was changed; otherwise . bool SetRenderPaused(bool paused); /// diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs index 9dbbea60f..2e1ea8c99 100644 --- a/src/Artemis.Core/Services/RgbService.cs +++ b/src/Artemis.Core/Services/RgbService.cs @@ -8,6 +8,7 @@ using Artemis.Core.Services.Models; using Artemis.Core.SkiaSharp; using Artemis.Storage.Entities.Surface; using Artemis.Storage.Repositories.Interfaces; +using Ninject; using RGB.NET.Core; using Serilog; @@ -22,21 +23,27 @@ namespace Artemis.Core.Services private readonly List _devices; private readonly List _enabledDevices; private readonly ILogger _logger; + private readonly IKernel _kernel; + private readonly ISettingsService _settingsService; private readonly IPluginManagementService _pluginManagementService; private readonly PluginSetting _renderScaleSetting; private readonly PluginSetting _targetFrameRateSetting; + private readonly PluginSetting _preferredGraphicsContext; private readonly SKTextureBrush _textureBrush = new(null) {CalculationMode = RenderMode.Absolute}; private Dictionary _ledMap; private ListLedGroup? _surfaceLedGroup; private SKTexture? _texture; - public RgbService(ILogger logger, ISettingsService settingsService, IPluginManagementService pluginManagementService, IDeviceRepository deviceRepository) + public RgbService(ILogger logger, IKernel kernel, ISettingsService settingsService, IPluginManagementService pluginManagementService, IDeviceRepository deviceRepository) { _logger = logger; + _kernel = kernel; + _settingsService = settingsService; _pluginManagementService = pluginManagementService; _deviceRepository = deviceRepository; _targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 30); _renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.25); + _preferredGraphicsContext = _settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan"); Surface = new RGBSurface(); Utilities.RenderScaleMultiplier = (int) (1 / _renderScaleSetting.Value); @@ -46,6 +53,7 @@ namespace Artemis.Core.Services Surface.SurfaceLayoutChanged += SurfaceOnLayoutChanged; _targetFrameRateSetting.SettingChanged += TargetFrameRateSettingOnSettingChanged; _renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged; + _preferredGraphicsContext.SettingChanged += PreferredGraphicsContextOnSettingChanged; _enabledDevices = new List(); _devices = new List(); _ledMap = new Dictionary(); @@ -61,6 +69,7 @@ namespace Artemis.Core.Services Utilities.ShutdownRequested += UtilitiesOnShutdownRequested; } + public TimerUpdateTrigger UpdateTrigger { get; } protected virtual void OnDeviceRemoved(DeviceEventArgs e) @@ -135,13 +144,18 @@ namespace Artemis.Core.Services private void RenderScaleSettingOnSettingChanged(object? sender, EventArgs e) { Utilities.RenderScaleMultiplier = (int) (1 / _renderScaleSetting.Value); - + _texture?.Invalidate(); foreach (ArtemisDevice artemisDevice in Devices) artemisDevice.CalculateRenderProperties(); OnLedsChanged(); } + private void PreferredGraphicsContextOnSettingChanged(object? sender, EventArgs e) + { + ApplyPreferredGraphicsContext(false); + } + public IReadOnlyCollection EnabledDevices { get; } public IReadOnlyCollection Devices { get; } public IReadOnlyDictionary LedMap { get; private set; } @@ -271,6 +285,7 @@ namespace Artemis.Core.Services private IManagedGraphicsContext? _newGraphicsContext; + public SKTexture OpenRender() { if (RenderOpen) @@ -333,6 +348,40 @@ namespace Artemis.Core.Services } } + public void ApplyPreferredGraphicsContext(bool forceSoftware) + { + if (forceSoftware) + { + _logger.Warning("Startup argument '--force-software-render' is applied, forcing software rendering"); + UpdateGraphicsContext(null); + return; + } + + if (_preferredGraphicsContext.Value == "Software") + { + UpdateGraphicsContext(null); + return; + } + + IGraphicsContextProvider? provider = _kernel.TryGet(); + if (provider == null) + { + _logger.Warning("No graphics context provider found, defaulting to software rendering"); + UpdateGraphicsContext(null); + return; + } + + IManagedGraphicsContext? context = provider.GetGraphicsContext(_preferredGraphicsContext.Value); + if (context == null) + { + _logger.Warning("No graphics context named '{Context}' found, defaulting to software rendering", _preferredGraphicsContext.Value); + UpdateGraphicsContext(null); + return; + } + + UpdateGraphicsContext(context); + } + public void UpdateGraphicsContext(IManagedGraphicsContext? managedGraphicsContext) { if (ReferenceEquals(managedGraphicsContext, Constants.ManagedGraphicsContext)) diff --git a/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj b/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj index f338cad81..bb41301e6 100644 --- a/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj +++ b/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj @@ -33,6 +33,7 @@ + diff --git a/src/Artemis.UI.Windows/Ninject/WindowsModule.cs b/src/Artemis.UI.Windows/Ninject/WindowsModule.cs index 3a79ea6c3..2badd961e 100644 --- a/src/Artemis.UI.Windows/Ninject/WindowsModule.cs +++ b/src/Artemis.UI.Windows/Ninject/WindowsModule.cs @@ -1,4 +1,5 @@ -using Artemis.UI.Shared.Providers; +using Artemis.Core.Services; +using Artemis.UI.Shared.Providers; using Artemis.UI.Windows.Providers; using Ninject.Modules; @@ -12,6 +13,7 @@ public class WindowsModule : NinjectModule public override void Load() { Kernel!.Bind().To().InSingletonScope(); + Kernel!.Bind().To().InSingletonScope(); } #endregion diff --git a/src/Artemis.UI.Windows/Providers/GraphicsContextProvider.cs b/src/Artemis.UI.Windows/Providers/GraphicsContextProvider.cs new file mode 100644 index 000000000..a06d146e6 --- /dev/null +++ b/src/Artemis.UI.Windows/Providers/GraphicsContextProvider.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Artemis.Core.Services; +using Artemis.Core.SkiaSharp; +using Artemis.UI.Windows.SkiaSharp; + +namespace Artemis.UI.Windows.Providers; + +public class GraphicsContextProvider : IGraphicsContextProvider +{ + private VulkanContext? _vulkanContext; + + /// + public IReadOnlyCollection GraphicsContextNames => new List {"Vulkan"}.AsReadOnly(); + + /// + public IManagedGraphicsContext? GetGraphicsContext(string name) + { + if (name == "Vulkan") + { + _vulkanContext ??= new VulkanContext(); + return _vulkanContext; + } + + return null; + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Kernel32.cs b/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Kernel32.cs new file mode 100644 index 000000000..e12c564bc --- /dev/null +++ b/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Kernel32.cs @@ -0,0 +1,21 @@ +using System; +using System.Runtime.InteropServices; + +namespace Artemis.UI.Windows.SkiaSharp.Vulkan; + +internal class Kernel32 +{ + private const string kernel32 = "kernel32.dll"; + + static Kernel32() + { + CurrentModuleHandle = GetModuleHandle(null); + if (CurrentModuleHandle == IntPtr.Zero) + throw new Exception("Could not get module handle."); + } + + public static IntPtr CurrentModuleHandle { get; } + + [DllImport(kernel32, CallingConvention = CallingConvention.Winapi, BestFitMapping = false, ThrowOnUnmappableChar = true)] + public static extern IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPTStr)] string lpModuleName); +} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/SkiaSharp/Vulkan/VkContext.cs b/src/Artemis.UI.Windows/SkiaSharp/Vulkan/VkContext.cs new file mode 100644 index 000000000..d31012447 --- /dev/null +++ b/src/Artemis.UI.Windows/SkiaSharp/Vulkan/VkContext.cs @@ -0,0 +1,34 @@ +using System; +using SharpVk; +using SharpVk.Khronos; +using SkiaSharp; + +namespace Artemis.UI.Windows.SkiaSharp.Vulkan; + +internal class VkContext : IDisposable +{ + public virtual Instance Instance { get; protected set; } + + public virtual PhysicalDevice PhysicalDevice { get; protected set; } + + public virtual Surface Surface { get; protected set; } + + public virtual Device Device { get; protected set; } + + public virtual Queue GraphicsQueue { get; protected set; } + + public virtual Queue PresentQueue { get; protected set; } + + public virtual uint GraphicsFamily { get; protected set; } + + public virtual uint PresentFamily { get; protected set; } + + public virtual GRVkGetProcedureAddressDelegate GetProc { get; protected set; } + + public virtual GRSharpVkGetProcedureAddressDelegate SharpVkGetProc { get; protected set; } + + public virtual void Dispose() + { + Instance?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Win32VkContext.cs b/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Win32VkContext.cs new file mode 100644 index 000000000..7c95696c3 --- /dev/null +++ b/src/Artemis.UI.Windows/SkiaSharp/Vulkan/Win32VkContext.cs @@ -0,0 +1,87 @@ +using System; +using System.Linq; +using Avalonia.Win32; +using SharpVk; +using SharpVk.Khronos; + +namespace Artemis.UI.Windows.SkiaSharp.Vulkan; + +internal sealed class Win32VkContext : VkContext +{ + public Win32VkContext() + { + Window = new WindowImpl(); + Instance = Instance.Create(null, new[] {"VK_KHR_surface", "VK_KHR_win32_surface"}); + PhysicalDevice = Instance.EnumeratePhysicalDevices().First(); + Surface = Instance.CreateWin32Surface(Kernel32.CurrentModuleHandle, Window.Handle.Handle); + + (GraphicsFamily, PresentFamily) = FindQueueFamilies(); + + DeviceQueueCreateInfo[] queueInfos = + { + 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 = Proc; + + SharpVkGetProc = (name, instance, device) => + { + if (device != null) + return device.GetProcedureAddress(name); + if (instance != null) + return instance.GetProcedureAddress(name); + + // SharpVk includes the static functions on Instance, but this is not actually correct + // since the functions are static, they are not tied to an instance. For example, + // VkCreateInstance is not found on an instance, it is creating said instance. + // Other libraries, such as VulkanCore, use another type to do this. + return Instance.GetProcedureAddress(name); + }; + } + + public WindowImpl Window { get; } + + public override void Dispose() + { + base.Dispose(); + Window.Dispose(); + } + + private IntPtr Proc(string name, IntPtr instanceHandle, IntPtr deviceHandle) + { + if (deviceHandle != IntPtr.Zero) + return Device.GetProcedureAddress(name); + + return Instance.GetProcedureAddress(name); + } + + private (uint, uint) FindQueueFamilies() + { + QueueFamilyProperties[] queueFamilyProperties = PhysicalDevice.GetQueueFamilyProperties(); + + var graphicsFamily = queueFamilyProperties + .Select((properties, index) => new {properties, index}) + .SkipWhile(pair => !pair.properties.QueueFlags.HasFlag(QueueFlags.Graphics)) + .FirstOrDefault(); + + if (graphicsFamily == null) + throw new Exception("Unable to find graphics queue"); + + uint? presentFamily = default; + + for (uint i = 0; i < queueFamilyProperties.Length; ++i) + { + if (PhysicalDevice.GetSurfaceSupport(i, Surface)) + presentFamily = i; + } + + if (!presentFamily.HasValue) + throw new Exception("Unable to find present queue"); + + return ((uint) graphicsFamily.index, presentFamily.Value); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/SkiaSharp/VulkanContext.cs b/src/Artemis.UI.Windows/SkiaSharp/VulkanContext.cs new file mode 100644 index 000000000..a0684548f --- /dev/null +++ b/src/Artemis.UI.Windows/SkiaSharp/VulkanContext.cs @@ -0,0 +1,64 @@ +using System; +using Artemis.Core.SkiaSharp; +using Artemis.UI.Exceptions; +using Artemis.UI.Windows.SkiaSharp.Vulkan; +using SkiaSharp; + +namespace Artemis.UI.Windows.SkiaSharp +{ + public class VulkanContext : IManagedGraphicsContext + { + private readonly GRVkBackendContext _vulkanBackendContext; + private readonly Win32VkContext _vulkanContext; + + public VulkanContext() + { + // Try everything in separate try-catch blocks to provide some accuracy in error reporting + try + { + _vulkanContext = new Win32VkContext(); + } + catch (Exception e) + { + throw new ArtemisGraphicsContextException("Failed to create Vulkan context", e); + } + + try + { + _vulkanBackendContext = new GRVkBackendContext + { + VkInstance = (IntPtr) _vulkanContext.Instance.RawHandle.ToUInt64(), + VkPhysicalDevice = (IntPtr) _vulkanContext.PhysicalDevice.RawHandle.ToUInt64(), + VkDevice = (IntPtr) _vulkanContext.Device.RawHandle.ToUInt64(), + VkQueue = (IntPtr) _vulkanContext.GraphicsQueue.RawHandle.ToUInt64(), + GraphicsQueueIndex = _vulkanContext.GraphicsFamily, + GetProcedureAddress = _vulkanContext.GetProc + }; + } + catch (Exception e) + { + throw new ArtemisGraphicsContextException("Failed to create Vulkan backend context", e); + } + + try + { + GraphicsContext = GRContext.CreateVulkan(_vulkanBackendContext); + if (GraphicsContext == null) + throw new ArtemisGraphicsContextException("GRContext.CreateVulkan returned null"); + } + catch (Exception e) + { + throw new ArtemisGraphicsContextException("Failed to create Vulkan graphics context", e); + } + + GraphicsContext.Flush(); + } + + /// + public void Dispose() + { + } + + public GRContext GraphicsContext { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/packages.lock.json b/src/Artemis.UI.Windows/packages.lock.json index fb91c11dc..60dc02a9c 100644 --- a/src/Artemis.UI.Windows/packages.lock.json +++ b/src/Artemis.UI.Windows/packages.lock.json @@ -90,6 +90,16 @@ "Splat": "14.1.45" } }, + "SkiaSharp.Vulkan.SharpVk": { + "type": "Direct", + "requested": "[2.80.3, )", + "resolved": "2.80.3", + "contentHash": "IeR9oOHBsJUqpuVs23XgZXnrFV6WuOTaLpFhLVlXt2XILWIRrlrqx1PILgJm5bLqesceJLYZyMxVb/Ow7/uReA==", + "dependencies": { + "SharpVk": "0.4.2", + "SkiaSharp": "2.80.3" + } + }, "Avalonia.Angle.Windows.Natives": { "type": "Transitive", "resolved": "2.1.0.2020091801", @@ -738,6 +748,15 @@ "Serilog": "2.10.0" } }, + "SharpVk": { + "type": "Transitive", + "resolved": "0.4.2", + "contentHash": "0CzZJWKw6CTmxKOXzCCyTKCD7tZB6g2+tm2VSSCXWTHlIMHxlRzbH5BaqkYCGo9Y23wp0hPuz2U3NifMH1VI6w==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.4.0", + "System.ValueTuple": "4.4.0" + } + }, "ShimSkiaSharp": { "type": "Transitive", "resolved": "0.5.12", diff --git a/src/Artemis.UI/Screens/Root/SplashView.axaml b/src/Artemis.UI/Screens/Root/SplashView.axaml index a802cd821..06512173b 100644 --- a/src/Artemis.UI/Screens/Root/SplashView.axaml +++ b/src/Artemis.UI/Screens/Root/SplashView.axaml @@ -3,8 +3,10 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:svg="clr-namespace:Avalonia.Svg.Skia;assembly=Avalonia.Svg.Skia" + xmlns:root="clr-namespace:Artemis.UI.Screens.Root" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.Root.SplashView" + x:DataType="root:SplashViewModel" Icon="/Assets/Images/Logo/application.ico" Title="Artemis 2.0" Height="450" @@ -20,12 +22,13 @@ Artemis is initializing... - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Root/SplashViewModel.cs b/src/Artemis.UI/Screens/Root/SplashViewModel.cs index d4f21eb52..f4bc36241 100644 --- a/src/Artemis.UI/Screens/Root/SplashViewModel.cs +++ b/src/Artemis.UI/Screens/Root/SplashViewModel.cs @@ -55,7 +55,7 @@ namespace Artemis.UI.Screens.Root private void PluginManagementServiceOnPluginFeatureEnabling(object? sender, PluginFeatureEventArgs e) { - Status = "Enabling: " + e.PluginFeature.GetType().Name.Humanize(); + Status = "Enabling: " + e.PluginFeature.Info.Name; } private void PluginManagementServiceOnPluginFeatureEnabled(object? sender, PluginFeatureEventArgs e) diff --git a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs index bbfb902d2..8b4660b89 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs @@ -13,6 +13,7 @@ using Artemis.Core.Services; using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared; using Avalonia; +using DynamicData; using FluentAvalonia.Styling; using ReactiveUI; using Serilog.Events; @@ -26,15 +27,19 @@ namespace Artemis.UI.Screens.Settings private readonly IDebugService _debugService; private readonly FluentAvaloniaTheme _fluentAvaloniaTheme; - public GeneralTabViewModel(ISettingsService settingsService, IPluginManagementService pluginManagementService, IDebugService debugService) + public GeneralTabViewModel(ISettingsService settingsService, IPluginManagementService pluginManagementService, IDebugService debugService, IGraphicsContextProvider? graphicsContextProvider) { DisplayName = "General"; _settingsService = settingsService; _debugService = debugService; _fluentAvaloniaTheme = AvaloniaLocator.Current.GetService(); - + List layerBrushProviders = pluginManagementService.GetFeaturesOfType(); LayerBrushDescriptors = new ObservableCollection(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); + GraphicsContexts = new ObservableCollection {"Software"}; + if (graphicsContextProvider != null) + GraphicsContexts.AddRange(graphicsContextProvider.GraphicsContextNames); + _defaultLayerBrushDescriptor = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference { LayerBrushProviderId = "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba", @@ -46,7 +51,7 @@ namespace Artemis.UI.Screens.Settings ShowSetupWizard = ReactiveCommand.Create(ExecuteShowSetupWizard); ShowDebugger = ReactiveCommand.Create(ExecuteShowDebugger); ShowDataFolder = ReactiveCommand.Create(ExecuteShowDataFolder); - + this.WhenActivated(d => { UIColorScheme.SettingChanged += UIColorSchemeOnSettingChanged; @@ -73,12 +78,7 @@ namespace Artemis.UI.Screens.Settings public ReactiveCommand ShowDataFolder { get; } public ObservableCollection LayerBrushDescriptors { get; } - - public ObservableCollection GraphicsContexts { get; } = new() - { - "Software", - "Vulkan" - }; + public ObservableCollection GraphicsContexts { get; } public ObservableCollection RenderScales { get; } = new() { @@ -111,7 +111,7 @@ namespace Artemis.UI.Screens.Settings get => RenderScales.FirstOrDefault(s => Math.Abs(s.Value - CoreRenderScale.Value) < 0.01); set { - if (value != null) + if (value != null) CoreRenderScale.Value = value.Value; } } @@ -121,7 +121,7 @@ namespace Artemis.UI.Screens.Settings get => TargetFrameRates.FirstOrDefault(s => Math.Abs(s.Value - CoreTargetFrameRate.Value) < 0.01); set { - if (value != null) + if (value != null) CoreTargetFrameRate.Value = (int) value.Value; } } diff --git a/src/Artemis.UI/Services/Interfaces/IRegistrationService.cs b/src/Artemis.UI/Services/Interfaces/IRegistrationService.cs index 838947dbc..d17e28d1b 100644 --- a/src/Artemis.UI/Services/Interfaces/IRegistrationService.cs +++ b/src/Artemis.UI/Services/Interfaces/IRegistrationService.cs @@ -6,7 +6,6 @@ void RegisterBuiltInDataModelInputs(); void RegisterBuiltInPropertyEditors(); void RegisterControllers(); - void ApplyPreferredGraphicsContext(); void RegisterBuiltInNodeTypes(); } } \ No newline at end of file diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs index 038adc4ae..906d69bbe 100644 --- a/src/Artemis.UI/Services/RegistrationService.cs +++ b/src/Artemis.UI/Services/RegistrationService.cs @@ -90,11 +90,7 @@ public class RegistrationService : IRegistrationService public void RegisterControllers() { } - - public void ApplyPreferredGraphicsContext() - { - } - + public void RegisterBuiltInNodeTypes() { _nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(bool), new SKColor(0xFFCD3232));