Browse Source

Try to get the XShmCompletionEvent without DeferredDisplayEvents

pull/17118/head
lindexi 2 years ago
parent
commit
8b775e3e7b
  1. 2
      src/Avalonia.X11/X11Platform.cs
  2. 15
      src/Avalonia.X11/X11Window.cs
  3. 70
      src/Avalonia.X11/XShmExtensions/X11ShmImage.cs

2
src/Avalonia.X11/X11Platform.cs

@ -370,6 +370,8 @@ namespace Avalonia
/// </summary> /// </summary>
public bool? UseRetainedFramebuffer { get; set; } public bool? UseRetainedFramebuffer { get; set; }
public bool? UseXShmFramebuffer { get; set; }
public X11PlatformOptions() public X11PlatformOptions()
{ {
try try

15
src/Avalonia.X11/X11Window.cs

@ -26,6 +26,7 @@ using Avalonia.Input.Platform;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.Dialogs; using Avalonia.Dialogs;
using Avalonia.Platform.Storage.FileIO; using Avalonia.Platform.Storage.FileIO;
using Avalonia.X11.XShmExtensions;
// ReSharper disable IdentifierTypo // ReSharper disable IdentifierTypo
// ReSharper disable StringLiteralTypo // ReSharper disable StringLiteralTypo
@ -195,6 +196,13 @@ namespace Avalonia.X11
new X11FramebufferSurface(_x11.DeferredDisplay, _renderHandle, new X11FramebufferSurface(_x11.DeferredDisplay, _renderHandle,
depth, _platform.Options.UseRetainedFramebuffer ?? false) depth, _platform.Options.UseRetainedFramebuffer ?? false)
}; };
if (_platform.Options.UseXShmFramebuffer is true)
{
var x11ShmFramebufferSurface = new X11ShmFramebufferSurface(this, _x11.DeferredDisplay, _handle, _renderHandle);
_x11ShmFramebufferSurface = x11ShmFramebufferSurface;
surfaces.Insert(0, x11ShmFramebufferSurface);
}
if (egl != null) if (egl != null)
surfaces.Insert(0, surfaces.Insert(0,
@ -611,6 +619,12 @@ namespace Avalonia.X11
return; return;
HandleKeyEvent(ref ev); HandleKeyEvent(ref ev);
} }
else if (ev.type == XEventName.XShmCompletionEvent)
{
// Because the XShmCompletionEvent only occurs when the XShmPutImage is called, and the XShmPutImage only be called when use X11ShmFramebufferSurface, so we can safely assume that the _x11ShmFramebufferSurface is not null.
Debug.Assert(_x11ShmFramebufferSurface!=null, "If application can receive the XShmCompletionEvent, that the _x11ShmFramebufferSurface must not be null.");
_x11ShmFramebufferSurface?.OnXShmCompletionEvent(ref ev);
}
} }
private Thickness? GetFrameExtents() private Thickness? GetFrameExtents()
@ -798,6 +812,7 @@ namespace Avalonia.X11
new PixelSize(MaxWindowDimension, MaxWindowDimension)); new PixelSize(MaxWindowDimension, MaxWindowDimension));
private double _scaling = 1; private double _scaling = 1;
private X11ShmFramebufferSurface? _x11ShmFramebufferSurface;
private void ScheduleInput(RawInputEventArgs args, ref XEvent xev) private void ScheduleInput(RawInputEventArgs args, ref XEvent xev)
{ {

70
src/Avalonia.X11/XShmExtensions/X11ShmImage.cs

@ -9,16 +9,51 @@ using Avalonia.Platform;
namespace Avalonia.X11.XShmExtensions; namespace Avalonia.X11.XShmExtensions;
class X11ShmFramebufferContext
{
public X11ShmFramebufferContext(X11Window x11Window, IntPtr display, IntPtr windowHandle, IntPtr renderHandle)
{
X11Window = x11Window;
Display = display;
WindowHandle = windowHandle;
RenderHandle = renderHandle;
}
public X11Window X11Window { get; }
public IntPtr Display { get; }
public IntPtr WindowHandle { get; }
public IntPtr RenderHandle { get; }
}
internal class X11ShmFramebufferSurface : IFramebufferPlatformSurface internal class X11ShmFramebufferSurface : IFramebufferPlatformSurface
{ {
public X11ShmFramebufferSurface(X11Window x11Window, IntPtr display, IntPtr windowHandle, IntPtr renderHandle)
{
_context = new X11ShmFramebufferContext(x11Window, display, windowHandle, renderHandle);
}
private readonly X11ShmFramebufferContext _context;
public IFramebufferRenderTarget CreateFramebufferRenderTarget() public IFramebufferRenderTarget CreateFramebufferRenderTarget()
{ {
return new X11ShmImageSwapchain(); return new X11ShmImageSwapchain(_context);
}
public void OnXShmCompletionEvent(ref XEvent ev)
{
} }
} }
internal class X11ShmImage internal class X11ShmImage
{ {
/// <summary>
/// Returns false if we haven't got a completion event since the last Present, can call ProcessPendingEvents here
/// </summary>
public bool IsReady { get; }
} }
internal class X11ShmImageManager internal class X11ShmImageManager
@ -26,20 +61,47 @@ internal class X11ShmImageManager
} }
class DeferredDisplayEvents //class DeferredDisplayEvents
{ //{
} //}
internal class X11ShmImageSwapchain : IFramebufferRenderTarget internal class X11ShmImageSwapchain : IFramebufferRenderTarget
{ {
public X11ShmImageSwapchain(X11ShmFramebufferContext context)
{
_context = context;
}
private readonly X11ShmFramebufferContext _context;
private Queue<X11ShmImage> _availableQueue = new();
private Queue<X11ShmImage> _presentationQueue = new();
private PixelSize? _lastSize;
public void Dispose() public void Dispose()
{ {
} }
private void DrainPresentationQueue()
{
while (_presentationQueue.Count > 0 && _presentationQueue.Peek().IsReady)
{
_availableQueue.Enqueue(_presentationQueue.Dequeue());
}
}
public ILockedFramebuffer Lock() public ILockedFramebuffer Lock()
{ {
/*
1) gets the current window geometry, if it doesn't match the lastSize disposes images and clears queues
2) calls DrainPresentationQueue();
3) if there is an image in _availableQueue - use this image
4) else if there are no images in _availableQueue and presentationQueue.Count < swapchainSize - create new image
5) else synchronously wait for the first image from _presentationQueue and use it
6) return a framebuffer associated with chosen image
*/
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }

Loading…
Cancel
Save