diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs
index d5d5f211e9..6ea067d8b7 100644
--- a/src/Android/Avalonia.Android/AndroidPlatform.cs
+++ b/src/Android/Avalonia.Android/AndroidPlatform.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using Avalonia.Controls;
using Avalonia.Android;
using Avalonia.Android.Platform;
@@ -22,6 +24,36 @@ namespace Avalonia
.UseSkia();
}
}
+
+ public enum AndroidRenderingMode
+ {
+ ///
+ /// Avalonia is rendered into a framebuffer.
+ ///
+ Software = 1,
+
+ ///
+ /// Enables android EGL rendering.
+ ///
+ Egl = 2
+ }
+
+ public sealed class AndroidPlatformOptions
+ {
+ ///
+ /// Gets or sets Avalonia rendering modes with fallbacks.
+ /// The first element in the array has the highest priority.
+ /// The default value is: , .
+ ///
+ ///
+ /// If application should work on as wide range of devices as possible, at least add as a fallback value.
+ ///
+ /// Thrown if no values were matched.
+ public IReadOnlyList RenderingMode { get; set; } = new[]
+ {
+ AndroidRenderingMode.Egl, AndroidRenderingMode.Software
+ };
+ }
}
namespace Avalonia.Android
@@ -47,18 +79,39 @@ namespace Avalonia.Android
.Bind().ToConstant(new ChoreographerTimer())
.Bind().ToSingleton();
- if (Options.UseGpu)
+ var graphics = InitializeGraphics(Options);
+ if (graphics is not null)
{
- EglPlatformGraphics.TryInitialize();
+ AvaloniaLocator.CurrentMutable.Bind().ToConstant(graphics);
}
-
- Compositor = new Compositor(AvaloniaLocator.Current.GetService());
+
+ Compositor = new Compositor(graphics);
}
- }
+
+ private static IPlatformGraphics InitializeGraphics(AndroidPlatformOptions opts)
+ {
+ if (opts.RenderingMode is null || !opts.RenderingMode.Any())
+ {
+ throw new InvalidOperationException($"{nameof(AndroidPlatformOptions)}.{nameof(AndroidPlatformOptions.RenderingMode)} must not be empty or null");
+ }
- public sealed class AndroidPlatformOptions
- {
- public bool UseDeferredRendering { get; set; } = false;
- public bool UseGpu { get; set; } = true;
+ foreach (var renderingMode in opts.RenderingMode)
+ {
+ if (renderingMode == AndroidRenderingMode.Software)
+ {
+ return null;
+ }
+
+ if (renderingMode == AndroidRenderingMode.Egl)
+ {
+ if (EglPlatformGraphics.TryCreate() is { } egl)
+ {
+ return egl;
+ }
+ }
+ }
+
+ throw new InvalidOperationException($"{nameof(AndroidPlatformOptions)}.{nameof(AndroidPlatformOptions.RenderingMode)} has a value of \"{string.Join(", ", opts.RenderingMode)}\", but no options were applied.");
+ }
}
}
diff --git a/src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs b/src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs
index 07e304febe..cf81999095 100644
--- a/src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs
+++ b/src/Avalonia.OpenGL/Egl/EglPlatformGraphics.cs
@@ -16,13 +16,6 @@ namespace Avalonia.OpenGL.Egl
_display = display;
}
- public static void TryInitialize()
- {
- var feature = TryCreate();
- if (feature != null)
- AvaloniaLocator.CurrentMutable.Bind().ToConstant(feature);
- }
-
public static EglPlatformGraphics? TryCreate() => TryCreate(() => new EglDisplay(new EglDisplayCreationOptions
{
Egl = new EglInterface(),
diff --git a/src/Avalonia.X11/Glx/GlxPlatformFeature.cs b/src/Avalonia.X11/Glx/GlxPlatformFeature.cs
index 06766e0963..58336522c1 100644
--- a/src/Avalonia.X11/Glx/GlxPlatformFeature.cs
+++ b/src/Avalonia.X11/Glx/GlxPlatformFeature.cs
@@ -15,18 +15,6 @@ namespace Avalonia.X11.Glx
IPlatformGraphicsContext IPlatformGraphics.CreateContext() => Display.CreateContext();
public IPlatformGraphicsContext GetSharedContext() => throw new NotSupportedException();
-
- public static bool TryInitialize(X11Info x11, IList glProfiles)
- {
- var feature = TryCreate(x11, glProfiles);
- if (feature != null)
- {
- AvaloniaLocator.CurrentMutable.Bind().ToConstant(feature);
- return true;
- }
-
- return false;
- }
public static GlxPlatformGraphics TryCreate(X11Info x11, IList glProfiles)
{
diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs
index a880e4ba1a..7324481aaa 100644
--- a/src/Avalonia.X11/X11Platform.cs
+++ b/src/Avalonia.X11/X11Platform.cs
@@ -93,17 +93,13 @@ namespace Avalonia.X11
XI2 = xi2;
}
- if (options.UseGpu)
+ var graphics = InitializeGraphics(options, Info);
+ if (graphics is not null)
{
- if (options.UseEGL)
- EglPlatformGraphics.TryInitialize();
- else
- GlxPlatformGraphics.TryInitialize(Info, Options.GlProfiles);
+ AvaloniaLocator.CurrentMutable.Bind().ToConstant(graphics);
}
- var gl = AvaloniaLocator.Current.GetService();
-
- Compositor = new Compositor(gl);
+ Compositor = new Compositor(graphics);
}
public IntPtr DeferredDisplay { get; set; }
@@ -185,25 +181,81 @@ namespace Avalonia.X11
return false;
}
+
+ private static IPlatformGraphics InitializeGraphics(X11PlatformOptions opts, X11Info info)
+ {
+ if (opts.RenderingMode is null || !opts.RenderingMode.Any())
+ {
+ throw new InvalidOperationException($"{nameof(X11PlatformOptions)}.{nameof(X11PlatformOptions.RenderingMode)} must not be empty or null");
+ }
+
+ foreach (var renderingMode in opts.RenderingMode)
+ {
+ if (renderingMode == X11RenderingMode.Software)
+ {
+ return null;
+ }
+
+ if (renderingMode == X11RenderingMode.Glx)
+ {
+ if (GlxPlatformGraphics.TryCreate(info, opts.GlProfiles) is { } glx)
+ {
+ return glx;
+ }
+ }
+
+ if (renderingMode == X11RenderingMode.Egl)
+ {
+ if (EglPlatformGraphics.TryCreate() is { } egl)
+ {
+ return egl;
+ }
+ }
+ }
+
+ throw new InvalidOperationException($"{nameof(X11PlatformOptions)}.{nameof(X11PlatformOptions.RenderingMode)} has a value of \"{string.Join(", ", opts.RenderingMode)}\", but no options were applied.");
+ }
}
}
namespace Avalonia
{
+ public enum X11RenderingMode
+ {
+ ///
+ /// Avalonia is rendered into a framebuffer.
+ ///
+ Software = 1,
+
+ ///
+ /// Enables Glx rendering.
+ ///
+ Glx = 2,
+
+ ///
+ /// Enables native Linux EGL rendering.
+ ///
+ Egl = 3
+ }
+
///
/// Platform-specific options which apply to Linux.
///
public class X11PlatformOptions
{
///
- /// Enables native Linux EGL when set to true. The default value is false.
+ /// Gets or sets Avalonia rendering modes with fallbacks.
+ /// The first element in the array has the highest priority.
+ /// The default value is: , .
///
- public bool UseEGL { get; set; }
-
- ///
- /// Determines whether to use GPU for rendering in your project. The default value is true.
- ///
- public bool UseGpu { get; set; } = true;
+ ///
+ /// If application should work on as wide range of devices as possible, at least add as a fallback value.
+ ///
+ /// Thrown if no values were matched.
+ public IReadOnlyList RenderingMode { get; set; } = new[]
+ {
+ X11RenderingMode.Glx, X11RenderingMode.Software
+ };
///
/// Embeds popups to the window when set to true. The default value is false.
diff --git a/src/Windows/Avalonia.Win32/Win32PlatformOptions.cs b/src/Windows/Avalonia.Win32/Win32PlatformOptions.cs
index 9eeb36b7d1..f4765a558f 100644
--- a/src/Windows/Avalonia.Win32/Win32PlatformOptions.cs
+++ b/src/Windows/Avalonia.Win32/Win32PlatformOptions.cs
@@ -19,7 +19,7 @@ public enum Win32RenderingMode
///
/// Avalonia would try to use native Widows OpenGL with GPU rendering.
///
- Wgl
+ Wgl = 3
}
public enum Win32CompositionMode