فهرست منبع

Added preferred render api setting

Krzysztof Krysiński 2 هفته پیش
والد
کامیت
239b5663e9

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit 539a77bffc3ec75ae99d101434280c176fea80df
+Subproject commit f165926f94cc08ab774fd1f86de75d90a95ea146

+ 7 - 3
src/PixiEditor.Desktop/Program.cs

@@ -3,6 +3,7 @@ using Avalonia;
 using Avalonia.Logging;
 using Drawie.Interop.Avalonia;
 using Drawie.Interop.VulkanAvalonia;
+using PixiEditor.Helpers;
 
 namespace PixiEditor.Desktop;
 
@@ -17,16 +18,18 @@ public class Program
 
     // Avalonia configuration, don't remove; also used by visual designer.
     public static AppBuilder BuildAvaloniaApp()
-        => AppBuilder.Configure<App>()
+    {
+        bool openGlPreferred = string.Equals(RenderApiPreferenceManager.TryReadRenderApiPreference(), "opengl", StringComparison.OrdinalIgnoreCase);
+        return AppBuilder.Configure<App>()
             .UsePlatformDetect()
             .With(new Win32PlatformOptions()
             {
-                RenderingMode = new Win32RenderingMode[] { Win32RenderingMode.Vulkan, Win32RenderingMode.Wgl },
+                RenderingMode = openGlPreferred ? [ Win32RenderingMode.Wgl, Win32RenderingMode.Vulkan] : [ Win32RenderingMode.Vulkan, Win32RenderingMode.Wgl],
                 OverlayPopups = true,
             })
             .With(new X11PlatformOptions()
             {
-                RenderingMode = new X11RenderingMode[] { X11RenderingMode.Vulkan, X11RenderingMode.Glx },
+                RenderingMode = openGlPreferred ? [ X11RenderingMode.Glx, X11RenderingMode.Vulkan] : [ X11RenderingMode.Vulkan, X11RenderingMode.Glx],
                 OverlayPopups = true,
             })
             .With(new SkiaOptions()
@@ -38,4 +41,5 @@ public class Program
             .LogToTrace(LogEventLevel.Verbose, "Vulkan")
 #endif
             .LogToTrace();
+    }
 }

+ 5 - 0
src/PixiEditor.Linux/LinuxOperatingSystem.cs

@@ -43,6 +43,11 @@ public sealed class LinuxOperatingSystem : IOperatingSystem
         return true;
     }
 
+    public string[] GetAvailableRenderers()
+    {
+        return ["Vulkan", "OpenGL"];
+    }
+
     public void HandleActivatedWithFile(FileActivatedEventArgs fileActivatedEventArgs)
     {
         // TODO: Check if this is executed on Linux at all

+ 5 - 0
src/PixiEditor.MacOs/MacOperatingSystem.cs

@@ -39,4 +39,9 @@ public sealed class MacOperatingSystem : IOperatingSystem
     {
         return true;
     }
+
+    public string[] GetAvailableRenderers()
+    {
+        return ["OpenGL"];
+    }
 }

+ 2 - 0
src/PixiEditor.OperatingSystem/IOperatingSystem.cs

@@ -36,5 +36,7 @@ public interface IOperatingSystem
 
     public bool HandleNewInstance(Dispatcher? dispatcher, Action<string, bool> openInExistingAction,
         IApplicationLifetime lifetime);
+
+    public string[] GetAvailableRenderers();
 }
 

+ 5 - 0
src/PixiEditor.Windows/WindowsOperatingSystem.cs

@@ -92,6 +92,11 @@ public sealed class WindowsOperatingSystem : IOperatingSystem
         return false;
     }
 
+    public string[] GetAvailableRenderers()
+    {
+        return ["Vulkan", "OpenGL"];
+    }
+
     public void HandleActivatedWithFile(FileActivatedEventArgs fileActivatedEventArgs) { }
 
     public void HandleActivatedWithUri(ProtocolActivatedEventArgs openUriEventArgs) { }

+ 5 - 1
src/PixiEditor/Data/Localization/Languages/en.json

@@ -1123,5 +1123,9 @@
   "NORMALIZE_COORDINATES": "Normalize Coordinates",
   "TRANSFORMED_POSITION": "Transformed Position",
   "ACCOUNT_PROVIDER_NOT_AVAILABLE": "This build of PixiEditor does not support accounts. Use the official build from pixieditor.net to manage your account.",
