Skip to content

Commit a1a43dd

Browse files
committed
Changed X11 capture to only use a single fullscreen texture
1 parent 07a175e commit a1a43dd

File tree

1 file changed

+37
-153
lines changed

1 file changed

+37
-153
lines changed
Lines changed: 37 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.Runtime.CompilerServices;
43
using System.Runtime.InteropServices;
54
using ScreenCapture.NET.Downscale;
@@ -18,8 +17,11 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
1817
private readonly object _captureLock = new();
1918

2019
private nint _display;
21-
22-
private readonly Dictionary<CaptureZone<ColorBGRA>, ZoneTextures> _textures = new();
20+
private nint _drawable;
21+
private nint _imageHandle;
22+
private X11.XImage _image;
23+
private int _size;
24+
private unsafe ReadOnlySpan<byte> Data => new(_image.data, _size);
2325

2426
#endregion
2527

@@ -43,53 +45,44 @@ protected override bool PerformScreenCapture()
4345
{
4446
lock (_captureLock)
4547
{
46-
if (_display == 0)
48+
if ((_display == 0) || (_imageHandle == 0))
4749
{
4850
Restart();
4951
return false;
5052
}
5153

52-
lock (CaptureZones)
53-
lock (_textures)
54-
foreach (CaptureZone<ColorBGRA> captureZone in CaptureZones)
55-
{
56-
if (!_textures.TryGetValue(captureZone, out ZoneTextures? textures)) break;
57-
textures.Update();
58-
}
54+
X11.XGetSubImage(_display, _drawable, 0, 0, (uint)Display.Width, (uint)Display.Height, X11.ALL_PLANES, X11.ZPIXMAP, _imageHandle, 0, 0);
5955

6056
return true;
6157
}
6258
}
6359

