Core - Added the ability to change graphics context at runtime

Settings - Added setting for switching between software-based and Vulkan-based rendering
This commit is contained in:
Robert committed 2021-03-22 19:29:53 +01:00
1 parent d7e302fb23
commit f888fb5697
19 files changed
+281 -270

No files matched your search

+5 -14
View File
@@ -2,9 +2,10 @@
using System.Collections.Generic;
using System.IO;
using Artemis.Core.JsonConverters;
using Artemis.Core.Services;
using Artemis.Core.Services.Core;
using Artemis.Core.SkiaSharp;
using Newtonsoft.Json;
using SkiaSharp;
namespace Artemis.Core
{
@@ -118,20 +119,10 @@ namespace Artemis.Core
typeof(decimal)
};
private static GRContext? _skiaGraphicsContext;
/// <summary>
/// Gets or sets the graphics context to be used for rendering by SkiaSharp
/// Gets the graphics context to be used for rendering by SkiaSharp. Can be set via
/// <see cref="IRgbService.UpdateGraphicsContext" />.
/// </summary>
public static GRContext? SkiaGraphicsContext
{
get => _skiaGraphicsContext;
set
{
if (_skiaGraphicsContext != null)
throw new ArtemisCoreException($"{nameof(SkiaGraphicsContext)} can only be set once.");
_skiaGraphicsContext = value;
}
}
public static IManagedGraphicsContext? ManagedGraphicsContext { get; internal set; }
}
}
@@ -0,0 +1,25 @@
using System;
namespace Artemis.Core
{
/// <summary>
/// Represents SkiaSharp graphics-context related errors
/// </summary>
public class ArtemisGraphicsContextException : Exception
{
/// <inheritdoc />
public ArtemisGraphicsContextException()
{
}
/// <inheritdoc />
public ArtemisGraphicsContextException(string message) : base(message)
{
}
/// <inheritdoc />
public ArtemisGraphicsContextException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
+3 -3
View File
@@ -36,11 +36,11 @@ namespace Artemis.Core
int width = (int) pathBounds.Width;
int height = (int) pathBounds.Height;
SKImageInfo imageInfo = new SKImageInfo(width, height);
if (Constants.SkiaGraphicsContext == null)
SKImageInfo imageInfo = new(width, height);
if (Constants.ManagedGraphicsContext?.GraphicsContext == null)
Surface = SKSurface.Create(imageInfo);
else
Surface = SKSurface.Create(Constants.SkiaGraphicsContext, true, imageInfo);
Surface = SKSurface.Create(Constants.ManagedGraphicsContext.GraphicsContext, true, imageInfo);
Path = new SKPath(path);
Path.Transform(SKMatrix.CreateTranslation(pathBounds.Left * -1, pathBounds.Top * -1));
+4 -5
View File
@@ -1,6 +1,5 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Artemis.Core.SkiaSharp;
using RGB.NET.Core;
using RGB.NET.Presets.Textures.Sampler;
using SkiaSharp;
@@ -17,14 +16,14 @@ namespace Artemis.Core
#region Constructors
internal SKTexture(int width, int height, float renderScale)
internal SKTexture(IManagedGraphicsContext? managedGraphicsContext, int width, int height, float renderScale)
: base(width, height, 4, new AverageByteSampler())
{
ImageInfo = new SKImageInfo(width, height);
if (Constants.SkiaGraphicsContext == null)
if (managedGraphicsContext == null)
Surface = SKSurface.Create(ImageInfo);
else
Surface = SKSurface.Create(Constants.SkiaGraphicsContext, true, ImageInfo);
Surface = SKSurface.Create(managedGraphicsContext.GraphicsContext, true, ImageInfo);
RenderScale = renderScale;
}
+2
View File
@@ -59,6 +59,7 @@ namespace Artemis.Core.Services
UpdatePluginCache();
_rgbService.IsRenderPaused = true;
_rgbService.Surface.Updating += SurfaceOnUpdating;
_loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel();
@@ -242,6 +243,7 @@ namespace Artemis.Core.Services
IsElevated
);
_rgbService.IsRenderPaused = false;
OnInitialized();
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Artemis.Core.SkiaSharp;
using RGB.NET.Core;
namespace Artemis.Core.Services
@@ -50,6 +51,16 @@ namespace Artemis.Core.Services
/// </summary>
void CloseRender();
/// <summary>
/// Updates the graphics context to the provided <paramref name="managedGraphicsContext"></paramref>.
/// <para>Note: The old graphics context will be used until the next frame starts rendering and is disposed afterwards.</para>
/// </summary>
/// <param name="managedGraphicsContext">
/// The new managed graphics context. If <see langword="null" />, software rendering
/// is used.
/// </param>
void UpdateGraphicsContext(IManagedGraphicsContext? managedGraphicsContext);
/// <summary>
/// Adds the given device provider to the <see cref="Surface" />
/// </summary>
+31 -7
View File
@@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Core.DeviceProviders;
using Artemis.Core.Services.Models;
using Artemis.Core.SkiaSharp;
using Artemis.Storage.Entities.Surface;
using Artemis.Storage.Repositories.Interfaces;
using RGB.NET.Core;
@@ -51,7 +52,7 @@ namespace Artemis.Core.Services
UpdateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value};
Surface.RegisterUpdateTrigger(UpdateTrigger);
}
public TimerUpdateTrigger UpdateTrigger { get; }
protected virtual void OnDeviceRemoved(DeviceEventArgs e)
@@ -118,9 +119,7 @@ namespace Artemis.Core.Services
public IReadOnlyCollection<ArtemisDevice> Devices => _devices.AsReadOnly();
public IReadOnlyDictionary<Led, ArtemisLed> LedMap => new ReadOnlyDictionary<Led, ArtemisLed>(_ledMap);
/// <inheritdoc />
public RGBSurface Surface { get; set; }
public bool IsRenderPaused { get; set; }
public bool RenderOpen { get; private set; }
@@ -215,6 +214,8 @@ namespace Artemis.Core.Services
#region Rendering
private IManagedGraphicsContext? _newGraphicsContext;
public SKTexture OpenRender()
{
if (RenderOpen)
@@ -231,7 +232,7 @@ namespace Artemis.Core.Services
{
if (!RenderOpen)
throw new ArtemisCoreException("Render pipeline is already closed");
RenderOpen = false;
_texture?.CopyPixelData();
}
@@ -241,15 +242,38 @@ namespace Artemis.Core.Services
if (RenderOpen)
throw new ArtemisCoreException("Cannot update the texture while rendering");
SKTexture? oldTexture = _texture;
IManagedGraphicsContext? graphicsContext = Constants.ManagedGraphicsContext = _newGraphicsContext;
if (!ReferenceEquals(graphicsContext, _newGraphicsContext))
graphicsContext = _newGraphicsContext;
if (graphicsContext != null)
_logger.Debug("Creating SKTexture with graphics context {graphicsContext}", graphicsContext.GetType().Name);
else
_logger.Debug("Creating SKTexture with software-based graphics context");
float renderScale = (float) _renderScaleSetting.Value;
int width = Math.Max(1, MathF.Min(Surface.Boundary.Size.Width * renderScale, 4096).RoundToInt());
int height = Math.Max(1, MathF.Min(Surface.Boundary.Size.Height * renderScale, 4096).RoundToInt());
_texture = new SKTexture(width, height, renderScale);
_texture?.Dispose();
_texture = new SKTexture(graphicsContext, width, height, renderScale);
_textureBrush.Texture = _texture;
oldTexture?.Dispose();
if (!ReferenceEquals(_newGraphicsContext, Constants.ManagedGraphicsContext = _newGraphicsContext))
{
Constants.ManagedGraphicsContext?.Dispose();
Constants.ManagedGraphicsContext = _newGraphicsContext;
_newGraphicsContext = null;
}
}
public void UpdateGraphicsContext(IManagedGraphicsContext? managedGraphicsContext)
{
if (ReferenceEquals(managedGraphicsContext, Constants.ManagedGraphicsContext))
return;
_newGraphicsContext = managedGraphicsContext;
_texture?.Invalidate();
}
#endregion
@@ -0,0 +1,16 @@
using System;
using SkiaSharp;
namespace Artemis.Core.SkiaSharp
{
/// <summary>
/// Represents a managed wrapper around a SkiaSharp context
/// </summary>
public interface IManagedGraphicsContext : IDisposable
{
/// <summary>
/// Gets the graphics context created by this wrapper
/// </summary>
GRContext GraphicsContext { get; }
}
}