From 19944c519c5c929475c9af4baaa94600b2372423 Mon Sep 17 00:00:00 2001 From: Diogo Trindade Date: Thu, 11 Apr 2024 09:20:34 +0100 Subject: [PATCH] Chroma - perf improvements --- ...Artemis.Plugins.LayerBrushes.Chroma.csproj | 3 +- .../Module/ChromaDataModel.cs | 17 +++-- .../Module/ChromaModule.cs | 26 +++---- .../Services/ChromaService.cs | 70 +++++++++---------- .../plugin.json | 2 +- 5 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/Artemis.Plugins.LayerBrushes.Chroma/Artemis.Plugins.LayerBrushes.Chroma.csproj b/src/Artemis.Plugins.LayerBrushes.Chroma/Artemis.Plugins.LayerBrushes.Chroma.csproj index e03a3b5..401800e 100644 --- a/src/Artemis.Plugins.LayerBrushes.Chroma/Artemis.Plugins.LayerBrushes.Chroma.csproj +++ b/src/Artemis.Plugins.LayerBrushes.Chroma/Artemis.Plugins.LayerBrushes.Chroma.csproj @@ -4,11 +4,12 @@ x64 true enable + CA1416 - + diff --git a/src/Artemis.Plugins.LayerBrushes.Chroma/Module/ChromaDataModel.cs b/src/Artemis.Plugins.LayerBrushes.Chroma/Module/ChromaDataModel.cs index 0f8051a..5950255 100644 --- a/src/Artemis.Plugins.LayerBrushes.Chroma/Module/ChromaDataModel.cs +++ b/src/Artemis.Plugins.LayerBrushes.Chroma/Module/ChromaDataModel.cs @@ -2,19 +2,24 @@ using SkiaSharp; using System; using System.Collections.Generic; +using Artemis.Plugins.LayerBrushes.Chroma.Services; namespace Artemis.Plugins.LayerBrushes.Chroma.Module; public class ChromaDataModel : DataModel { - public bool IsActive { get; set; } - public string? CurrentApplication { get; set; } - public List ApplicationList { get; internal set; } = new(); - public List PidList { get; internal set; } = new(); - public string[] PriorityList { get; internal set; } = Array.Empty(); + public bool IsActive => Service.IsActive; + public string? CurrentApplication => Service.CurrentApp; + public string[] ApplicationList => Service.AppNames; + public uint[] PidList => Service.AppIds; + public string[] PriorityList { get; internal set; } = []; + + internal ChromaService Service { get; set; } = null!; } -public class ChromaDeviceDataModel : DataModel { } +public class ChromaDeviceDataModel : DataModel +{ +} public class ChromaLedDataModel : DataModel { diff --git a/src/Artemis.Plugins.LayerBrushes.Chroma/Module/ChromaModule.cs b/src/Artemis.Plugins.LayerBrushes.Chroma/Module/ChromaModule.cs index e9b219b..1f3e48f 100644 --- a/src/Artemis.Plugins.LayerBrushes.Chroma/Module/ChromaModule.cs +++ b/src/Artemis.Plugins.LayerBrushes.Chroma/Module/ChromaModule.cs @@ -6,14 +6,13 @@ using SkiaSharp; using System; using System.Collections.Generic; -using System.Linq; namespace Artemis.Plugins.LayerBrushes.Chroma.Module; [PluginFeature(Name = "Chroma")] public class ChromaModule : Module { - public override List ActivationRequirements { get; } = new(); + public override List ActivationRequirements { get; } = []; private readonly ILogger _logger; private readonly ChromaService _chroma; @@ -29,20 +28,25 @@ public ChromaModule(ChromaService chroma, ChromaRegistryService registry, ILogge public override void Enable() { + DataModel.Service = _chroma; + CreateStructure(); _chroma.MatrixUpdated += OnMatrixUpdated; - _chroma.AppListUpdated += OnAppListUpdated; - OnAppListUpdated(this, EventArgs.Empty); try { DataModel.PriorityList = _registry.GetRazerSdkInfo().PriorityList; + var artemis = DataModel.PriorityList.IndexOf("Artemis.UI.Windows.exe"); + if (artemis != -1 && artemis != DataModel.PriorityList.Length - 1) + { + _logger.Error("Artemis is not the last item in the Razer Chroma SDK priority list, the Chroma grabber may not work correctly."); + } } catch (Exception e) { _logger.Error(e, "Error setting priority list."); - DataModel.PriorityList = Array.Empty(); + DataModel.PriorityList = []; } AddDefaultProfile(DefaultCategoryName.Games, Plugin.ResolveRelativePath("profile.zip")); @@ -51,21 +55,12 @@ public override void Enable() public override void Disable() { _chroma.MatrixUpdated -= OnMatrixUpdated; - _chroma.AppListUpdated -= OnAppListUpdated; } public override void Update(double deltaTime) { } - private void OnAppListUpdated(object? sender, EventArgs args) - { - DataModel.IsActive = _chroma.IsActive; - DataModel.CurrentApplication = _chroma.CurrentApp; - DataModel.ApplicationList = _chroma.AppNames.ToList(); - DataModel.PidList = _chroma.AppIds.Select(p => (int)p).ToList(); - } - private void OnMatrixUpdated(object? sender, MatrixUpdatedEventArgs e) { var (deviceType, colors) = e; @@ -90,9 +85,8 @@ private void CreateStructure() var deviceDataModel = DataModel.AddDynamicChild(rzDeviceType.ToStringFast(), new ChromaDeviceDataModel()); var map = DefaultChromaLedMap.GetDeviceMap(rzDeviceType); - for (var i = 0; i < map.Length; i++) + foreach (var ledId in map) { - var ledId = map[i]; if (ledId == LedId.Invalid) continue; diff --git a/src/Artemis.Plugins.LayerBrushes.Chroma/Services/ChromaService.cs b/src/Artemis.Plugins.LayerBrushes.Chroma/Services/ChromaService.cs index b59a3c5..1d3b9de 100644 --- a/src/Artemis.Plugins.LayerBrushes.Chroma/Services/ChromaService.cs +++ b/src/Artemis.Plugins.LayerBrushes.Chroma/Services/ChromaService.cs @@ -2,45 +2,47 @@ using SkiaSharp; using System; using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; using Artemis.Core; using RazerSdkReader; using RazerSdkReader.Structures; namespace Artemis.Plugins.LayerBrushes.Chroma.Services; -public readonly record struct MatrixUpdatedEventArgs(RzDeviceType DeviceType, SKColor[] Matrix); +public record MatrixUpdatedEventArgs(RzDeviceType DeviceType, SKColor[] Matrix); +// ReSharper disable once ClassNeverInstantiated.Global public sealed class ChromaService : IPluginService, IDisposable { private readonly SKColor[][] _matrices; - private readonly List _apps; - private readonly List _pids; private readonly ChromaReader _reader; private readonly Profiler _profiler; private readonly object _lock; - + private readonly MatrixUpdatedEventArgs[] _matrixUpdatedEventArgs; + public event EventHandler? MatrixUpdated; public event EventHandler? AppListUpdated; - + public bool IsActive => !string.IsNullOrWhiteSpace(CurrentApp) && CurrentApp != "Artemis.UI.Windows.exe"; public string? CurrentApp { get; private set; } public uint? CurrentAppId { get; private set; } - public IEnumerable AppNames => _apps; - public IEnumerable AppIds => _pids; + public string[] AppNames { get; } + public uint[] AppIds { get; } public ChromaService(Plugin plugin) { _profiler = plugin.GetProfiler("Chroma Service"); _lock = new object(); - _apps = []; - _pids = []; - + AppNames = new string[50]; + AppIds = new uint[50]; + var deviceTypes = Enum.GetValues(); - _matrices = new SKColor[deviceTypes.Length][]; - for (var i = 0; i < _matrices.Length; i++) - _matrices[i] = new SKColor[deviceTypes[i].GetLength()]; + _matrices = deviceTypes.Select(deviceType => new SKColor[deviceType.GetLength()]).ToArray(); + _matrixUpdatedEventArgs = deviceTypes.Select(deviceType => new MatrixUpdatedEventArgs(deviceType, _matrices[(int)deviceType])).ToArray(); - _reader = new(); + _reader = new ChromaReader(); _reader.KeyboardUpdated += RazerEmulatorReaderOnKeyboardUpdated; _reader.MouseUpdated += RazerEmulatorReaderOnMouseUpdated; _reader.MousepadUpdated += RazerEmulatorReaderOnMousepadUpdated; @@ -65,26 +67,21 @@ public ChromaService(Plugin plugin) private void RazerEmulatorReaderOnKeyboardUpdated(object? sender, in ChromaKeyboard e) => UpdateMatrix(RzDeviceType.Keyboard, in e); - private void UpdateMatrix(RzDeviceType deviceType, in T data) where T : IColorProvider + private void UpdateMatrix(RzDeviceType deviceType, in T data) where T : IColorProvider { var profilerName = deviceType.ToStringFast(); - + _profiler.StartMeasurement(profilerName); + lock (_lock) { - var matrix = _matrices[(int) deviceType]; - - Span colors = stackalloc ChromaColor[matrix.Length]; - + var matrix = _matrices[(int)deviceType]; + //SKColor and ChromaColor are the same size and layout, + //so we can just write to it directly. + var colors = MemoryMarshal.Cast(matrix); data.GetColors(colors); - for (var i = 0; i < colors.Length; i++) - { - var rzColor = colors[i]; - matrix[i] = new SKColor(rzColor.R, rzColor.G, rzColor.B); - } - - MatrixUpdated?.Invoke(this, new MatrixUpdatedEventArgs(deviceType, matrix)); + MatrixUpdated?.Invoke(this, _matrixUpdatedEventArgs[(int)deviceType]); } _profiler.StopMeasurement(profilerName); @@ -92,19 +89,22 @@ private void UpdateMatrix(RzDeviceType deviceType, in T data) where T : ICol private void UpdateAppListData(in ChromaAppData app) { - _apps.Clear(); - _pids.Clear(); - + _profiler.StartMeasurement("AppList"); + CurrentAppId = app.CurrentAppId; CurrentApp = app.CurrentAppName; - - foreach(ref readonly var appInfo in app.AppInfo) + + ReadOnlySpan apps = app.AppInfo; + for (var i = 0; i < apps.Length; i++) { - _apps.Add(appInfo.AppName); - _pids.Add(appInfo.AppId); + ref readonly var appInfo = ref apps[i]; + AppNames[i] = appInfo.AppName; + AppIds[i] = appInfo.AppId; } - + AppListUpdated?.Invoke(this, EventArgs.Empty); + + _profiler.StopMeasurement("AppList"); } public void Dispose() diff --git a/src/Artemis.Plugins.LayerBrushes.Chroma/plugin.json b/src/Artemis.Plugins.LayerBrushes.Chroma/plugin.json index 365f85c..d02c936 100644 --- a/src/Artemis.Plugins.LayerBrushes.Chroma/plugin.json +++ b/src/Artemis.Plugins.LayerBrushes.Chroma/plugin.json @@ -5,7 +5,7 @@ "Author": "diogotr7", "Icon": "Snake", "Description": "Provides a layer that displays lighting from Razer Chroma supported games on all devices Artemis supports.", - "Version": "1.2.0.1", + "Version": "1.3.0.0", "Main": "Artemis.Plugins.LayerBrushes.Chroma.dll", "Platforms": "Windows" } \ No newline at end of file