mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
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:
parent
d7e302fb23
commit
f888fb5697
@ -2,9 +2,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Artemis.Core.JsonConverters;
|
using Artemis.Core.JsonConverters;
|
||||||
|
using Artemis.Core.Services;
|
||||||
using Artemis.Core.Services.Core;
|
using Artemis.Core.Services.Core;
|
||||||
|
using Artemis.Core.SkiaSharp;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace Artemis.Core
|
namespace Artemis.Core
|
||||||
{
|
{
|
||||||
@ -118,20 +119,10 @@ namespace Artemis.Core
|
|||||||
typeof(decimal)
|
typeof(decimal)
|
||||||
};
|
};
|
||||||
|
|
||||||
private static GRContext? _skiaGraphicsContext;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public static GRContext? SkiaGraphicsContext
|
public static IManagedGraphicsContext? ManagedGraphicsContext { get; internal set; }
|
||||||
{
|
|
||||||
get => _skiaGraphicsContext;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_skiaGraphicsContext != null)
|
|
||||||
throw new ArtemisCoreException($"{nameof(SkiaGraphicsContext)} can only be set once.");
|
|
||||||
_skiaGraphicsContext = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -36,11 +36,11 @@ namespace Artemis.Core
|
|||||||
int width = (int) pathBounds.Width;
|
int width = (int) pathBounds.Width;
|
||||||
int height = (int) pathBounds.Height;
|
int height = (int) pathBounds.Height;
|
||||||
|
|
||||||
SKImageInfo imageInfo = new SKImageInfo(width, height);
|
SKImageInfo imageInfo = new(width, height);
|
||||||
if (Constants.SkiaGraphicsContext == null)
|
if (Constants.ManagedGraphicsContext?.GraphicsContext == null)
|
||||||
Surface = SKSurface.Create(imageInfo);
|
Surface = SKSurface.Create(imageInfo);
|
||||||
else
|
else
|
||||||
Surface = SKSurface.Create(Constants.SkiaGraphicsContext, true, imageInfo);
|
Surface = SKSurface.Create(Constants.ManagedGraphicsContext.GraphicsContext, true, imageInfo);
|
||||||
|
|
||||||
Path = new SKPath(path);
|
Path = new SKPath(path);
|
||||||
Path.Transform(SKMatrix.CreateTranslation(pathBounds.Left * -1, pathBounds.Top * -1));
|
Path.Transform(SKMatrix.CreateTranslation(pathBounds.Left * -1, pathBounds.Top * -1));
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using Artemis.Core.SkiaSharp;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
using RGB.NET.Presets.Textures.Sampler;
|
using RGB.NET.Presets.Textures.Sampler;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
@ -17,14 +16,14 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
#region Constructors
|
#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())
|
: base(width, height, 4, new AverageByteSampler())
|
||||||
{
|
{
|
||||||
ImageInfo = new SKImageInfo(width, height);
|
ImageInfo = new SKImageInfo(width, height);
|
||||||
if (Constants.SkiaGraphicsContext == null)
|
if (managedGraphicsContext == null)
|
||||||
Surface = SKSurface.Create(ImageInfo);
|
Surface = SKSurface.Create(ImageInfo);
|
||||||
else
|
else
|
||||||
Surface = SKSurface.Create(Constants.SkiaGraphicsContext, true, ImageInfo);
|
Surface = SKSurface.Create(managedGraphicsContext.GraphicsContext, true, ImageInfo);
|
||||||
RenderScale = renderScale;
|
RenderScale = renderScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -59,6 +59,7 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
UpdatePluginCache();
|
UpdatePluginCache();
|
||||||
|
|
||||||
|
_rgbService.IsRenderPaused = true;
|
||||||
_rgbService.Surface.Updating += SurfaceOnUpdating;
|
_rgbService.Surface.Updating += SurfaceOnUpdating;
|
||||||
_loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel();
|
_loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel();
|
||||||
|
|
||||||
@ -242,6 +243,7 @@ namespace Artemis.Core.Services
|
|||||||
IsElevated
|
IsElevated
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_rgbService.IsRenderPaused = false;
|
||||||
OnInitialized();
|
OnInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Artemis.Core.SkiaSharp;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
|
|
||||||
namespace Artemis.Core.Services
|
namespace Artemis.Core.Services
|
||||||
@ -50,6 +51,16 @@ namespace Artemis.Core.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void CloseRender();
|
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>
|
/// <summary>
|
||||||
/// Adds the given device provider to the <see cref="Surface" />
|
/// Adds the given device provider to the <see cref="Surface" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core.DeviceProviders;
|
using Artemis.Core.DeviceProviders;
|
||||||
using Artemis.Core.Services.Models;
|
using Artemis.Core.Services.Models;
|
||||||
|
using Artemis.Core.SkiaSharp;
|
||||||
using Artemis.Storage.Entities.Surface;
|
using Artemis.Storage.Entities.Surface;
|
||||||
using Artemis.Storage.Repositories.Interfaces;
|
using Artemis.Storage.Repositories.Interfaces;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
@ -51,7 +52,7 @@ namespace Artemis.Core.Services
|
|||||||
UpdateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value};
|
UpdateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value};
|
||||||
Surface.RegisterUpdateTrigger(UpdateTrigger);
|
Surface.RegisterUpdateTrigger(UpdateTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimerUpdateTrigger UpdateTrigger { get; }
|
public TimerUpdateTrigger UpdateTrigger { get; }
|
||||||
|
|
||||||
protected virtual void OnDeviceRemoved(DeviceEventArgs e)
|
protected virtual void OnDeviceRemoved(DeviceEventArgs e)
|
||||||
@ -118,9 +119,7 @@ namespace Artemis.Core.Services
|
|||||||
public IReadOnlyCollection<ArtemisDevice> Devices => _devices.AsReadOnly();
|
public IReadOnlyCollection<ArtemisDevice> Devices => _devices.AsReadOnly();
|
||||||
public IReadOnlyDictionary<Led, ArtemisLed> LedMap => new ReadOnlyDictionary<Led, ArtemisLed>(_ledMap);
|
public IReadOnlyDictionary<Led, ArtemisLed> LedMap => new ReadOnlyDictionary<Led, ArtemisLed>(_ledMap);
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public RGBSurface Surface { get; set; }
|
public RGBSurface Surface { get; set; }
|
||||||
|
|
||||||
public bool IsRenderPaused { get; set; }
|
public bool IsRenderPaused { get; set; }
|
||||||
public bool RenderOpen { get; private set; }
|
public bool RenderOpen { get; private set; }
|
||||||
|
|
||||||
@ -215,6 +214,8 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
#region Rendering
|
#region Rendering
|
||||||
|
|
||||||
|
private IManagedGraphicsContext? _newGraphicsContext;
|
||||||
|
|
||||||
public SKTexture OpenRender()
|
public SKTexture OpenRender()
|
||||||
{
|
{
|
||||||
if (RenderOpen)
|
if (RenderOpen)
|
||||||
@ -231,7 +232,7 @@ namespace Artemis.Core.Services
|
|||||||
{
|
{
|
||||||
if (!RenderOpen)
|
if (!RenderOpen)
|
||||||
throw new ArtemisCoreException("Render pipeline is already closed");
|
throw new ArtemisCoreException("Render pipeline is already closed");
|
||||||
|
|
||||||
RenderOpen = false;
|
RenderOpen = false;
|
||||||
_texture?.CopyPixelData();
|
_texture?.CopyPixelData();
|
||||||
}
|
}
|
||||||
@ -241,15 +242,38 @@ namespace Artemis.Core.Services
|
|||||||
if (RenderOpen)
|
if (RenderOpen)
|
||||||
throw new ArtemisCoreException("Cannot update the texture while rendering");
|
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;
|
float renderScale = (float) _renderScaleSetting.Value;
|
||||||
int width = Math.Max(1, MathF.Min(Surface.Boundary.Size.Width * renderScale, 4096).RoundToInt());
|
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());
|
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;
|
_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
|
#endregion
|
||||||
|
|||||||
16
src/Artemis.Core/SkiaSharp/IManagedGraphicsContext.cs
Normal file
16
src/Artemis.Core/SkiaSharp/IManagedGraphicsContext.cs
Normal file
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -68,12 +68,10 @@ namespace Artemis.UI
|
|||||||
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
|
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
|
||||||
|
|
||||||
// Create and bind the root view, this is a tray icon so don't show it with the window manager
|
// Create and bind the root view, this is a tray icon so don't show it with the window manager
|
||||||
Execute.OnUIThread(() =>
|
Execute.OnUIThreadSync(() =>
|
||||||
{
|
{
|
||||||
UIElement view = viewManager.CreateAndBindViewForModelIfNecessary(RootViewModel);
|
UIElement view = viewManager.CreateAndBindViewForModelIfNecessary(RootViewModel);
|
||||||
((TrayViewModel) RootViewModel).SetTaskbarIcon(view);
|
((TrayViewModel) RootViewModel).SetTaskbarIcon(view);
|
||||||
|
|
||||||
CreateGraphicsContext();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize the core async so the UI can show the progress
|
// Initialize the core async so the UI can show the progress
|
||||||
@ -96,6 +94,11 @@ namespace Artemis.UI
|
|||||||
registrationService.RegisterInputProvider();
|
registrationService.RegisterInputProvider();
|
||||||
registrationService.RegisterControllers();
|
registrationService.RegisterControllers();
|
||||||
|
|
||||||
|
Execute.OnUIThreadSync(() =>
|
||||||
|
{
|
||||||
|
registrationService.ApplyPreferredGraphicsContext();
|
||||||
|
});
|
||||||
|
|
||||||
// Initialize background services
|
// Initialize background services
|
||||||
Kernel.Get<IDeviceLayoutService>();
|
Kernel.Get<IDeviceLayoutService>();
|
||||||
}
|
}
|
||||||
@ -133,22 +136,6 @@ namespace Artemis.UI
|
|||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateGraphicsContext()
|
|
||||||
{
|
|
||||||
Win32VkContext vulkanContext = new();
|
|
||||||
GRVkBackendContext vulkanBackendContext = new()
|
|
||||||
{
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
Constants.SkiaGraphicsContext = GRContext.CreateVulkan(vulkanBackendContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleFatalException(Exception e, ILogger logger)
|
private void HandleFatalException(Exception e, ILogger logger)
|
||||||
{
|
{
|
||||||
logger.Fatal(e, "Fatal exception during initialization, shutting down.");
|
logger.Fatal(e, "Fatal exception during initialization, shutting down.");
|
||||||
|
|||||||
22
src/Artemis.UI/Exceptions/ArtemisGraphicsContextException.cs
Normal file
22
src/Artemis.UI/Exceptions/ArtemisGraphicsContextException.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Exceptions
|
||||||
|
{
|
||||||
|
public class ArtemisGraphicsContextException : Exception
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ArtemisGraphicsContextException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ArtemisGraphicsContextException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ArtemisGraphicsContextException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:dataTemplateSelectors="clr-namespace:Artemis.UI.DataTemplateSelectors"
|
xmlns:dataTemplateSelectors="clr-namespace:Artemis.UI.DataTemplateSelectors"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=System.Runtime"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:GeneralSettingsTabViewModel}">
|
d:DataContext="{d:DesignInstance local:GeneralSettingsTabViewModel}">
|
||||||
@ -307,6 +308,30 @@
|
|||||||
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">Rendering</TextBlock>
|
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">Rendering</TextBlock>
|
||||||
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
|
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
|
||||||
<StackPanel Margin="15">
|
<StackPanel Margin="15">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Grid.Column="0">
|
||||||
|
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Preferred render method</TextBlock>
|
||||||
|
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
|
||||||
|
Software-based rendering is done purely on the CPU while Vulkan uses GPU-acceleration
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||||
|
<ComboBox Width="80" SelectedItem="{Binding PreferredGraphicsContext}" >
|
||||||
|
<system:String>Software</system:String>
|
||||||
|
<system:String>Vulkan</system:String>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
|
|||||||
@ -3,15 +3,10 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection.Metadata;
|
|
||||||
using System.Security.Principal;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.LayerBrushes;
|
using Artemis.Core.LayerBrushes;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.Core.Services.Core;
|
|
||||||
using Artemis.UI.Properties;
|
|
||||||
using Artemis.UI.Screens.StartupWizard;
|
using Artemis.UI.Screens.StartupWizard;
|
||||||
using Artemis.UI.Services;
|
using Artemis.UI.Services;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
@ -30,6 +25,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
|
|||||||
private readonly IDialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
private readonly IKernel _kernel;
|
private readonly IKernel _kernel;
|
||||||
private readonly IMessageService _messageService;
|
private readonly IMessageService _messageService;
|
||||||
|
private readonly IRegistrationService _registrationService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
private readonly IUpdateService _updateService;
|
private readonly IUpdateService _updateService;
|
||||||
private readonly IWindowManager _windowManager;
|
private readonly IWindowManager _windowManager;
|
||||||
@ -45,7 +41,8 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
|
|||||||
ISettingsService settingsService,
|
ISettingsService settingsService,
|
||||||
IUpdateService updateService,
|
IUpdateService updateService,
|
||||||
IPluginManagementService pluginManagementService,
|
IPluginManagementService pluginManagementService,
|
||||||
IMessageService messageService)
|
IMessageService messageService,
|
||||||
|
IRegistrationService registrationService)
|
||||||
{
|
{
|
||||||
DisplayName = "GENERAL";
|
DisplayName = "GENERAL";
|
||||||
|
|
||||||
@ -56,6 +53,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
|
|||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
_updateService = updateService;
|
_updateService = updateService;
|
||||||
_messageService = messageService;
|
_messageService = messageService;
|
||||||
|
_registrationService = registrationService;
|
||||||
|
|
||||||
LogLevels = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(LogEventLevel)));
|
LogLevels = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(LogEventLevel)));
|
||||||
ColorSchemes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ApplicationColorScheme)));
|
ColorSchemes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ApplicationColorScheme)));
|
||||||
@ -209,6 +207,17 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string PreferredGraphicsContext
|
||||||
|
{
|
||||||
|
get => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan").Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan").Value = value;
|
||||||
|
_settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan").Save();
|
||||||
|
_registrationService.ApplyPreferredGraphicsContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public double RenderScale
|
public double RenderScale
|
||||||
{
|
{
|
||||||
get => _settingsService.GetSetting("Core.RenderScale", 0.5).Value;
|
get => _settingsService.GetSetting("Core.RenderScale", 0.5).Value;
|
||||||
@ -316,10 +325,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool taskCreated = false;
|
bool taskCreated = false;
|
||||||
if (!recreate)
|
if (!recreate) taskCreated = SettingsUtilities.IsAutoRunTaskCreated();
|
||||||
{
|
|
||||||
taskCreated = SettingsUtilities.IsAutoRunTaskCreated();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StartWithWindows && !taskCreated)
|
if (StartWithWindows && !taskCreated)
|
||||||
SettingsUtilities.CreateAutoRunTask(TimeSpan.FromSeconds(AutoRunDelay));
|
SettingsUtilities.CreateAutoRunTask(TimeSpan.FromSeconds(AutoRunDelay));
|
||||||
@ -335,7 +341,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public enum ApplicationColorScheme
|
public enum ApplicationColorScheme
|
||||||
{
|
{
|
||||||
Light,
|
Light,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Controllers;
|
using Artemis.UI.Controllers;
|
||||||
@ -8,6 +9,7 @@ using Artemis.UI.DefaultTypes.PropertyInput;
|
|||||||
using Artemis.UI.InputProviders;
|
using Artemis.UI.InputProviders;
|
||||||
using Artemis.UI.Ninject;
|
using Artemis.UI.Ninject;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Artemis.UI.SkiaSharp;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Artemis.UI.Services
|
namespace Artemis.UI.Services
|
||||||
@ -15,28 +17,37 @@ namespace Artemis.UI.Services
|
|||||||
public class RegistrationService : IRegistrationService
|
public class RegistrationService : IRegistrationService
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly ICoreService _coreService;
|
||||||
private readonly IDataModelUIService _dataModelUIService;
|
private readonly IDataModelUIService _dataModelUIService;
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly IInputService _inputService;
|
private readonly IInputService _inputService;
|
||||||
private readonly IWebServerService _webServerService;
|
private readonly IWebServerService _webServerService;
|
||||||
|
private readonly IRgbService _rgbService;
|
||||||
|
private readonly ISettingsService _settingsService;
|
||||||
private bool _registeredBuiltInDataModelDisplays;
|
private bool _registeredBuiltInDataModelDisplays;
|
||||||
private bool _registeredBuiltInDataModelInputs;
|
private bool _registeredBuiltInDataModelInputs;
|
||||||
private bool _registeredBuiltInPropertyEditors;
|
private bool _registeredBuiltInPropertyEditors;
|
||||||
|
|
||||||
public RegistrationService(ILogger logger,
|
public RegistrationService(ILogger logger,
|
||||||
|
ICoreService coreService,
|
||||||
IDataModelUIService dataModelUIService,
|
IDataModelUIService dataModelUIService,
|
||||||
IProfileEditorService profileEditorService,
|
IProfileEditorService profileEditorService,
|
||||||
IPluginManagementService pluginManagementService,
|
IPluginManagementService pluginManagementService,
|
||||||
IInputService inputService,
|
IInputService inputService,
|
||||||
IWebServerService webServerService)
|
IWebServerService webServerService,
|
||||||
|
IRgbService rgbService,
|
||||||
|
ISettingsService settingsService)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_coreService = coreService;
|
||||||
_dataModelUIService = dataModelUIService;
|
_dataModelUIService = dataModelUIService;
|
||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
_pluginManagementService = pluginManagementService;
|
_pluginManagementService = pluginManagementService;
|
||||||
_inputService = inputService;
|
_inputService = inputService;
|
||||||
_webServerService = webServerService;
|
_webServerService = webServerService;
|
||||||
|
_rgbService = rgbService;
|
||||||
|
_settingsService = settingsService;
|
||||||
|
|
||||||
LoadPluginModules();
|
LoadPluginModules();
|
||||||
pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling;
|
pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling;
|
||||||
@ -97,6 +108,39 @@ namespace Artemis.UI.Services
|
|||||||
_webServerService.AddController<RemoteController>();
|
_webServerService.AddController<RemoteController>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void ApplyPreferredGraphicsContext()
|
||||||
|
{
|
||||||
|
if (_coreService.StartupArguments.Contains("--force-software-render"))
|
||||||
|
{
|
||||||
|
_logger.Warning("Startup argument '--force-software-render' is applied, forcing software rendering.");
|
||||||
|
_rgbService.UpdateGraphicsContext(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginSetting<string> preferredGraphicsContext = _settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (preferredGraphicsContext.Value)
|
||||||
|
{
|
||||||
|
case "Software":
|
||||||
|
_rgbService.UpdateGraphicsContext(null);
|
||||||
|
break;
|
||||||
|
case "Vulkan":
|
||||||
|
_rgbService.UpdateGraphicsContext(new VulkanContext());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Warning(e, "Failed to apply preferred graphics context {preferred}", preferredGraphicsContext.Value);
|
||||||
|
_rgbService.UpdateGraphicsContext(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void PluginServiceOnPluginEnabling(object sender, PluginEventArgs e)
|
private void PluginServiceOnPluginEnabling(object sender, PluginEventArgs e)
|
||||||
{
|
{
|
||||||
e.Plugin.Kernel.Load(new[] {new PluginUIModule(e.Plugin)});
|
e.Plugin.Kernel.Load(new[] {new PluginUIModule(e.Plugin)});
|
||||||
@ -116,5 +160,6 @@ namespace Artemis.UI.Services
|
|||||||
void RegisterBuiltInPropertyEditors();
|
void RegisterBuiltInPropertyEditors();
|
||||||
void RegisterInputProvider();
|
void RegisterInputProvider();
|
||||||
void RegisterControllers();
|
void RegisterControllers();
|
||||||
|
void ApplyPreferredGraphicsContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,109 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Artemis.UI.SkiaSharp
|
|
||||||
{
|
|
||||||
internal class User32
|
|
||||||
{
|
|
||||||
private const string user32 = "user32.dll";
|
|
||||||
|
|
||||||
public const uint IDC_ARROW = 32512;
|
|
||||||
|
|
||||||
public const uint IDI_APPLICATION = 32512;
|
|
||||||
public const uint IDI_WINLOGO = 32517;
|
|
||||||
|
|
||||||
public const int SW_HIDE = 0;
|
|
||||||
|
|
||||||
public const uint CS_VREDRAW = 0x1;
|
|
||||||
public const uint CS_HREDRAW = 0x2;
|
|
||||||
public const uint CS_OWNDC = 0x20;
|
|
||||||
|
|
||||||
public const uint WS_EX_CLIENTEDGE = 0x00000200;
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
|
||||||
public static extern ushort RegisterClass(ref Win32Window.WNDCLASS lpWndClass);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
|
||||||
public static extern ushort UnregisterClass([MarshalAs(UnmanagedType.LPTStr)] string lpClassName, IntPtr hInstance);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
||||||
public static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
||||||
public static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi)]
|
|
||||||
public static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
|
||||||
public static extern IntPtr CreateWindowEx(uint dwExStyle, [MarshalAs(UnmanagedType.LPTStr)] string lpClassName, [MarshalAs(UnmanagedType.LPTStr)] string lpWindowName, WindowStyles dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);
|
|
||||||
|
|
||||||
public static IntPtr CreateWindow(string lpClassName, string lpWindowName, WindowStyles dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam)
|
|
||||||
{
|
|
||||||
return CreateWindowEx(0, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
||||||
public static extern IntPtr GetDC(IntPtr hWnd);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
public static extern bool DestroyWindow(IntPtr hWnd);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
public static extern bool IsWindow(IntPtr hWnd);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
||||||
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
public static extern bool AdjustWindowRectEx(ref RECT lpRect, WindowStyles dwStyle, bool bMenu, uint dwExStyle);
|
|
||||||
|
|
||||||
[DllImport(user32, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
public static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct RECT
|
|
||||||
{
|
|
||||||
public int left;
|
|
||||||
public int top;
|
|
||||||
public int right;
|
|
||||||
public int bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum WindowStyles : uint
|
|
||||||
{
|
|
||||||
WS_BORDER = 0x800000,
|
|
||||||
WS_CAPTION = 0xc00000,
|
|
||||||
WS_CHILD = 0x40000000,
|
|
||||||
WS_CLIPCHILDREN = 0x2000000,
|
|
||||||
WS_CLIPSIBLINGS = 0x4000000,
|
|
||||||
WS_DISABLED = 0x8000000,
|
|
||||||
WS_DLGFRAME = 0x400000,
|
|
||||||
WS_GROUP = 0x20000,
|
|
||||||
WS_HSCROLL = 0x100000,
|
|
||||||
WS_MAXIMIZE = 0x1000000,
|
|
||||||
WS_MAXIMIZEBOX = 0x10000,
|
|
||||||
WS_MINIMIZE = 0x20000000,
|
|
||||||
WS_MINIMIZEBOX = 0x20000,
|
|
||||||
WS_OVERLAPPED = 0x0,
|
|
||||||
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_SIZEFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
|
|
||||||
WS_POPUP = 0x80000000u,
|
|
||||||
WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
|
|
||||||
WS_SIZEFRAME = 0x40000,
|
|
||||||
WS_SYSMENU = 0x80000,
|
|
||||||
WS_TABSTOP = 0x10000,
|
|
||||||
WS_VISIBLE = 0x10000000,
|
|
||||||
WS_VSCROLL = 0x200000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Artemis.UI.SkiaSharp
|
namespace Artemis.UI.SkiaSharp.Vulkan
|
||||||
{
|
{
|
||||||
internal class Kernel32
|
internal class Kernel32
|
||||||
{
|
{
|
||||||
@ -6,7 +6,7 @@ using Instance = SharpVk.Instance;
|
|||||||
using PhysicalDevice = SharpVk.PhysicalDevice;
|
using PhysicalDevice = SharpVk.PhysicalDevice;
|
||||||
using Queue = SharpVk.Queue;
|
using Queue = SharpVk.Queue;
|
||||||
|
|
||||||
namespace Artemis.UI.SkiaSharp
|
namespace Artemis.UI.SkiaSharp.Vulkan
|
||||||
{
|
{
|
||||||
internal class VkContext : IDisposable
|
internal class VkContext : IDisposable
|
||||||
{
|
{
|
||||||
@ -4,7 +4,7 @@ using System.Windows.Forms;
|
|||||||
using SharpVk;
|
using SharpVk;
|
||||||
using SharpVk.Khronos;
|
using SharpVk.Khronos;
|
||||||
|
|
||||||
namespace Artemis.UI.SkiaSharp
|
namespace Artemis.UI.SkiaSharp.Vulkan
|
||||||
{
|
{
|
||||||
internal sealed class Win32VkContext : VkContext
|
internal sealed class Win32VkContext : VkContext
|
||||||
{
|
{
|
||||||
65
src/Artemis.UI/SkiaSharp/VulkanContext.cs
Normal file
65
src/Artemis.UI/SkiaSharp/VulkanContext.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.Core.SkiaSharp;
|
||||||
|
using Artemis.UI.Exceptions;
|
||||||
|
using Artemis.UI.SkiaSharp.Vulkan;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace Artemis.UI.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_vulkanBackendContext?.Dispose();
|
||||||
|
_vulkanContext?.Dispose();
|
||||||
|
GraphicsContext?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GRContext GraphicsContext { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,97 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Artemis.UI.SkiaSharp
|
|
||||||
{
|
|
||||||
internal class Win32Window : IDisposable
|
|
||||||
{
|
|
||||||
private ushort classRegistration;
|
|
||||||
|
|
||||||
public string WindowClassName { get; }
|
|
||||||
|
|
||||||
public IntPtr WindowHandle { get; private set; }
|
|
||||||
|
|
||||||
public IntPtr DeviceContextHandle { get; private set; }
|
|
||||||
|
|
||||||
public Win32Window(string className)
|
|
||||||
{
|
|
||||||
WindowClassName = className;
|
|
||||||
|
|
||||||
var wc = new WNDCLASS
|
|
||||||
{
|
|
||||||
cbClsExtra = 0,
|
|
||||||
cbWndExtra = 0,
|
|
||||||
hbrBackground = IntPtr.Zero,
|
|
||||||
hCursor = User32.LoadCursor(IntPtr.Zero, (int)User32.IDC_ARROW),
|
|
||||||
hIcon = User32.LoadIcon(IntPtr.Zero, (IntPtr)User32.IDI_APPLICATION),
|
|
||||||
hInstance = Kernel32.CurrentModuleHandle,
|
|
||||||
lpfnWndProc = (WNDPROC)User32.DefWindowProc,
|
|
||||||
lpszClassName = WindowClassName,
|
|
||||||
lpszMenuName = null,
|
|
||||||
style = User32.CS_HREDRAW | User32.CS_VREDRAW | User32.CS_OWNDC
|
|
||||||
};
|
|
||||||
|
|
||||||
classRegistration = User32.RegisterClass(ref wc);
|
|
||||||
if (classRegistration == 0)
|
|
||||||
throw new Exception($"Could not register window class: {className}");
|
|
||||||
|
|
||||||
WindowHandle = User32.CreateWindow(
|
|
||||||
WindowClassName,
|
|
||||||
$"The Invisible Man ({className})",
|
|
||||||
User32.WindowStyles.WS_OVERLAPPEDWINDOW,
|
|
||||||
0, 0,
|
|
||||||
1, 1,
|
|
||||||
IntPtr.Zero, IntPtr.Zero, Kernel32.CurrentModuleHandle, IntPtr.Zero);
|
|
||||||
if (WindowHandle == IntPtr.Zero)
|
|
||||||
throw new Exception($"Could not create window: {className}");
|
|
||||||
|
|
||||||
DeviceContextHandle = User32.GetDC(WindowHandle);
|
|
||||||
if (DeviceContextHandle == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
throw new Exception($"Could not get device context: {className}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (WindowHandle != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
if (DeviceContextHandle != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
User32.ReleaseDC(WindowHandle, DeviceContextHandle);
|
|
||||||
DeviceContextHandle = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
User32.DestroyWindow(WindowHandle);
|
|
||||||
WindowHandle = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (classRegistration != 0)
|
|
||||||
{
|
|
||||||
User32.UnregisterClass(WindowClassName, Kernel32.CurrentModuleHandle);
|
|
||||||
classRegistration = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public delegate IntPtr WNDPROC(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct WNDCLASS
|
|
||||||
{
|
|
||||||
public uint style;
|
|
||||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
|
||||||
public WNDPROC lpfnWndProc;
|
|
||||||
public int cbClsExtra;
|
|
||||||
public int cbWndExtra;
|
|
||||||
public IntPtr hInstance;
|
|
||||||
public IntPtr hIcon;
|
|
||||||
public IntPtr hCursor;
|
|
||||||
public IntPtr hbrBackground;
|
|
||||||
[MarshalAs(UnmanagedType.LPTStr)]
|
|
||||||
public string lpszMenuName;
|
|
||||||
[MarshalAs(UnmanagedType.LPTStr)]
|
|
||||||
public string lpszClassName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user