From ec2600f246a842ac61f02a20431c4bab04b6db67 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 14 May 2023 18:57:14 +0200 Subject: [PATCH] Ladybird: Make resizing the window a lot less laggy While resizing, we now pad the shared bitmap allocations with 256 pixels extra in both axes. This avoids churning through huge allocations for every single resize step. We also don't reallocate at all when making the window smaller. 3 seconds after the user stops resizing, we resize the backing stores again so they fit the window perfectly. --- Ladybird/WebContentView.cpp | 84 +++++++++++++++++++++++++++---------- Ladybird/WebContentView.h | 11 ++++- 2 files changed, 71 insertions(+), 24 deletions(-) diff --git a/Ladybird/WebContentView.cpp b/Ladybird/WebContentView.cpp index 54d793b35d..82e80a452b 100644 --- a/Ladybird/WebContentView.cpp +++ b/Ladybird/WebContentView.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Andreas Kling + * Copyright (c) 2022-2023, Andreas Kling * Copyright (c) 2023, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause @@ -77,6 +77,10 @@ WebContentView::WebContentView(StringView webdriver_content_ipc_path, WebView::E }); create_client(enable_callgrind_profiling); + + m_backing_store_shrink_timer = Core::Timer::create_single_shot(3000, [this] { + resize_backing_stores_if_needed(WindowResizeInProgress::No); + }).release_value_but_fixme_should_propagate_errors(); } WebContentView::~WebContentView() @@ -410,9 +414,29 @@ void WebContentView::paintEvent(QPaintEvent*) QPainter painter(viewport()); painter.scale(m_inverse_pixel_scaling_ratio, m_inverse_pixel_scaling_ratio); - if (auto* bitmap = m_client_state.has_usable_bitmap ? m_client_state.front_bitmap.bitmap.ptr() : m_backup_bitmap.ptr()) { + Gfx::Bitmap const* bitmap = nullptr; + Gfx::IntSize bitmap_size; + + if (m_client_state.has_usable_bitmap) { + bitmap = m_client_state.front_bitmap.bitmap.ptr(); + bitmap_size = m_client_state.front_bitmap.last_painted_size; + + } else { + bitmap = m_backup_bitmap.ptr(); + bitmap_size = m_backup_bitmap_size; + } + + if (bitmap) { QImage q_image(bitmap->scanline_u8(0), bitmap->width(), bitmap->height(), QImage::Format_RGB32); - painter.drawImage(QPoint(0, 0), q_image); + painter.drawImage(QPoint(0, 0), q_image, QRect(0, 0, bitmap_size.width(), bitmap_size.height())); + + if (bitmap_size.width() < width()) { + painter.fillRect(bitmap_size.width(), 0, width() - bitmap_size.width(), bitmap->height(), palette().base()); + } + if (bitmap_size.height() < height()) { + painter.fillRect(0, bitmap_size.height(), width(), height() - bitmap_size.height(), palette().base()); + } + return; } @@ -423,43 +447,57 @@ void WebContentView::resizeEvent(QResizeEvent* event) { QAbstractScrollArea::resizeEvent(event); handle_resize(); + m_backing_store_shrink_timer->restart(); } void WebContentView::handle_resize() { update_viewport_rect(); + resize_backing_stores_if_needed(WindowResizeInProgress::Yes); +} +void WebContentView::resize_backing_stores_if_needed(WindowResizeInProgress window_resize_in_progress) +{ if (m_client_state.has_usable_bitmap) { // NOTE: We keep the outgoing front bitmap as a backup so we have something to paint until we get a new one. m_backup_bitmap = m_client_state.front_bitmap.bitmap; + m_backup_bitmap_size = m_client_state.front_bitmap.last_painted_size; } - if (m_client_state.front_bitmap.bitmap) - client().async_remove_backing_store(m_client_state.front_bitmap.id); - - if (m_client_state.back_bitmap.bitmap) - client().async_remove_backing_store(m_client_state.back_bitmap.id); - - m_client_state.front_bitmap = {}; - m_client_state.back_bitmap = {}; m_client_state.has_usable_bitmap = false; - auto available_size = m_viewport_rect.size(); - - if (available_size.is_empty()) + if (m_viewport_rect.is_empty()) return; - if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRx8888, available_size); !new_bitmap_or_error.is_error()) { - m_client_state.front_bitmap.bitmap = new_bitmap_or_error.release_value(); - m_client_state.front_bitmap.id = m_client_state.next_bitmap_id++; - client().async_add_backing_store(m_client_state.front_bitmap.id, m_client_state.front_bitmap.bitmap->to_shareable_bitmap()); + Gfx::IntSize minimum_needed_size; + + if (window_resize_in_progress == WindowResizeInProgress::Yes) { + // Pad the minimum needed size so that we don't have to keep reallocating backing stores while the window is being resized. + minimum_needed_size = { m_viewport_rect.width() + 256, m_viewport_rect.height() + 256 }; + } else { + // If we're not in the middle of a resize, we can shrink the backing store size to match the viewport size. + minimum_needed_size = m_viewport_rect.size(); + m_client_state.front_bitmap = {}; + m_client_state.back_bitmap = {}; } - if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRx8888, available_size); !new_bitmap_or_error.is_error()) { - m_client_state.back_bitmap.bitmap = new_bitmap_or_error.release_value(); - m_client_state.back_bitmap.id = m_client_state.next_bitmap_id++; - client().async_add_backing_store(m_client_state.back_bitmap.id, m_client_state.back_bitmap.bitmap->to_shareable_bitmap()); - } + auto reallocate_backing_store_if_needed = [&](SharedBitmap& backing_store) { + if (!backing_store.bitmap || !backing_store.bitmap->size().contains(minimum_needed_size)) { + if (auto new_bitmap_or_error = Gfx::Bitmap::create_shareable(Gfx::BitmapFormat::BGRx8888, minimum_needed_size); !new_bitmap_or_error.is_error()) { + if (backing_store.bitmap) + client().async_remove_backing_store(backing_store.id); + + backing_store.pending_paints = 0; + backing_store.bitmap = new_bitmap_or_error.release_value(); + backing_store.id = m_client_state.next_bitmap_id++; + client().async_add_backing_store(backing_store.id, backing_store.bitmap->to_shareable_bitmap()); + } + backing_store.last_painted_size = m_viewport_rect.size(); + } + }; + + reallocate_backing_store_if_needed(m_client_state.front_bitmap); + reallocate_backing_store_if_needed(m_client_state.back_bitmap); request_repaint(); } diff --git a/Ladybird/WebContentView.h b/Ladybird/WebContentView.h index ab3e064fae..983134d97b 100644 --- a/Ladybird/WebContentView.h +++ b/Ladybird/WebContentView.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Andreas Kling + * Copyright (c) 2022-2023, Andreas Kling * Copyright (c) 2023, Linus Groh * * SPDX-License-Identifier: BSD-2-Clause @@ -203,6 +203,12 @@ private: void update_viewport_rect(); void handle_resize(); + enum class WindowResizeInProgress { + No, + Yes, + }; + void resize_backing_stores_if_needed(WindowResizeInProgress); + void ensure_js_console_widget(); void ensure_inspector_widget(); @@ -222,6 +228,9 @@ private: void handle_web_content_process_crash(); RefPtr m_backup_bitmap; + Gfx::IntSize m_backup_bitmap_size; StringView m_webdriver_content_ipc_path; + + RefPtr m_backing_store_shrink_timer; };