diff --git a/ScreenCapture.NET.X11/X11ScreenCapture.cs b/ScreenCapture.NET.X11/X11ScreenCapture.cs index 0531622..cf13cef 100644 --- a/ScreenCapture.NET.X11/X11ScreenCapture.cs +++ b/ScreenCapture.NET.X11/X11ScreenCapture.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using ScreenCapture.NET.Downscale; @@ -18,8 +17,11 @@ public sealed class X11ScreenCapture : AbstractScreenCapture private readonly object _captureLock = new(); private nint _display; - - private readonly Dictionary, ZoneTextures> _textures = new(); + private nint _drawable; + private nint _imageHandle; + private X11.XImage _image; + private int _size; + private unsafe ReadOnlySpan Data => new(_image.data, _size); #endregion @@ -43,19 +45,13 @@ public sealed class X11ScreenCapture : AbstractScreenCapture { lock (_captureLock) { - if (_display == 0) + if ((_display == 0) || (_imageHandle == 0)) { Restart(); return false; } - lock (CaptureZones) - lock (_textures) - foreach (CaptureZone captureZone in CaptureZones) - { - if (!_textures.TryGetValue(captureZone, out ZoneTextures? textures)) break; - textures.Update(); - } + X11.XGetSubImage(_display, _drawable, 0, 0, (uint)Display.Width, (uint)Display.Height, X11.ALL_PLANES, X11.ZPIXMAP, _imageHandle, 0, 0); return true; } @@ -63,33 +59,30 @@ public sealed class X11ScreenCapture : AbstractScreenCapture protected override void PerformCaptureZoneUpdate(CaptureZone captureZone, in Span buffer) { - lock (_textures) + using IDisposable @lock = captureZone.Lock(); { - using IDisposable @lock = captureZone.Lock(); - { - if (captureZone.DownscaleLevel == 0) - CopyZone(captureZone, buffer); - else - DownscaleZone(captureZone, buffer); - } + if (captureZone.DownscaleLevel == 0) + CopyZone(captureZone, buffer); + else + DownscaleZone(captureZone, buffer); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CopyZone(CaptureZone captureZone, in Span buffer) { - if (!_textures.TryGetValue(captureZone, out ZoneTextures? textures)) return; - - ReadOnlySpan source = MemoryMarshal.Cast(textures.Data); + ReadOnlySpan source = MemoryMarshal.Cast(Data); Span target = MemoryMarshal.Cast(buffer); + int offsetX = captureZone.X; + int offsetY = captureZone.Y; int width = captureZone.Width; int height = captureZone.Height; - int sourceStride = textures.Image.bytes_per_line / ColorBGRA.ColorFormat.BytesPerPixel; + int sourceStride = _image.bytes_per_line / captureZone.ColorFormat.BytesPerPixel; for (int y = 0; y < height; y++) { - int sourceOffset = y * sourceStride; + int sourceOffset = ((y + offsetY) * sourceStride) + offsetX; int targetOffset = y * width; source.Slice(sourceOffset, width).CopyTo(target.Slice(targetOffset, width)); } @@ -98,9 +91,7 @@ public sealed class X11ScreenCapture : AbstractScreenCapture [MethodImpl(MethodImplOptions.AggressiveInlining)] private void DownscaleZone(CaptureZone captureZone, in Span buffer) { - if (!_textures.TryGetValue(captureZone, out ZoneTextures? textures)) return; - - ReadOnlySpan source = textures.Data; + ReadOnlySpan source = Data; Span target = buffer; int blockSize = captureZone.DownscaleLevel switch @@ -116,17 +107,19 @@ public sealed class X11ScreenCapture : AbstractScreenCapture _ => (int)Math.Pow(2, captureZone.DownscaleLevel), }; + int offsetX = captureZone.X; + int offsetY = captureZone.Y; int width = captureZone.Width; int height = captureZone.Height; int stride = captureZone.Stride; int bpp = captureZone.ColorFormat.BytesPerPixel; - int sourceStride = textures.Image.bytes_per_line / ColorBGRA.ColorFormat.BytesPerPixel; + int sourceStride = _image.bytes_per_line / bpp; Span scaleBuffer = stackalloc byte[bpp]; for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) { - AverageByteSampler.Sample(new SamplerInfo(x * blockSize, y * blockSize, blockSize, blockSize, sourceStride, bpp, source), scaleBuffer); + AverageByteSampler.Sample(new SamplerInfo((x + offsetX) * blockSize, (y + offsetY) * blockSize, blockSize, blockSize, sourceStride, bpp, source), scaleBuffer); int targetOffset = (y * stride) + (x * bpp); @@ -138,57 +131,6 @@ public sealed class X11ScreenCapture : AbstractScreenCapture } } - /// - public override CaptureZone RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel = 0) - { - CaptureZone captureZone = base.RegisterCaptureZone(x, y, width, height, downscaleLevel); - - lock (_textures) - InitializeCaptureZone(captureZone); - - return captureZone; - } - - /// - public override bool UnregisterCaptureZone(CaptureZone captureZone) - { - if (!base.UnregisterCaptureZone(captureZone)) return false; - - lock (_textures) - { - if (_textures.TryGetValue(captureZone, out ZoneTextures? textures)) - { - textures.Dispose(); - _textures.Remove(captureZone); - - return true; - } - - return false; - } - } - - /// - public override void UpdateCaptureZone(CaptureZone captureZone, int? x = null, int? y = null, int? width = null, int? height = null, int? downscaleLevel = null) - { - base.UpdateCaptureZone(captureZone, x, y, width, height, downscaleLevel); - - if ((width != null) || (height != null)) - { - lock (_textures) - { - if (_textures.TryGetValue(captureZone, out ZoneTextures? textures)) - { - textures.Dispose(); - InitializeCaptureZone(captureZone); - } - } - } - } - - private void InitializeCaptureZone(in CaptureZone captureZone) - => _textures[captureZone] = new ZoneTextures(_display, captureZone.Display.Index, captureZone.X, captureZone.Y, captureZone.UnscaledWidth, captureZone.UnscaledHeight); - /// public override void Restart() { @@ -200,6 +142,14 @@ public sealed class X11ScreenCapture : AbstractScreenCapture try { _display = X11.XOpenDisplay(X11.DISPLAY_NAME); + + nint screen = X11.XScreenOfDisplay(_display, Display.Index); + _drawable = X11.XRootWindowOfScreen(screen); + _imageHandle = X11.XGetImage(_display, _drawable, 0, 0, (uint)Display.Width, (uint)Display.Height, X11.ALL_PLANES, X11.ZPIXMAP); + _image = Marshal.PtrToStructure(_imageHandle); + _size = _image.bytes_per_line * _image.height; + + if (_image.bits_per_pixel != (ColorBGRA.ColorFormat.BytesPerPixel * 8)) throw new NotSupportedException("The X-Server is configured to a not supported pixel-format. Needs to be 32 bit per pixel BGR."); } catch { @@ -214,87 +164,21 @@ public sealed class X11ScreenCapture : AbstractScreenCapture lock (_captureLock) { - try - { - foreach ((CaptureZone _, ZoneTextures textures) in _textures) - textures.Dispose(); - - DisposeDisplay(); - } + try { DisposeDisplay(); } catch { /**/ } } } private void DisposeDisplay() { - if (_display == 0) return; + if (_imageHandle != 0) + try { X11.XDestroyImage(_imageHandle); } catch { /**/ } - try { X11.XCloseDisplay(_display); } catch { /**/ } + _image = default; + + if (_display != 0) + try { X11.XCloseDisplay(_display); } catch { /**/ } } #endregion - - private sealed class ZoneTextures : IDisposable - { - #region Properties & Fields - - private readonly int _screenNumber; - private readonly int _x; - private readonly int _y; - private readonly uint _width; - private readonly uint _height; - private readonly int _size; - - private nint _display; - private nint _drawable; - public nint ImageHandle { get; private set; } - public X11.XImage Image { get; private set; } - public unsafe ReadOnlySpan Data => new(Image.data, _size); - - #endregion - - #region Constructors - - public ZoneTextures(nint display, int screenNumber, int x, int y, int width, int height) - { - this._screenNumber = screenNumber; - this._x = x; - this._y = y; - this._width = (uint)width; - this._height = (uint)height; - - _size = width * height * ColorBGRA.ColorFormat.BytesPerPixel; - Initialize(display); - } - - #endregion - - #region Methods - - public void Initialize(nint display) - { - Dispose(); - - _display = display; - - nint screen = X11.XScreenOfDisplay(_display, _screenNumber); - _drawable = X11.XRootWindowOfScreen(screen); - ImageHandle = X11.XGetImage(display, _drawable, _x, _y, _width, _height, X11.ALL_PLANES, X11.ZPIXMAP); - Image = Marshal.PtrToStructure(ImageHandle); - - if (Image.bits_per_pixel != (ColorBGRA.ColorFormat.BytesPerPixel * 8)) throw new NotSupportedException("The X-Server is configured to a not supported pixel-format. Needs to be 32 bit per pixel BGR."); - } - - public void Update() => X11.XGetSubImage(_display, _drawable, _x, _y, _width, _height, X11.ALL_PLANES, X11.ZPIXMAP, ImageHandle, 0, 0); - - public void Dispose() - { - if (ImageHandle != 0) - try { X11.XDestroyImage(ImageHandle); } catch { /**/ } - - Image = default; - } - - #endregion - } } \ No newline at end of file