mirror of
https://github.com/DarthAffe/ScreenCapture.NET.git
synced 2025-12-12 13:28:35 +00:00
Changed X11 capture to only use a single fullscreen texture
This commit is contained in:
parent
07a175e552
commit
a1a43ddcfc
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using ScreenCapture.NET.Downscale;
|
using ScreenCapture.NET.Downscale;
|
||||||
@ -18,8 +17,11 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
|
|||||||
private readonly object _captureLock = new();
|
private readonly object _captureLock = new();
|
||||||
|
|
||||||
private nint _display;
|
private nint _display;
|
||||||
|
private nint _drawable;
|
||||||
private readonly Dictionary<CaptureZone<ColorBGRA>, ZoneTextures> _textures = new();
|
private nint _imageHandle;
|
||||||
|
private X11.XImage _image;
|
||||||
|
private int _size;
|
||||||
|
private unsafe ReadOnlySpan<byte> Data => new(_image.data, _size);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -43,19 +45,13 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
|
|||||||
{
|
{
|
||||||
lock (_captureLock)
|
lock (_captureLock)
|
||||||
{
|
{
|
||||||
if (_display == 0)
|
if ((_display == 0) || (_imageHandle == 0))
|
||||||
{
|
{
|
||||||
Restart();
|
Restart();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (CaptureZones)
|
X11.XGetSubImage(_display, _drawable, 0, 0, (uint)Display.Width, (uint)Display.Height, X11.ALL_PLANES, X11.ZPIXMAP, _imageHandle, 0, 0);
|
||||||
lock (_textures)
|
|
||||||
foreach (CaptureZone<ColorBGRA> captureZone in CaptureZones)
|
|
||||||
{
|
|
||||||
if (!_textures.TryGetValue(captureZone, out ZoneTextures? textures)) break;
|
|
||||||
textures.Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -63,33 +59,30 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
|
|||||||
|
|
||||||
protected override void PerformCaptureZoneUpdate(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
|
protected override void PerformCaptureZoneUpdate(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
|
||||||
{
|
{
|
||||||
lock (_textures)
|
using IDisposable @lock = captureZone.Lock();
|
||||||
{
|
{
|
||||||
using IDisposable @lock = captureZone.Lock();
|
if (captureZone.DownscaleLevel == 0)
|
||||||
{
|
CopyZone(captureZone, buffer);
|
||||||
if (captureZone.DownscaleLevel == 0)
|
else
|
||||||
CopyZone(captureZone, buffer);
|
DownscaleZone(captureZone, buffer);
|
||||||
else
|
|
||||||
DownscaleZone(captureZone, buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void CopyZone(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
|
private void CopyZone(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
|
||||||
{
|
{
|
||||||
if (!_textures.TryGetValue(captureZone, out ZoneTextures? textures)) return;
|
ReadOnlySpan<ColorBGRA> source = MemoryMarshal.Cast<byte, ColorBGRA>(Data);
|
||||||
|
|
||||||
ReadOnlySpan<ColorBGRA> source = MemoryMarshal.Cast<byte, ColorBGRA>(textures.Data);
|
|
||||||
Span<ColorBGRA> target = MemoryMarshal.Cast<byte, ColorBGRA>(buffer);
|
Span<ColorBGRA> target = MemoryMarshal.Cast<byte, ColorBGRA>(buffer);
|
||||||
|
|
||||||
|
int offsetX = captureZone.X;
|
||||||
|
int offsetY = captureZone.Y;
|
||||||
int width = captureZone.Width;
|
int width = captureZone.Width;
|
||||||
int height = captureZone.Height;
|
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++)
|
for (int y = 0; y < height; y++)
|
||||||
{
|
{
|
||||||
int sourceOffset = y * sourceStride;
|
int sourceOffset = ((y + offsetY) * sourceStride) + offsetX;
|
||||||
int targetOffset = y * width;
|
int targetOffset = y * width;
|
||||||
source.Slice(sourceOffset, width).CopyTo(target.Slice(targetOffset, width));
|
source.Slice(sourceOffset, width).CopyTo(target.Slice(targetOffset, width));
|
||||||
}
|
}
|
||||||
@ -98,9 +91,7 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void DownscaleZone(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
|
private void DownscaleZone(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
|
||||||
{
|
{
|
||||||
if (!_textures.TryGetValue(captureZone, out ZoneTextures? textures)) return;
|
ReadOnlySpan<byte> source = Data;
|
||||||
|
|
||||||
ReadOnlySpan<byte> source = textures.Data;
|
|
||||||
Span<byte> target = buffer;
|
Span<byte> target = buffer;
|
||||||
|
|
||||||
int blockSize = captureZone.DownscaleLevel switch
|
int blockSize = captureZone.DownscaleLevel switch
|
||||||
@ -116,17 +107,19 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
|
|||||||
_ => (int)Math.Pow(2, captureZone.DownscaleLevel),
|
_ => (int)Math.Pow(2, captureZone.DownscaleLevel),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int offsetX = captureZone.X;
|
||||||
|
int offsetY = captureZone.Y;
|
||||||
int width = captureZone.Width;
|
int width = captureZone.Width;
|
||||||
int height = captureZone.Height;
|
int height = captureZone.Height;
|
||||||
int stride = captureZone.Stride;
|
int stride = captureZone.Stride;
|
||||||
int bpp = captureZone.ColorFormat.BytesPerPixel;
|
int bpp = captureZone.ColorFormat.BytesPerPixel;
|
||||||
int sourceStride = textures.Image.bytes_per_line / ColorBGRA.ColorFormat.BytesPerPixel;
|
int sourceStride = _image.bytes_per_line / bpp;
|
||||||
|
|
||||||
Span<byte> scaleBuffer = stackalloc byte[bpp];
|
Span<byte> scaleBuffer = stackalloc byte[bpp];
|
||||||
for (int y = 0; y < height; y++)
|
for (int y = 0; y < height; y++)
|
||||||
for (int x = 0; x < width; x++)
|
for (int x = 0; x < width; x++)
|
||||||
{
|
{
|
||||||
AverageByteSampler.Sample(new SamplerInfo<byte>(x * blockSize, y * blockSize, blockSize, blockSize, sourceStride, bpp, source), scaleBuffer);
|
AverageByteSampler.Sample(new SamplerInfo<byte>((x + offsetX) * blockSize, (y + offsetY) * blockSize, blockSize, blockSize, sourceStride, bpp, source), scaleBuffer);
|
||||||
|
|
||||||
int targetOffset = (y * stride) + (x * bpp);
|
int targetOffset = (y * stride) + (x * bpp);
|
||||||
|
|
||||||
@ -138,57 +131,6 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override CaptureZone<ColorBGRA> RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel = 0)
|
|
||||||
{
|
|
||||||
CaptureZone<ColorBGRA> captureZone = base.RegisterCaptureZone(x, y, width, height, downscaleLevel);
|
|
||||||
|
|
||||||
lock (_textures)
|
|
||||||
InitializeCaptureZone(captureZone);
|
|
||||||
|
|
||||||
return captureZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool UnregisterCaptureZone(CaptureZone<ColorBGRA> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void UpdateCaptureZone(CaptureZone<ColorBGRA> 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<ColorBGRA> captureZone)
|
|
||||||
=> _textures[captureZone] = new ZoneTextures(_display, captureZone.Display.Index, captureZone.X, captureZone.Y, captureZone.UnscaledWidth, captureZone.UnscaledHeight);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Restart()
|
public override void Restart()
|
||||||
{
|
{
|
||||||
@ -200,6 +142,14 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_display = X11.XOpenDisplay(X11.DISPLAY_NAME);
|
_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<X11.XImage>(_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
|
catch
|
||||||
{
|
{
|
||||||
@ -214,87 +164,21 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
|
|||||||
|
|
||||||
lock (_captureLock)
|
lock (_captureLock)
|
||||||
{
|
{
|
||||||
try
|
try { DisposeDisplay(); }
|
||||||
{
|
|
||||||
foreach ((CaptureZone<ColorBGRA> _, ZoneTextures textures) in _textures)
|
|
||||||
textures.Dispose();
|
|
||||||
|
|
||||||
DisposeDisplay();
|
|
||||||
}
|
|
||||||
catch { /**/ }
|
catch { /**/ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeDisplay()
|
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
|
#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<byte> 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<X11.XImage>(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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user