-  "STEAM_OFFLINE": "Cannot validate the account. Steam is offline. Make sure Steam client is running and you are logged in."
+  "STEAM_OFFLINE": "Cannot validate the account. Steam is offline. Make sure Steam client is running and you are logged in.",
+  "ERROR_GPU_RESOURCES_CREATION": "Failed to create resources: Try updating your GPU drivers or try setting different rendering api in settings. \nError: '{0}'",
+  "ERROR_SAVING_PREFERENCES_DESC": "Failed to save preferences with error: '{0}'. Please check if you have write permissions to the PixiEditor data folder.",
+  "ERROR_SAVING_PREFERENCES": "Failed to save preferences",
+  "PREFERRED_RENDERER": "Preferred Render Api"
 }

+ 41 - 0
src/PixiEditor/Helpers/RenderApiPreferenceManager.cs

@@ -0,0 +1,41 @@
+namespace PixiEditor.Helpers;
+
+public static class RenderApiPreferenceManager
+{
+    public static string? FirstReadApiPreference { get; } = TryReadRenderApiPreference() ?? null;
+    public static string? TryReadRenderApiPreference()
+    {
+        try
+        {
+            using var stream =
+                new FileStream(
+                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+                        "PixiEditor",
+                        "render_api.config"), FileMode.Open, FileAccess.Read, FileShare.Read);
+            using var reader = new StreamReader(stream);
+            string? renderApi = reader.ReadLine();
+            if (string.IsNullOrEmpty(renderApi))
+            {
+                return null;
+            }
+
+            return renderApi;
+        }
+        catch (Exception)
+        {
+            return null;
+        }
+    }
+
+    public static void UpdateRenderApiPreference(string renderApi)
+    {
+        using var stream =
+            new FileStream(
+                Path.Combine(
+                    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+                    "PixiEditor",
+                    "render_api.config"), FileMode.Create, FileAccess.Write, FileShare.None);
+        using var writer = new StreamWriter(stream);
+        writer.WriteLine(renderApi);
+    }
+}

+ 14 - 2
src/PixiEditor/Models/Preferences/PreferencesSettings.cs

@@ -2,6 +2,9 @@
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 using PixiEditor.Extensions.CommonApi.UserPreferences;
+using PixiEditor.Helpers;
+using PixiEditor.Models.Dialogs;
+using PixiEditor.UI.Common.Localization;
 
 namespace PixiEditor.Models.Preferences;
 
@@ -89,8 +92,17 @@ internal class PreferencesSettings : IPreferences
             Init();
         }
 
-        File.WriteAllText(PathToRoamingUserPreferences, JsonConvert.SerializeObject(Preferences));
-        File.WriteAllText(PathToLocalPreferences, JsonConvert.SerializeObject(LocalPreferences));
+        try
+        {
+            File.WriteAllText(PathToRoamingUserPreferences, JsonConvert.SerializeObject(Preferences));
+            File.WriteAllText(PathToLocalPreferences, JsonConvert.SerializeObject(LocalPreferences));
+        }
+        catch (Exception ex)
+        {
+            NoticeDialog.Show(
+                new LocalizedString("ERROR_SAVING_PREFERENCES_DESC", ex.Message),
+                "ERROR_SAVING_PREFERENCES");
+        }
     }
 
     public Dictionary<string, List<Action<string, object>>> Callbacks { get; set; } = new Dictionary<string, List<Action<string, object>>>();

+ 57 - 3
src/PixiEditor/ViewModels/UserPreferences/Settings/GeneralSettings.cs

@@ -1,26 +1,40 @@
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
+using Drawie.Backend.Core.Bridge;
 using PixiEditor.Extensions.CommonApi.UserPreferences;
