diff --git a/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs b/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs new file mode 100644 index 0000000000..e92ad02c7a --- /dev/null +++ b/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs @@ -0,0 +1,27 @@ +using Avalonia.LinuxFramebuffer.Output; +using Avalonia.Media; +using JetBrains.Annotations; + +namespace Avalonia.LinuxFramebuffer +{ + public class DrmOutputOptions + { + /// + /// Scaling factor. + /// Default: 1.0 + /// + public double Scaling { get; set; } = 1.0; + + /// + /// If true an two cycle buffer swapping is processed at init. + /// Default: True + /// + public bool EnableInitialBufferSwapping { get; set; } = true; + + /// + /// Color for + /// Default: R0 G0 B0 A0 + /// + public Color InitialBufferSwappingColor { get; set; } = new Color(0, 0, 0, 0); + } +} diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs index 4add4c423b..a642766809 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs @@ -140,6 +140,8 @@ public static class LinuxFramebufferPlatformExtensions public static int StartLinuxDrm(this T builder, string[] args, string card = null, double scaling = 1) where T : AppBuilderBase, new() => StartLinuxDirect(builder, args, new DrmOutput(card) {Scaling = scaling}); + public static int StartLinuxDrm(this T builder, string[] args, string card = null, bool connectorsForceProbe = false, [CanBeNull] DrmOutputOptions options = null) + where T : AppBuilderBase, new() => StartLinuxDirect(builder, args, new DrmOutput(card, connectorsForceProbe, options)); public static int StartLinuxDirect(this T builder, string[] args, IOutputBackend backend) where T : AppBuilderBase, new() diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs index 9c476b1b63..04bc2c1f67 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs @@ -162,6 +162,8 @@ namespace Avalonia.LinuxFramebuffer.Output [DllImport(libdrm, SetLastError = true)] public static extern drmModeConnector* drmModeGetConnector(int fd, uint connector); [DllImport(libdrm, SetLastError = true)] + public static extern drmModeConnector* drmModeGetConnectorCurrent(int fd, uint connector); + [DllImport(libdrm, SetLastError = true)] public static extern void drmModeFreeConnector(drmModeConnector* res); [DllImport(libdrm, SetLastError = true)] diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmBindings.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmBindings.cs index de281245f1..070e1a95bc 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmBindings.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmBindings.cs @@ -84,7 +84,7 @@ namespace Avalonia.LinuxFramebuffer.Output { public List Connectors { get; }= new List(); internal Dictionary Encoders { get; } = new Dictionary(); - public DrmResources(int fd) + public DrmResources(int fd, bool connectorsForceProbe = false) { var res = drmModeGetResources(fd); if (res == null) @@ -107,7 +107,7 @@ namespace Avalonia.LinuxFramebuffer.Output for (var c = 0; c < res->count_connectors; c++) { - var conn = drmModeGetConnector(fd, res->connectors[c]); + var conn = connectorsForceProbe ? drmModeGetConnector(fd, res->connectors[c]) : drmModeGetConnectorCurrent(fd, res->connectors[c]); Connectors.Add(new DrmConnector(conn)); drmModeFreeConnector(conn); } @@ -168,7 +168,7 @@ namespace Avalonia.LinuxFramebuffer.Output } } - public DrmResources GetResources() => new DrmResources(Fd); + public DrmResources GetResources(bool connectorsForceProbe = false) => new DrmResources(Fd, connectorsForceProbe); public void Dispose() { close(Fd); diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs index 99c4b62716..ce210019c0 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs @@ -7,6 +7,7 @@ using Avalonia.OpenGL; using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Surfaces; using Avalonia.Platform.Interop; +using JetBrains.Annotations; using static Avalonia.LinuxFramebuffer.NativeUnsafeMethods; using static Avalonia.LinuxFramebuffer.Output.LibDrm; using static Avalonia.LinuxFramebuffer.Output.LibDrm.GbmColorFormats; @@ -15,20 +16,35 @@ namespace Avalonia.LinuxFramebuffer.Output { public unsafe class DrmOutput : IGlOutputBackend, IGlPlatformSurface { + private DrmOutputOptions _outputOptions = new(); private DrmCard _card; public PixelSize PixelSize => _mode.Resolution; - public double Scaling { get; set; } + + public double Scaling + { + get => _outputOptions.Scaling; + set => _outputOptions.Scaling = value; + } public IGlContext PrimaryContext => _deferredContext; private EglPlatformOpenGlInterface _platformGl; public IPlatformOpenGlInterface PlatformOpenGlInterface => _platformGl; - public DrmOutput(string path = null) + public DrmOutput(DrmCard card, DrmResources resources, DrmConnector connector, DrmModeInfo modeInfo, + DrmOutputOptions? options = null) { + if(options != null) + _outputOptions = options; + Init(card, resources, connector, modeInfo); + } + public DrmOutput(string path = null, bool connectorsForceProbe = false, [CanBeNull] DrmOutputOptions options = null) + { + if(options != null) + _outputOptions = options; + var card = new DrmCard(path); - var resources = card.GetResources(); - + var resources = card.GetResources(connectorsForceProbe); var connector = resources.Connectors.FirstOrDefault(x => x.Connection == DrmModeConnection.DRM_MODE_CONNECTED); @@ -142,9 +158,14 @@ namespace Avalonia.LinuxFramebuffer.Output _deferredContext = _platformGl.PrimaryEglContext; + var initialBufferSwappingColorR = _outputOptions.InitialBufferSwappingColor.R / 255.0f; + var initialBufferSwappingColorG = _outputOptions.InitialBufferSwappingColor.G / 255.0f; + var initialBufferSwappingColorB = _outputOptions.InitialBufferSwappingColor.B / 255.0f; + var initialBufferSwappingColorA = _outputOptions.InitialBufferSwappingColor.A / 255.0f; using (_deferredContext.MakeCurrent(_eglSurface)) { - _deferredContext.GlInterface.ClearColor(0, 0, 0, 0); + _deferredContext.GlInterface.ClearColor(initialBufferSwappingColorR, initialBufferSwappingColorG, + initialBufferSwappingColorB, initialBufferSwappingColorA); _deferredContext.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT); _eglSurface.SwapBuffers(); } @@ -162,13 +183,17 @@ namespace Avalonia.LinuxFramebuffer.Output _mode = mode; _currentBo = bo; - // Go trough two cycles of buffer swapping (there are render artifacts otherwise) - for(var c=0;c<2;c++) - using (CreateGlRenderTarget().BeginDraw()) - { - _deferredContext.GlInterface.ClearColor(0, 0, 0, 0); - _deferredContext.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT); - } + if (_outputOptions.EnableInitialBufferSwapping) + { + //Go trough two cycles of buffer swapping (there are render artifacts otherwise) + for(var c=0;c<2;c++) + using (CreateGlRenderTarget().BeginDraw()) + { + _deferredContext.GlInterface.ClearColor(initialBufferSwappingColorR, initialBufferSwappingColorG, + initialBufferSwappingColorB, initialBufferSwappingColorA); + _deferredContext.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT); + } + } }