@@ -912,12 +912,10 @@ pub struct ScreenshotEditorWindow {
912912 /// renders.
913913 exporting : bool ,
914914 export_status : ExportStatus ,
915- /// The latest GPU frame, already BGRA in gpui's atlas format.
916- frame : Option < Arc < RenderImage > > ,
917- /// The same frame as tight RGBA. `Preview.tsx` reads the preview canvas
918- /// back to blur/pixelate mask regions (`:537-687`); the mask overlay
919- /// resamples this instead of the atlas image.
920- pub ( crate ) frame_rgba : Option < Arc < Vec < u8 > > > ,
915+ /// The latest GPU frame, already BGRA in gpui's atlas format. `Preview.tsx`
916+ /// reads the preview canvas back to blur/pixelate mask regions
917+ /// (`:537-687`); the mask overlay resamples these same pixels.
918+ pub ( crate ) frame : Option < Arc < RenderImage > > ,
921919 pub ( crate ) mask_frame_revision : u64 ,
922920 pub ( crate ) frame_size : ( f32 , f32 ) ,
923921 /// `originalImageSize` -- the source PNG's dimensions, which the crop
@@ -1003,7 +1001,6 @@ impl ScreenshotEditorWindow {
10031001 exporting : false ,
10041002 export_status : ExportStatus :: Idle ,
10051003 frame : None ,
1006- frame_rgba : None ,
10071004 mask_frame_revision : 0 ,
10081005 frame_size : ( 1. , 1. ) ,
10091006 image_size : None ,
@@ -1126,15 +1123,13 @@ impl ScreenshotEditorWindow {
11261123 pub fn frame_arrived (
11271124 & mut self ,
11281125 image : Arc < RenderImage > ,
1129- rgba : Arc < Vec < u8 > > ,
11301126 size : ( u32 , u32 ) ,
11311127 window : & mut Window ,
11321128 cx : & mut Context < Self > ,
11331129 ) {
11341130 let next = ( size. 0 . max ( 1 ) as f32 , size. 1 . max ( 1 ) as f32 ) ;
11351131 self . rescale_annotations_for ( next) ;
11361132 self . frame_size = next;
1137- self . frame_rgba = Some ( rgba) ;
11381133 self . mask_frame_revision = self
11391134 . mask_frame_revision
11401135 . checked_add ( 1 )
@@ -4747,26 +4742,10 @@ fn render_input_key(project: &mut ProjectConfiguration) -> Option<Vec<u8>> {
47474742 Some ( key)
47484743}
47494744
4750- /// One rendered frame, in both the forms the window needs: tight RGBA (what a
4751- /// mask overlay resamples) and the BGRA copy gpui's atlas takes. The rows are
4752- /// copied once and the swap runs over a clone, so the padded GPU buffer is
4753- /// walked a single time.
4754- fn frame_buffers ( frame : & RenderedFrame ) -> Option < ( Arc < Vec < u8 > > , Arc < RenderImage > ) > {
4755- let rgba = cap_gpui_kernels:: frame:: unpad_rows (
4756- & frame. data ,
4757- frame. width as usize * 4 ,
4758- frame. padded_bytes_per_row as usize ,
4759- frame. height as usize ,
4760- ) ?;
4761- let mut bgra = rgba. clone ( ) ;
4762- cap_gpui_kernels:: frame:: swap_red_blue ( & mut bgra) ;
4763- let buffer = image:: RgbaImage :: from_raw ( frame. width , frame. height , bgra) ?;
4764- Some ( (
4765- Arc :: new ( rgba) ,
4766- Arc :: new ( RenderImage :: new ( smallvec:: smallvec![ image:: Frame :: new(
4767- buffer
4768- ) ] ) ) ,
4769- ) )
4745+ /// Only the newest queued frame is ever shown, so older ones are dropped
4746+ /// before the copy rather than converted and replaced.
4747+ fn latest_frame < T > ( frame : T , frames : & flume:: Receiver < T > ) -> T {
4748+ frames. drain ( ) . last ( ) . unwrap_or ( frame)
47704749}
47714750
47724751/// Read the bundle, start the still renderer on tokio, pump frames back --
@@ -4837,13 +4816,14 @@ pub fn load_screenshot_project(
48374816 return ;
48384817 }
48394818
4840- while let Ok ( ( frame, revision) ) = frame_rx. recv_async ( ) . await {
4819+ while let Ok ( frame) = frame_rx. recv_async ( ) . await {
4820+ let ( frame, revision) = latest_frame ( frame, & frame_rx) ;
48414821 let size = ( frame. width , frame. height ) ;
4842- let buffers = cx
4822+ let image = cx
48434823 . background_executor ( )
4844- . spawn ( async move { frame_buffers ( & frame) } )
4824+ . spawn ( async move { crate :: editor_window :: frame_image ( & frame) } )
48454825 . await ;
4846- let Some ( ( rgba , image) ) = buffers else {
4826+ let Some ( image) = image else {
48474827 tracing:: warn!( "a rendered screenshot frame could not be converted for display" ) ;
48484828 continue ;
48494829 } ;
@@ -4855,7 +4835,7 @@ pub fn load_screenshot_project(
48554835 ) ;
48564836 if handle
48574837 . update ( cx, |view, window, cx| {
4858- view. frame_arrived ( image, rgba , size, window, cx)
4838+ view. frame_arrived ( image, size, window, cx)
48594839 } )
48604840 . is_err ( )
48614841 {
@@ -4887,6 +4867,56 @@ mod tests {
48874867 assert_eq ! ( CHECKER_TILE % ( CHECKER_CELL * 2 ) , 0 ) ;
48884868 }
48894869
4870+ #[ test]
4871+ fn the_displayed_frame_matches_unpadding_then_swapping_a_copy ( ) {
4872+ for ( width, height) in [ ( 1u32 , 1u32 ) , ( 3 , 5 ) , ( 7 , 2 ) , ( 33 , 9 ) , ( 1001 , 3 ) ] {
4873+ let row_bytes = width * 4 ;
4874+ for stride in [ row_bytes, row_bytes + 4 , row_bytes. next_multiple_of ( 256 ) ] {
4875+ let frame = RenderedFrame {
4876+ data : Arc :: new (
4877+ ( 0 ..stride as usize * height as usize )
4878+ . map ( |index| ( index * 7 + index / 251 ) as u8 )
4879+ . collect ( ) ,
4880+ ) ,
4881+ width,
4882+ height,
4883+ padded_bytes_per_row : stride,
4884+ frame_number : 0 ,
4885+ target_time_ns : 0 ,
4886+ } ;
4887+ let rgba = cap_gpui_kernels:: frame:: unpad_rows (
4888+ & frame. data ,
4889+ row_bytes as usize ,
4890+ stride as usize ,
4891+ height as usize ,
4892+ )
4893+ . unwrap ( ) ;
4894+ let mut bgra = rgba. clone ( ) ;
4895+ cap_gpui_kernels:: frame:: swap_red_blue ( & mut bgra) ;
4896+
4897+ let image = crate :: editor_window:: frame_image ( & frame) . unwrap ( ) ;
4898+ assert_eq ! (
4899+ image. size( 0 ) ,
4900+ gpui:: size(
4901+ gpui:: DevicePixels :: from( width) ,
4902+ gpui:: DevicePixels :: from( height)
4903+ )
4904+ ) ;
4905+ assert_eq ! ( image. as_bytes( 0 ) . unwrap( ) , bgra. as_slice( ) ) ;
4906+ }
4907+ }
4908+ }
4909+
4910+ #[ test]
4911+ fn only_the_newest_queued_frame_is_converted ( ) {
4912+ let ( frame_tx, frame_rx) = flume:: bounded ( 2 ) ;
4913+ assert_eq ! ( latest_frame( 1 , & frame_rx) , 1 ) ;
4914+ frame_tx. send ( 2 ) . unwrap ( ) ;
4915+ frame_tx. send ( 3 ) . unwrap ( ) ;
4916+ assert_eq ! ( latest_frame( 1 , & frame_rx) , 3 ) ;
4917+ assert ! ( frame_rx. is_empty( ) ) ;
4918+ }
4919+
48904920 /// `PaddingPopover`'s guard (`context.tsx:30-42`).
48914921 #[ test]
48924922 fn an_invisible_background_is_one_with_nothing_to_show ( ) {
@@ -5182,7 +5212,7 @@ mod tests {
51825212 ) ) ;
51835213 setup_rx. recv_async ( ) . await . unwrap ( ) . unwrap ( ) ;
51845214 let ( first, _) = frame_rx. recv_async ( ) . await . unwrap ( ) ;
5185- assert ! ( frame_buffers ( & first) . is_some( ) ) ;
5215+ assert ! ( crate :: editor_window :: frame_image ( & first) . is_some( ) ) ;
51865216
51875217 let renders = Arc :: new ( std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ) ;
51885218 let render_ms = Arc :: new ( std:: sync:: Mutex :: new ( Vec :: new ( ) ) ) ;
@@ -5194,10 +5224,12 @@ mod tests {
51945224 ( renders. clone ( ) , render_ms. clone ( ) , sent_at. clone ( ) ) ;
51955225 tokio:: spawn ( async move {
51965226 while let Ok ( ( frame, revision) ) = frame_rx. recv_async ( ) . await {
5197- let buffers = tokio:: task:: spawn_blocking ( move || frame_buffers ( & frame) )
5198- . await
5199- . unwrap ( ) ;
5200- assert ! ( buffers. is_some( ) ) ;
5227+ let image = tokio:: task:: spawn_blocking ( move || {
5228+ crate :: editor_window:: frame_image ( & frame)
5229+ } )
5230+ . await
5231+ . unwrap ( ) ;
5232+ assert ! ( image. is_some( ) ) ;
52015233 if let Some ( sent) = sent_at. lock ( ) . unwrap ( ) . remove ( & revision) {
52025234 render_ms
52035235 . lock ( )
0 commit comments