+using PixiEditor.Helpers;
+using PixiEditor.Models.Dialogs;
+using PixiEditor.Models.IO;
+using PixiEditor.OperatingSystem;
 using PixiEditor.UI.Common.Localization;
 
 namespace PixiEditor.ViewModels.UserPreferences.Settings;
 
 internal class GeneralSettings : SettingsGroup
 {
+    private string? selectedRenderApi = RenderApiPreferenceManager.TryReadRenderApiPreference();
+
+    private List<string>? availableRenderApis = IOperatingSystem.Current?.GetAvailableRenderers()?.ToList() ??
+                                                new List<string>();
+
     private LanguageData? selectedLanguage = ILocalizationProvider.Current?.SelectedLanguage;
+
     private List<LanguageData>? availableLanguages = ILocalizationProvider.Current?.LocalizationData.Languages
         .OrderByDescending(x => x == ILocalizationProvider.Current.FollowSystem)
-        .ThenByDescending(x => CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == x.Code || CultureInfo.InstalledUICulture.TwoLetterISOLanguageName == x.Code)
+        .ThenByDescending(x =>
+            CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == x.Code ||
+            CultureInfo.InstalledUICulture.TwoLetterISOLanguageName == x.Code)
         .ThenBy(x => x.Name).ToList();
 
     private bool isDebugModeEnabled = GetPreference(nameof(IsDebugModeEnabled), false);
+
     public bool IsDebugModeEnabled
     {
         get => isDebugModeEnabled;
         set => RaiseAndUpdatePreference(ref isDebugModeEnabled, value);
     }
-    
+
     public List<LanguageData>? AvailableLanguages
     {
         get => availableLanguages;
@@ -40,10 +54,50 @@ internal class GeneralSettings : SettingsGroup
         }
     }
 
-    private bool isAnalyticsEnabled = GetPreference(PreferencesConstants.AnalyticsEnabled, PreferencesConstants.AnalyticsEnabledDefault);
+    private bool isAnalyticsEnabled =
+        GetPreference(PreferencesConstants.AnalyticsEnabled, PreferencesConstants.AnalyticsEnabledDefault);
+
     public bool AnalyticsEnabled
     {
         get => isAnalyticsEnabled;
         set => RaiseAndUpdatePreference(ref isAnalyticsEnabled, value);
     }
+
+    public List<string> AvailableRenderApis
+    {
+        get
+        {
+            if (availableRenderApis == null || availableRenderApis.Count == 0)
+            {
+                availableRenderApis = new List<string>(IOperatingSystem.Current?.GetAvailableRenderers() ?? []);
+            }
+
+            return availableRenderApis;
+        }
+    }
+
+    public string SelectedRenderApi
+    {
+        get => selectedRenderApi ?? AvailableRenderApis.FirstOrDefault() ?? string.Empty;
+        set
+        {
+            if (SetProperty(ref selectedRenderApi, value))
+            {
+                try
+                {
+                    RenderApiPreferenceManager.UpdateRenderApiPreference(value);
+                    OnPropertyChanged(nameof(RenderApiChangePending));
+                }
+                catch (Exception ex)
+                {
+                    NoticeDialog.Show(
+                        new LocalizedString("ERROR_SAVING_PREFERENCES_DESC", ex.Message),
+                        "ERROR_SAVING_PREFERENCES");
+                }
+            }
+        }
+    }
+
+    public bool RenderApiChangePending =>
+        selectedRenderApi != RenderApiPreferenceManager.FirstReadApiPreference;
 }

+ 21 - 1
src/PixiEditor/Views/Rendering/Scene.cs

@@ -1,5 +1,6 @@
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
+using System.Globalization;
 using Avalonia;
 using Avalonia.Animation;
 using Avalonia.Input;
@@ -741,11 +742,30 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
     protected (bool success, string info) InitializeGraphicsResources(Compositor targetCompositor,
         CompositionDrawingSurface compositionDrawingSurface, ICompositionGpuInterop interop)
     {
-        resources = IDrawieInteropContext.Current.CreateResources(compositionDrawingSurface, interop);
+        try
+        {
+            resources = IDrawieInteropContext.Current.CreateResources(compositionDrawingSurface, interop);
+        }
+        catch (Exception e)
+        {
+            return (false, new LocalizedString("ERROR_GPU_RESOURCES_CREATION", e.Message));
+        }
 
         return (true, string.Empty);
     }
 
