11using System ;
2- using System . Collections . Generic ;
32using System . Runtime . CompilerServices ;
43using System . Runtime . InteropServices ;
54using 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