11use core:: fmt;
2+ use core:: num:: NonZeroU16 ;
23
34use anyhow:: { Context , Result } ;
45use ironrdp_acceptor:: DesktopSize ;
6+ use ironrdp_graphics:: diff:: { find_different_rects_sub, Rect } ;
57use ironrdp_pdu:: encode_vec;
68use ironrdp_pdu:: fast_path:: UpdateCode ;
79use ironrdp_pdu:: geometry:: ExclusiveRectangle ;
@@ -29,7 +31,6 @@ enum CodecId {
2931
3032pub ( crate ) struct UpdateEncoder {
3133 desktop_size : DesktopSize ,
32- // FIXME: draw updates on the framebuffer
3334 framebuffer : Option < Framebuffer > ,
3435 bitmap_updater : BitmapUpdater ,
3536}
@@ -63,7 +64,7 @@ impl UpdateEncoder {
6364 pub ( crate ) fn update ( & mut self , update : DisplayUpdate ) -> EncoderIter < ' _ > {
6465 EncoderIter {
6566 encoder : self ,
66- update : Some ( update) ,
67+ state : State :: Start ( update) ,
6768 }
6869 }
6970
@@ -122,14 +123,41 @@ impl UpdateEncoder {
122123 Ok ( UpdateFragmenter :: new ( UpdateCode :: PositionPointer , encode_vec ( & pos) ?) )
123124 }
124125
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 ] ) {
133161 if bitmap. x == 0
134162 && bitmap. y == 0
135163 && bitmap. width . get ( ) == self . desktop_size . width
@@ -139,32 +167,86 @@ impl UpdateEncoder {
139167 Ok ( framebuffer) => self . framebuffer = Some ( framebuffer) ,
140168 Err ( err) => warn ! ( "Failed to convert bitmap to framebuffer: {}" , err) ,
141169 }
170+ } else if let Some ( fb) = self . framebuffer . as_mut ( ) {
171+ fb. update_diffs ( & bitmap, diffs) ;
142172 }
143- res
144173 }
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 ,
145195}
146196
147197pub ( crate ) struct EncoderIter < ' a > {
148198 encoder : & ' a mut UpdateEncoder ,
149- update : Option < DisplayUpdate > ,
199+ state : State ,
150200}
151201
152202impl EncoderIter < ' _ > {
153203 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+ }
168250 }
169251}
170252
0 commit comments