Commit c98fcadd authored by Khushal's avatar Khushal Committed by Commit Bot

viz/media: Plumb preferred frame interval for media.

Plumb the frame rate of video updates to the display compositor. This
information is used to configure the display to tick at the video's
frame rate if possible.

R=liberato@chromium.org

Bug: 938106
Change-Id: Ic720900181f58eddf65069c3a6d4cc480a98efb2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1556458
Commit-Queue: Eric Karl <ericrk@chromium.org>
Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Reviewed-by: default avatarEric Karl <ericrk@chromium.org>
Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Auto-Submit: Khushal <khushalsagar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#652902}
parent 6aef680e
...@@ -93,6 +93,10 @@ class CC_EXPORT VideoFrameProvider { ...@@ -93,6 +93,10 @@ class CC_EXPORT VideoFrameProvider {
// frame missed its intended deadline. // frame missed its intended deadline.
virtual void PutCurrentFrame() = 0; virtual void PutCurrentFrame() = 0;
// Returns the interval at which the provider expects to have new frames for
// the client.
virtual base::TimeDelta GetPreferredRenderInterval() = 0;
protected: protected:
virtual ~VideoFrameProvider() {} virtual ~VideoFrameProvider() {}
}; };
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "cc/test/fake_video_frame_provider.h" #include "cc/test/fake_video_frame_provider.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
namespace cc { namespace cc {
FakeVideoFrameProvider::FakeVideoFrameProvider() FakeVideoFrameProvider::FakeVideoFrameProvider()
...@@ -35,4 +37,8 @@ void FakeVideoFrameProvider::PutCurrentFrame() { ...@@ -35,4 +37,8 @@ void FakeVideoFrameProvider::PutCurrentFrame() {
++put_current_frame_count_; ++put_current_frame_count_;
} }
base::TimeDelta FakeVideoFrameProvider::GetPreferredRenderInterval() {
return viz::BeginFrameArgs::MinInterval();
}
} // namespace cc } // namespace cc
...@@ -22,6 +22,7 @@ class FakeVideoFrameProvider : public VideoFrameProvider { ...@@ -22,6 +22,7 @@ class FakeVideoFrameProvider : public VideoFrameProvider {
bool HasCurrentFrame() override; bool HasCurrentFrame() override;
scoped_refptr<media::VideoFrame> GetCurrentFrame() override; scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
void PutCurrentFrame() override; void PutCurrentFrame() override;
base::TimeDelta GetPreferredRenderInterval() override;
Client* client() { return client_; } Client* client() { return client_; }
......
...@@ -148,6 +148,8 @@ class VIZ_COMMON_EXPORT CompositorFrameMetadata { ...@@ -148,6 +148,8 @@ class VIZ_COMMON_EXPORT CompositorFrameMetadata {
// was allocated. // was allocated.
base::TimeTicks local_surface_id_allocation_time; base::TimeTicks local_surface_id_allocation_time;
base::Optional<base::TimeDelta> preferred_frame_interval;
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
float max_page_scale_factor = 0.f; float max_page_scale_factor = 0.f;
gfx::SizeF root_layer_size; gfx::SizeF root_layer_size;
......
...@@ -417,6 +417,11 @@ SubmitResult CompositorFrameSinkSupport::MaybeSubmitCompositorFrameInternal( ...@@ -417,6 +417,11 @@ SubmitResult CompositorFrameSinkSupport::MaybeSubmitCompositorFrameInternal(
} }
} }
if (frame.metadata.preferred_frame_interval) {
frame_sink_manager_->SetPreferredFrameIntervalForFrameSinkId(
frame_sink_id_, *frame.metadata.preferred_frame_interval);
}
Surface* prev_surface = Surface* prev_surface =
surface_manager_->GetSurfaceForId(last_created_surface_id_); surface_manager_->GetSurfaceForId(last_created_surface_id_);
Surface* current_surface = nullptr; Surface* current_surface = nullptr;
......
...@@ -583,6 +583,14 @@ const CompositorFrameSinkSupport* FrameSinkManagerImpl::GetFrameSinkForId( ...@@ -583,6 +583,14 @@ const CompositorFrameSinkSupport* FrameSinkManagerImpl::GetFrameSinkForId(
return nullptr; return nullptr;
} }
void FrameSinkManagerImpl::SetPreferredFrameIntervalForFrameSinkId(
const FrameSinkId& id,
base::TimeDelta interval) {
auto it = frame_sink_data_.find(id);
DCHECK(it != frame_sink_data_.end());
it->second.preferred_frame_interval = interval;
}
base::TimeDelta FrameSinkManagerImpl::GetPreferredFrameIntervalForFrameSinkId( base::TimeDelta FrameSinkManagerImpl::GetPreferredFrameIntervalForFrameSinkId(
const FrameSinkId& id) const { const FrameSinkId& id) const {
auto it = frame_sink_data_.find(id); auto it = frame_sink_data_.find(id);
......
...@@ -197,6 +197,8 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl ...@@ -197,6 +197,8 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
const CompositorFrameSinkSupport* GetFrameSinkForId( const CompositorFrameSinkSupport* GetFrameSinkForId(
const FrameSinkId& frame_sink_id) const; const FrameSinkId& frame_sink_id) const;
void SetPreferredFrameIntervalForFrameSinkId(const FrameSinkId& id,
base::TimeDelta interval);
base::TimeDelta GetPreferredFrameIntervalForFrameSinkId( base::TimeDelta GetPreferredFrameIntervalForFrameSinkId(
const FrameSinkId& id) const; const FrameSinkId& id) const;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/config/gpu_finch_features.h" #include "gpu/config/gpu_finch_features.h"
#include "gpu/ipc/client/gpu_channel_host.h" #include "gpu/ipc/client/gpu_channel_host.h"
#include "media/base/media_switches.h"
#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/android/window_android.h" #include "ui/android/window_android.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -46,31 +47,38 @@ class CompositorImplBrowserTest ...@@ -46,31 +47,38 @@ class CompositorImplBrowserTest
CompositorImplBrowserTest() {} CompositorImplBrowserTest() {}
void SetUp() override { void SetUp() override {
std::vector<base::Feature> features;
switch (GetParam()) { switch (GetParam()) {
case CompositorImplMode::kNormal: case CompositorImplMode::kNormal:
break; break;
case CompositorImplMode::kViz: case CompositorImplMode::kViz:
scoped_feature_list_.InitAndEnableFeature( features =
features::kVizDisplayCompositor); std::vector<base::Feature>({features::kVizDisplayCompositor});
break; break;
case CompositorImplMode::kVizSkDDL: case CompositorImplMode::kVizSkDDL:
scoped_feature_list_.InitWithFeatures( features = std::vector<base::Feature>(
{features::kVizDisplayCompositor, features::kUseSkiaRenderer, {features::kVizDisplayCompositor, features::kUseSkiaRenderer,
features::kDefaultEnableOopRasterization}, features::kDefaultEnableOopRasterization});
{});
break; break;
} }
AppendFeatures(&features);
scoped_feature_list_.InitWithFeatures(features, {});
ContentBrowserTest::SetUp(); ContentBrowserTest::SetUp();
} }
virtual std::string GetTestUrl() { return "/title1.html"; }
virtual void AppendFeatures(std::vector<base::Feature>* features) {}
protected: protected:
void SetUpOnMainThread() override { void SetUpOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(embedded_test_server()->Start());
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.ServeFilesFromSourceDirectory(GetTestDataFilePath()); https_server.ServeFilesFromSourceDirectory(GetTestDataFilePath());
ASSERT_TRUE(https_server.Start()); ASSERT_TRUE(https_server.Start());
GURL http_url(embedded_test_server()->GetURL("/title1.html")); GURL http_url(embedded_test_server()->GetURL(GetTestUrl()));
ASSERT_TRUE(NavigateToURL(shell(), http_url)); ASSERT_TRUE(NavigateToURL(shell(), http_url));
} }
...@@ -91,7 +99,6 @@ class CompositorImplBrowserTest ...@@ -91,7 +99,6 @@ class CompositorImplBrowserTest
web_contents()->GetRenderWidgetHostView()); web_contents()->GetRenderWidgetHostView());
} }
private:
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(CompositorImplBrowserTest); DISALLOW_COPY_AND_ASSIGN(CompositorImplBrowserTest);
...@@ -267,5 +274,40 @@ IN_PROC_BROWSER_TEST_P(CompositorImplBrowserTest, ...@@ -267,5 +274,40 @@ IN_PROC_BROWSER_TEST_P(CompositorImplBrowserTest,
CompositorSwapRunLoop(compositor_impl()).RunUntilSwap(); CompositorSwapRunLoop(compositor_impl()).RunUntilSwap();
} }
class CompositorImplBrowserTestRefreshRate
: public CompositorImplBrowserTest,
public ui::WindowAndroid::TestHooks {
public:
std::string GetTestUrl() override { return "/media/tulip2.webm"; }
void AppendFeatures(std::vector<base::Feature>* features) override {
features->push_back(media::kUseSurfaceLayerForVideo);
}
// WindowAndroid::TestHooks impl.
std::vector<float> GetSupportedRates() override {
return {120.f, 90.f, 60.f};
}
void SetPreferredRate(float refresh_rate) override {
if (fabs(refresh_rate - expected_refresh_rate_) < 2.f)
run_loop_->Quit();
}
float expected_refresh_rate_ = 0.f;
std::unique_ptr<base::RunLoop> run_loop_;
};
IN_PROC_BROWSER_TEST_P(CompositorImplBrowserTestRefreshRate, VideoPreference) {
window()->SetTestHooks(this);
expected_refresh_rate_ = 60.f;
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
run_loop_.reset();
window()->SetTestHooks(nullptr);
}
INSTANTIATE_TEST_SUITE_P(P,
CompositorImplBrowserTestRefreshRate,
::testing::Values(CompositorImplMode::kViz));
} // namespace } // namespace
} // namespace content } // namespace content
...@@ -402,6 +402,11 @@ void WebMediaPlayerMSCompositor::PutCurrentFrame() { ...@@ -402,6 +402,11 @@ void WebMediaPlayerMSCompositor::PutCurrentFrame() {
current_frame_rendered_ = true; current_frame_rendered_ = true;
} }
base::TimeDelta WebMediaPlayerMSCompositor::GetPreferredRenderInterval() {
DCHECK(video_frame_compositor_task_runner_->BelongsToCurrentThread());
return viz::BeginFrameArgs::MinInterval();
}
void WebMediaPlayerMSCompositor::StartRendering() { void WebMediaPlayerMSCompositor::StartRendering() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
{ {
......
...@@ -101,6 +101,7 @@ class CONTENT_EXPORT WebMediaPlayerMSCompositor ...@@ -101,6 +101,7 @@ class CONTENT_EXPORT WebMediaPlayerMSCompositor
bool HasCurrentFrame() override; bool HasCurrentFrame() override;
scoped_refptr<media::VideoFrame> GetCurrentFrame() override; scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
void PutCurrentFrame() override; void PutCurrentFrame() override;
base::TimeDelta GetPreferredRenderInterval() override;
void StartRendering(); void StartRendering();
void StopRendering(); void StopRendering();
......
...@@ -43,5 +43,8 @@ specific_include_rules = { ...@@ -43,5 +43,8 @@ specific_include_rules = {
], ],
"gpu_memory_buffer_video_frame_pool_unittest.cc": [ "gpu_memory_buffer_video_frame_pool_unittest.cc": [
"+components/viz/test/test_context_provider.h", "+components/viz/test/test_context_provider.h",
],
"null_video_sink_unittest.cc": [
"+components/viz/common/frame_sinks/begin_frame_args.h",
] ]
} }
...@@ -550,6 +550,7 @@ source_set("unit_tests") { ...@@ -550,6 +550,7 @@ source_set("unit_tests") {
] ]
deps = [ deps = [
"//base/test:test_support", "//base/test:test_support",
"//components/viz/common",
"//gpu/command_buffer/common", "//gpu/command_buffer/common",
"//media:test_support", "//media:test_support",
"//skia", "//skia",
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/test/simple_test_tick_clock.h" #include "base/test/simple_test_tick_clock.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "media/base/gmock_callback_support.h" #include "media/base/gmock_callback_support.h"
#include "media/base/null_video_sink.h" #include "media/base/null_video_sink.h"
#include "media/base/test_helpers.h" #include "media/base/test_helpers.h"
...@@ -46,6 +47,9 @@ class NullVideoSinkTest : public testing::Test, ...@@ -46,6 +47,9 @@ class NullVideoSinkTest : public testing::Test,
gfx::Rect(natural_size), natural_size, gfx::Rect(natural_size), natural_size,
timestamp); timestamp);
} }
base::TimeDelta GetPreferredRenderInterval() override {
return viz::BeginFrameArgs::MinInterval();
}
// VideoRendererSink::RenderCallback implementation. // VideoRendererSink::RenderCallback implementation.
MOCK_METHOD3(Render, MOCK_METHOD3(Render,
......
...@@ -38,6 +38,10 @@ class MEDIA_EXPORT VideoRendererSink { ...@@ -38,6 +38,10 @@ class MEDIA_EXPORT VideoRendererSink {
// not actually rendered. Must be called before the next Render() call. // not actually rendered. Must be called before the next Render() call.
virtual void OnFrameDropped() = 0; virtual void OnFrameDropped() = 0;
// Returns the interval at which the sink expects to have new frames for the
// client.
virtual base::TimeDelta GetPreferredRenderInterval() = 0;
virtual ~RenderCallback() {} virtual ~RenderCallback() {}
}; };
......
...@@ -79,6 +79,7 @@ component("blink") { ...@@ -79,6 +79,7 @@ component("blink") {
deps = [ deps = [
"//base", "//base",
"//cc", "//cc",
"//components/viz/common",
"//gpu", "//gpu",
"//media", "//media",
"//media:shared_memory_support", "//media:shared_memory_support",
......
...@@ -4,6 +4,7 @@ include_rules = [ ...@@ -4,6 +4,7 @@ include_rules = [
"+cc/layers/video_frame_provider.h", "+cc/layers/video_frame_provider.h",
"+cc/layers/video_layer.h", "+cc/layers/video_layer.h",
"+components/scheduler", # Only allowed in tests. "+components/scheduler", # Only allowed in tests.
"+components/viz/common/frame_sinks/begin_frame_args.h",
"+components/viz/common/gpu/context_provider.h", "+components/viz/common/gpu/context_provider.h",
"+components/viz/common/surfaces/frame_sink_id.h", "+components/viz/common/surfaces/frame_sink_id.h",
"+gin", "+gin",
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
#include "base/time/default_tick_clock.h" #include "base/time/default_tick_clock.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "media/base/bind_to_current_loop.h" #include "media/base/bind_to_current_loop.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
...@@ -176,6 +177,15 @@ bool VideoFrameCompositor::HasCurrentFrame() { ...@@ -176,6 +177,15 @@ bool VideoFrameCompositor::HasCurrentFrame() {
return static_cast<bool>(GetCurrentFrame()); return static_cast<bool>(GetCurrentFrame());
} }
base::TimeDelta VideoFrameCompositor::GetPreferredRenderInterval() {
DCHECK(task_runner_->BelongsToCurrentThread());
base::AutoLock lock(callback_lock_);
if (!callback_)
return viz::BeginFrameArgs::MinInterval();
return callback_->GetPreferredRenderInterval();
}
void VideoFrameCompositor::Start(RenderCallback* callback) { void VideoFrameCompositor::Start(RenderCallback* callback) {
// Called from the media thread, so acquire the callback under lock before // Called from the media thread, so acquire the callback under lock before
// returning in case a Stop() call comes in before the PostTask is processed. // returning in case a Stop() call comes in before the PostTask is processed.
......
...@@ -93,6 +93,7 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, ...@@ -93,6 +93,7 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink,
bool HasCurrentFrame() override; bool HasCurrentFrame() override;
scoped_refptr<VideoFrame> GetCurrentFrame() override; scoped_refptr<VideoFrame> GetCurrentFrame() override;
void PutCurrentFrame() override; void PutCurrentFrame() override;
base::TimeDelta GetPreferredRenderInterval() override;
// Returns |current_frame_|, without offering a guarantee as to how recently // Returns |current_frame_|, without offering a guarantee as to how recently
// it was updated. In certain applications, one might need to periodically // it was updated. In certain applications, one might need to periodically
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h" #include "base/test/simple_test_tick_clock.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/frame_sink_id.h"
#include "media/base/gmock_callback_support.h" #include "media/base/gmock_callback_support.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
...@@ -107,6 +108,10 @@ class VideoFrameCompositorTest : public VideoRendererSink::RenderCallback, ...@@ -107,6 +108,10 @@ class VideoFrameCompositorTest : public VideoRendererSink::RenderCallback,
bool)); bool));
MOCK_METHOD0(OnFrameDropped, void()); MOCK_METHOD0(OnFrameDropped, void());
base::TimeDelta GetPreferredRenderInterval() override {
return preferred_render_interval_;
}
void StartVideoRendererSink() { void StartVideoRendererSink() {
EXPECT_CALL(*submitter_, StartRendering()); EXPECT_CALL(*submitter_, StartRendering());
const bool had_current_frame = !!compositor_->GetCurrentFrame(); const bool had_current_frame = !!compositor_->GetCurrentFrame();
...@@ -131,6 +136,7 @@ class VideoFrameCompositorTest : public VideoRendererSink::RenderCallback, ...@@ -131,6 +136,7 @@ class VideoFrameCompositorTest : public VideoRendererSink::RenderCallback,
compositor()->PutCurrentFrame(); compositor()->PutCurrentFrame();
} }
base::TimeDelta preferred_render_interval_;
base::SimpleTestTickClock tick_clock_; base::SimpleTestTickClock tick_clock_;
StrictMock<MockWebVideoFrameSubmitter>* submitter_; StrictMock<MockWebVideoFrameSubmitter>* submitter_;
std::unique_ptr<StrictMock<MockWebVideoFrameSubmitter>> client_; std::unique_ptr<StrictMock<MockWebVideoFrameSubmitter>> client_;
...@@ -341,6 +347,16 @@ TEST_P(VideoFrameCompositorTest, UpdateCurrentFrameIfStale) { ...@@ -341,6 +347,16 @@ TEST_P(VideoFrameCompositorTest, UpdateCurrentFrameIfStale) {
StopVideoRendererSink(false); StopVideoRendererSink(false);
} }
TEST_P(VideoFrameCompositorTest, PreferredRenderInterval) {
preferred_render_interval_ = base::TimeDelta::FromSeconds(1);
compositor_->Start(this);
EXPECT_EQ(compositor_->GetPreferredRenderInterval(),
preferred_render_interval_);
compositor_->Stop();
EXPECT_EQ(compositor_->GetPreferredRenderInterval(),
viz::BeginFrameArgs::MinInterval());
}
INSTANTIATE_TEST_SUITE_P(SubmitterEnabled, INSTANTIATE_TEST_SUITE_P(SubmitterEnabled,
VideoFrameCompositorTest, VideoFrameCompositorTest,
::testing::Bool()); ::testing::Bool());
......
...@@ -328,6 +328,11 @@ void VideoRendererImpl::OnFrameDropped() { ...@@ -328,6 +328,11 @@ void VideoRendererImpl::OnFrameDropped() {
algorithm_->OnLastFrameDropped(); algorithm_->OnLastFrameDropped();
} }
base::TimeDelta VideoRendererImpl::GetPreferredRenderInterval() {
base::AutoLock auto_lock(lock_);
return algorithm_->average_frame_duration();
}
void VideoRendererImpl::OnVideoDecoderStreamInitialized(bool success) { void VideoRendererImpl::OnVideoDecoderStreamInitialized(bool success) {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
......
...@@ -84,6 +84,7 @@ class MEDIA_EXPORT VideoRendererImpl ...@@ -84,6 +84,7 @@ class MEDIA_EXPORT VideoRendererImpl
base::TimeTicks deadline_max, base::TimeTicks deadline_max,
bool background_rendering) override; bool background_rendering) override;
void OnFrameDropped() override; void OnFrameDropped() override;
base::TimeDelta GetPreferredRenderInterval() override;
private: private:
// Callback for |video_decoder_stream_| initialization. // Callback for |video_decoder_stream_| initialization.
......
...@@ -885,6 +885,9 @@ TEST_F(VideoRendererImplTest, RenderingStartedThenStopped) { ...@@ -885,6 +885,9 @@ TEST_F(VideoRendererImplTest, RenderingStartedThenStopped) {
// the previous call, the total should be 4 * 115200. // the previous call, the total should be 4 * 115200.
EXPECT_EQ(115200, last_pipeline_statistics.video_memory_usage); EXPECT_EQ(115200, last_pipeline_statistics.video_memory_usage);
EXPECT_EQ(renderer_->GetPreferredRenderInterval(),
last_pipeline_statistics.video_frame_duration_average);
// Consider the case that rendering is faster than we setup the test event. // Consider the case that rendering is faster than we setup the test event.
// In that case, when we run out of the frames, BUFFERING_HAVE_NOTHING will // In that case, when we run out of the frames, BUFFERING_HAVE_NOTHING will
// be called. And then during SatisfyPendingDecodeWithEndOfStream, // be called. And then during SatisfyPendingDecodeWithEndOfStream,
......
...@@ -57,7 +57,8 @@ bool StructTraits<viz::mojom::CompositorFrameMetadataDataView, ...@@ -57,7 +57,8 @@ bool StructTraits<viz::mojom::CompositorFrameMetadataDataView,
data.ReadBeginFrameAck(&out->begin_frame_ack) && data.ReadBeginFrameAck(&out->begin_frame_ack) &&
data.ReadLocalSurfaceIdAllocationTime( data.ReadLocalSurfaceIdAllocationTime(
&out->local_surface_id_allocation_time) && &out->local_surface_id_allocation_time) &&
!out->local_surface_id_allocation_time.is_null(); !out->local_surface_id_allocation_time.is_null() &&
data.ReadPreferredFrameInterval(&out->preferred_frame_interval);
} }
} // namespace mojo } // namespace mojo
...@@ -114,6 +114,11 @@ struct StructTraits<viz::mojom::CompositorFrameMetadataDataView, ...@@ -114,6 +114,11 @@ struct StructTraits<viz::mojom::CompositorFrameMetadataDataView,
return metadata.local_surface_id_allocation_time; return metadata.local_surface_id_allocation_time;
} }
static base::Optional<base::TimeDelta> preferred_frame_interval(
const viz::CompositorFrameMetadata& metadata) {
return metadata.preferred_frame_interval;
}
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
static float max_page_scale_factor( static float max_page_scale_factor(
const viz::CompositorFrameMetadata& metadata) { const viz::CompositorFrameMetadata& metadata) {
......
...@@ -48,6 +48,12 @@ struct CompositorFrameMetadata { ...@@ -48,6 +48,12 @@ struct CompositorFrameMetadata {
mojo_base.mojom.TimeTicks local_surface_id_allocation_time; mojo_base.mojom.TimeTicks local_surface_id_allocation_time;
// Specifies the interval at which the client's content is updated. This can
// be used to configure the display to the optimal vsync interval available.
// If unspecified, or set to BeginFrameArgs::MinInterval, it is assumed that
// the client can animate at the maximum frame rate supported by the Display.
mojo_base.mojom.TimeDelta? preferred_frame_interval;
[EnableIf=is_android] [EnableIf=is_android]
float bottom_controls_height; float bottom_controls_height;
......
...@@ -52,6 +52,7 @@ class MockCompositorFrameSink : public viz::mojom::blink::CompositorFrameSink { ...@@ -52,6 +52,7 @@ class MockCompositorFrameSink : public viz::mojom::blink::CompositorFrameSink {
void(mojo::ScopedSharedBufferHandle, void(mojo::ScopedSharedBufferHandle,
gpu::mojom::blink::MailboxPtr)); gpu::mojom::blink::MailboxPtr));
MOCK_METHOD1(DidDeleteSharedBitmap, void(gpu::mojom::blink::MailboxPtr)); MOCK_METHOD1(DidDeleteSharedBitmap, void(gpu::mojom::blink::MailboxPtr));
MOCK_METHOD1(SetPreferredFrameInterval, void(base::TimeDelta));
private: private:
mojo::Binding<viz::mojom::blink::CompositorFrameSink> binding_; mojo::Binding<viz::mojom::blink::CompositorFrameSink> binding_;
......
...@@ -490,6 +490,10 @@ viz::CompositorFrame VideoFrameSubmitter::CreateCompositorFrame( ...@@ -490,6 +490,10 @@ viz::CompositorFrame VideoFrameSubmitter::CreateCompositorFrame(
viz::CompositorFrame compositor_frame; viz::CompositorFrame compositor_frame;
compositor_frame.metadata.begin_frame_ack = begin_frame_ack; compositor_frame.metadata.begin_frame_ack = begin_frame_ack;
compositor_frame.metadata.frame_token = ++next_frame_token_; compositor_frame.metadata.frame_token = ++next_frame_token_;
compositor_frame.metadata.preferred_frame_interval =
video_frame_provider_
? video_frame_provider_->GetPreferredRenderInterval()
: viz::BeginFrameArgs::MinInterval();
base::TimeTicks value; base::TimeTicks value;
if (video_frame && video_frame->metadata()->GetTimeTicks( if (video_frame && video_frame->metadata()->GetTimeTicks(
......
...@@ -48,6 +48,12 @@ class MockVideoFrameProvider : public cc::VideoFrameProvider { ...@@ -48,6 +48,12 @@ class MockVideoFrameProvider : public cc::VideoFrameProvider {
MOCK_METHOD0(GetCurrentFrame, scoped_refptr<media::VideoFrame>()); MOCK_METHOD0(GetCurrentFrame, scoped_refptr<media::VideoFrame>());
MOCK_METHOD0(PutCurrentFrame, void()); MOCK_METHOD0(PutCurrentFrame, void());
base::TimeDelta GetPreferredRenderInterval() override {
return preferred_interval;
}
base::TimeDelta preferred_interval;
private: private:
DISALLOW_COPY_AND_ASSIGN(MockVideoFrameProvider); DISALLOW_COPY_AND_ASSIGN(MockVideoFrameProvider);
}; };
...@@ -908,4 +914,34 @@ TEST_F(VideoFrameSubmitterTest, PageVisibilityControlsSubmission) { ...@@ -908,4 +914,34 @@ TEST_F(VideoFrameSubmitterTest, PageVisibilityControlsSubmission) {
scoped_task_environment_.RunUntilIdle(); scoped_task_environment_.RunUntilIdle();
} }
TEST_F(VideoFrameSubmitterTest, PreferredInterval) {
video_frame_provider_->preferred_interval = base::TimeDelta::FromSeconds(1);
EXPECT_CALL(*sink_, SetNeedsBeginFrame(true));
submitter_->StartRendering();
scoped_task_environment_.RunUntilIdle();
EXPECT_CALL(*video_frame_provider_, UpdateCurrentFrame(_, _))
.WillOnce(Return(true));
EXPECT_CALL(*video_frame_provider_, GetCurrentFrame())
.WillOnce(Return(media::VideoFrame::CreateFrame(
media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
gfx::Size(8, 8), base::TimeDelta())));
EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _));
EXPECT_CALL(*video_frame_provider_, PutCurrentFrame());
EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _, _));
EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
EXPECT_CALL(*resource_provider_, ReleaseFrameResources());
viz::BeginFrameArgs args = begin_frame_source_->CreateBeginFrameArgs(
BEGINFRAME_FROM_HERE, now_src_.get());
submitter_->OnBeginFrame(args, {});
scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(sink_->last_submitted_compositor_frame()
.metadata.preferred_frame_interval,
video_frame_provider_->preferred_interval);
}
} // namespace blink } // namespace blink
...@@ -281,6 +281,9 @@ float WindowAndroid::GetRefreshRate() { ...@@ -281,6 +281,9 @@ float WindowAndroid::GetRefreshRate() {
} }
std::vector<float> WindowAndroid::GetSupportedRefreshRates() { std::vector<float> WindowAndroid::GetSupportedRefreshRates() {
if (test_hooks_)
return test_hooks_->GetSupportedRates();
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
base::android::ScopedJavaLocalRef<jfloatArray> j_supported_refresh_rates = base::android::ScopedJavaLocalRef<jfloatArray> j_supported_refresh_rates =
Java_WindowAndroid_getSupportedRefreshRates(env, GetJavaObject()); Java_WindowAndroid_getSupportedRefreshRates(env, GetJavaObject());
...@@ -296,6 +299,11 @@ void WindowAndroid::SetPreferredRefreshRate(float refresh_rate) { ...@@ -296,6 +299,11 @@ void WindowAndroid::SetPreferredRefreshRate(float refresh_rate) {
if (force_60hz_refresh_rate_) if (force_60hz_refresh_rate_)
return; return;
if (test_hooks_) {
test_hooks_->SetPreferredRate(refresh_rate);
return;
}
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
Java_WindowAndroid_setPreferredRefreshRate(env, GetJavaObject(), Java_WindowAndroid_setPreferredRefreshRate(env, GetJavaObject(),
refresh_rate); refresh_rate);
...@@ -461,6 +469,17 @@ display::Display WindowAndroid::GetDisplayWithWindowColorSpace() { ...@@ -461,6 +469,17 @@ display::Display WindowAndroid::GetDisplayWithWindowColorSpace() {
return display; return display;
} }
void WindowAndroid::SetTestHooks(TestHooks* hooks) {
test_hooks_ = hooks;
if (!test_hooks_)
return;
if (compositor_) {
compositor_->OnUpdateSupportedRefreshRates(
test_hooks_->GetSupportedRates());
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Native JNI methods // Native JNI methods
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
......
...@@ -126,6 +126,14 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid { ...@@ -126,6 +126,14 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
void SetForce60HzRefreshRate(); void SetForce60HzRefreshRate();
class TestHooks {
public:
virtual ~TestHooks() = default;
virtual std::vector<float> GetSupportedRates() = 0;
virtual void SetPreferredRate(float refresh_rate) = 0;
};
void SetTestHooks(TestHooks* hooks);
private: private:
class WindowBeginFrameSource; class WindowBeginFrameSource;
class ScopedOnBeginFrame; class ScopedOnBeginFrame;
...@@ -154,6 +162,7 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid { ...@@ -154,6 +162,7 @@ class UI_ANDROID_EXPORT WindowAndroid : public ViewAndroid {
float mouse_wheel_scroll_factor_; float mouse_wheel_scroll_factor_;
bool vsync_paused_ = false; bool vsync_paused_ = false;
TestHooks* test_hooks_ = nullptr;
bool force_60hz_refresh_rate_ = false; bool force_60hz_refresh_rate_ = false;
DISALLOW_COPY_AND_ASSIGN(WindowAndroid); DISALLOW_COPY_AND_ASSIGN(WindowAndroid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment