diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc | 178 |
1 files changed, 149 insertions, 29 deletions
diff --git a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc index 4d98fc00725..c7424e0dc51 100644 --- a/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc +++ b/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc @@ -8,37 +8,128 @@ #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/feature_list.h" #include "base/metrics/histogram_macros.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/trace_event/trace_event.h" +#include "build/build_config.h" #include "cc/metrics/video_playback_roughness_reporter.h" #include "components/power_scheduler/power_mode.h" #include "components/power_scheduler/power_mode_arbiter.h" #include "components/power_scheduler/power_mode_voter.h" #include "components/viz/common/resources/resource_id.h" #include "components/viz/common/resources/returned_resource.h" +#include "components/viz/common/surfaces/frame_sink_bundle_id.h" #include "media/base/video_frame.h" #include "media/base/video_types.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/viz/public/cpp/gpu/context_provider_command_buffer.h" #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-blink.h" +#include "services/viz/public/mojom/compositing/frame_sink_bundle.mojom-blink.h" #include "services/viz/public/mojom/hit_test/hit_test_region_list.mojom-blink.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" #include "third_party/blink/public/mojom/frame_sinks/embedded_frame_sink.mojom-blink.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/graphics/canvas_resource.h" +#include "third_party/blink/renderer/platform/graphics/video_frame_sink_bundle.h" #include "ui/gfx/presentation_feedback.h" namespace blink { +namespace { + +// If enabled, every VideoFrameSubmitter will share a FrameSinkBundle with every +// other VideoFrameSubmitter living on the same thread with the same parent +// FrameSinkId. This is used to aggregate Viz communication and substantially +// reduce IPC traffic when many VideoFrameSubmitters are active within a frame. +const base::Feature kUseVideoFrameSinkBundle{"UseVideoFrameSinkBundle", + base::FEATURE_DISABLED_BY_DEFAULT}; + +} // namespace + +// Helper CompositorFrameSink implementation which sits locally between a +// VideoFrameSubmitter and a thread-local FrameSinkBundle connection to Viz. +// This queues outgoing messages so they can be delivered in batches. With +// many active VideoFrameSubmitters in the same frame, this can significantly +// reduce Viz communication overhead. +class VideoFrameSubmitter::FrameSinkBundleProxy + : public viz::mojom::blink::CompositorFrameSink { + public: + FrameSinkBundleProxy(VideoFrameSinkBundle& bundle, + const viz::FrameSinkId& frame_sink_id) + : bundle_(bundle), + bundle_id_(bundle.bundle_id()), + frame_sink_id_(frame_sink_id) {} + FrameSinkBundleProxy(const FrameSinkBundleProxy&) = delete; + FrameSinkBundleProxy& operator=(const FrameSinkBundleProxy&) = delete; + + ~FrameSinkBundleProxy() override { bundle_.RemoveClient(frame_sink_id_); } + + void OnContextLost() { bundle_.OnContextLost(bundle_id_); } + + // viz::mojom::Blink::CompositorFrameSink: + void SetNeedsBeginFrame(bool needs_begin_frame) override { + bundle_.SetNeedsBeginFrame(frame_sink_id_.sink_id(), needs_begin_frame); + } + + // Not used by VideoFrameSubmitter. + void SetWantsAnimateOnlyBeginFrames() override { NOTREACHED(); } + + void SubmitCompositorFrame( + const viz::LocalSurfaceId& local_surface_id, + viz::CompositorFrame frame, + absl::optional<viz::HitTestRegionList> hit_test_region_list, + uint64_t submit_time) override { + bundle_.SubmitCompositorFrame(frame_sink_id_.sink_id(), local_surface_id, + std::move(frame), + std::move(hit_test_region_list), submit_time); + } + + // Not used by VideoFrameSubmitter. + void SubmitCompositorFrameSync( + const viz::LocalSurfaceId& local_surface_id, + viz::CompositorFrame frame, + absl::optional<viz::HitTestRegionList> hit_test_region_list, + uint64_t submit_time, + SubmitCompositorFrameSyncCallback callback) override { + NOTREACHED(); + } + + void DidNotProduceFrame(const viz::BeginFrameAck& ack) override { + bundle_.DidNotProduceFrame(frame_sink_id_.sink_id(), ack); + } + + void DidAllocateSharedBitmap(base::ReadOnlySharedMemoryRegion region, + const gpu::Mailbox& id) override { + bundle_.DidAllocateSharedBitmap(frame_sink_id_.sink_id(), std::move(region), + id); + } + + void DidDeleteSharedBitmap(const gpu::Mailbox& id) override { + bundle_.DidDeleteSharedBitmap(frame_sink_id_.sink_id(), id); + } + + void InitializeCompositorFrameSinkType( + viz::mojom::blink::CompositorFrameSinkType type) override { + bundle_.InitializeCompositorFrameSinkType(frame_sink_id_.sink_id(), type); + } + + private: + VideoFrameSinkBundle& bundle_; + const viz::FrameSinkBundleId bundle_id_; + const viz::FrameSinkId frame_sink_id_; +}; + VideoFrameSubmitter::VideoFrameSubmitter( WebContextProviderCallback context_provider_callback, cc::VideoPlaybackRoughnessReporter::ReportingCallback roughness_reporting_callback, + const viz::FrameSinkId& parent_frame_sink_id, std::unique_ptr<VideoFrameResourceProvider> resource_provider) : context_provider_callback_(context_provider_callback), resource_provider_(std::move(resource_provider)), - rotation_(media::VIDEO_ROTATION_0), + parent_frame_sink_id_(parent_frame_sink_id), roughness_reporter_(std::make_unique<cc::VideoPlaybackRoughnessReporter>( std::move(roughness_reporting_callback))), frame_trackers_(false, nullptr), @@ -119,9 +210,9 @@ void VideoFrameSubmitter::Initialize(cc::VideoFrameProvider* provider, weak_ptr_factory_.GetWeakPtr())); } -void VideoFrameSubmitter::SetRotation(media::VideoRotation rotation) { +void VideoFrameSubmitter::SetTransform(media::VideoTransformation transform) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - rotation_ = rotation; + transform_ = transform; } void VideoFrameSubmitter::EnableSubmission(viz::SurfaceId surface_id) { @@ -172,8 +263,14 @@ void VideoFrameSubmitter::OnContextLost() { resource_provider_->OnContextLost(); - // |compositor_frame_sink_| should be reset last. - compositor_frame_sink_.reset(); + // NOTE: These objects should be reset last; and if `bundle_proxy`_ is set, it + // should be reset after `remote_frame_sink_`. + compositor_frame_sink_ = nullptr; + remote_frame_sink_.reset(); + if (bundle_proxy_) { + bundle_proxy_->OnContextLost(); + bundle_proxy_.reset(); + } context_provider_callback_.Run( context_provider_, @@ -196,10 +293,16 @@ void VideoFrameSubmitter::OnBeginFrame( last_begin_frame_args_ = args; - for (const auto& pair : timing_details) { - if (viz::FrameTokenGT(pair.key, *next_frame_token_)) + WTF::Vector<uint32_t> frame_tokens; + for (const auto& id : timing_details.Keys()) + frame_tokens.push_back(id); + std::sort(frame_tokens.begin(), frame_tokens.end()); + + for (const auto& frame_token : frame_tokens) { + if (viz::FrameTokenGT(frame_token, *next_frame_token_)) continue; - auto& feedback = pair.value.presentation_feedback; + auto& feedback = + timing_details.find(frame_token)->value.presentation_feedback; #if defined(OS_LINUX) || defined(OS_CHROMEOS) // TODO: On Linux failure flag is unreliable, and perfectly rendered frames // are reported as failures all the time. @@ -209,10 +312,11 @@ void VideoFrameSubmitter::OnBeginFrame( feedback.flags & gfx::PresentationFeedback::kFailure; #endif if (!presentation_failure && - !ignorable_submitted_frames_.contains(pair.key)) { + !ignorable_submitted_frames_.contains(frame_token)) { frame_trackers_.NotifyFramePresented( - pair.key, gfx::PresentationFeedback( - feedback.timestamp, feedback.interval, feedback.flags)); + frame_token, + gfx::PresentationFeedback(feedback.timestamp, feedback.interval, + feedback.flags)); // We assume that presentation feedback is reliable if // 1. (kHWCompletion) OS told us that the frame was shown at that time @@ -222,13 +326,13 @@ void VideoFrameSubmitter::OnBeginFrame( gfx::PresentationFeedback::kHWCompletion | gfx::PresentationFeedback::kVSync; bool reliable_timestamp = feedback.flags & reliable_feedback_mask; - roughness_reporter_->FramePresented(pair.key, feedback.timestamp, + roughness_reporter_->FramePresented(frame_token, feedback.timestamp, reliable_timestamp); } - ignorable_submitted_frames_.erase(pair.key); + ignorable_submitted_frames_.erase(frame_token); TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0( - "media", "VideoFrameSubmitter", TRACE_ID_LOCAL(pair.key), + "media", "VideoFrameSubmitter", TRACE_ID_LOCAL(frame_token), feedback.timestamp); } frame_trackers_.NotifyBeginImplFrame(args); @@ -353,9 +457,24 @@ void VideoFrameSubmitter::StartSubmitting() { Platform::Current()->GetBrowserInterfaceBroker()->GetInterface( provider.BindNewPipeAndPassReceiver()); - provider->CreateCompositorFrameSink( - frame_sink_id_, receiver_.BindNewPipeAndPassRemote(), - compositor_frame_sink_.BindNewPipeAndPassReceiver()); + if (base::FeatureList::IsEnabled(kUseVideoFrameSinkBundle)) { + auto& bundle = VideoFrameSinkBundle::GetOrCreateSharedInstance( + *provider.get(), parent_frame_sink_id_, is_media_stream_); + provider->CreateBundledCompositorFrameSink( + frame_sink_id_, bundle.bundle_id(), + receiver_.BindNewPipeAndPassRemote(), + remote_frame_sink_.BindNewPipeAndPassReceiver()); + bundle.AddClient(frame_sink_id_, this, remote_frame_sink_); + bundle_proxy_ = + std::make_unique<FrameSinkBundleProxy>(bundle, frame_sink_id_); + compositor_frame_sink_ = bundle_proxy_.get(); + } else { + provider->CreateCompositorFrameSink( + frame_sink_id_, receiver_.BindNewPipeAndPassRemote(), + remote_frame_sink_.BindNewPipeAndPassReceiver()); + compositor_frame_sink_ = remote_frame_sink_.get(); + } + if (!surface_embedder_.is_bound()) { provider->ConnectToEmbedder(frame_sink_id_, surface_embedder_.BindNewPipeAndPassReceiver()); @@ -363,12 +482,9 @@ void VideoFrameSubmitter::StartSubmitting() { GenerateNewSurfaceId(); } - compositor_frame_sink_.set_disconnect_handler(base::BindOnce( + remote_frame_sink_.set_disconnect_handler(base::BindOnce( &VideoFrameSubmitter::OnContextLost, base::Unretained(this))); - if (!compositor_frame_sink_) - return; - compositor_frame_sink_->InitializeCompositorFrameSinkType( is_media_stream_ ? viz::mojom::CompositorFrameSinkType::kMediaStream : viz::mojom::CompositorFrameSinkType::kVideo); @@ -467,8 +583,11 @@ bool VideoFrameSubmitter::SubmitFrame( last_frame_id_ = video_frame->unique_id(); gfx::Size frame_size(video_frame->natural_size()); - if (rotation_ == media::VIDEO_ROTATION_90 || - rotation_ == media::VIDEO_ROTATION_270) { + + // Prefer the frame level transform if set. + auto transform = video_frame->metadata().transformation.value_or(transform_); + if (transform.rotation == media::VIDEO_ROTATION_90 || + transform.rotation == media::VIDEO_ROTATION_270) { frame_size = gfx::Size(frame_size.height(), frame_size.width()); } @@ -493,8 +612,8 @@ bool VideoFrameSubmitter::SubmitFrame( roughness_reporter_->FrameSubmitted(frame_token, *video_frame.get(), last_begin_frame_args_.interval); } - auto compositor_frame = CreateCompositorFrame(frame_token, begin_frame_ack, - std::move(video_frame)); + auto compositor_frame = CreateCompositorFrame( + frame_token, begin_frame_ack, std::move(video_frame), transform); WebVector<viz::ResourceId> resources; const auto& quad_list = compositor_frame.render_pass_list.back()->quad_list; @@ -534,8 +653,8 @@ void VideoFrameSubmitter::SubmitEmptyFrame() { last_frame_id_.reset(); auto begin_frame_ack = viz::BeginFrameAck::CreateManualAckWithDamage(); auto frame_token = ++next_frame_token_; - auto compositor_frame = - CreateCompositorFrame(frame_token, begin_frame_ack, nullptr); + auto compositor_frame = CreateCompositorFrame( + frame_token, begin_frame_ack, nullptr, media::kNoTransformation); compositor_frame_sink_->SubmitCompositorFrame( child_local_surface_id_allocator_.GetCurrentLocalSurfaceId(), @@ -576,7 +695,8 @@ bool VideoFrameSubmitter::ShouldSubmit() const { viz::CompositorFrame VideoFrameSubmitter::CreateCompositorFrame( uint32_t frame_token, const viz::BeginFrameAck& begin_frame_ack, - scoped_refptr<media::VideoFrame> video_frame) { + scoped_refptr<media::VideoFrame> video_frame, + media::VideoTransformation transform) { DCHECK(!frame_size_.IsEmpty()); viz::CompositorFrame compositor_frame; @@ -627,7 +747,7 @@ viz::CompositorFrame VideoFrameSubmitter::CreateCompositorFrame( video_frame->ColorSpace().GetContentColorUsage(); const bool is_opaque = media::IsOpaque(video_frame->format()); resource_provider_->AppendQuads(render_pass.get(), std::move(video_frame), - rotation_, is_opaque); + transform, is_opaque); } compositor_frame.render_pass_list.emplace_back(std::move(render_pass)); |