2026-05-20 13:14:36 -03:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2026-present, the Ladybird developers.
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
*/
|
|
|
|
|
|
2026-05-24 16:57:32 -03:00
|
|
|
#include <AK/NonnullOwnPtr.h>
|
2026-06-15 14:29:43 -03:00
|
|
|
#include <AK/Optional.h>
|
|
|
|
|
#include <LibGfx/CanvasCommandList.h>
|
2026-05-20 13:14:36 -03:00
|
|
|
#include <LibGfx/PaintingSurface.h>
|
|
|
|
|
#include <LibMedia/VideoFrame.h>
|
2026-05-24 16:57:32 -03:00
|
|
|
#include <LibWeb/Compositor/CompositorHost.h>
|
2026-06-15 14:29:43 -03:00
|
|
|
#include <LibWeb/HTML/Canvas/RemoteCanvas2DTransport.h>
|
|
|
|
|
#include <LibWeb/WebGL/RemoteWebGLTransport.h>
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
#include <WebContent/CompositorConnection.h>
|
|
|
|
|
#include <WebContent/ConnectionFromClient.h>
|
2026-05-20 13:14:36 -03:00
|
|
|
#include <WebContent/WebContentCompositorHost.h>
|
|
|
|
|
|
|
|
|
|
namespace WebContent {
|
|
|
|
|
|
2026-06-15 14:29:43 -03:00
|
|
|
class WebContentRemoteWebGLTransport final : public Web::WebGL::RemoteWebGLTransport {
|
|
|
|
|
public:
|
|
|
|
|
explicit WebContentRemoteWebGLTransport(NonnullRefPtr<CompositorConnection> connection)
|
|
|
|
|
: m_connection(move(connection))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
virtual CreateResult create_context(Web::WebGL::WebGLVersion webgl_version, Gfx::IntSize initial_size, bool depth, bool stencil, bool antialias) override
|
|
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
VERIFY(!m_canvas_id.has_value());
|
2026-06-15 14:29:43 -03:00
|
|
|
CreateResult result;
|
|
|
|
|
auto canvas_id = m_connection->create_webgl_context(webgl_version, initial_size, depth, stencil, antialias, result.supported_extensions);
|
|
|
|
|
if (canvas_id.has_value()) {
|
|
|
|
|
result.success = true;
|
2026-06-15 14:37:51 -03:00
|
|
|
m_canvas_id = *canvas_id;
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual Optional<Web::Painting::CanvasId> canvas_id() const override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
return m_canvas_id;
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual void destroy_context() override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return;
|
|
|
|
|
m_connection->destroy_canvas_context(*m_canvas_id);
|
|
|
|
|
m_canvas_id.clear();
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual void send_commands(ByteBuffer const& commands, Vector<Gfx::DecodedImageFrame> const& bitmaps) override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return;
|
|
|
|
|
m_connection->send_webgl_commands(*m_canvas_id, commands, bitmaps);
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual void present_canvas(bool preserve_drawing_buffer) override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return;
|
|
|
|
|
m_connection->present_webgl_canvas(*m_canvas_id, preserve_drawing_buffer);
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual ByteBuffer sync_call(ByteBuffer request) override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return {};
|
|
|
|
|
return m_connection->webgl_sync_call(*m_canvas_id, move(request));
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual Web::WebGL::ReadPixelsResult read_pixels_robust_angle(Web::WebGL::GLint x, Web::WebGL::GLint y, Web::WebGL::GLsizei width, Web::WebGL::GLsizei height, Web::WebGL::GLenum format, Web::WebGL::GLenum type, Web::WebGL::GLsizei buf_size, Core::AnonymousBuffer pixels) override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return {};
|
|
|
|
|
return m_connection->read_webgl_pixels(*m_canvas_id, x, y, width, height, format, type, buf_size, pixels);
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual void read_buffer_sub_data(Web::WebGL::GLenum target, Web::WebGL::GLintptr offset, Web::WebGL::GLintptr size, Core::AnonymousBuffer data) override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return;
|
|
|
|
|
m_connection->read_webgl_buffer_sub_data(*m_canvas_id, target, offset, size, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual Gfx::ShareableBitmap read_back_drawing_buffer(Gfx::IntRect const& rect) override
|
|
|
|
|
{
|
|
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return {};
|
|
|
|
|
return m_connection->get_canvas_pixels(*m_canvas_id, rect);
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<CompositorConnection> m_connection;
|
2026-06-15 14:37:51 -03:00
|
|
|
Optional<Web::Painting::CanvasId> m_canvas_id;
|
2026-06-15 14:29:43 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class WebContentRemoteCanvas2DTransport final : public Web::HTML::RemoteCanvas2DTransport {
|
|
|
|
|
public:
|
|
|
|
|
explicit WebContentRemoteCanvas2DTransport(NonnullRefPtr<CompositorConnection> connection)
|
|
|
|
|
: m_connection(move(connection))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual bool create_context(Gfx::IntSize size, bool alpha) override
|
|
|
|
|
{
|
|
|
|
|
VERIFY(!m_canvas_id.has_value());
|
|
|
|
|
auto canvas_id = m_connection->create_canvas_2d_context(size, alpha);
|
|
|
|
|
if (!canvas_id.has_value())
|
|
|
|
|
return false;
|
|
|
|
|
m_canvas_id = *canvas_id;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual Optional<Web::Painting::CanvasId> canvas_id() const override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
return m_canvas_id;
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual void destroy_context() override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return;
|
|
|
|
|
m_connection->destroy_canvas_context(*m_canvas_id);
|
|
|
|
|
m_canvas_id.clear();
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-18 18:12:08 -03:00
|
|
|
virtual void update_commands(Gfx::CanvasCommandList const& commands, bool commit) override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return;
|
2026-06-18 18:12:08 -03:00
|
|
|
m_connection->update_canvas_2d_commands(*m_canvas_id, commands, commit);
|
2026-06-15 14:29:43 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-15 14:37:51 -03:00
|
|
|
virtual RefPtr<Gfx::Bitmap> read_back_pixels(Gfx::IntRect const& rect) override
|
2026-06-15 14:29:43 -03:00
|
|
|
{
|
2026-06-15 14:37:51 -03:00
|
|
|
if (!m_canvas_id.has_value())
|
|
|
|
|
return nullptr;
|
|
|
|
|
auto shareable_bitmap = m_connection->get_canvas_pixels(*m_canvas_id, rect);
|
2026-06-15 14:29:43 -03:00
|
|
|
if (!shareable_bitmap.is_valid())
|
|
|
|
|
return nullptr;
|
|
|
|
|
return shareable_bitmap.bitmap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NonnullRefPtr<CompositorConnection> m_connection;
|
2026-06-15 14:37:51 -03:00
|
|
|
Optional<Web::Painting::CanvasId> m_canvas_id;
|
2026-06-15 14:29:43 -03:00
|
|
|
};
|
|
|
|
|
|
2026-05-24 17:25:20 -03:00
|
|
|
class WebContentCompositorHost final : public Web::Compositor::CompositorHost {
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
public:
|
2026-05-24 17:25:20 -03:00
|
|
|
explicit WebContentCompositorHost(ConnectionFromClient& client)
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
: m_client(client)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2026-06-15 14:29:43 -03:00
|
|
|
virtual RefPtr<Web::WebGL::RemoteWebGLTransport> create_webgl_transport() override
|
|
|
|
|
{
|
|
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
return adopt_ref(*new WebContentRemoteWebGLTransport(*connection));
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual RefPtr<Web::HTML::RemoteCanvas2DTransport> create_canvas_2d_transport() override
|
|
|
|
|
{
|
|
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
return adopt_ref(*new WebContentRemoteCanvas2DTransport(*connection));
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
virtual void destroy_context(Web::Compositor::CompositorContextId context_id) override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
connection->destroy_context(context_id);
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
m_client.did_destroy_compositor_context(context_id);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-18 01:10:37 -03:00
|
|
|
virtual void set_parent_context(Web::Compositor::CompositorContextId context_id, Optional<Web::Compositor::CompositorContextId> parent_context_id) override
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
2026-06-18 01:10:37 -03:00
|
|
|
connection->set_parent_context(context_id, parent_context_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void stop_presenting_to_client(Web::Compositor::CompositorContextId context_id) override
|
|
|
|
|
{
|
|
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
connection->stop_presenting_to_client(context_id);
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
2026-05-27 12:51:03 -03:00
|
|
|
virtual void update_display_list(Web::Compositor::CompositorContextId context_id, NonnullRefPtr<Web::Painting::DisplayList> display_list, Web::Painting::AccumulatedVisualContextTree visual_context_tree, Web::Painting::DisplayListResourceTransaction&& resource_transaction, Web::Painting::ScrollStateSnapshot&& scroll_state_snapshot) override
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
2026-05-27 12:51:03 -03:00
|
|
|
connection->update_display_list(context_id, display_list, visual_context_tree, resource_transaction, scroll_state_snapshot);
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
2026-06-02 15:39:40 -03:00
|
|
|
virtual void update_visual_context_tree(Web::Compositor::CompositorContextId context_id, Web::Painting::AccumulatedVisualContextTree visual_context_tree) override
|
|
|
|
|
{
|
|
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
connection->update_visual_context_tree(context_id, visual_context_tree);
|
|
|
|
|
}
|
|
|
|
|
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
virtual void update_video_frame(Web::Compositor::CompositorContextId context_id, Web::Painting::VideoFrameResourceId frame_id, NonnullRefPtr<Media::VideoFrame const> frame) override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
connection->update_video_frame(context_id, frame_id, frame);
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void clear_video_frame(Web::Compositor::CompositorContextId context_id, Web::Painting::VideoFrameResourceId frame_id) override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
connection->clear_video_frame(context_id, frame_id);
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void update_scroll_state(Web::Compositor::CompositorContextId context_id, Web::Painting::ScrollStateSnapshot&& scroll_state_snapshot) override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
connection->update_scroll_state(context_id, scroll_state_snapshot);
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void invalidate_wheel_event_listener_state(Web::Compositor::CompositorContextId context_id, u64 generation) override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
connection->invalidate_wheel_event_listener_state(context_id, generation);
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual Web::Compositor::AsyncScrollEnqueueResult async_scroll_by(Web::Compositor::CompositorContextId context_id, Web::UniqueNodeID expected_document_id, Gfx::FloatPoint position,
|
|
|
|
|
Gfx::FloatPoint delta_in_device_pixels, Gfx::IntRect viewport_rect, Web::Compositor::AsyncScrollOperationTracking operation_tracking) override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
return connection->async_scroll_by(context_id, expected_document_id, position, delta_in_device_pixels, viewport_rect, operation_tracking);
|
|
|
|
|
return {};
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool should_defer_main_thread_present_for_async_scroll(Web::Compositor::CompositorContextId context_id) const override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
return connection->should_defer_main_thread_present_for_async_scroll(context_id);
|
|
|
|
|
return false;
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual Web::Compositor::PendingAsyncScrollUpdates take_pending_async_scroll_updates(Web::Compositor::CompositorContextId context_id) override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
return connection->take_pending_async_scroll_updates(context_id);
|
|
|
|
|
return {};
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
2026-05-27 14:26:14 -03:00
|
|
|
virtual void viewport_size_updated(Web::Compositor::CompositorContextId context_id, Gfx::IntSize viewport_size, Web::Compositor::WindowResizingInProgress window_resize_in_progress) override
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
2026-05-27 14:26:14 -03:00
|
|
|
connection->viewport_size_updated(context_id, viewport_size, window_resize_in_progress);
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void present_frame(Web::Compositor::CompositorContextId context_id, Gfx::IntRect viewport_rect) override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection())
|
|
|
|
|
connection->present_frame(context_id, viewport_rect);
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void request_screenshot(Web::Compositor::CompositorContextId context_id, NonnullRefPtr<Gfx::PaintingSurface> target_surface, Function<void()>&& callback) override
|
|
|
|
|
{
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
if (auto* connection = compositor_connection()) {
|
|
|
|
|
connection->request_screenshot(context_id, move(target_surface), move(callback));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (callback)
|
|
|
|
|
callback();
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
}
|
|
|
|
|
|
LibWeb+LibWebView+WebContent: Recover after Compositor process crashes
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
2026-05-23 22:36:24 -03:00
|
|
|
CompositorConnection* compositor_connection() const
|
LibWebView+WebContent: Add feature-gated Compositor process backend
We are moving toward an architecture where the browser owns a single
process that holds the GPU context, so Skia resources can be shared
across every renderer and WebContent processes can be sandboxed away
from direct GPU access. A dedicated Compositor helper process is the
first step. The earlier commits laid the foundation; this one turns the
helper on as a selectable backend, gated behind
--enable-compositor-process so the existing in-process path stays the
shipping default.
Default topology -- one compositor per WebContent, in-process:
+---------+
| Browser |
+---------+
/ | \
v v v
+---+ +---+ +---+ each WebContent runs its own
|WC | |WC | |WC | CompositorThread on a dedicated
|+C+| |+C+| |+C+| thread, with its own GPU context.
+---+ +---+ +---+
Opt-in topology -- one single-threaded Compositor, shared by all WCs:
+---------+ control +-------------------+
| Browser |<----------->| Compositor |
+---------+ | (single thread, |
/ | \ | single GPU ctx, |
v v v data | shared by all |
[WC] [WC] [WC] ---------->| connected WCs) |
+-------------------+
Three IPC channels carry the work in the opt-in topology. The
existing Browser<->WebContent channel gains context allocation.
A new Browser<->Compositor channel carries context lifetime,
viewport, UI input, and presentation acks plus backing-store and
frame upcalls. A new WebContent<->Compositor channel carries
display lists, scroll state, video, compositor surfaces, async
scrolling, presentation, and screenshots, with upcalls for
delegated input and compositor loss.
2026-05-22 11:17:27 -03:00
|
|
|
{
|
|
|
|
|
return m_client.compositor_process_connection();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ConnectionFromClient& m_client;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
NonnullOwnPtr<Web::Compositor::CompositorHost> create_web_content_compositor_host(ConnectionFromClient& client)
|
2026-05-20 13:14:36 -03:00
|
|
|
{
|
2026-05-24 17:25:20 -03:00
|
|
|
return make<WebContentCompositorHost>(client);
|
2026-05-20 13:14:36 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|