From 221ba1aac89f9472bd8b50310f36a832efcba76b Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Sat, 5 Jun 2021 08:55:33 +0200 Subject: LibVT: Improve scrolling performance Previously, we would remove lines from the buffer, create new lines and insert them into the buffer when we scrolled. Since scrolling does not always happen at the last line, this meant `Line` objects were pointlessly moved forwards, and then immediately backwards. We now swap them in-place and clear those lines that are "inserted". As a result, performance is better and scrolling is smoother in `vim` and `nano`. --- Userland/Libraries/LibVT/Terminal.cpp | 45 ++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'Userland/Libraries') diff --git a/Userland/Libraries/LibVT/Terminal.cpp b/Userland/Libraries/LibVT/Terminal.cpp index 1323bdac83..bb64076859 100644 --- a/Userland/Libraries/LibVT/Terminal.cpp +++ b/Userland/Libraries/LibVT/Terminal.cpp @@ -775,20 +775,28 @@ void Terminal::scroll_up(u16 region_top, u16 region_bottom, size_t count) // NOTE: We have to invalidate the cursor first. invalidate_cursor(); - if (!m_use_alternate_screen_buffer && max_history_size() != 0) + bool should_move_to_scrollback = !m_use_alternate_screen_buffer && max_history_size() != 0; + if (should_move_to_scrollback) { for (size_t i = 0; i < count; ++i) add_line_to_history(move(active_buffer().ptr_at(region_top + i))); + } - if (count == region_size) { - for (u16 row = region_top; row <= region_bottom; ++row) + // Move lines into their new place. + for (u16 row = region_top; row + count <= region_bottom; ++row) + swap(active_buffer().ptr_at(row), active_buffer().ptr_at(row + count)); + // Clear 'new' lines at the bottom. + if (should_move_to_scrollback) { + // Since we moved the previous lines into history, we can't just clear them. + for (u16 row = region_bottom + 1 - count; row <= region_bottom; ++row) + active_buffer().ptr_at(row) = make(columns()); + } else { + // The new lines haven't been moved and we don't want to leak memory. + for (u16 row = region_bottom + 1 - count; row <= region_bottom; ++row) active_buffer()[row].clear(Attribute()); - return; } - - active_buffer().remove(region_top, count); - for (size_t i = 0; i < count; ++i) - active_buffer().insert(region_bottom - count + i + 1, make(m_columns)); - for (u16 row = region_top; row <= region_bottom; ++row) + // Set dirty flag on swapped lines. + // The other lines have implicitly been set dirty by being cleared. + for (u16 row = region_top; row <= region_bottom - count; ++row) active_buffer()[row].set_dirty(true); if (!m_use_alternate_screen_buffer && max_history_size() != 0) m_client.terminal_history_changed(); @@ -806,16 +814,15 @@ void Terminal::scroll_down(u16 region_top, u16 region_bottom, size_t count) // NOTE: We have to invalidate the cursor first. invalidate_cursor(); - if (count == region_size) { - for (u16 row = region_top; row <= region_bottom; ++row) - active_buffer()[row].set_dirty(true); - return; - } - - active_buffer().remove(region_bottom - count + 1, count); - for (size_t i = 0; i < count; ++i) - active_buffer().insert(region_top, make(m_columns)); - for (u16 row = region_top; row <= region_bottom; ++row) + // Move lines into their new place. + for (int row = region_bottom; row >= static_cast(region_top + count); --row) + swap(active_buffer().ptr_at(row), active_buffer().ptr_at(row - count)); + // Clear the 'new' lines at the top. + for (u16 row = region_top; row < region_top + count; ++row) + active_buffer()[row].clear(Attribute()); + // Set dirty flag on swapped lines. + // The other lines have implicitly been set dirty by being cleared. + for (u16 row = region_top + count; row <= region_bottom; ++row) active_buffer()[row].set_dirty(true); } -- cgit v1.2.3