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

Rendering - Improved sampling performance

Plugins - Added update/render time measuring
Settings - Added a way to enable 60/144 FPS 🕵🏻‍♂️
This commit is contained in:
Robert 2021-03-22 21:12:58 +01:00
parent fc9476247f
commit 97668ee932
8 changed files with 141 additions and 75 deletions

View File

@ -318,7 +318,7 @@ namespace Artemis.Core
if (Path == null || LayerBrush == null)
throw new ArtemisCoreException("The layer is not yet ready for rendering");
if (timeline.IsFinished)
if (!Leds.Any() || timeline.IsFinished)
return;
ApplyTimeline(timeline);

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Artemis.Core.DataModelExpansions;
using Artemis.Storage.Entities.Module;
@ -186,13 +187,17 @@ namespace Artemis.Core.Modules
internal virtual void InternalUpdate(double deltaTime)
{
StartUpdateMeasure();
if (IsUpdateAllowed)
Update(deltaTime);
StopUpdateMeasure();
}
internal virtual void InternalRender(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
{
StartRenderMeasure();
Render(deltaTime, canvas, canvasInfo);
StopRenderMeasure();
}
internal virtual void Activate(bool isOverride)

View File

@ -150,6 +150,7 @@ namespace Artemis.Core.Modules
internal override void InternalUpdate(double deltaTime)
{
StartUpdateMeasure();
if (IsUpdateAllowed)
Update(deltaTime);
@ -165,10 +166,12 @@ namespace Artemis.Core.Modules
}
ProfileUpdated(deltaTime);
StopUpdateMeasure();
}
internal override void InternalRender(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
{
StartRenderMeasure();
Render(deltaTime, canvas, canvasInfo);
lock (_lock)
@ -178,6 +181,7 @@ namespace Artemis.Core.Modules
}
ProfileRendered(deltaTime, canvas, canvasInfo);
StopRenderMeasure();
}
internal async Task ChangeActiveProfileAnimated(Profile? profile, IEnumerable<ArtemisDevice> devices)