6460
protected override void PerformCaptureZoneUpdate(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
6561
{
66-
lock (_textures)
62+
using IDisposable @lock = captureZone.Lock();
6763
{
68-
using IDisposable @lock = captureZone.Lock();
69-
{
70-
if (captureZone.DownscaleLevel == 0)
71-
CopyZone(captureZone, buffer);
72-
else
73-
DownscaleZone(captureZone, buffer);
74-
}
64+
if (captureZone.DownscaleLevel == 0)
65+
CopyZone(captureZone, buffer);
66+
else
67+
DownscaleZone(captureZone, buffer);
7568
}
7669
}
7770

7871
[MethodImpl(MethodImplOptions.AggressiveInlining)]
7972
private void CopyZone(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
8073
{
81-
if (!_textures.TryGetValue(captureZone, out ZoneTextures? textures)) return;
82-
83-
ReadOnlySpan<ColorBGRA> source = MemoryMarshal.Cast<byte, ColorBGRA>(textures.Data);
74+
ReadOnlySpan<ColorBGRA> source = MemoryMarshal.Cast<byte, ColorBGRA>(Data);
8475
Span<ColorBGRA> target = MemoryMarshal.Cast<byte, ColorBGRA>(buffer);
8576

77+
int offsetX = captureZone.X;
78+
int offsetY = captureZone.Y;
8679
int width = captureZone.Width;
8780
int height = captureZone.Height;
88-
int sourceStride = textures.Image.bytes_per_line / ColorBGRA.ColorFormat.BytesPerPixel;
81+
int sourceStride = _image.bytes_per_line / captureZone.ColorFormat.BytesPerPixel;
8982

9083
for (int y = 0; y < height; y++)
9184
{
92-
int sourceOffset = y * sourceStride;
85+
int sourceOffset = ((y + offsetY) * sourceStride) + offsetX;
9386
int targetOffset = y * width;
9487
source.Slice(sourceOffset, width).CopyTo(target.Slice(targetOffset, width));
9588
}
@@ -98,9 +91,7 @@ private void CopyZone(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
9891
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9992
private void DownscaleZone(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
10093
{
101-
if (!_textures.TryGetValue(captureZone, out ZoneTextures? textures)) return;
102-
103-
ReadOnlySpan<byte> source = textures.Data;
94+
ReadOnlySpan<byte> source = Data;
10495
Span<byte> target = buffer;
10596

10697
int blockSize = captureZone.DownscaleLevel switch
@@ -116,17 +107,19 @@ private void DownscaleZone(CaptureZone<ColorBGRA> captureZone, in Span<byte> buf
116107
_ => (int)Math.Pow(2, captureZone.DownscaleLevel),
117108
};
118109

110+
int offsetX = captureZone.X;
111+
int offsetY = captureZone.Y;
119112
int width = captureZone.Width;
120113
int height = captureZone.Height;
121114
int stride = captureZone.Stride;
122115
int bpp = captureZone.ColorFormat.BytesPerPixel;
123-
int sourceStride = textures.Image.bytes_per_line / ColorBGRA.ColorFormat.BytesPerPixel;
116+
int sourceStride = _image.bytes_per_line / bpp;
124117

125118
Span<byte> scaleBuffer = stackalloc byte[bpp];
126119
for (int y = 0; y < height; y++)
127120
for (int x = 0; x < width; x++)
128121
{
129-
AverageByteSampler.Sample(new SamplerInfo<byte>(x * blockSize, y * blockSize, blockSize, blockSize, sourceStride, bpp, source), scaleBuffer);
122+
AverageByteSampler.Sample(new SamplerInfo<byte>((x + offsetX) * blockSize, (y + offsetY) * blockSize, blockSize, blockSize, sourceStride, bpp, source), scaleBuffer);
130123

131124
int targetOffset = (y * stride) + (x * bpp);
132125

@@ -138,57 +131,6 @@ private void DownscaleZone(CaptureZone<ColorBGRA> captureZone, in Span<byte> buf
138131
}
139132
}
140133

141-
/// <inheritdoc />
142-
public override CaptureZone<ColorBGRA> RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel = 0)
143-
{
144-
CaptureZone<ColorBGRA> captureZone = base.RegisterCaptureZone(x, y, width, height, downscaleLevel);
145-
146-
lock (_textures)
147-
InitializeCaptureZone(captureZone);
148-
149-
return captureZone;
150-
}
151-
152-
/// <inheritdoc />
153-
public override bool UnregisterCaptureZone(CaptureZone<ColorBGRA> captureZone)
154-
{
155-
if (!base.UnregisterCaptureZone(captureZone)) return false;
156-
157-
lock (_textures)
158-
{
159-
if (_textures.TryGetValue(captureZone, out ZoneTextures? textures))
160-
{
161-
textures.Dispose();
162-
_textures.Remove(captureZone);
163-
164-
return true;
165-
}
166-
167-
return false;
168-
}
169-
}
170-
171-
/// <inheritdoc />
172-
public override void UpdateCaptureZone(CaptureZone<ColorBGRA> captureZone, int? x = null, int? y = null, int? width = null, int? height = null, int? downscaleLevel = null)
173-
{
174-
base.UpdateCaptureZone(captureZone, x, y, width, height, downscaleLevel);
175-
176-
if ((width != null) || (height != null))
177-
{
178-
lock (_textures)
179-
{
180-
if (_textures.TryGetValue(captureZone, out ZoneTextures? textures))
181-
{
182-
textures.Dispose();
183-
InitializeCaptureZone(captureZone);
184-
}
185-
}
186-
}
187-
}
188-
189-
private void InitializeCaptureZone(in CaptureZone<ColorBGRA> captureZone)
190-
=> _textures[captureZone] = new ZoneTextures(_display, captureZone.Display.Index, captureZone.X, captureZone.Y, captureZone.UnscaledWidth, captureZone.UnscaledHeight);
191-
192134
/// <inheritdoc />
193135
public override void Restart()
194136
{
@@ -200,6 +142,14 @@ public override void Restart()
200142
try
201143
{
202144
_display = X11.XOpenDisplay(X11.DISPLAY_NAME);
145+
146+
nint screen = X11.XScreenOfDisplay(_display, Display.Index);
147+
_drawable = X11.XRootWindowOfScreen(screen);
148+
_imageHandle = X11.XGetImage(_display, _drawable, 0, 0, (uint)Display.Width, (uint)Display.Height, X11.ALL_PLANES, X11.ZPIXMAP);
149+
_image = Marshal.PtrToStructure<X11.XImage>(_imageHandle);
150+
_size = _image.bytes_per_line * _image.height;
151+
152+
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.");
203153
}
204154
catch
205155
{
@@ -214,87 +164,21 @@ protected override void Dispose(bool disposing)
214164

215165
lock (_captureLock)
216166
{
217-
try
218-
{
219-
foreach ((CaptureZone<ColorBGRA> _, ZoneTextures textures) in _textures)
220-
textures.Dispose();
221-
222-
DisposeDisplay();
223-
}
167+
try { DisposeDisplay(); }
224168
catch { /**/ }
225169
}
226170
}
227171

228172
private void DisposeDisplay()
229173
{
230-
if (_display == 0) return;
174+
if (_imageHandle != 0)
175+
try { X11.XDestroyImage(_imageHandle); } catch { /**/ }
176+
177+
_image = default;
231178

232-
try { X11.XCloseDisplay(_display); } catch { /**/ }
179+
if (_display != 0)
180+
try { X11.XCloseDisplay(_display); } catch { /**/ }
233181
}
234182

235183
#endregion
236-
237-
private sealed class ZoneTextures : IDisposable
238-
{
239-
#region Properties & Fields
240-
241-
private readonly int _screenNumber;
242-
private readonly int _x;
243-
private readonly int _y;
244-
private readonly uint _width;
245-
private readonly uint _height;
246-
private readonly int _size;
247-
248-
private nint _display;
249-
private nint _drawable;
250-
public nint ImageHandle { get; private set; }
251-
public X11.XImage Image { get; private set; }
252-
public unsafe ReadOnlySpan<byte> Data => new(Image.data, _size);
253-
254-
#endregion
255-
256-
#region Constructors
257-
258-
public ZoneTextures(nint display, int screenNumber, int x, int y, int width, int height)
259-
{
260-
this._screenNumber = screenNumber;
261-
this._x = x;
262-
this._y = y;
263-
this._width = (uint)width;
264-
this._height = (uint)height;
265-
266-
_size = width * height * ColorBGRA.ColorFormat.BytesPerPixel;
267-
Initialize(display);
268-
}
269-
270-
#endregion
271-
272-
#region Methods
273-
274-
public void Initialize(nint display)
275-
{
276-
Dispose();
277-
278-
_display = display;
279-
280-
nint screen = X11.XScreenOfDisplay(_display, _screenNumber);
281-
_drawable = X11.XRootWindowOfScreen(screen);
282-
ImageHandle = X11.XGetImage(display, _drawable, _x, _y, _width, _height, X11.ALL_PLANES, X11.ZPIXMAP);
283-
Image = Marshal.PtrToStructure<X11.XImage>(ImageHandle);
284-
285-
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.");
286-
}
287-
288-
public void Update() => X11.XGetSubImage(_display, _drawable, _x, _y, _width, _height, X11.ALL_PLANES, X11.ZPIXMAP, ImageHandle, 0, 0);
289-
290-
public void Dispose()
291-
{
292-
if (ImageHandle != 0)
293-
try { X11.XDestroyImage(ImageHandle); } catch { /**/ }
294-
295-
Image = default;
296-
}
297-
298-
#endregion
299-
}
300184
}

0 commit comments

Comments
 (0)