From cb722ca18b6128dfee6f257bbb454cfdbac6b417 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Tue, 1 Apr 2025 00:06:01 +0200 Subject: [PATCH] LibWeb: Allow working on N+1 frame while N is rasterizing This change allows us to overlap rasterization and rendering work across threads: while the rasterization thread processes frame N, the main thread can simultaneously work on producing the display list for frame N+1. --- Services/WebContent/BackingStoreManager.h | 17 ++++++++++++++--- Services/WebContent/PageClient.cpp | 23 ++++++++++++----------- Services/WebContent/PageClient.h | 7 +------ 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/Services/WebContent/BackingStoreManager.h b/Services/WebContent/BackingStoreManager.h index 7c39c0d8134..6b02a9af5d3 100644 --- a/Services/WebContent/BackingStoreManager.h +++ b/Services/WebContent/BackingStoreManager.h @@ -25,14 +25,25 @@ public: void reallocate_backing_stores(Gfx::IntSize); void restart_resize_timer(); - Web::Painting::BackingStore* back_store() { return m_back_store.ptr(); } - i32 front_id() const { return m_front_bitmap_id; } + struct BackingStore { + i32 bitmap_id { -1 }; + Web::Painting::BackingStore* store { nullptr }; + }; - void swap_back_and_front(); + BackingStore acquire_store_for_next_frame() + { + BackingStore backing_store; + backing_store.bitmap_id = m_back_bitmap_id; + backing_store.store = m_back_store.ptr(); + swap_back_and_front(); + return backing_store; + } BackingStoreManager(PageClient&); private: + void swap_back_and_front(); + // FIXME: We should come up with an ownership model for this class that makes the GC-checker happy IGNORE_GC PageClient& m_page_client; diff --git a/Services/WebContent/PageClient.cpp b/Services/WebContent/PageClient.cpp index 64bcc3174a3..ff99b62d789 100644 --- a/Services/WebContent/PageClient.cpp +++ b/Services/WebContent/PageClient.cpp @@ -81,12 +81,7 @@ PageClient::~PageClient() = default; bool PageClient::is_ready_to_paint() const { - return m_paint_state == PaintState::Ready; -} - -void PageClient::ready_to_paint() -{ - m_paint_state = PaintState::Ready; + return m_number_of_queued_rasterization_tasks <= 1; } void PageClient::visit_edges(JS::Cell::Visitor& visitor) @@ -220,18 +215,24 @@ void PageClient::process_screenshot_requests() } } +void PageClient::ready_to_paint() +{ + m_number_of_queued_rasterization_tasks--; + VERIFY(m_number_of_queued_rasterization_tasks >= 0 && m_number_of_queued_rasterization_tasks < 2); +} + void PageClient::paint_next_frame() { - auto back_store = m_backing_store_manager.back_store(); + auto [backing_store_id, back_store] = m_backing_store_manager.acquire_store_for_next_frame(); if (!back_store) return; - m_paint_state = PaintState::WaitingForClient; + VERIFY(m_number_of_queued_rasterization_tasks <= 1); + m_number_of_queued_rasterization_tasks++; auto viewport_rect = page().css_to_device_rect(page().top_level_traversable()->viewport_rect()); - start_display_list_rendering(viewport_rect, *back_store, {}, [this, viewport_rect]() { - m_backing_store_manager.swap_back_and_front(); - client().async_did_paint(m_id, viewport_rect.to_type(), m_backing_store_manager.front_id()); + start_display_list_rendering(viewport_rect, *back_store, {}, [this, viewport_rect, backing_store_id] { + client().async_did_paint(m_id, viewport_rect.to_type(), backing_store_id); }); } diff --git a/Services/WebContent/PageClient.h b/Services/WebContent/PageClient.h index f96da84e314..e89450dfb87 100644 --- a/Services/WebContent/PageClient.h +++ b/Services/WebContent/PageClient.h @@ -190,12 +190,7 @@ private: bool m_should_show_line_box_borders { false }; bool m_has_focus { false }; - enum class PaintState { - Ready, - WaitingForClient, - }; - - PaintState m_paint_state { PaintState::Ready }; + i32 m_number_of_queued_rasterization_tasks { 0 }; struct ScreenshotTask { Optional node_id;