summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
diff options
context:
space:
mode:
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.cc178
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));