diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index a897569a01..137fa4bc54 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -875,7 +875,6 @@ set(SOURCES Painting/RadioButtonPaintable.cpp Painting/ReplacedElementCommon.cpp Painting/ResolvedCSSFilter.cpp - Painting/VideoFrameSource.cpp Painting/ResizeHandle.cpp Painting/Scrollbar.cpp Painting/ScrollFrame.cpp diff --git a/Libraries/LibWeb/Compositor/CompositorThread.cpp b/Libraries/LibWeb/Compositor/CompositorThread.cpp index 9e5a5cd659..7360c8e7e7 100644 --- a/Libraries/LibWeb/Compositor/CompositorThread.cpp +++ b/Libraries/LibWeb/Compositor/CompositorThread.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,15 @@ struct UpdateScrollStateCommand { Painting::ScrollStateSnapshot scroll_state_snapshot; }; +struct UpdateVideoFrameCommand { + Painting::VideoFrameResourceId frame_id; + NonnullRefPtr frame; +}; + +struct ClearVideoFrameCommand { + Painting::VideoFrameResourceId frame_id; +}; + struct UpdateCompositorSurfaceCommand { Painting::CompositorSurfaceId surface_id; Gfx::SharedImage shared_image; @@ -88,8 +98,8 @@ struct ScreenshotCommand { }; using CompositorCommand = Variant; + UpdateScrollStateCommand, UpdateVideoFrameCommand, ClearVideoFrameCommand, UpdateCompositorSurfaceCommand, + ClearCompositorSurfaceCommand, ViewportSizeUpdatedCommand, PresentFrameCommand, ScreenshotCommand>; struct CompositorCommandEnvelope { CompositorContextId context_id; @@ -610,6 +620,12 @@ public: } } }, + [&context](UpdateVideoFrameCommand& cmd) { + context.display_list_resource_storage.update_video_frame(cmd.frame_id, move(cmd.frame)); + }, + [&context](ClearVideoFrameCommand& cmd) { + context.display_list_resource_storage.clear_video_frame(cmd.frame_id); + }, [&context](UpdateCompositorSurfaceCommand& cmd) { context.display_list_resource_storage.update_compositor_surface(cmd.surface_id, move(cmd.shared_image)); }, @@ -1304,6 +1320,16 @@ void CompositorThread::Context::update_display_list( m_thread_data->enqueue_command(m_context_id, UpdateDisplayListCommand { move(display_list), move(resource_transaction), move(scroll_state_snapshot) }); } +void CompositorThread::Context::update_video_frame(Painting::VideoFrameResourceId frame_id, NonnullRefPtr frame) +{ + m_thread_data->enqueue_command(m_context_id, UpdateVideoFrameCommand { frame_id, move(frame) }); +} + +void CompositorThread::Context::clear_video_frame(Painting::VideoFrameResourceId frame_id) +{ + m_thread_data->enqueue_command(m_context_id, ClearVideoFrameCommand { frame_id }); +} + void CompositorThread::Context::update_compositor_surface(Painting::CompositorSurfaceId surface_id, Gfx::SharedImage&& shared_image) { m_thread_data->enqueue_command(m_context_id, UpdateCompositorSurfaceCommand { surface_id, move(shared_image) }); diff --git a/Libraries/LibWeb/Compositor/CompositorThread.h b/Libraries/LibWeb/Compositor/CompositorThread.h index c4d708499a..14beacf3c0 100644 --- a/Libraries/LibWeb/Compositor/CompositorThread.h +++ b/Libraries/LibWeb/Compositor/CompositorThread.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,8 @@ public: void set_presentation_mode(PresentationMode); void update_display_list(NonnullRefPtr, Painting::DisplayListResourceTransaction&&, Painting::ScrollStateSnapshot&&); + void update_video_frame(Painting::VideoFrameResourceId, NonnullRefPtr); + 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&&); diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 7f5dc52c33..ecf70cd291 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -50,7 +50,6 @@ class DisplayList; class DisplayListPlayerSkia; class DisplayListRecorder; class DisplayListResourceStorage; -class VideoFrameSource; struct GradientPaintStyle; struct PatternPaintStyle; class ScrollStateSnapshot; diff --git a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index d9e5ab9c5d..5e5ba53552 100644 --- a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -131,6 +131,8 @@ void HTMLMediaElement::finalize() // already cleared. m_controls.clear(); + clear_compositor_video_frame(); + document().page().unregister_media_element({}, unique_id()); } @@ -1549,11 +1551,37 @@ void HTMLMediaElement::set_audio_track_enabled(Badge, GC::Ptrdisable_an_audio_track(audio_track->track_in_playback_manager()); } -Painting::VideoFrameSource& HTMLMediaElement::ensure_video_frame_source() +Painting::VideoFrameResourceId HTMLMediaElement::ensure_video_frame_resource_id() { - if (!m_video_frame_source) - m_video_frame_source = Painting::VideoFrameSource::create(); - return *m_video_frame_source; + if (!m_video_frame_resource_id.has_value()) + m_video_frame_resource_id = Painting::allocate_video_frame_resource_id(); + return *m_video_frame_resource_id; +} + +void HTMLMediaElement::update_compositor_video_frame(NonnullRefPtr frame) +{ + auto frame_id = ensure_video_frame_resource_id(); + if (auto navigable = document().navigable(); navigable && navigable->has_compositor_context()) + navigable->compositor_context().update_video_frame(frame_id, move(frame)); +} + +void HTMLMediaElement::clear_compositor_video_frame() +{ + if (!m_video_frame_resource_id.has_value()) + return; + if (auto navigable = document().navigable(); navigable && navigable->has_compositor_context()) + navigable->compositor_context().clear_video_frame(*m_video_frame_resource_id); +} + +void HTMLMediaElement::update_current_video_frame() +{ + if (auto current_frame = m_selected_video_track_sink->current_frame()) + update_compositor_video_frame(NonnullRefPtr { *current_frame }); + else + clear_compositor_video_frame(); + + auto intrinsic_dimensions_changed = update_intrinsic_video_dimensions(); + set_needs_repaint(intrinsic_dimensions_changed ? InvalidateDisplayList::Yes : InvalidateDisplayList::No); } void HTMLMediaElement::set_selected_video_track(Badge, GC::Ptr video_track) @@ -1563,8 +1591,7 @@ void HTMLMediaElement::set_selected_video_track(Badge, GC::Ptrvideo_tracks().contains_slow(video_track->track_in_playback_manager())) return; - if (m_video_frame_source) - m_video_frame_source->clear(); + clear_compositor_video_frame(); auto previous_track = m_selected_video_track; @@ -1573,12 +1600,7 @@ void HTMLMediaElement::set_selected_video_track(Badge, GC::Ptrget_or_create_the_displaying_video_sink_for_track(video_track->track_in_playback_manager()); auto sink_update_result = m_selected_video_track_sink->update(); if (sink_update_result == Media::DisplayingVideoSinkUpdateResult::NewFrameAvailable) { - if (auto current_frame = m_selected_video_track_sink->current_frame()) - ensure_video_frame_source().update(move(current_frame)); - else if (m_video_frame_source) - m_video_frame_source->clear(); - update_intrinsic_video_dimensions(); - set_needs_repaint(); + update_current_video_frame(); } else if (auto* video_element = as_if(this)) { auto const& video_data = video_track->track_in_playback_manager().video_data(); video_element->set_intrinsic_video_dimensions(Gfx::Size(video_data.pixel_width, video_data.pixel_height)); @@ -1598,14 +1620,8 @@ void HTMLMediaElement::update_video_frame_and_timeline() if (m_selected_video_track_sink) { auto sink_update_result = m_selected_video_track_sink->update(); - if (sink_update_result == Media::DisplayingVideoSinkUpdateResult::NewFrameAvailable) { - if (auto current_frame = m_selected_video_track_sink->current_frame()) - ensure_video_frame_source().update(move(current_frame)); - else if (m_video_frame_source) - m_video_frame_source->clear(); - update_intrinsic_video_dimensions(); - set_needs_repaint(); - } + if (sink_update_result == Media::DisplayingVideoSinkUpdateResult::NewFrameAvailable) + update_current_video_frame(); } // Wait for the seek to complete before updating the timestamp, otherwise we'll display the timestamp from @@ -2008,6 +2024,7 @@ void HTMLMediaElement::forget_media_resource_specific_tracks() m_audio_tracks->remove_all_tracks(); m_video_tracks->remove_all_tracks(); m_playback_manager.clear(); + clear_compositor_video_frame(); // NB: At this point, we no longer have any selected tracks to derive the video dimensions from. update_intrinsic_video_dimensions(); diff --git a/Libraries/LibWeb/HTML/HTMLMediaElement.h b/Libraries/LibWeb/HTML/HTMLMediaElement.h index 6224ea0961..e5cf68cf27 100644 --- a/Libraries/LibWeb/HTML/HTMLMediaElement.h +++ b/Libraries/LibWeb/HTML/HTMLMediaElement.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -21,7 +22,7 @@ #include #include #include -#include +#include #include #include @@ -170,9 +171,10 @@ public: RefPtr const& selected_video_track_sink() const { return m_selected_video_track_sink; } - Painting::VideoFrameSource& ensure_video_frame_source(); + Painting::VideoFrameResourceId ensure_video_frame_resource_id(); + Optional video_frame_resource_id() const { return m_video_frame_resource_id; } - virtual void update_intrinsic_video_dimensions() { } + virtual bool update_intrinsic_video_dimensions() { return false; } virtual void update_natural_dimensions() { } protected: @@ -245,6 +247,9 @@ private: void volume_or_muted_attribute_changed(); void update_volume(); + void update_compositor_video_frame(NonnullRefPtr); + void clear_compositor_video_frame(); + void update_current_video_frame(); bool is_eligible_for_autoplay() const; @@ -380,7 +385,7 @@ private: bool m_has_enabled_preferred_audio_track { false }; bool m_has_selected_preferred_video_track { false }; - RefPtr m_video_frame_source; + Optional m_video_frame_resource_id; }; } diff --git a/Libraries/LibWeb/HTML/HTMLVideoElement.cpp b/Libraries/LibWeb/HTML/HTMLVideoElement.cpp index cf8d0c44ad..5577bd366e 100644 --- a/Libraries/LibWeb/HTML/HTMLVideoElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLVideoElement.cpp @@ -138,21 +138,23 @@ u32 HTMLVideoElement::video_height() const return 0; } -void HTMLVideoElement::update_intrinsic_video_dimensions() +bool HTMLVideoElement::update_intrinsic_video_dimensions() { if (selected_video_track_sink() == nullptr) { + auto had_intrinsic_video_dimensions = m_intrinsic_video_dimensions.has_value(); set_intrinsic_video_dimensions({}); - return; + return had_intrinsic_video_dimensions; } auto current_frame = selected_video_track_sink()->current_frame(); if (current_frame == nullptr) - return; + return false; auto current_frame_size = current_frame->size(); if (current_frame_size == m_intrinsic_video_dimensions) - return; + return false; set_intrinsic_video_dimensions(current_frame_size); + return true; } void HTMLVideoElement::update_natural_dimensions() diff --git a/Libraries/LibWeb/HTML/HTMLVideoElement.h b/Libraries/LibWeb/HTML/HTMLVideoElement.h index 09d026e139..5ba9882743 100644 --- a/Libraries/LibWeb/HTML/HTMLVideoElement.h +++ b/Libraries/LibWeb/HTML/HTMLVideoElement.h @@ -38,7 +38,7 @@ public: u32 video_width() const; u32 video_height() const; - virtual void update_intrinsic_video_dimensions() override; + virtual bool update_intrinsic_video_dimensions() override; virtual void update_natural_dimensions() override; Optional> natural_media_size() const; Optional natural_element_size() const; diff --git a/Libraries/LibWeb/Painting/DisplayList.h b/Libraries/LibWeb/Painting/DisplayList.h index 93e65faff4..48f004fab5 100644 --- a/Libraries/LibWeb/Painting/DisplayList.h +++ b/Libraries/LibWeb/Painting/DisplayList.h @@ -23,7 +23,6 @@ #include #include #include -#include namespace Web::Painting { @@ -97,7 +96,7 @@ private: virtual void draw_scaled_decoded_image_frame(DrawScaledDecodedImageFrame const&) = 0; virtual void draw_repeated_decoded_image_frame(DrawRepeatedDecodedImageFrame const&) = 0; virtual void draw_compositor_surface(DrawCompositorSurface const&) = 0; - virtual void draw_video_frame_source(DrawVideoFrameSource const&) = 0; + virtual void draw_video_frame(DrawVideoFrame const&) = 0; virtual void save(Save const&) = 0; virtual void save_layer(SaveLayer const&) = 0; virtual void restore(Restore const&) = 0; diff --git a/Libraries/LibWeb/Painting/DisplayListCommand.cpp b/Libraries/LibWeb/Painting/DisplayListCommand.cpp index 7c713abdec..403864623c 100644 --- a/Libraries/LibWeb/Painting/DisplayListCommand.cpp +++ b/Libraries/LibWeb/Painting/DisplayListCommand.cpp @@ -45,7 +45,7 @@ void DrawCompositorSurface::dump(StringBuilder& builder) const builder.appendff(" dst_rect={}", dst_rect); } -void DrawVideoFrameSource::dump(StringBuilder& builder) const +void DrawVideoFrame::dump(StringBuilder& builder) const { builder.appendff(" dst_rect={}", dst_rect); } diff --git a/Libraries/LibWeb/Painting/DisplayListCommand.h b/Libraries/LibWeb/Painting/DisplayListCommand.h index 5f3e59940e..bbb9f30728 100644 --- a/Libraries/LibWeb/Painting/DisplayListCommand.h +++ b/Libraries/LibWeb/Painting/DisplayListCommand.h @@ -39,7 +39,7 @@ class DisplayList; V(DrawScaledDecodedImageFrame, draw_scaled_decoded_image_frame) \ V(DrawRepeatedDecodedImageFrame, draw_repeated_decoded_image_frame) \ V(DrawCompositorSurface, draw_compositor_surface) \ - V(DrawVideoFrameSource, draw_video_frame_source) \ + V(DrawVideoFrame, draw_video_frame) \ V(Save, save) \ V(SaveLayer, save_layer) \ V(Restore, restore) \ @@ -177,12 +177,12 @@ struct DrawCompositorSurface { void dump(StringBuilder&) const; }; -struct DrawVideoFrameSource { - static constexpr StringView command_name = "DrawVideoFrameSource"sv; - static constexpr DisplayListCommandType command_type = DisplayListCommandType::DrawVideoFrameSource; +struct DrawVideoFrame { + static constexpr StringView command_name = "DrawVideoFrame"sv; + static constexpr DisplayListCommandType command_type = DisplayListCommandType::DrawVideoFrame; Gfx::IntRect dst_rect; - VideoFrameResourceId source_id; + VideoFrameResourceId video_frame_id; Gfx::ScalingMode scaling_mode; [[nodiscard]] Gfx::IntRect bounding_rect() const { return dst_rect; } diff --git a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index 26057d0be8..10f1eceffb 100644 --- a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -39,7 +39,6 @@ #include #include #include -#include namespace Web::Painting { @@ -183,9 +182,9 @@ void DisplayListPlayerSkia::draw_compositor_surface(DrawCompositorSurface const& canvas.drawImageRect(image.get(), src_rect, dst_rect, to_skia_sampling_options(command.scaling_mode), &paint, SkCanvas::kStrict_SrcRectConstraint); } -void DisplayListPlayerSkia::draw_video_frame_source(DrawVideoFrameSource const& command) +void DisplayListPlayerSkia::draw_video_frame(DrawVideoFrame const& command) { - auto frame = resource_storage().video_frame_source(command.source_id).current_frame(); + auto frame = resource_storage().video_frame(command.video_frame_id); if (!frame) return; diff --git a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h index 1e8accea78..47a187173d 100644 --- a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h +++ b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h @@ -29,7 +29,7 @@ private: void draw_scaled_decoded_image_frame(DrawScaledDecodedImageFrame const&) override; void draw_repeated_decoded_image_frame(DrawRepeatedDecodedImageFrame const&) override; void draw_compositor_surface(DrawCompositorSurface const&) override; - void draw_video_frame_source(DrawVideoFrameSource const&) override; + void draw_video_frame(DrawVideoFrame const&) override; void add_clip_rect(AddClipRect const&) override; void save(Save const&) override; void save_layer(SaveLayer const&) override; diff --git a/Libraries/LibWeb/Painting/DisplayListRecorder.cpp b/Libraries/LibWeb/Painting/DisplayListRecorder.cpp index b7839e1e5d..e053730f04 100644 --- a/Libraries/LibWeb/Painting/DisplayListRecorder.cpp +++ b/Libraries/LibWeb/Painting/DisplayListRecorder.cpp @@ -510,13 +510,13 @@ void DisplayListRecorder::draw_compositor_surface(Gfx::IntRect const& dst_rect, }); } -void DisplayListRecorder::draw_video_frame_source(Gfx::IntRect const& dst_rect, NonnullRefPtr source, Gfx::ScalingMode scaling_mode) +void DisplayListRecorder::draw_video_frame(Gfx::IntRect const& dst_rect, VideoFrameResourceId frame_id, RefPtr frame, Gfx::ScalingMode scaling_mode) { if (dst_rect.is_empty()) return; - append_command(DrawVideoFrameSource { + append_command(DrawVideoFrame { .dst_rect = dst_rect, - .source_id = resource_storage().add_video_frame_source(move(source)), + .video_frame_id = resource_storage().add_video_frame(frame_id, move(frame)), .scaling_mode = scaling_mode, }); } diff --git a/Libraries/LibWeb/Painting/DisplayListRecorder.h b/Libraries/LibWeb/Painting/DisplayListRecorder.h index 2273bafe52..02c5d21a6c 100644 --- a/Libraries/LibWeb/Painting/DisplayListRecorder.h +++ b/Libraries/LibWeb/Painting/DisplayListRecorder.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,7 @@ public: void draw_scaled_decoded_image_frame(Gfx::IntRect const& dst_rect, Gfx::IntRect const& clip_rect, Gfx::DecodedImageFrame frame, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor); void draw_compositor_surface(Gfx::IntRect const& dst_rect, CompositorSurfaceId, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor); - void draw_video_frame_source(Gfx::IntRect const& dst_rect, NonnullRefPtr, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor); + void draw_video_frame(Gfx::IntRect const& dst_rect, VideoFrameResourceId, RefPtr, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor); void draw_repeated_decoded_image_frame(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, Gfx::DecodedImageFrame frame, Gfx::ScalingMode scaling_mode, bool repeat_x, bool repeat_y); diff --git a/Libraries/LibWeb/Painting/DisplayListResourceIds.h b/Libraries/LibWeb/Painting/DisplayListResourceIds.h index 6c45cc64da..262eb75705 100644 --- a/Libraries/LibWeb/Painting/DisplayListResourceIds.h +++ b/Libraries/LibWeb/Painting/DisplayListResourceIds.h @@ -18,6 +18,12 @@ AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, VideoFrameResourceId); AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, DisplayListResourceId); AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, CompositorSurfaceId); +inline VideoFrameResourceId allocate_video_frame_resource_id() +{ + static Atomic s_next_id { 1 }; + return VideoFrameResourceId { s_next_id.fetch_add(1, AK::MemoryOrder::memory_order_relaxed) }; +} + inline CompositorSurfaceId allocate_compositor_surface_id() { static Atomic s_next_id { 1 }; diff --git a/Libraries/LibWeb/Painting/DisplayListResourceStorage.cpp b/Libraries/LibWeb/Painting/DisplayListResourceStorage.cpp index 45af183fe0..4edfc3305e 100644 --- a/Libraries/LibWeb/Painting/DisplayListResourceStorage.cpp +++ b/Libraries/LibWeb/Painting/DisplayListResourceStorage.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -28,11 +29,10 @@ ImageFrameResourceId DisplayListResourceStorage::add_image_frame(Gfx::DecodedIma return { id }; } -VideoFrameResourceId DisplayListResourceStorage::add_video_frame_source(NonnullRefPtr source) +VideoFrameResourceId DisplayListResourceStorage::add_video_frame(VideoFrameResourceId id, RefPtr frame) { - auto id = source->id(); - m_video_frame_sources.ensure(id, [&] { return move(source); }); - return { id }; + m_video_frames.set(id.value(), move(frame), AK::HashSetExistingEntryBehavior::Keep); + return id; } DisplayListResourceId DisplayListResourceStorage::add_display_list(NonnullRefPtr display_list) @@ -57,8 +57,8 @@ void DisplayListResourceStorage::append_referenced_resources_from( add_font(source.font(id)); for (auto id : referenced_resources.image_frames) add_image_frame(source.image_frame(id)); - for (auto id : referenced_resources.video_frame_sources) - add_video_frame_source(source.video_frame_source(id)); + for (auto id : referenced_resources.video_frames) + add_video_frame(id, source.video_frame(id)); for (auto id : referenced_resources.display_lists) add_display_list(source.display_list(id)); } @@ -80,8 +80,8 @@ void DisplayListResourceStorage::collect_referenced_resources( referenced_resources.fonts.set(command.font_id, AK::HashSetExistingEntryBehavior::Keep); if constexpr (requires { command.frame_id; }) referenced_resources.image_frames.set(command.frame_id, AK::HashSetExistingEntryBehavior::Keep); - if constexpr (requires { video_frame_source(command.source_id); }) - referenced_resources.video_frame_sources.set(command.source_id, AK::HashSetExistingEntryBehavior::Keep); + if constexpr (requires { command.video_frame_id; }) + referenced_resources.video_frames.set(command.video_frame_id, AK::HashSetExistingEntryBehavior::Keep); if constexpr (requires { command.paint_style; command.paint_kind; }) { if (command.paint_kind == decltype(command.paint_kind)::PaintStyle && command.paint_style.type == DisplayListPaintStyleType::Pattern) @@ -139,9 +139,9 @@ DisplayListResourceTransaction DisplayListResourceStorage::create_transaction( if (!previous.image_frames.contains(id)) transaction.image_frames.append(image_frame(id)); } - for (auto id : current.video_frame_sources) { - if (!previous.video_frame_sources.contains(id)) - transaction.video_frame_sources.append(video_frame_source(id)); + for (auto id : current.video_frames) { + if (!previous.video_frames.contains(id)) + transaction.video_frames.append({ id, video_frame(id) }); } for (auto id : current.display_lists) { if (!previous.display_lists.contains(id)) @@ -156,9 +156,9 @@ DisplayListResourceTransaction DisplayListResourceStorage::create_transaction( if (!current.image_frames.contains(id)) transaction.image_frame_ids_to_remove.append(id); } - for (auto id : previous.video_frame_sources) { - if (!current.video_frame_sources.contains(id)) - transaction.video_frame_source_ids_to_remove.append(id); + for (auto id : previous.video_frames) { + if (!current.video_frames.contains(id)) + transaction.video_frame_ids_to_remove.append(id); } for (auto id : previous.display_lists) { if (!current.display_lists.contains(id)) @@ -173,8 +173,8 @@ void DisplayListResourceStorage::apply_transaction(DisplayListResourceTransactio add_font(*font); for (auto const& frame : transaction.image_frames) add_image_frame(frame); - for (auto& source : transaction.video_frame_sources) - add_video_frame_source(move(source)); + for (auto& video_frame : transaction.video_frames) + add_video_frame(video_frame.id, move(video_frame.frame)); for (auto& display_list : transaction.display_lists) add_display_list(move(display_list)); @@ -182,8 +182,8 @@ void DisplayListResourceStorage::apply_transaction(DisplayListResourceTransactio m_fonts.remove(id.value()); for (auto id : transaction.image_frame_ids_to_remove) m_image_frames.remove(id.value()); - for (auto id : transaction.video_frame_source_ids_to_remove) - m_video_frame_sources.remove(id.value()); + for (auto id : transaction.video_frame_ids_to_remove) + m_video_frames.remove(id.value()); for (auto id : transaction.display_list_ids_to_remove) m_display_lists.remove(id.value()); } @@ -192,10 +192,21 @@ void DisplayListResourceStorage::retain_only(DisplayListResourceSet const& resou { m_fonts.remove_all_matching([&](auto id, auto const&) { return !resource_set.fonts.contains(FontResourceId { id }); }); m_image_frames.remove_all_matching([&](auto id, auto const&) { return !resource_set.image_frames.contains(ImageFrameResourceId { id }); }); - m_video_frame_sources.remove_all_matching([&](auto id, auto const&) { return !resource_set.video_frame_sources.contains(VideoFrameResourceId { id }); }); + m_video_frames.remove_all_matching([&](auto id, auto const&) { return !resource_set.video_frames.contains(VideoFrameResourceId { id }); }); m_display_lists.remove_all_matching([&](auto id, auto const&) { return !resource_set.display_lists.contains(DisplayListResourceId { id }); }); } +void DisplayListResourceStorage::update_video_frame(VideoFrameResourceId frame_id, NonnullRefPtr frame) +{ + m_video_frames.set(frame_id.value(), move(frame)); +} + +void DisplayListResourceStorage::clear_video_frame(VideoFrameResourceId frame_id) +{ + if (m_video_frames.contains(frame_id.value())) + 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)); diff --git a/Libraries/LibWeb/Painting/DisplayListResourceStorage.h b/Libraries/LibWeb/Painting/DisplayListResourceStorage.h index ee230a7cea..5247c32fde 100644 --- a/Libraries/LibWeb/Painting/DisplayListResourceStorage.h +++ b/Libraries/LibWeb/Painting/DisplayListResourceStorage.h @@ -12,32 +12,38 @@ #include #include #include +#include #include #include #include #include +#include #include #include -#include namespace Web::Painting { struct DisplayListResourceSet { HashTable fonts; HashTable image_frames; - HashTable video_frame_sources; + HashTable video_frames; HashTable display_lists; }; +struct DisplayListVideoFrameResource { + VideoFrameResourceId id; + RefPtr frame; +}; + struct DisplayListResourceTransaction { Vector> fonts; Vector image_frames; - Vector> video_frame_sources; + Vector video_frames; Vector> display_lists; Vector font_ids_to_remove; Vector image_frame_ids_to_remove; - Vector video_frame_source_ids_to_remove; + Vector video_frame_ids_to_remove; Vector display_list_ids_to_remove; }; @@ -51,7 +57,7 @@ public: FontResourceId add_font(Gfx::Font const&); ImageFrameResourceId add_image_frame(Gfx::DecodedImageFrame const&); - VideoFrameResourceId add_video_frame_source(NonnullRefPtr); + VideoFrameResourceId add_video_frame(VideoFrameResourceId, RefPtr = nullptr); DisplayListResourceId add_display_list(NonnullRefPtr); void append_referenced_resources_from(DisplayListResourceStorage const& source, ReadonlyBytes command_bytes); void apply_transaction(DisplayListResourceTransaction&&); @@ -59,12 +65,14 @@ public: DisplayListResourceSet collect_referenced_resources(DisplayList const&) const; DisplayListResourceSet collect_referenced_resources(ReadonlyBytes command_bytes) const; void retain_only(DisplayListResourceSet const&); + void update_video_frame(VideoFrameResourceId, NonnullRefPtr); + 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 id) const { return m_image_frames.get(id.value()).value(); } - VideoFrameSource const& video_frame_source(VideoFrameResourceId id) const { return *m_video_frame_sources.get(id.value()).value(); } + RefPtr video_frame(VideoFrameResourceId id) const { return m_video_frames.get(id.value()).value(); } DisplayList const& display_list(DisplayListResourceId id) const { return *m_display_lists.get(id.value()).value(); } Optional compositor_surface(CompositorSurfaceId id) const { return m_compositor_surfaces.get(id.value()); } @@ -73,7 +81,7 @@ private: HashMap> m_fonts; HashMap m_image_frames; - HashMap> m_video_frame_sources; + HashMap> m_video_frames; HashMap> m_display_lists; HashMap m_compositor_surfaces; }; diff --git a/Libraries/LibWeb/Painting/VideoFrameSource.cpp b/Libraries/LibWeb/Painting/VideoFrameSource.cpp deleted file mode 100644 index e63f7cdc89..0000000000 --- a/Libraries/LibWeb/Painting/VideoFrameSource.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2026, Aliaksandr Kalenik - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace Web::Painting { - -static Atomic s_next_id { 1 }; - -NonnullRefPtr VideoFrameSource::create() -{ - return adopt_ref(*new VideoFrameSource()); -} - -VideoFrameSource::VideoFrameSource() - : m_id(s_next_id.fetch_add(1, AK::MemoryOrder::memory_order_relaxed)) -{ -} - -VideoFrameSource::~VideoFrameSource() = default; - -void VideoFrameSource::update(RefPtr frame) -{ - RefPtr old; - { - Sync::MutexLocker const locker { m_mutex }; - old = move(m_frame); - m_frame = move(frame); - } -} - -void VideoFrameSource::clear() -{ - RefPtr old; - { - Sync::MutexLocker const locker { m_mutex }; - old = move(m_frame); - } -} - -RefPtr VideoFrameSource::current_frame() const -{ - Sync::MutexLocker const locker { m_mutex }; - return m_frame; -} - -} diff --git a/Libraries/LibWeb/Painting/VideoFrameSource.h b/Libraries/LibWeb/Painting/VideoFrameSource.h deleted file mode 100644 index 84f9f29b56..0000000000 --- a/Libraries/LibWeb/Painting/VideoFrameSource.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2026, Aliaksandr Kalenik - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace Web::Painting { - -class VideoFrameSource final : public AtomicRefCounted { -public: - static NonnullRefPtr create(); - ~VideoFrameSource(); - - u64 id() const { return m_id; } - - void update(RefPtr); - void clear(); - RefPtr current_frame() const; - -private: - VideoFrameSource(); - - u64 m_id { 0 }; - mutable Sync::Mutex m_mutex; - RefPtr m_frame; -}; - -} diff --git a/Libraries/LibWeb/Painting/VideoPaintable.cpp b/Libraries/LibWeb/Painting/VideoPaintable.cpp index 7e5bb29916..920a4314d3 100644 --- a/Libraries/LibWeb/Painting/VideoPaintable.cpp +++ b/Libraries/LibWeb/Painting/VideoPaintable.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -61,8 +62,9 @@ void VideoPaintable::paint(DisplayListRecordingContext& context, PaintPhase phas }; auto paint_video_frame = [&]() { - auto& source = const_cast(video_element).ensure_video_frame_source(); - auto current = source.current_frame(); + RefPtr current; + if (auto const& sink = video_element.selected_video_track_sink()) + current = sink->current_frame(); Gfx::IntSize src_size; if (current) @@ -76,7 +78,9 @@ void VideoPaintable::paint(DisplayListRecordingContext& context, PaintPhase phas if (dst_rect.is_empty()) return; auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(), src_size, dst_rect.size()); - context.display_list_recorder().draw_video_frame_source(dst_rect, source, scaling_mode); + RefPtr frame = current; + auto frame_id = const_cast(video_element).ensure_video_frame_resource_id(); + context.display_list_recorder().draw_video_frame(dst_rect, frame_id, move(frame), scaling_mode); }; auto paint_transparent_black = [&]() {