Chromium Code Reviews| Index: services/ui/ws/frame_generator_unittest.cc |
| diff --git a/services/ui/ws/frame_generator_unittest.cc b/services/ui/ws/frame_generator_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d6fd77bd36a1ddfd1934b8517d4b06ae8554ef13 |
| --- /dev/null |
| +++ b/services/ui/ws/frame_generator_unittest.cc |
| @@ -0,0 +1,256 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "services/ui/ws/frame_generator.h" |
| + |
| +#include "base/macros.h" |
| +#include "cc/output/compositor_frame_sink.h" |
| +#include "cc/scheduler/begin_frame_source.h" |
| +#include "cc/test/begin_frame_args_test.cc" |
| +#include "cc/test/fake_external_begin_frame_source.h" |
| +#include "services/ui/ws/frame_generator_delegate.h" |
| +#include "services/ui/ws/server_window.h" |
| +#include "services/ui/ws/server_window_delegate.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace ui { |
| +namespace ws { |
| +namespace test { |
| + |
| +class TestFrameGeneratorDelegate : public FrameGeneratorDelegate { |
| + public: |
| + TestFrameGeneratorDelegate() {} |
| + ~TestFrameGeneratorDelegate() override {} |
| + |
| + // FrameGeneratorDelegate implementation: |
| + bool IsInHighContrastMode() override { return false; } |
| +}; |
| + |
| +class TestServerWindowDelegate : public ServerWindowDelegate { |
| + public: |
| + TestServerWindowDelegate() {} |
| + ~TestServerWindowDelegate() override {} |
| + |
| + // ServerWindowDelegate implementation: |
| + cc::mojom::DisplayCompositor* GetDisplayCompositor() override { |
| + return nullptr; |
| + } |
| + |
| + ServerWindow* GetRootWindow(const ServerWindow* window) override { |
| + return nullptr; |
| + } |
| +}; |
| + |
| +// FakeCompositorFrameSink observes a FakeExternalBeginFrameSource and receives |
| +// CompositorFrame from a FrameGenerator. |
| +class FakeCompositorFrameSink : public cc::CompositorFrameSink, |
| + public cc::BeginFrameObserver, |
| + public cc::ExternalBeginFrameSourceClient { |
| + public: |
| + FakeCompositorFrameSink() |
| + : cc::CompositorFrameSink(nullptr, nullptr, nullptr, nullptr) {} |
| + |
| + // cc::CompositorFrameSink implementation: |
| + bool BindToClient(cc::CompositorFrameSinkClient* client) override { |
| + if (!cc::CompositorFrameSink::BindToClient(client)) |
| + return false; |
| + |
| + external_begin_frame_source_ = |
| + base::MakeUnique<cc::ExternalBeginFrameSource>(this); |
| + client_->SetBeginFrameSource(external_begin_frame_source_.get()); |
| + return true; |
| + } |
| + |
| + void DetachFromClient() override { |
| + cc::CompositorFrameSink::DetachFromClient(); |
| + } |
| + |
| + void SubmitCompositorFrame(cc::CompositorFrame frame) override { |
| + ++number_frames_received_; |
| + last_frame_ = std::move(frame); |
| + last_referenced_surfaces_ = &last_frame_.metadata.referenced_surfaces; |
| + } |
| + |
| + // cc::BeginFrameObserver implementation. |
| + void OnBeginFrame(const cc::BeginFrameArgs& args) override { |
| + external_begin_frame_source_->OnBeginFrame(args); |
| + last_begin_frame_args_ = args; |
| + } |
| + |
| + const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override { |
| + return last_begin_frame_args_; |
| + } |
| + |
| + void OnBeginFrameSourcePausedChanged(bool paused) override {} |
| + |
| + // cc::ExternalBeginFrameSourceClient implementation: |
| + void OnNeedsBeginFrames(bool needs_begin_frames) override { |
| + needs_begin_frames_ = needs_begin_frames; |
| + UpdateNeedsBeginFramesInternal(); |
| + } |
| + |
| + void OnDidFinishFrame(const cc::BeginFrameAck& ack) override { |
| + external_begin_frame_source_->DidFinishFrame(this, ack); |
| + } |
| + |
| + void SetBeginFrameSource(cc::BeginFrameSource* source) { |
| + if (begin_frame_source_ && observing_begin_frames_) { |
| + begin_frame_source_->RemoveObserver(this); |
| + observing_begin_frames_ = false; |
| + } |
| + begin_frame_source_ = source; |
| + UpdateNeedsBeginFramesInternal(); |
| + } |
| + |
| + const std::vector<cc::SurfaceId>* last_referenced_surfaces() { |
| + return last_referenced_surfaces_; |
| + } |
| + |
| + int number_frames_received() { return number_frames_received_; } |
| + |
| + private: |
| + void UpdateNeedsBeginFramesInternal() { |
| + if (!begin_frame_source_) |
| + return; |
| + |
| + if (needs_begin_frames_ == observing_begin_frames_) |
| + return; |
| + |
| + observing_begin_frames_ = needs_begin_frames_; |
| + if (needs_begin_frames_) { |
| + begin_frame_source_->AddObserver(this); |
| + } else { |
| + begin_frame_source_->RemoveObserver(this); |
| + } |
| + } |
| + |
| + int number_frames_received_ = 0; |
| + std::unique_ptr<cc::ExternalBeginFrameSource> external_begin_frame_source_; |
| + cc::BeginFrameSource* begin_frame_source_ = nullptr; |
| + cc::BeginFrameArgs last_begin_frame_args_; |
| + bool observing_begin_frames_ = false; |
| + bool needs_begin_frames_ = false; |
| + cc::CompositorFrame last_frame_; |
| + const std::vector<cc::SurfaceId>* last_referenced_surfaces_ = nullptr; |
| +}; |
| + |
| +class FrameGeneratorTest : public testing::Test { |
| + public: |
| + FrameGeneratorTest() {} |
| + ~FrameGeneratorTest() override {} |
| + |
| + // testing::Test overrides: |
| + void SetUp() override { |
| + testing::Test::SetUp(); |
| + |
| + std::unique_ptr<FakeCompositorFrameSink> compositor_frame_sink = |
| + base::MakeUnique<FakeCompositorFrameSink>(); |
| + compositor_frame_sink_ = compositor_frame_sink.get(); |
| + |
| + constexpr float kRefreshRate = 0.f; |
| + constexpr bool kTickAutomatically = false; |
| + begin_frame_source_ = base::MakeUnique<cc::FakeExternalBeginFrameSource>( |
| + kRefreshRate, kTickAutomatically); |
| + compositor_frame_sink_->SetBeginFrameSource(begin_frame_source_.get()); |
| + delegate_ = base::MakeUnique<TestFrameGeneratorDelegate>(); |
| + server_window_delegate_ = base::MakeUnique<TestServerWindowDelegate>(); |
| + root_window_ = base::MakeUnique<ServerWindow>(server_window_delegate_.get(), |
| + WindowId()); |
| + root_window_->SetVisible(true); |
| + frame_generator_ = base::MakeUnique<FrameGenerator>( |
| + delegate_.get(), root_window_.get(), std::move(compositor_frame_sink)); |
| + }; |
| + |
| + int NumberOfFramesReceived() { |
| + return compositor_frame_sink_->number_frames_received(); |
| + } |
| + |
| + void IssueBeginFrame() { |
| + begin_frame_source_->TestOnBeginFrame(cc::CreateBeginFrameArgsForTesting( |
| + BEGINFRAME_FROM_HERE, 0, next_sequence_number_)); |
| + ++next_sequence_number_; |
| + } |
| + |
| + FrameGenerator* frame_generator() { return frame_generator_.get(); } |
| + |
| + const std::vector<cc::SurfaceId>* ReferencedSurfaces() { |
| + return compositor_frame_sink_->last_referenced_surfaces(); |
| + } |
| + |
| + private: |
| + FakeCompositorFrameSink* compositor_frame_sink_ = nullptr; |
| + std::unique_ptr<cc::FakeExternalBeginFrameSource> begin_frame_source_; |
| + std::unique_ptr<TestFrameGeneratorDelegate> delegate_; |
| + std::unique_ptr<TestServerWindowDelegate> server_window_delegate_; |
| + std::unique_ptr<ServerWindow> root_window_; |
| + std::unique_ptr<FrameGenerator> frame_generator_; |
| + int next_sequence_number_ = 1; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FrameGeneratorTest); |
| +}; |
| + |
| +TEST_F(FrameGeneratorTest, OnSurfaceCreated) { |
| + DCHECK_EQ(0, NumberOfFramesReceived()); |
| + DCHECK_EQ(nullptr, ReferencedSurfaces()); |
| + |
| + // FrameGenerator does not request BeginFrames upon creation. |
| + IssueBeginFrame(); |
| + EXPECT_EQ(0, NumberOfFramesReceived()); |
| + |
| + const cc::SurfaceId kArbitrarySurfaceId( |
| + cc::FrameSinkId(1, 1), |
| + cc::LocalSurfaceId(1, base::UnguessableToken::Create())); |
| + const cc::SurfaceInfo kArbitrarySurfaceInfo(kArbitrarySurfaceId, 1.0f, |
| + gfx::Size(100, 100)); |
| + frame_generator()->OnSurfaceCreated(kArbitrarySurfaceInfo); |
| + // FrameGenerator gets the missed BeginFrame when AddObserver() is called. |
|
Fady Samuel
2017/03/17 14:06:40
This comment is weird here. I would just remove it
Alex Z.
2017/03/17 14:43:00
Done. I took this note while debugging and missed
|
| + EXPECT_EQ(0, NumberOfFramesReceived()); |
| + |
| + IssueBeginFrame(); |
| + EXPECT_EQ(1, NumberOfFramesReceived()); |
| + |
| + // Verify that the CompositorFrame refers to the window manager's surface via |
| + // referenced_surfaces. |
| + const std::vector<cc::SurfaceId>* referenced_surfaces = ReferencedSurfaces(); |
| + EXPECT_TRUE(referenced_surfaces); |
| + EXPECT_EQ(kArbitrarySurfaceId, referenced_surfaces->front()); |
|
Fady Samuel
2017/03/17 14:06:40
Use EXPECT_THAT? https://cs.chromium.org/chromium/
Alex Z.
2017/03/17 14:43:00
Done.
|
| + |
| + // FrameGenerator stops requesting BeginFrames after submitting a |
| + // CompositorFrame. |
| + IssueBeginFrame(); |
| + EXPECT_EQ(1, NumberOfFramesReceived()); |
| +} |
| + |
| +TEST_F(FrameGeneratorTest, SetDeviceScaleFactor) { |
| + DCHECK_EQ(0, NumberOfFramesReceived()); |
| + const cc::SurfaceId kArbitrarySurfaceId( |
| + cc::FrameSinkId(1, 1), |
| + cc::LocalSurfaceId(1, base::UnguessableToken::Create())); |
| + const cc::SurfaceInfo kArbitrarySurfaceInfo(kArbitrarySurfaceId, 1.0f, |
| + gfx::Size(100, 100)); |
| + constexpr float kDefaultScaleFactor = 1.0f; |
| + constexpr float kArbitraryScaleFactor = 0.5f; |
| + |
| + // A valid SurfaceInfo is required before setting device scale factor. |
| + frame_generator()->OnSurfaceCreated(kArbitrarySurfaceInfo); |
| + IssueBeginFrame(); |
| + DCHECK_EQ(1, NumberOfFramesReceived()); |
|
Fady Samuel
2017/03/17 14:06:40
Verify that the device scale factor in the Composi
Alex Z.
2017/03/17 14:43:00
Done.
|
| + |
| + IssueBeginFrame(); |
| + DCHECK_EQ(1, NumberOfFramesReceived()); |
|
Fady Samuel
2017/03/17 14:06:40
Either remove this or comment about what it does?
Alex Z.
2017/03/17 14:43:00
Done.
|
| + |
| + // FrameGenerator does not request BeginFrames if its device scale factor |
| + // remains unchanged. |
| + frame_generator()->SetDeviceScaleFactor(kDefaultScaleFactor); |
| + IssueBeginFrame(); |
| + EXPECT_EQ(1, NumberOfFramesReceived()); |
| + |
| + frame_generator()->SetDeviceScaleFactor(kArbitraryScaleFactor); |
| + IssueBeginFrame(); |
| + EXPECT_EQ(2, NumberOfFramesReceived()); |
|
Fady Samuel
2017/03/17 14:06:40
Verify that the new compositorframe gets the new d
Alex Z.
2017/03/17 14:43:00
Done.
|
| +} |
| + |
| +} // namespace test |
| +} // namespace ws |
| +} // namespace ui |