LibWeb: Stop storing compositor surfaces as display list resources

Compositor surfaces are only used for nested navigables now. The
display list command already carries the CompositorSurfaceId, but
playback still resolved that id through DisplayListResourceStorage and
WebContent exposed IPC for direct surface updates and clears.

Keep published child surfaces as PaintingSurface entries on the
compositor ContextState and pass that map into Skia display list
playback. Publishing and detaching nested contexts now update the parent
cache entirely inside the compositor, so WebContent no longer needs
update_compositor_surface or clear_compositor_surface messages.
This commit is contained in:
Aliaksandr Kalenik 2026-06-17 19:45:57 +02:00 committed by Alexander Kalenik
parent 91bcd50224
commit 7ca410c66c
17 changed files with 58 additions and 133 deletions

View file

@ -46,16 +46,6 @@ void CompositorContextHandle::clear_video_frame(Painting::VideoFrameResourceId f
m_host.clear_video_frame(m_context_id, frame_id);
}
void CompositorContextHandle::update_compositor_surface(Painting::CompositorSurfaceId surface_id, Gfx::SharedImage&& shared_image)
{
m_host.update_compositor_surface(m_context_id, surface_id, move(shared_image));
}
void CompositorContextHandle::clear_compositor_surface(Painting::CompositorSurfaceId surface_id)
{
m_host.clear_compositor_surface(m_context_id, surface_id);
}
void CompositorContextHandle::update_scroll_state(Painting::ScrollStateSnapshot&& scroll_state_snapshot)
{
m_host.update_scroll_state(m_context_id, move(scroll_state_snapshot));

View file

@ -13,7 +13,6 @@
#include <AK/Types.h>
#include <LibGfx/Point.h>
#include <LibGfx/Rect.h>
#include <LibGfx/SharedImage.h>
#include <LibGfx/Size.h>
#include <LibMedia/Forward.h>
#include <LibWeb/Compositor/Types.h>
@ -39,8 +38,6 @@ public:
void update_visual_context_tree(Painting::AccumulatedVisualContextTree);
void update_video_frame(Painting::VideoFrameResourceId, NonnullRefPtr<Media::VideoFrame const>);
void clear_video_frame(Painting::VideoFrameResourceId);
void update_compositor_surface(Painting::CompositorSurfaceId, Gfx::SharedImage&&);
void clear_compositor_surface(Painting::CompositorSurfaceId);
void update_scroll_state(Painting::ScrollStateSnapshot&&);
void invalidate_wheel_event_listener_state(u64 generation);
AsyncScrollEnqueueResult async_scroll_by(UniqueNodeID expected_document_id, Gfx::FloatPoint position, Gfx::FloatPoint delta_in_device_pixels,
@ -79,8 +76,6 @@ public:
virtual void update_visual_context_tree(CompositorContextId, Painting::AccumulatedVisualContextTree) = 0;
virtual void update_video_frame(CompositorContextId, Painting::VideoFrameResourceId, NonnullRefPtr<Media::VideoFrame const>) = 0;
virtual void clear_video_frame(CompositorContextId, Painting::VideoFrameResourceId) = 0;
virtual void update_compositor_surface(CompositorContextId, Painting::CompositorSurfaceId, Gfx::SharedImage&&) = 0;
virtual void clear_compositor_surface(CompositorContextId, Painting::CompositorSurfaceId) = 0;
virtual void update_scroll_state(CompositorContextId, Painting::ScrollStateSnapshot&&) = 0;
virtual void invalidate_wheel_event_listener_state(CompositorContextId, u64 generation) = 0;
virtual AsyncScrollEnqueueResult async_scroll_by(CompositorContextId, UniqueNodeID expected_document_id, Gfx::FloatPoint position,

View file

@ -3776,8 +3776,8 @@ void Navigable::clear_compositor_surface()
{
if (!m_compositor_surface_id.has_value())
return;
if (auto parent = this->parent(); parent && parent->has_compositor_context())
parent->compositor_context().clear_compositor_surface(*m_compositor_surface_id);
if (has_compositor_context())
compositor_context().set_presentation_mode(Empty {});
m_compositor_surface_id.clear();
}

View file

@ -7,6 +7,7 @@
#define SK_SUPPORT_UNSPANNED_APIS
#include <AK/TemporaryChange.h>
#include <core/SkBitmap.h>
#include <core/SkBlurTypes.h>
#include <core/SkCanvas.h>
@ -57,6 +58,25 @@ DisplayListPlayerSkia::~DisplayListPlayerSkia()
{
}
void DisplayListPlayerSkia::execute(
DisplayList const& display_list,
AccumulatedVisualContextTree const& visual_context_tree,
DisplayListResourceStorage const& resource_storage,
ScrollStateSnapshot const& scroll_state_snapshot,
RefPtr<Gfx::PaintingSurface> surface,
CanvasSurfaceRegistry const* canvas_surface_registry,
CompositorSurfaceMap const* compositor_surfaces)
{
TemporaryChange compositor_surfaces_change { m_compositor_surfaces, compositor_surfaces };
DisplayListPlayer::execute(
display_list,
visual_context_tree,
resource_storage,
scroll_state_snapshot,
move(surface),
canvas_surface_registry);
}
static SkRRect to_skia_rrect(auto const& rect, Gfx::CornerRadii const& corner_radii)
{
SkRRect rrect;
@ -207,7 +227,14 @@ void DisplayListPlayerSkia::play_command(FillRect const& command)
void DisplayListPlayerSkia::play_command(DrawCompositorSurface const& command)
{
auto image = resource_storage().skia_image_for_compositor_surface(command.surface_id, m_skia_backend_context);
if (!m_compositor_surfaces)
return;
auto compositor_surface = m_compositor_surfaces->get(command.surface_id);
if (!compositor_surface.has_value())
return;
auto image = compositor_surface.value()->sk_image_snapshot<sk_sp<SkImage>>();
if (!image)
return;

View file

@ -7,6 +7,8 @@
#pragma once
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/NonnullRefPtr.h>
#include <AK/RefPtr.h>
#include <LibGfx/Forward.h>
#include <LibWeb/Painting/DisplayList.h>
@ -20,10 +22,22 @@ namespace Web::Painting {
class WEB_API DisplayListPlayerSkia final : public DisplayListPlayer {
public:
using CompositorSurfaceMap = HashMap<CompositorSurfaceId, NonnullRefPtr<Gfx::PaintingSurface>>;
DisplayListPlayerSkia();
explicit DisplayListPlayerSkia(RefPtr<Gfx::SkiaBackendContext>);
~DisplayListPlayerSkia();
using DisplayListPlayer::execute;
void execute(
DisplayList const&,
AccumulatedVisualContextTree const&,
DisplayListResourceStorage const&,
ScrollStateSnapshot const&,
RefPtr<Gfx::PaintingSurface>,
CanvasSurfaceRegistry const*,
CompositorSurfaceMap const*);
void flush(Gfx::PaintingSurface&) override;
void flush_async(Gfx::PaintingSurface&, Function<void()>&&);
void paint_scrollbar(Gfx::PaintingSurface&, PaintScrollBar const&);
@ -46,6 +60,7 @@ private:
ReadonlySpan<float> gradient_positions(DisplayListGradientColorStops) const;
RefPtr<Gfx::SkiaBackendContext> m_skia_backend_context;
CompositorSurfaceMap const* m_compositor_surfaces { nullptr };
};
}

View file

@ -6,7 +6,6 @@
#include <LibGfx/Filter.h>
#include <LibGfx/Font/Font.h>
#include <LibGfx/SharedImageBuffer.h>
#include <LibGfx/SkiaBackendContext.h>
#include <LibGfx/SkiaUtils.h>
#include <LibMedia/VideoFrame.h>
@ -364,31 +363,4 @@ void DisplayListResourceStorage::clear_video_frame(VideoFrameResourceId frame_id
m_video_frames.set(frame_id.value(), nullptr);
}
void DisplayListResourceStorage::update_compositor_surface(CompositorSurfaceId surface_id, Gfx::SharedImage&& shared_image)
{
auto shared_image_buffer = Gfx::SharedImageBuffer::import_from_shared_image(move(shared_image));
m_compositor_surfaces.set(surface_id.value(), make<DisplayListStoredImageFrameResource>(Gfx::DecodedImageFrame { *shared_image_buffer.bitmap() }));
}
void DisplayListResourceStorage::clear_compositor_surface(CompositorSurfaceId surface_id)
{
m_compositor_surfaces.remove(surface_id.value());
}
Optional<Gfx::DecodedImageFrame const&> DisplayListResourceStorage::compositor_surface(CompositorSurfaceId id) const
{
auto frame = m_compositor_surfaces.get(id.value());
if (!frame.has_value())
return {};
return frame.value()->frame;
}
sk_sp<SkImage> DisplayListResourceStorage::skia_image_for_compositor_surface(CompositorSurfaceId id, RefPtr<Gfx::SkiaBackendContext> const& skia_backend_context) const
{
auto resource = m_compositor_surfaces.get(id.value());
if (!resource.has_value())
return nullptr;
return skia_image_for_stored_image_frame(*resource.value(), skia_backend_context);
}
}

View file

@ -13,7 +13,6 @@
#include <AK/Noncopyable.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Optional.h>
#include <AK/RefPtr.h>
#include <AK/Span.h>
#include <AK/Vector.h>
@ -106,8 +105,6 @@ public:
void retain_only(DisplayListResourceSet const&);
void update_video_frame(VideoFrameResourceId, NonnullRefPtr<Media::VideoFrame const>);
void clear_video_frame(VideoFrameResourceId);
void update_compositor_surface(CompositorSurfaceId, Gfx::SharedImage&&);
void clear_compositor_surface(CompositorSurfaceId);
Gfx::Font const& font(FontResourceId id) const { return *m_fonts.get(id.value()).value(); }
Gfx::DecodedImageFrame const& image_frame(ImageFrameResourceId) const;
@ -116,8 +113,6 @@ public:
DisplayListResource const& display_list_resource(DisplayListResourceId id) const { return m_display_lists.get(id.value()).value(); }
DisplayList const& display_list(DisplayListResourceId id) const { return *display_list_resource(id).display_list; }
AccumulatedVisualContextTree const& display_list_visual_context_tree(DisplayListResourceId id) const { return display_list_resource(id).visual_context_tree; }
Optional<Gfx::DecodedImageFrame const&> compositor_surface(CompositorSurfaceId) const;
sk_sp<SkImage> skia_image_for_compositor_surface(CompositorSurfaceId, RefPtr<Gfx::SkiaBackendContext> const&) const;
private:
void collect_referenced_resources(ReadonlyBytes command_bytes, DisplayListResourceSet&) const;
@ -126,7 +121,6 @@ private:
HashMap<u64, NonnullOwnPtr<DisplayListStoredImageFrameResource>> m_image_frames;
HashMap<u64, RefPtr<Media::VideoFrame const>> m_video_frames;
HashMap<u64, DisplayListResource> m_display_lists;
HashMap<u64, NonnullOwnPtr<DisplayListStoredImageFrameResource>> m_compositor_surfaces;
HashMap<u64, size_t> m_font_cache_reference_counts;
HashMap<u64, size_t> m_image_frame_cache_reference_counts;

View file

@ -157,23 +157,6 @@ void CompositorState::clear_video_frame(Web::Compositor::CompositorContextId con
present_current_frame(context_id, *context);
}
void CompositorState::update_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id, Gfx::SharedImage&& shared_image)
{
auto* context = context_if_present(context_id);
VERIFY(context);
context->update_compositor_surface(surface_id, move(shared_image));
present_current_frame(context_id, *context);
}
void CompositorState::clear_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id)
{
auto* context = context_if_present(context_id);
VERIFY(context);
context->clear_compositor_surface(surface_id);
remove_child_surface(*context, context_id, surface_id);
present_current_frame(context_id, *context);
}
void CompositorState::invalidate_wheel_event_listener_state(Web::Compositor::CompositorContextId context_id, u64 generation)
{
auto* context = context_if_present(context_id);
@ -516,17 +499,6 @@ void CompositorState::detach_from_parent_surface(Web::Compositor::CompositorCont
present_current_frame(published_surface->parent_context_id, *parent_context);
}
void CompositorState::remove_child_surface(ContextState& context, Web::Compositor::CompositorContextId parent_context_id, Web::Painting::CompositorSurfaceId surface_id)
{
auto child_context_id = context.take_child_context_for_surface(surface_id);
if (!child_context_id.has_value())
return;
auto* child_context = context_if_present(*child_context_id);
VERIFY(child_context);
child_context->did_detach_from_parent_surface(parent_context_id, surface_id);
}
void CompositorState::resize_backing_stores_if_needed(Web::Compositor::CompositorContextId context_id, ContextState& context)
{
if (auto publication = context.resize_backing_stores_if_needed(m_skia_backend_context); publication.has_value()) {

View file

@ -84,8 +84,6 @@ public:
void update_scroll_state(Web::Compositor::CompositorContextId, Web::Painting::ScrollStateSnapshot&&);
void update_video_frame(Web::Compositor::CompositorContextId, Web::Painting::VideoFrameResourceId, NonnullRefPtr<Media::VideoFrame const>);
void clear_video_frame(Web::Compositor::CompositorContextId, Web::Painting::VideoFrameResourceId);
void update_compositor_surface(Web::Compositor::CompositorContextId, Web::Painting::CompositorSurfaceId, Gfx::SharedImage&&);
void clear_compositor_surface(Web::Compositor::CompositorContextId, Web::Painting::CompositorSurfaceId);
void invalidate_wheel_event_listener_state(Web::Compositor::CompositorContextId, u64 generation);
bool handle_mouse_event(Web::Compositor::CompositorContextId, Web::MouseEvent const&);
bool dispatch_mouse_event_to_web_content(Web::Compositor::CompositorContextId, Web::MouseEvent const&);
@ -120,7 +118,6 @@ private:
ContextState* context_if_present(Web::Compositor::CompositorContextId);
ContextState const* context_if_present(Web::Compositor::CompositorContextId) const;
void detach_from_parent_surface(Web::Compositor::CompositorContextId, ContextState&);
void remove_child_surface(ContextState&, Web::Compositor::CompositorContextId parent_context_id, Web::Painting::CompositorSurfaceId);
void schedule_backing_store_shrink(Web::Compositor::CompositorContextId, ContextState&);
void shrink_backing_stores_after_resize(Web::Compositor::CompositorContextId);
void resize_backing_stores_if_needed(Web::Compositor::CompositorContextId, ContextState&);

View file

@ -5,7 +5,6 @@
#include <LibGfx/Point.h>
#include <LibGfx/Rect.h>
#include <LibGfx/ShareableBitmap.h>
#include <LibGfx/SharedImage.h>
#include <LibGfx/Size.h>
#include <LibMedia/VideoFrame.h>
#include <LibWeb/Compositor/Types.h>
@ -30,9 +29,6 @@ endpoint CompositorWebContentServer
update_video_frame(Web::Compositor::CompositorContextId context_id, Web::Painting::VideoFrameResourceId frame_id, NonnullRefPtr<Media::VideoFrame const> frame) =|
clear_video_frame(Web::Compositor::CompositorContextId context_id, Web::Painting::VideoFrameResourceId frame_id) =|
update_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id, Gfx::SharedImage shared_image) =|
clear_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id) =|
create_canvas_2d_context(Gfx::IntSize size, bool alpha) => (bool success, Web::Painting::CanvasId canvas_id)
update_canvas_2d_commands(Web::Painting::CanvasId canvas_id, Gfx::CanvasCommandList commands) =|
destroy_canvas_context(Web::Painting::CanvasId canvas_id) =|

View file

@ -106,18 +106,6 @@ void ConnectionFromWebContent::clear_video_frame(Web::Compositor::CompositorCont
m_compositor_state->clear_video_frame(context_id, frame_id);
}
void ConnectionFromWebContent::update_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id, Gfx::SharedImage shared_image)
{
verify_context_is_owned_by_this_connection(context_id);
m_compositor_state->update_compositor_surface(context_id, surface_id, move(shared_image));
}
void ConnectionFromWebContent::clear_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id)
{
verify_context_is_owned_by_this_connection(context_id);
m_compositor_state->clear_compositor_surface(context_id, surface_id);
}
Messages::CompositorWebContentServer::CreateCanvas2dContextResponse ConnectionFromWebContent::create_canvas_2d_context(Gfx::IntSize size, bool alpha)
{
auto canvas_id = m_canvas_host.create_2d_context(size, alpha);

View file

@ -44,8 +44,6 @@ private:
virtual void update_scroll_state(Web::Compositor::CompositorContextId, Web::Painting::ScrollStateSnapshot) override;
virtual void update_video_frame(Web::Compositor::CompositorContextId, Web::Painting::VideoFrameResourceId, NonnullRefPtr<Media::VideoFrame const>) override;
virtual void clear_video_frame(Web::Compositor::CompositorContextId, Web::Painting::VideoFrameResourceId) override;
virtual void update_compositor_surface(Web::Compositor::CompositorContextId, Web::Painting::CompositorSurfaceId, Gfx::SharedImage) override;
virtual void clear_compositor_surface(Web::Compositor::CompositorContextId, Web::Painting::CompositorSurfaceId) override;
virtual Messages::CompositorWebContentServer::CreateCanvas2dContextResponse create_canvas_2d_context(Gfx::IntSize, bool) override;
virtual void update_canvas_2d_commands(Web::Painting::CanvasId, Gfx::CanvasCommandList) override;
virtual void destroy_canvas_context(Web::Painting::CanvasId) override;

View file

@ -13,6 +13,7 @@
#include <LibGfx/Color.h>
#include <LibGfx/PainterSkia.h>
#include <LibGfx/PaintingSurface.h>
#include <LibGfx/SharedImageBuffer.h>
#include <LibWeb/Page/InputEvent.h>
#include <LibWeb/Painting/DisplayListPlayerSkia.h>
@ -260,12 +261,13 @@ void ContextState::clear_video_frame(Web::Painting::VideoFrameResourceId frame_i
void ContextState::update_compositor_surface(Web::Painting::CompositorSurfaceId surface_id, Gfx::SharedImage&& shared_image)
{
m_display_list_resource_storage.update_compositor_surface(surface_id, move(shared_image));
auto shared_image_buffer = Gfx::SharedImageBuffer::import_from_shared_image(move(shared_image));
m_compositor_surfaces.set(surface_id, Gfx::PaintingSurface::wrap_bitmap(*shared_image_buffer.bitmap()));
}
void ContextState::clear_compositor_surface(Web::Painting::CompositorSurfaceId surface_id)
{
m_display_list_resource_storage.clear_compositor_surface(surface_id);
m_compositor_surfaces.remove(surface_id);
}
Gfx::SharedImage ContextState::snapshot_front_store()
@ -879,7 +881,14 @@ Web::Painting::AccumulatedVisualContextTree const& ContextState::visual_context_
void ContextState::paint_current_display_list(Web::Painting::DisplayListPlayerSkia& display_list_player, Gfx::PaintingSurface& surface)
{
VERIFY(m_display_list);
display_list_player.execute(*m_display_list, visual_context_tree_for_compositing(), m_display_list_resource_storage, m_scroll_state_snapshot, surface, &m_canvas_surface_registry);
display_list_player.execute(
*m_display_list,
visual_context_tree_for_compositing(),
m_display_list_resource_storage,
m_scroll_state_snapshot,
surface,
&m_canvas_surface_registry,
&m_compositor_surfaces);
m_viewport_scrollbar_controller.paint(surface, display_list_player, m_scroll_state_snapshot);
}

View file

@ -191,6 +191,7 @@ private:
Optional<Web::Painting::AccumulatedVisualContextTree> m_visual_context_tree;
mutable Optional<Web::Painting::AccumulatedVisualContextTree> m_visual_context_tree_for_compositing;
Web::Painting::DisplayListResourceStorage m_display_list_resource_storage;
HashMap<Web::Painting::CompositorSurfaceId, NonnullRefPtr<Gfx::PaintingSurface>> m_compositor_surfaces;
Web::Painting::ScrollStateSnapshot m_scroll_state_snapshot;
BackingStoreManager m_backing_store_manager;

View file

@ -79,20 +79,6 @@ void CompositorConnection::clear_video_frame(Web::Compositor::CompositorContextI
async_clear_video_frame(context_id, frame_id);
}
void CompositorConnection::update_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id, Gfx::SharedImage const& shared_image)
{
if (!can_send_message_to_compositor())
return;
async_update_compositor_surface(context_id, surface_id, shared_image);
}
void CompositorConnection::clear_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id)
{
if (!can_send_message_to_compositor())
return;
async_clear_compositor_surface(context_id, surface_id);
}
Optional<Web::Painting::CanvasId> CompositorConnection::create_canvas_2d_context(Gfx::IntSize size, bool alpha)
{
if (!can_send_message_to_compositor())

View file

@ -16,7 +16,6 @@
#include <LibGfx/Point.h>
#include <LibGfx/Rect.h>
#include <LibGfx/ShareableBitmap.h>
#include <LibGfx/SharedImage.h>
#include <LibGfx/Size.h>
#include <LibIPC/ConnectionToServer.h>
#include <LibMedia/Forward.h>
@ -45,8 +44,6 @@ public:
void update_scroll_state(Web::Compositor::CompositorContextId, Web::Painting::ScrollStateSnapshot const&);
void update_video_frame(Web::Compositor::CompositorContextId, Web::Painting::VideoFrameResourceId, NonnullRefPtr<Media::VideoFrame const> const&);
void clear_video_frame(Web::Compositor::CompositorContextId, Web::Painting::VideoFrameResourceId);
void update_compositor_surface(Web::Compositor::CompositorContextId, Web::Painting::CompositorSurfaceId, Gfx::SharedImage const&);
void clear_compositor_surface(Web::Compositor::CompositorContextId, Web::Painting::CompositorSurfaceId);
Optional<Web::Painting::CanvasId> create_canvas_2d_context(Gfx::IntSize, bool alpha);
void update_canvas_2d_commands(Web::Painting::CanvasId, Gfx::CanvasCommandList const&);
void destroy_canvas_context(Web::Painting::CanvasId);

View file

@ -208,18 +208,6 @@ private:
connection->clear_video_frame(context_id, frame_id);
}
virtual void update_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id, Gfx::SharedImage&& shared_image) override
{
if (auto* connection = compositor_connection())
connection->update_compositor_surface(context_id, surface_id, shared_image);
}
virtual void clear_compositor_surface(Web::Compositor::CompositorContextId context_id, Web::Painting::CompositorSurfaceId surface_id) override
{
if (auto* connection = compositor_connection())
connection->clear_compositor_surface(context_id, surface_id);
}
virtual void update_scroll_state(Web::Compositor::CompositorContextId context_id, Web::Painting::ScrollStateSnapshot&& scroll_state_snapshot) override
{
if (auto* connection = compositor_connection())