From 668fe61b1de666ba583fa43a317d47d269e0bb70 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 5 Jul 2020 16:26:15 +0200 Subject: [PATCH] WebContent: Coalesce pending paint events to reduce overdraw Instead of painting synchronously whenever a Paint request comes in, the WebContent process will now buffer pending paints and coalesce them and defer the actual paint using a zero-timer. This significantly reduces flickering already, without doing any double-buffering in the WebContentView widget. --- Services/WebContent/ClientConnection.cpp | 22 ++++++++++++++++++++-- Services/WebContent/ClientConnection.h | 9 +++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Services/WebContent/ClientConnection.cpp b/Services/WebContent/ClientConnection.cpp index 00bf8d7e31..f818fa5538 100644 --- a/Services/WebContent/ClientConnection.cpp +++ b/Services/WebContent/ClientConnection.cpp @@ -41,6 +41,7 @@ ClientConnection::ClientConnection(Core::LocalSocket& socket, int client_id) , m_page_host(PageHost::create(*this)) { s_connections.set(client_id, *this); + m_paint_flush_timer = Core::Timer::create_single_shot(0, [this] { flush_pending_paint_requests(); }); } ClientConnection::~ClientConnection() @@ -102,6 +103,13 @@ void ClientConnection::handle(const Messages::WebContentServer::Paint& message) dbg() << "handle: WebContentServer::Paint: content_rect=" << message.content_rect() << ", shbuf_id=" << message.shbuf_id(); #endif + for (auto& pending_paint : m_pending_paint_requests) { + if (pending_paint.bitmap->shbuf_id() == message.shbuf_id()) { + pending_paint.content_rect = message.content_rect(); + return; + } + } + auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id()); if (!shared_buffer) { dbg() << "WebContentServer::Paint: SharedBuffer already gone! Ignoring :^)"; @@ -112,8 +120,18 @@ void ClientConnection::handle(const Messages::WebContentServer::Paint& message) did_misbehave("WebContentServer::Paint: Cannot create Gfx::Bitmap wrapper around SharedBuffer"); return; } - m_page_host->paint(message.content_rect(), *shared_bitmap); - post_message(Messages::WebContentClient::DidPaint(message.content_rect(), message.shbuf_id())); + + m_pending_paint_requests.append({ message.content_rect(), shared_bitmap.release_nonnull() }); + m_paint_flush_timer->start(); +} + +void ClientConnection::flush_pending_paint_requests() +{ + for (auto& pending_paint : m_pending_paint_requests) { + m_page_host->paint(pending_paint.content_rect, *pending_paint.bitmap); + post_message(Messages::WebContentClient::DidPaint(pending_paint.content_rect, pending_paint.bitmap->shbuf_id())); + } + m_pending_paint_requests.clear(); } void ClientConnection::handle(const Messages::WebContentServer::MouseDown& message) diff --git a/Services/WebContent/ClientConnection.h b/Services/WebContent/ClientConnection.h index 5ee492132a..b2981e6be5 100644 --- a/Services/WebContent/ClientConnection.h +++ b/Services/WebContent/ClientConnection.h @@ -58,7 +58,16 @@ private: virtual void handle(const Messages::WebContentServer::MouseMove&) override; virtual void handle(const Messages::WebContentServer::MouseUp&) override; + void flush_pending_paint_requests(); + NonnullOwnPtr m_page_host; + + struct PaintRequest { + Gfx::IntRect content_rect; + NonnullRefPtr bitmap; + }; + Vector m_pending_paint_requests; + RefPtr m_paint_flush_timer; }; }