1
1
use core:: fmt;
2
+ use core:: num:: NonZeroU16 ;
2
3
3
4
use anyhow:: { Context , Result } ;
4
5
use ironrdp_acceptor:: DesktopSize ;
6
+ use ironrdp_graphics:: diff:: { find_different_rects_sub, Rect } ;
5
7
use ironrdp_pdu:: encode_vec;
6
8
use ironrdp_pdu:: fast_path:: UpdateCode ;
7
9
use ironrdp_pdu:: geometry:: ExclusiveRectangle ;
@@ -65,7 +67,7 @@ impl UpdateEncoder {
65
67
pub ( crate ) fn update ( & mut self , update : DisplayUpdate ) -> EncoderIter < ' _ > {
66
68
EncoderIter {
67
69
encoder : self ,
68
- update : Some ( update) ,
70
+ state : State :: Start ( update) ,
69
71
}
70
72
}
71
73
@@ -129,14 +131,40 @@ impl UpdateEncoder {
129
131
Ok ( UpdateFragmenter :: new ( UpdateCode :: PositionPointer , encode_vec ( & pos) ?) )
130
132
}
131
133
132
- async fn bitmap ( & mut self , bitmap : BitmapUpdate ) -> Result < UpdateFragmenter > {
133
- // Clone to satisfy spawn_blocking 'static requirement
134
- // this should be cheap, even if using bitmap, since vec![] will be empty
135
- let mut updater = self . bitmap_updater . clone ( ) ;
136
- let ( res, bitmap) =
137
- tokio:: task:: spawn_blocking ( move || time_warn ! ( "Encoding bitmap" , 10 , ( updater. handle( & bitmap) , bitmap) ) )
138
- . await
139
- . unwrap ( ) ;
134
+ fn bitmap_diffs ( & mut self , bitmap : & BitmapUpdate ) -> Vec < Rect > {
135
+ const USE_DIFFS : bool = true ;
136
+
137
+ if let Some ( Framebuffer {
138
+ data,
139
+ stride,
140
+ width,
141
+ height,
142
+ ..
143
+ } ) = USE_DIFFS . then_some ( self . framebuffer . as_ref ( ) ) . flatten ( )
144
+ {
145
+ find_different_rects_sub :: < 4 > (
146
+ data,
147
+ * stride,
148
+ width. get ( ) . into ( ) ,
149
+ height. get ( ) . into ( ) ,
150
+ & bitmap. data ,
151
+ bitmap. stride ,
152
+ bitmap. width . get ( ) . into ( ) ,
153
+ bitmap. height . get ( ) . into ( ) ,
154
+ bitmap. x . into ( ) ,
155
+ bitmap. y . into ( ) ,
156
+ )
157
+ } else {
158
+ vec ! [ Rect {
159
+ x: 0 ,
160
+ y: 0 ,
161
+ width: bitmap. width. get( ) . into( ) ,
162
+ height: bitmap. height. get( ) . into( ) ,
163
+ } ]
164
+ }
165
+ }
166
+
167
+ fn bitmap_update_framebuffer ( & mut self , bitmap : BitmapUpdate , diffs : & [ Rect ] ) {
140
168
if bitmap. x == 0
141
169
&& bitmap. y == 0
142
170
&& bitmap. width . get ( ) == self . desktop_size . width
@@ -146,34 +174,88 @@ impl UpdateEncoder {
146
174
Ok ( framebuffer) => self . framebuffer = Some ( framebuffer) ,
147
175
Err ( err) => warn ! ( "Failed to convert bitmap to framebuffer: {}" , err) ,
148
176
}
177
+ } else if let Some ( fb) = self . framebuffer . as_mut ( ) {
178
+ fb. update_diffs ( & bitmap, diffs) ;
149
179
}
150
- res
151
180
}
181
+
182
+ async fn bitmap ( & mut self , bitmap : BitmapUpdate ) -> Result < UpdateFragmenter > {
183
+ // Clone to satisfy spawn_blocking 'static requirement
184
+ // this should be cheap, even if using bitmap, since vec![] will be empty
185
+ let mut updater = self . bitmap_updater . clone ( ) ;
186
+ tokio:: task:: spawn_blocking ( move || time_warn ! ( "Encoding bitmap" , 10 , updater. handle( & bitmap) ) )
187
+ . await
188
+ . unwrap ( )
189
+ }
190
+ }
191
+
192
+ #[ derive( Debug , Default ) ]
193
+ enum State {
194
+ Start ( DisplayUpdate ) ,
195
+ BitmapDiffs {
196
+ diffs : Vec < Rect > ,
197
+ bitmap : BitmapUpdate ,
198
+ pos : usize ,
199
+ } ,
200
+ #[ default]
201
+ Ended ,
152
202
}
153
203
154
204
#[ cfg_attr( feature = "__bench" , visibility:: make( pub ) ) ]
155
205
pub ( crate ) struct EncoderIter < ' a > {
156
206
encoder : & ' a mut UpdateEncoder ,
157
- update : Option < DisplayUpdate > ,
207
+ state : State ,
158
208
}
159
209
160
210
impl EncoderIter < ' _ > {
161
211
#[ cfg_attr( feature = "__bench" , visibility:: make( pub ) ) ]
162
212
pub ( crate ) async fn next ( & mut self ) -> Option < Result < UpdateFragmenter > > {
163
- let update = self . update . take ( ) ?;
164
- let encoder = & mut self . encoder ;
165
-
166
- let res = match update {
167
- DisplayUpdate :: Bitmap ( bitmap) => encoder. bitmap ( bitmap) . await ,
168
- DisplayUpdate :: PointerPosition ( pos) => encoder. pointer_position ( pos) ,
169
- DisplayUpdate :: RGBAPointer ( ptr) => encoder. rgba_pointer ( ptr) ,
170
- DisplayUpdate :: ColorPointer ( ptr) => encoder. color_pointer ( ptr) ,
171
- DisplayUpdate :: HidePointer => encoder. hide_pointer ( ) ,
172
- DisplayUpdate :: DefaultPointer => encoder. default_pointer ( ) ,
173
- DisplayUpdate :: Resize ( _) => return None ,
174
- } ;
175
-
176
- Some ( res)
213
+ loop {
214
+ let state = core:: mem:: take ( & mut self . state ) ;
215
+ let encoder = & mut self . encoder ;
216
+
217
+ let res = match state {
218
+ State :: Start ( update) => match update {
219
+ DisplayUpdate :: Bitmap ( bitmap) => {
220
+ let diffs = encoder. bitmap_diffs ( & bitmap) ;
221
+ self . state = State :: BitmapDiffs { diffs, bitmap, pos : 0 } ;
222
+ continue ;
223
+ }
224
+ DisplayUpdate :: PointerPosition ( pos) => encoder. pointer_position ( pos) ,
225
+ DisplayUpdate :: RGBAPointer ( ptr) => encoder. rgba_pointer ( ptr) ,
226
+ DisplayUpdate :: ColorPointer ( ptr) => encoder. color_pointer ( ptr) ,
227
+ DisplayUpdate :: HidePointer => encoder. hide_pointer ( ) ,
228
+ DisplayUpdate :: DefaultPointer => encoder. default_pointer ( ) ,
229
+ DisplayUpdate :: Resize ( _) => return None ,
230
+ } ,
231
+ State :: BitmapDiffs { diffs, bitmap, pos } => {
232
+ let Some ( rect) = diffs. get ( pos) else {
233
+ encoder. bitmap_update_framebuffer ( bitmap, & diffs) ;
234
+ self . state = State :: Ended ;
235
+ return None ;
236
+ } ;
237
+ let Rect { x, y, width, height } = * rect;
238
+ let Some ( sub) = bitmap. sub (
239
+ u16:: try_from ( x) . unwrap ( ) ,
240
+ u16:: try_from ( y) . unwrap ( ) ,
241
+ NonZeroU16 :: new ( u16:: try_from ( width) . unwrap ( ) ) . unwrap ( ) ,
242
+ NonZeroU16 :: new ( u16:: try_from ( height) . unwrap ( ) ) . unwrap ( ) ,
243
+ ) else {
244
+ warn ! ( "Failed to extract bitmap subregion" ) ;
245
+ return None ;
246
+ } ;
247
+ self . state = State :: BitmapDiffs {
248
+ diffs,
249
+ bitmap,
250
+ pos : pos + 1 ,
251
+ } ;
252
+ encoder. bitmap ( sub) . await
253
+ }
254
+ State :: Ended => return None ,
255
+ } ;
256
+
257
+ return Some ( res) ;
258
+ }
177
259
}
178
260
}
179
261
0 commit comments