diff options
Diffstat (limited to 'src/server/render_stream.rs')
| -rw-r--r-- | src/server/render_stream.rs | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/src/server/render_stream.rs b/src/server/render_stream.rs index 41684c26..349454f3 100644 --- a/src/server/render_stream.rs +++ b/src/server/render_stream.rs @@ -145,9 +145,8 @@ impl ClientRenderState { } pub(crate) fn prepare_pane_surface_patch( - &mut self, + &self, mut patch: PaneSurfacePatch, - mut committed_surface: PaneSurfaceFrame, ) -> Option<PreparedRender> { let Self::Semantic { last_surface, @@ -165,11 +164,8 @@ impl ClientRenderState { } let next_revision = surface_revision.saturating_add(1); patch.surface_revision = next_revision; - committed_surface.surface_revision = next_revision; - committed_surface.graphics.assets.clear(); - Some(PreparedRender::Semantic { + Some(PreparedRender::SemanticPatch { message: ServerMessage::PaneSurfacePatch(patch), - committed_surface: Box::new(committed_surface), }) } @@ -188,6 +184,21 @@ impl ClientRenderState { *last_surface = Some(committed_surface); } ( + Self::Semantic { + last_surface, + surface_revision, + }, + PreparedRender::SemanticPatch { + message: ServerMessage::PaneSurfacePatch(patch), + }, + ) => { + let surface = last_surface + .as_deref_mut() + .expect("prepared patch baseline"); + apply_pane_surface_patch(surface, &patch); + *surface_revision = patch.surface_revision; + } + ( Self::TerminalAnsi { blit_encoder, seq, @@ -208,6 +219,28 @@ impl ClientRenderState { } } +// Planning validates all rows and pane IDs before any send. The server does not yield +// between planning and commit, so applying the accepted patch cannot fail partway through. +pub(super) fn apply_pane_surface_patch(surface: &mut PaneSurfaceFrame, patch: &PaneSurfacePatch) { + debug_assert_eq!(surface.boot_id, patch.boot_id); + debug_assert_eq!(surface.projection_revision, patch.projection_revision); + debug_assert_eq!(surface.surface_revision, patch.base_surface_revision); + for row in &patch.rows { + let start = usize::from(row.y) * usize::from(surface.frame.width) + usize::from(row.x); + surface.frame.cells[start..start + row.cells.len()].clone_from_slice(&row.cells); + } + for updated in &patch.panes { + let pane = surface + .panes + .iter_mut() + .find(|pane| pane.pane_id == updated.pane_id) + .expect("planned patch pane"); + pane.clone_from(updated); + } + surface.frame.cursor.clone_from(&patch.cursor); + surface.surface_revision = patch.surface_revision; +} + fn insert_graphics_before_sync_end(encoded: &mut Vec<u8>, graphics: &[u8]) { if graphics.is_empty() { return; @@ -226,6 +259,9 @@ pub(crate) enum PreparedRender { message: ServerMessage, committed_surface: Box<PaneSurfaceFrame>, }, + SemanticPatch { + message: ServerMessage, + }, TerminalAnsi { message: ServerMessage, frame: FrameData, @@ -236,7 +272,9 @@ pub(crate) enum PreparedRender { impl PreparedRender { pub(crate) fn message(&self) -> &ServerMessage { match self { - Self::Semantic { message, .. } | Self::TerminalAnsi { message, .. } => message, + Self::Semantic { message, .. } + | Self::SemanticPatch { message } + | Self::TerminalAnsi { message, .. } => message, } } |
