diff --git a/OnnxStack.UI/App.xaml.cs b/OnnxStack.UI/App.xaml.cs index b28d2065..deb02714 100644 --- a/OnnxStack.UI/App.xaml.cs +++ b/OnnxStack.UI/App.xaml.cs @@ -41,7 +41,7 @@ public App() builder.Services.AddTransient(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); - + builder.Services.AddSingleton(); // Build App _applicationHost = builder.Build(); } diff --git a/OnnxStack.UI/Dialogs/UpdateModelDialog.xaml b/OnnxStack.UI/Dialogs/UpdateModelDialog.xaml index 793dfda4..1ba41ecf 100644 --- a/OnnxStack.UI/Dialogs/UpdateModelDialog.xaml +++ b/OnnxStack.UI/Dialogs/UpdateModelDialog.xaml @@ -7,6 +7,8 @@ xmlns:userControls="clr-namespace:OnnxStack.UI.UserControls" mc:Ignorable="d" Name="UI" + MinWidth="1200" + MaxWidth="1200" Icon="/Images/Icon.png" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterOwner" @@ -27,16 +29,16 @@ - + - + - + @@ -53,40 +55,35 @@ - - - - - + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -148,22 +145,20 @@ - + - - + + + - - - - - - - + diff --git a/OnnxStack.UI/Dialogs/UpdateUpscaleModelDialog.xaml b/OnnxStack.UI/Dialogs/UpdateUpscaleModelDialog.xaml index 66103af6..9db538e0 100644 --- a/OnnxStack.UI/Dialogs/UpdateUpscaleModelDialog.xaml +++ b/OnnxStack.UI/Dialogs/UpdateUpscaleModelDialog.xaml @@ -74,22 +74,20 @@ - - - + + + + - - - - - - - + diff --git a/OnnxStack.UI/Models/DeviceInfo.cs b/OnnxStack.UI/Models/DeviceInfo.cs new file mode 100644 index 00000000..b1a0515c --- /dev/null +++ b/OnnxStack.UI/Models/DeviceInfo.cs @@ -0,0 +1,16 @@ +namespace OnnxStack.UI.Models +{ + public class DeviceInfo + { + public DeviceInfo(string name, int deviceId, int vram) + { + Name = name; + DeviceId = deviceId; + VRAM = vram; + } + + public string Name { get; set; } + public int DeviceId { get; set; } + public int VRAM { get; set; } + } +} diff --git a/OnnxStack.UI/Models/OnnxStackUIConfig.cs b/OnnxStack.UI/Models/OnnxStackUIConfig.cs index 49fac02a..f297a278 100644 --- a/OnnxStack.UI/Models/OnnxStackUIConfig.cs +++ b/OnnxStack.UI/Models/OnnxStackUIConfig.cs @@ -14,28 +14,27 @@ public class OnnxStackUIConfig : IConfigSection public int DefaultIntraOpNumThreads { get; set; } public ExecutionMode DefaultExecutionMode { get; set; } public ExecutionProvider DefaultExecutionProvider { get; set; } - public IEnumerable SupportedExecutionProviders => GetSupportedExecutionProviders(); + public ExecutionProvider SupportedExecutionProvider => GetSupportedExecutionProvider(); public ObservableCollection UpscaleModelSets { get; set; } = new ObservableCollection(); public ObservableCollection StableDiffusionModelSets { get; set; } = new ObservableCollection(); - public IEnumerable GetSupportedExecutionProviders() + public ExecutionProvider GetSupportedExecutionProvider() { #if DEBUG_CUDA || RELEASE_CUDA - yield return ExecutionProvider.Cuda; + return ExecutionProvider.Cuda; #elif DEBUG_TENSORRT || RELEASE_TENSORRT - yield return ExecutionProvider.TensorRT; + return ExecutionProvider.TensorRT; #else - yield return ExecutionProvider.DirectML; + return ExecutionProvider.DirectML; #endif - yield return ExecutionProvider.Cpu; } public void Initialize() { - DefaultExecutionProvider = SupportedExecutionProviders.Contains(DefaultExecutionProvider) + DefaultExecutionProvider = DefaultExecutionProvider == SupportedExecutionProvider || DefaultExecutionProvider == ExecutionProvider.Cpu ? DefaultExecutionProvider - : SupportedExecutionProviders.First(); + : SupportedExecutionProvider; } } diff --git a/OnnxStack.UI/OnnxStack.Adapter.dll b/OnnxStack.UI/OnnxStack.Adapter.dll new file mode 100644 index 00000000..ed0e899f Binary files /dev/null and b/OnnxStack.UI/OnnxStack.Adapter.dll differ diff --git a/OnnxStack.UI/OnnxStack.UI.csproj b/OnnxStack.UI/OnnxStack.UI.csproj index 1998c6d9..7e43cd12 100644 --- a/OnnxStack.UI/OnnxStack.UI.csproj +++ b/OnnxStack.UI/OnnxStack.UI.csproj @@ -10,6 +10,7 @@ x64 Debug;Release;Debug-Cuda;Debug-TensorRT;Release-Cuda;Release-TensorRT x64 + True @@ -39,7 +40,6 @@ true PreserveNewest - @@ -69,4 +69,10 @@ + + + Always + + + diff --git a/OnnxStack.UI/Services/DeviceService.cs b/OnnxStack.UI/Services/DeviceService.cs new file mode 100644 index 00000000..7ed606e2 --- /dev/null +++ b/OnnxStack.UI/Services/DeviceService.cs @@ -0,0 +1,113 @@ +using Microsoft.Extensions.Logging; +using OnnxStack.UI.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace OnnxStack.UI.Services +{ + public class DeviceService : IDeviceService + { + private readonly ILogger _logger; + private IReadOnlyList _devices; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + public DeviceService(ILogger logger) + { + _logger = logger; + _devices = GetDevices(); + } + + /// + /// Gets the devices. + /// + public IReadOnlyList Devices => _devices; + + + /// + /// Gets the devices. + /// + /// + private IReadOnlyList GetDevices() + { + _logger.LogInformation("[GetDevices] - Query Devices..."); + var devices = new List { new DeviceInfo("CPU", 0, 0) }; + + try + { + var adapters = new AdapterInfo[10]; + AdapterInterop.GetAdapters(adapters); + devices.AddRange(adapters + .Where(x => x.DedicatedVideoMemory > 0) + .Select(GetDeviceInfo) + .ToList()); + devices.ForEach(x => _logger.LogInformation($"[GetDevices] - Found Device: {x.Name}, DeviceId: {x.DeviceId}")); + } + catch (Exception ex) + { + devices.Add(new DeviceInfo("GPU0", 0, 0)); + devices.Add(new DeviceInfo("GPU1", 1, 0)); + _logger.LogError($"[GetDevices] - Failed to query devices, {ex.Message}"); + } + + _logger.LogInformation($"[GetDevices] - Query devices complete, Devices Found: {devices.Count}"); + return devices; + } + + + /// + /// Gets the device information. + /// + /// The adapter. + /// + private static DeviceInfo GetDeviceInfo(AdapterInfo adapter) + { + string description; + unsafe + { + description = new string(adapter.Description); + } + var deviceId = (int)adapter.Id; + var vram = (int)(adapter.DedicatedVideoMemory / 1024 / 1024); + return new DeviceInfo(description, deviceId, vram); + } + } + + public static partial class AdapterInterop + { + [LibraryImport("OnnxStack.Adapter.dll")] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + public static partial int GetAdapter([MarshalAs(UnmanagedType.Bool)] bool preferHighPerformance); + + [LibraryImport("OnnxStack.Adapter.dll")] + [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] + public static partial void GetAdapters(AdapterInfo[] adapterArray); + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct AdapterInfo + { + public uint Id; + public uint VendorId; + public uint DeviceId; + public uint SubSysId; + public uint Revision; + public ulong DedicatedVideoMemory; + public ulong DedicatedSystemMemory; + public ulong SharedSystemMemory; + public Luid AdapterLuid; + public fixed char Description[128]; + } + + [StructLayout(LayoutKind.Sequential)] + public struct Luid + { + public uint LowPart; + public int HighPart; + } +} diff --git a/OnnxStack.UI/Services/IDeviceService.cs b/OnnxStack.UI/Services/IDeviceService.cs new file mode 100644 index 00000000..aa2928c7 --- /dev/null +++ b/OnnxStack.UI/Services/IDeviceService.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using OnnxStack.UI.Models; + +namespace OnnxStack.UI.Services +{ + public interface IDeviceService + { + IReadOnlyList Devices { get; } + } +} \ No newline at end of file diff --git a/OnnxStack.UI/UserControls/DevicePickerControl.xaml b/OnnxStack.UI/UserControls/DevicePickerControl.xaml new file mode 100644 index 00000000..425f9c7a --- /dev/null +++ b/OnnxStack.UI/UserControls/DevicePickerControl.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + diff --git a/OnnxStack.UI/UserControls/DevicePickerControl.xaml.cs b/OnnxStack.UI/UserControls/DevicePickerControl.xaml.cs new file mode 100644 index 00000000..ec3d48a9 --- /dev/null +++ b/OnnxStack.UI/UserControls/DevicePickerControl.xaml.cs @@ -0,0 +1,139 @@ +using OnnxStack.Core.Config; +using OnnxStack.UI.Models; +using OnnxStack.UI.Services; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Windows; +using System.Windows.Controls; + +namespace OnnxStack.UI.UserControls +{ + /// + /// Interaction logic for DevicePickerControl.xaml + /// + public partial class DevicePickerControl : UserControl, INotifyPropertyChanged + { + private readonly IDeviceService _deviceService; + private DeviceInfo _selectedDevice; + + /// + /// Initializes a new instance of the class. + /// + public DevicePickerControl() + { + if (!DesignerProperties.GetIsInDesignMode(this)) + _deviceService = App.GetService(); + + InitializeComponent(); + } + + public static readonly DependencyProperty UISettingsProperty = + DependencyProperty.Register("UISettings", typeof(OnnxStackUIConfig), typeof(DevicePickerControl), new PropertyMetadata((c, e) => + { + if (c is DevicePickerControl control) + control.OnSettingsChanged(); + })); + + public static readonly DependencyProperty ExecutionProviderProperty = + DependencyProperty.Register("ExecutionProvider", typeof(ExecutionProvider?), typeof(DevicePickerControl), new PropertyMetadata((c, e) => + { + if (c is DevicePickerControl control) + control.OnSettingsChanged(); + })); + + public static readonly DependencyProperty DeviceIdProperty = + DependencyProperty.Register("DeviceId", typeof(int?), typeof(DevicePickerControl), new PropertyMetadata((c, e) => + { + if (c is DevicePickerControl control) + control.OnSettingsChanged(); + })); + + + /// + /// Gets or sets the UI settings. + /// + public OnnxStackUIConfig UISettings + { + get { return (OnnxStackUIConfig)GetValue(UISettingsProperty); } + set { SetValue(UISettingsProperty, value); } + } + + /// + /// Gets or sets the ExecutionProvider. + /// + public ExecutionProvider? ExecutionProvider + { + get { return (ExecutionProvider?)GetValue(ExecutionProviderProperty); } + set { SetValue(ExecutionProviderProperty, value); } + } + + /// + /// Gets or sets the DeviceId. + /// + public int? DeviceId + { + get { return (int?)GetValue(DeviceIdProperty); } + set { SetValue(DeviceIdProperty, value); } + } + + /// + /// Gets the devices. + /// + public IReadOnlyList Devices => _deviceService.Devices; + + + /// + /// Gets or sets the selected device. + /// + public DeviceInfo SelectedDevice + { + get { return _selectedDevice; } + set { _selectedDevice = value; OnSelectedDeviceChanged(); } + } + + + /// + /// Called when UISettings changed. + /// + private void OnSettingsChanged() + { + SelectedDevice = ExecutionProvider == Core.Config.ExecutionProvider.Cpu + ? Devices.FirstOrDefault() + : Devices.FirstOrDefault(x => x.Name != "CPU" && x.DeviceId == DeviceId); + } + + + /// + /// Called when SelectedDevice changed. + /// + private void OnSelectedDeviceChanged() + { + if (_selectedDevice is null) + return; + + if (_selectedDevice.Name == "CPU") + { + DeviceId = 0; + ExecutionProvider = Core.Config.ExecutionProvider.Cpu; + } + else + { + DeviceId = _selectedDevice.DeviceId; + ExecutionProvider = UISettings.SupportedExecutionProvider; + } + + NotifyPropertyChanged(nameof(SelectedDevice)); + } + + #region INotifyPropertyChanged + public event PropertyChangedEventHandler PropertyChanged; + + public void NotifyPropertyChanged([CallerMemberName] string property = "") + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); + } + #endregion + } +} diff --git a/OnnxStack.UI/Views/SettingsView.xaml b/OnnxStack.UI/Views/SettingsView.xaml index 0136eb5b..5e63be16 100644 --- a/OnnxStack.UI/Views/SettingsView.xaml +++ b/OnnxStack.UI/Views/SettingsView.xaml @@ -37,35 +37,40 @@ - - - - - - - - - + - + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + +