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 ;
@@ -29,7 +31,6 @@ enum CodecId {
29
31
30
32
pub ( crate ) struct UpdateEncoder {
31
33
desktop_size : DesktopSize ,
32
- // FIXME: draw updates on the framebuffer
33
34
framebuffer : Option < Framebuffer > ,
34
35
bitmap_updater : BitmapUpdater ,
35
36
}
@@ -63,7 +64,7 @@ impl UpdateEncoder {
63
64
pub ( crate ) fn update ( & mut self , update : DisplayUpdate ) -> EncoderIter < ' _ > {
64
65
EncoderIter {
65
66
encoder : self ,
66
- update : Some ( update) ,
67
+ state : State :: Start ( update) ,
67
68
}
68
69
}
69
70
@@ -122,14 +123,41 @@ impl UpdateEncoder {
122
123
Ok ( UpdateFragmenter :: new ( UpdateCode :: PositionPointer , encode_vec ( & pos) ?) )
123
124
}
124
125
125
- async fn bitmap ( & mut self , bitmap : BitmapUpdate ) -> Result < UpdateFragmenter > {
126
- // Clone to satisfy spawn_blocking 'static requirement
127
- // this should be cheap, even if using bitmap, since vec![] will be empty
128
- let mut updater = self . bitmap_updater . clone ( ) ;
129
- let ( res, bitmap) =
130
- tokio:: task:: spawn_blocking ( move || time_warn ! ( "Encoding bitmap" , 10 , ( updater. handle( & bitmap) , bitmap) ) )
131
- . await
132
- . unwrap ( ) ;
126
+ fn bitmap_diffs ( & mut self , bitmap : & BitmapUpdate ) -> Vec < Rect > {
127
+ // TODO: we may want to make it optional for servers that already provide damaged regions
128
+ const USE_DIFFS : bool = true ;
129
+
130
+ if let Some ( Framebuffer {
131
+ data,
132
+ stride,
133
+ width,
134
+ height,
135
+ ..
136
+ } ) = USE_DIFFS . then_some ( self . framebuffer . as_ref ( ) ) . flatten ( )
137
+ {
138
+ find_different_rects_sub :: < 4 > (
139
+ data,
140
+ * stride,
141
+ width. get ( ) . into ( ) ,
142
+ height. get ( ) . into ( ) ,
143
+ & bitmap. data ,
144
+ bitmap. stride ,
145
+ bitmap. width . get ( ) . into ( ) ,
146
+ bitmap. height . get ( ) . into ( ) ,
147
+ bitmap. x . into ( ) ,
148
+ bitmap. y . into ( ) ,
149
+ )
150
+ } else {
151
+ vec ! [ Rect {
152
+ x: 0 ,
153
+ y: 0 ,
154
+ width: bitmap. width. get( ) . into( ) ,
155
+ height: bitmap. height. get( ) . into( ) ,
156
+ } ]
157
+ }
158
+ }
159
+
160
+ fn bitmap_update_framebuffer ( & mut self , bitmap : BitmapUpdate , diffs : & [ Rect ] ) {
133
161
if bitmap. x == 0
134
162
&& bitmap. y == 0
135
163
&& bitmap. width . get ( ) == self . desktop_size . width
@@ -139,32 +167,86 @@ impl UpdateEncoder {
139
167
Ok ( framebuffer) => self . framebuffer = Some ( framebuffer) ,
140
168
Err ( err) => warn ! ( "Failed to convert bitmap to framebuffer: {}" , err) ,
141
169
}
170
+ } else if let Some ( fb) = self . framebuffer . as_mut ( ) {
171
+ fb. update_diffs ( & bitmap, diffs) ;
142
172
}
143
- res
144
173
}
174
+
175
+ async fn bitmap ( & mut self , bitmap : BitmapUpdate ) -> Result < UpdateFragmenter > {
176
+ // Clone to satisfy spawn_blocking 'static requirement
177
+ // this should be cheap, even if using bitmap, since vec![] will be empty
178
+ let mut updater = self . bitmap_updater . clone ( ) ;
179
+ tokio:: task:: spawn_blocking ( move || time_warn ! ( "Encoding bitmap" , 10 , updater. handle( & bitmap) ) )
180
+ . await
181
+ . unwrap ( )
182
+ }
183
+ }
184
+
185
+ #[ derive( Debug , Default ) ]
186
+ enum State {
187
+ Start ( DisplayUpdate ) ,
188
+ BitmapDiffs {
189
+ diffs : Vec < Rect > ,
190
+ bitmap : BitmapUpdate ,
191
+ pos : usize ,
192
+ } ,
193
+ #[ default]
194
+ Ended ,
145
195
}
146
196
147
197
pub ( crate ) struct EncoderIter < ' a > {
148
198
encoder : & ' a mut UpdateEncoder ,
149
- update : Option < DisplayUpdate > ,
199
+ state : State ,
150
200
}
151
201
152
202
impl EncoderIter < ' _ > {
153
203
pub ( crate ) async fn next ( & mut self ) -> Option < Result < UpdateFragmenter > > {
154
- let update = self . update . take ( ) ?;
155
- let encoder = & mut self . encoder ;
156
-
157
- let res = match update {
158
- DisplayUpdate :: Bitmap ( bitmap) => encoder. bitmap ( bitmap) . await ,
159
- DisplayUpdate :: PointerPosition ( pos) => UpdateEncoder :: pointer_position ( pos) ,
160
- DisplayUpdate :: RGBAPointer ( ptr) => UpdateEncoder :: rgba_pointer ( ptr) ,
161
- DisplayUpdate :: ColorPointer ( ptr) => UpdateEncoder :: color_pointer ( ptr) ,
162
- DisplayUpdate :: HidePointer => UpdateEncoder :: hide_pointer ( ) ,
163
- DisplayUpdate :: DefaultPointer => UpdateEncoder :: default_pointer ( ) ,
164
- DisplayUpdate :: Resize ( _) => return None ,
165
- } ;
166
-
167
- Some ( res)
204
+ loop {
205
+ let state = core:: mem:: take ( & mut self . state ) ;
206
+ let encoder = & mut self . encoder ;
207
+
208
+ let res = match state {
209
+ State :: Start ( update) => match update {
210
+ DisplayUpdate :: Bitmap ( bitmap) => {
211
+ let diffs = encoder. bitmap_diffs ( & bitmap) ;
212
+ self . state = State :: BitmapDiffs { diffs, bitmap, pos : 0 } ;
213
+ continue ;
214
+ }
215
+ DisplayUpdate :: PointerPosition ( pos) => UpdateEncoder :: pointer_position ( pos) ,
216
+ DisplayUpdate :: RGBAPointer ( ptr) => UpdateEncoder :: rgba_pointer ( ptr) ,
217
+ DisplayUpdate :: ColorPointer ( ptr) => UpdateEncoder :: color_pointer ( ptr) ,
218
+ DisplayUpdate :: HidePointer => UpdateEncoder :: hide_pointer ( ) ,
219
+ DisplayUpdate :: DefaultPointer => UpdateEncoder :: default_pointer ( ) ,
220
+ DisplayUpdate :: Resize ( _) => return None ,
221
+ } ,
222
+ State :: BitmapDiffs { diffs, bitmap, pos } => {
223
+ let Some ( rect) = diffs. get ( pos) else {
224
+ encoder. bitmap_update_framebuffer ( bitmap, & diffs) ;
225
+ self . state = State :: Ended ;
226
+ return None ;
227
+ } ;
228
+ let Rect { x, y, width, height } = * rect;
229
+ let Some ( sub) = bitmap. sub (
230
+ u16:: try_from ( x) . unwrap ( ) ,
231
+ u16:: try_from ( y) . unwrap ( ) ,
232
+ NonZeroU16 :: new ( u16:: try_from ( width) . unwrap ( ) ) . unwrap ( ) ,
233
+ NonZeroU16 :: new ( u16:: try_from ( height) . unwrap ( ) ) . unwrap ( ) ,
234
+ ) else {
235
+ warn ! ( "Failed to extract bitmap subregion" ) ;
236
+ return None ;
237
+ } ;
238
+ self . state = State :: BitmapDiffs {
239
+ diffs,
240
+ bitmap,
241
+ pos : pos + 1 ,
242
+ } ;
243
+ encoder. bitmap ( sub) . await
244
+ }
245
+ State :: Ended => return None ,
246
+ } ;
247
+
248
+ return Some ( res) ;
249
+ }
168
250
}
169
251
}
170
252
0 commit comments