+    public override void Render(DrawingContext context)
+    {
+        if (!string.IsNullOrEmpty(info))
+        {
+            Point center = new Point(Bounds.Width / 2, Bounds.Height / 2);
+            context.DrawText(
+                new FormattedText(info, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Typeface.Default, 12,
+                    Brushes.White),
+                center);
+        }
+    }
+
     protected async Task FreeGraphicsResources()
     {
         renderTexture?.Dispose();

+ 34 - 10
src/PixiEditor/Views/Windows/Settings/SettingsWindow.axaml

@@ -192,6 +192,30 @@
                                       IsChecked="{Binding SettingsSubViewModel.Tools.EnableSharedToolbar}"
                                       ui:Translator.Key="ENABLE_SHARED_TOOLBAR" />
 
+                            <TextBlock ui:Translator.Key="Rendering" Classes="h5" />
+
+                            <Label Target="primaryToolsetComboBox" ui:Translator.Key="PREFERRED_RENDERER"
+                                   VerticalAlignment="Center" />
+
+                            <StackPanel Orientation="Horizontal" Spacing="5">
+                                <ComboBox Classes="leftOffset" Width="200" HorizontalAlignment="Left"
+                                          ItemsSource="{Binding SettingsSubViewModel.General.AvailableRenderApis}"
+                                          SelectedItem="{Binding SettingsSubViewModel.General.SelectedRenderApi, Mode=TwoWay}">
+                                    <ComboBox.ItemTemplate>
+                                        <DataTemplate>
+                                            <TextBlock ui:Translator.Key="{Binding}" />
+                                        </DataTemplate>
+                                    </ComboBox.ItemTemplate>
+                                </ComboBox>
+                                <Button Command="{cmds:Command Name=PixiEditor.Restart}"
+                                        Background="{DynamicResource ThemeAccentBrush}"
+                                        IsVisible="{Binding SettingsSubViewModel.General.RenderApiChangePending}"
+                                        d:Content="Restart to apply changes"
+                                        ui:Translator.Key="RESTART"
+                                        HorizontalAlignment="Left"
+                                        VerticalAlignment="Center" />
+                            </StackPanel>
+
                             <TextBlock ui:Translator.Key="DEBUG" Classes="h5" />
                             <CheckBox Classes="leftOffset"
                                       IsChecked="{Binding SettingsSubViewModel.General.IsDebugModeEnabled}"
@@ -322,12 +346,12 @@
                                               ItemsSource="{Binding SettingsSubViewModel.Update.UpdateChannels}"
                                               SelectedValue="{Binding SettingsSubViewModel.Update.UpdateChannelName}" />
                                     <TextBlock Cursor="Help"
-                                           Classes="pixi-icon"
-                                           Text="{DynamicResource icon-help}"
-                                           VerticalAlignment="Center"
-                                           ToolTip.ShowDelay="0"
-                                           IsVisible="{Binding !ShowUpdateTab}"
-                                           ui:Translator.TooltipKey="UPDATE_CHANNEL_HELP_TOOLTIP" />
+                                               Classes="pixi-icon"
+                                               Text="{DynamicResource icon-help}"
+                                               VerticalAlignment="Center"
+                                               ToolTip.ShowDelay="0"
+                                               IsVisible="{Binding !ShowUpdateTab}"
+                                               ui:Translator.TooltipKey="UPDATE_CHANNEL_HELP_TOOLTIP" />
                                     <!-- ToolTipService.InitialShowDelay="0"-->
                                 </StackPanel>
                             </StackPanel>
@@ -373,12 +397,12 @@
                             <StackPanel Spacing="5" Orientation="Horizontal" Classes="leftOffset">
                                 <Label Content="X" />
                                 <controls:SizeInput MinSize="0.5" Decimals="1"
-                                                 Size="{Binding SettingsSubViewModel.Scene.CustomBackgroundScaleX, Mode=TwoWay}"
-                                                 HorizontalAlignment="Left" />
+                                                    Size="{Binding SettingsSubViewModel.Scene.CustomBackgroundScaleX, Mode=TwoWay}"
+                                                    HorizontalAlignment="Left" />
                                 <Label Content="Y" />
                                 <controls:SizeInput MinSize="0.5" Decimals="1"
-                                                 Size="{Binding SettingsSubViewModel.Scene.CustomBackgroundScaleY, Mode=TwoWay}"
-                                                 HorizontalAlignment="Left" />
+                                                    Size="{Binding SettingsSubViewModel.Scene.CustomBackgroundScaleY, Mode=TwoWay}"
+                                                    HorizontalAlignment="Left" />
                             </StackPanel>
 
                             <StackPanel Orientation="Horizontal" Spacing="5">