View File

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Artemis.Storage.Entities.Plugins;
@ -10,9 +11,11 @@ namespace Artemis.Core
/// </summary>
public abstract class PluginFeature : CorePropertyChanged, IDisposable
{
private readonly Stopwatch _renderStopwatch = new();
private readonly Stopwatch _updateStopwatch = new();
private bool _isEnabled;
private Exception? _loadException;
/// <summary>
/// Gets the plugin feature info related to this feature
/// </summary>
@ -46,6 +49,16 @@ namespace Artemis.Core
/// </summary>
public string Id => $"{GetType().FullName}-{Plugin.Guid.ToString().Substring(0, 8)}"; // Not as unique as a GUID but good enough and stays readable
/// <summary>
/// Gets the last measured update time of the feature
/// </summary>
public TimeSpan UpdateTime { get; private set; }
/// <summary>
/// Gets the last measured render time of the feature
/// </summary>
public TimeSpan RenderTime { get; private set; }
internal PluginFeatureEntity Entity { get; set; } = null!; // Will be set right after construction
/// <summary>
@ -58,6 +71,66 @@ namespace Artemis.Core
/// </summary>
public abstract void Disable();
/// <summary>
/// Occurs when the feature is enabled
/// </summary>
public event EventHandler? Enabled;
/// <summary>
/// Occurs when the feature is disabled
/// </summary>
public event EventHandler? Disabled;
/// <summary>
/// Releases the unmanaged resources used by the plugin feature and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing) InternalDisable();
}
/// <summary>
/// Triggers the Enabled event
/// </summary>
protected virtual void OnEnabled()
{
Enabled?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Triggers the Disabled event
/// </summary>
protected virtual void OnDisabled()
{
Disabled?.Invoke(this, EventArgs.Empty);
}
internal void StartUpdateMeasure()
{
_updateStopwatch.Start();
}
internal void StopUpdateMeasure()
{
UpdateTime = _updateStopwatch.Elapsed;
_updateStopwatch.Reset();
}
internal void StartRenderMeasure()
{
_renderStopwatch.Start();
}
internal void StopRenderMeasure()
{
RenderTime = _renderStopwatch.Elapsed;
_renderStopwatch.Reset();
}
internal void SetEnabled(bool enable, bool isAutoEnable = false)
{
if (enable == IsEnabled)
@ -133,25 +206,6 @@ namespace Artemis.Core
Disable();
}
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the plugin feature and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
InternalDisable();
}
}
#endregion
/// <inheritdoc />
public void Dispose()
{
@ -187,35 +241,5 @@ namespace Artemis.Core
}
#endregion
#region Events
/// <summary>
/// Occurs when the feature is enabled
/// </summary>
public event EventHandler? Enabled;
/// <summary>
/// Occurs when the feature is disabled
/// </summary>
public event EventHandler? Disabled;
/// <summary>
/// Triggers the Enabled event
/// </summary>
protected virtual void OnEnabled()
{
Enabled?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Triggers the Disabled event
/// </summary>
protected virtual void OnDisabled()
{
Disabled?.Invoke(this, EventArgs.Empty);
}
#endregion
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Runtime.InteropServices;
using Artemis.Core.SkiaSharp;
using RGB.NET.Core;
using RGB.NET.Presets.Textures.Sampler;
@ -11,34 +12,39 @@ namespace Artemis.Core
/// </summary>
public sealed class SKTexture : PixelTexture<byte>, IDisposable
{
private SKPixmap? _pixelData;
private SKImage? _rasterImage;
private readonly SKPixmap _pixelData;
private readonly IntPtr _pixelDataPtr;
#region Constructors
internal SKTexture(IManagedGraphicsContext? managedGraphicsContext, int width, int height, float renderScale)
: base(width, height, 4, new AverageByteSampler())
internal SKTexture(IManagedGraphicsContext? graphicsContext, int width, int height, float scale) : base(width, height, 4, new AverageByteSampler())
{
ImageInfo = new SKImageInfo(width, height);
if (managedGraphicsContext == null)
Surface = SKSurface.Create(ImageInfo);
else
Surface = SKSurface.Create(managedGraphicsContext.GraphicsContext, true, ImageInfo);
RenderScale = renderScale;
Surface = graphicsContext == null
? SKSurface.Create(ImageInfo)
: SKSurface.Create(graphicsContext.GraphicsContext, true, ImageInfo);
RenderScale = scale;
_pixelDataPtr = Marshal.AllocHGlobal(ImageInfo.BytesSize);
_pixelData = new SKPixmap(ImageInfo, _pixelDataPtr, ImageInfo.RowBytes);
}
#endregion
#region Methods
/// <summary>
/// Invalidates the texture
/// </summary>
public void Invalidate()
{
IsInvalid = true;
}
internal void CopyPixelData()
{
using SKImage skImage = Surface.Snapshot();
_rasterImage?.Dispose();
_pixelData?.Dispose();
_rasterImage = skImage.ToRasterImage();
_pixelData = _rasterImage.PeekPixels();
skImage.ReadPixels(_pixelData);
}
/// <inheritdoc />
@ -64,7 +70,7 @@ namespace Artemis.Core
/// <summary>
/// Gets the color data in RGB format
/// </summary>
protected override ReadOnlySpan<byte> Data => _pixelData != null ? _pixelData.GetPixelSpan() : ReadOnlySpan<byte>.Empty;
protected override ReadOnlySpan<byte> Data => _pixelData.GetPixelSpan();
/// <summary>
/// Gets the render scale of the texture
@ -77,19 +83,29 @@ namespace Artemis.Core
/// </summary>
public bool IsInvalid { get; private set; }
/// <summary>
/// Invalidates the texture
/// </summary>
public void Invalidate()
#endregion
#region IDisposable
private void ReleaseUnmanagedResources()
{
IsInvalid = true;
Marshal.FreeHGlobal(_pixelDataPtr);
}
/// <inheritdoc />
public void Dispose()
{
Surface.Dispose();
_pixelData?.Dispose();
_pixelData.Dispose();
ReleaseUnmanagedResources();
GC.SuppressFinalize(this);
}
/// <inheritdoc />
~SKTexture()
{
ReleaseUnmanagedResources();
}
#endregion

View File

@ -35,6 +35,9 @@
<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

@ -20,6 +20,7 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
private int _renderWidth;
private int _renderHeight;
private string _frameTargetPath;
private string _renderer;
public RenderDebugViewModel(ICoreService coreService)
{
@ -51,6 +52,12 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
set => SetAndNotify(ref _renderHeight, value);
}
public string Renderer
{
get => _renderer;
set => SetAndNotify(ref _renderer, value);
}
public void SaveFrame()
{
VistaSaveFileDialog dialog = new VistaSaveFileDialog {Filter = "Portable network graphic (*.png)|*.png", Title = "Save render frame"};
@ -69,6 +76,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
{
_coreService.FrameRendered += CoreServiceOnFrameRendered;
_coreService.FrameRendering += CoreServiceOnFrameRendering;
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
base.OnActivate();
}
@ -88,8 +97,6 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
RenderWidth = bitmapInfo.Width;
// ReSharper disable twice CompareOfFloatsByEqualityOperator
if (CurrentFrame is not WriteableBitmap writable || writable.Width != bitmapInfo.Width || writable.Height != bitmapInfo.Height)
{
CurrentFrame = e.Texture.Surface.Snapshot().ToWriteableBitmap();

View File

@ -42,7 +42,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
IUpdateService updateService,
IPluginManagementService pluginManagementService,
IMessageService messageService,
IRegistrationService registrationService)
IRegistrationService registrationService,
ICoreService coreService
)
{
DisplayName = "GENERAL";
@ -64,6 +66,11 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
TargetFrameRates = new List<Tuple<string, int>>();
for (int i = 10; i <= 30; i += 5)
TargetFrameRates.Add(new Tuple<string, int>(i + " FPS", i));
if (coreService.StartupArguments.Contains("--pcmr"))
{
TargetFrameRates.Add(new Tuple<string, int>("60 FPS (lol)", 60));
TargetFrameRates.Add(new Tuple<string, int>("144 FPS (omegalol)", 144));
}
List<LayerBrushProvider> layerBrushProviders = pluginManagementService.GetFeaturesOfType<LayerBrushProvider>();