blob: 19bf33c98fcf79f79652293f56e2510e91f4a2ea [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <utility>
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/unguessable_token.h"
#include "cc/slim/layer.h"
#include "cc/slim/solid_color_layer.h"
#include "cc/slim/surface_layer.h"
#include "cc/slim/test_frame_sink_impl.h"
#include "cc/slim/test_layer_tree_client.h"
#include "cc/slim/test_layer_tree_impl.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/common/surfaces/surface_range.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/overlay_transform.h"
namespace cc::slim {
namespace {
class SlimLayerTreeTest : public testing::Test {
public:
void SetUp() override {
layer_tree_ = std::make_unique<TestLayerTreeImpl>(&client_);
}
void ExpectNeedsBeginFrameThenReset(
const base::WeakPtr<TestFrameSinkImpl>& sink) {
EXPECT_TRUE(layer_tree_->NeedsBeginFrames());
EXPECT_TRUE(sink->needs_begin_frames());
layer_tree_->ResetNeedsBeginFrame();
EXPECT_FALSE(layer_tree_->NeedsBeginFrames());
EXPECT_FALSE(sink->needs_begin_frames());
}
void BeginFrame(const base::WeakPtr<TestFrameSinkImpl>& sink) {
base::TimeTicks frame_time = base::TimeTicks::Now();
base::TimeDelta interval = viz::BeginFrameArgs::DefaultInterval();
viz::BeginFrameArgs begin_frame_args = viz::BeginFrameArgs::Create(
BEGINFRAME_FROM_HERE,
/*source_id=*/1, ++sequence_id_, frame_time, frame_time + interval,
interval, viz::BeginFrameArgs::NORMAL);
sink->OnBeginFrame(begin_frame_args, /*timing_details=*/{},
/*frame_ack=*/false, {});
}
base::WeakPtr<TestFrameSinkImpl> SetupLayerTreeForDraw() {
layer_tree_->SetVisible(true);
auto frame_sink = TestFrameSinkImpl::Create();
auto weak_frame_sink = frame_sink->GetWeakPtr();
layer_tree_->SetFrameSink(std::move(frame_sink));
EXPECT_TRUE(weak_frame_sink);
gfx::Rect viewport(0, 0, 100, 100);
float scale_factor = 2.0f;
base::UnguessableToken token = base::UnguessableToken::Create();
viz::LocalSurfaceId local_surface_id(1u, 2u, token);
layer_tree_->SetViewportRectAndScale(viewport, scale_factor,
local_surface_id);
{
auto solid_color_layer = SolidColorLayer::Create();
solid_color_layer->SetBounds(viewport.size());
solid_color_layer->SetBackgroundColor(SkColors::kRed);
solid_color_layer->SetIsDrawable(true);
layer_tree_->SetRoot(std::move(solid_color_layer));
}
return weak_frame_sink;
}
protected:
TestLayerTreeClient client_;
std::unique_ptr<TestLayerTreeImpl> layer_tree_;
uint64_t sequence_id_ = 0;
};
TEST_F(SlimLayerTreeTest, SmokeTest) {
EXPECT_TRUE(layer_tree_->GetUIResourceManager());
gfx::Rect viewport(0, 0, 100, 100);
float scale_factor = 2.0f;
base::UnguessableToken token = base::UnguessableToken::Create();
viz::LocalSurfaceId local_surface_id(1u, 2u, token);
layer_tree_->SetViewportRectAndScale(viewport, scale_factor,
local_surface_id);
EXPECT_FALSE(layer_tree_->IsVisible());
layer_tree_->SetVisible(true);
EXPECT_TRUE(layer_tree_->IsVisible());
layer_tree_->set_display_transform_hint(
gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL);
layer_tree_->UpdateTopControlsVisibleHeight(20.0f);
}
TEST_F(SlimLayerTreeTest, InitAndReleaseFrameSink) {
EXPECT_EQ(client_.request_new_frame_sink_count(), 0u);
layer_tree_->SetVisible(true);
EXPECT_EQ(client_.request_new_frame_sink_count(), 1u);
auto frame_sink = TestFrameSinkImpl::Create();
auto weak_frame_sink = frame_sink->GetWeakPtr();
frame_sink->SetBindToClientResult(true);
layer_tree_->SetFrameSink(std::move(frame_sink));
ASSERT_TRUE(weak_frame_sink);
EXPECT_TRUE(weak_frame_sink->bind_to_client_called());
EXPECT_EQ(client_.request_new_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_initialize_layer_tree_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_fail_to_initialize_layer_tree_frame_sink_count(), 0u);
EXPECT_EQ(client_.did_lose_layer_tree_frame_sink_count(), 0u);
layer_tree_->SetVisible(false);
ASSERT_TRUE(weak_frame_sink);
layer_tree_->ReleaseLayerTreeFrameSink();
ASSERT_FALSE(weak_frame_sink);
EXPECT_EQ(client_.request_new_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_initialize_layer_tree_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_fail_to_initialize_layer_tree_frame_sink_count(), 0u);
EXPECT_EQ(client_.did_lose_layer_tree_frame_sink_count(), 0u);
layer_tree_->SetVisible(true);
EXPECT_EQ(client_.request_new_frame_sink_count(), 2u);
EXPECT_EQ(client_.did_initialize_layer_tree_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_fail_to_initialize_layer_tree_frame_sink_count(), 0u);
EXPECT_EQ(client_.did_lose_layer_tree_frame_sink_count(), 0u);
}
TEST_F(SlimLayerTreeTest, FrameSinkInitFailure) {
EXPECT_EQ(client_.request_new_frame_sink_count(), 0u);
layer_tree_->SetVisible(true);
EXPECT_EQ(client_.request_new_frame_sink_count(), 1u);
auto frame_sink = TestFrameSinkImpl::Create();
auto weak_frame_sink = frame_sink->GetWeakPtr();
frame_sink->SetBindToClientResult(false);
layer_tree_->SetFrameSink(std::move(frame_sink));
EXPECT_EQ(client_.request_new_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_initialize_layer_tree_frame_sink_count(), 0u);
EXPECT_EQ(client_.did_fail_to_initialize_layer_tree_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_lose_layer_tree_frame_sink_count(), 0u);
frame_sink = TestFrameSinkImpl::Create();
weak_frame_sink = frame_sink->GetWeakPtr();
frame_sink->SetBindToClientResult(true);
layer_tree_->SetFrameSink(std::move(frame_sink));
EXPECT_EQ(client_.request_new_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_initialize_layer_tree_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_fail_to_initialize_layer_tree_frame_sink_count(), 1u);
EXPECT_EQ(client_.did_lose_layer_tree_frame_sink_count(), 0u);
}
TEST_F(SlimLayerTreeTest, LoseFrameSink) {
EXPECT_EQ(client_.request_new_frame_sink_count(), 0u);
layer_tree_->SetVisible(true);
EXPECT_EQ(client_.request_new_frame_sink_count(), 1u);
auto frame_sink = TestFrameSinkImpl::Create();
auto weak_frame_sink = frame_sink->GetWeakPtr();
layer_tree_->SetFrameSink(std::move(frame_sink));
ASSERT_TRUE(weak_frame_sink);
EXPECT_TRUE(weak_frame_sink->bind_to_client_called());
weak_frame_sink->OnContextLost();
ASSERT_FALSE(weak_frame_sink);
EXPECT_EQ(client_.request_new_frame_sink_count(), 2u);
frame_sink = TestFrameSinkImpl::Create();
weak_frame_sink = frame_sink->GetWeakPtr();
layer_tree_->SetFrameSink(std::move(frame_sink));
ASSERT_TRUE(weak_frame_sink);
EXPECT_TRUE(weak_frame_sink->bind_to_client_called());
}
TEST_F(SlimLayerTreeTest, NeedsBeginFrame) {
layer_tree_->SetVisible(true);
auto frame_sink = TestFrameSinkImpl::Create();
auto weak_frame_sink = frame_sink->GetWeakPtr();
layer_tree_->SetFrameSink(std::move(frame_sink));
ASSERT_TRUE(weak_frame_sink);
// Needs begin frame from SetVisible.
ExpectNeedsBeginFrameThenReset(weak_frame_sink);
gfx::Rect viewport(0, 0, 100, 100);
float scale_factor = 2.0f;
base::UnguessableToken token = base::UnguessableToken::Create();
viz::LocalSurfaceId local_surface_id(1u, 2u, token);
layer_tree_->SetViewportRectAndScale(viewport, scale_factor,
local_surface_id);
ExpectNeedsBeginFrameThenReset(weak_frame_sink);
layer_tree_->SetNeedsAnimate();
ExpectNeedsBeginFrameThenReset(weak_frame_sink);
layer_tree_->SetNeedsAnimate();
ExpectNeedsBeginFrameThenReset(weak_frame_sink);
layer_tree_->set_background_color(SkColors::kGreen);
ExpectNeedsBeginFrameThenReset(weak_frame_sink);
auto root_layer = Layer::Create();
layer_tree_->SetRoot(root_layer);
ExpectNeedsBeginFrameThenReset(weak_frame_sink);
auto child = Layer::Create();
root_layer->AddChild(child);
ExpectNeedsBeginFrameThenReset(weak_frame_sink);
root_layer->SetBounds(viewport.size());
ExpectNeedsBeginFrameThenReset(weak_frame_sink);
child->RemoveFromParent();
ExpectNeedsBeginFrameThenReset(weak_frame_sink);
}
TEST_F(SlimLayerTreeTest, NumUnneddedBeginFrameBeforeStop) {
uint32_t n = 10;
layer_tree_ = std::make_unique<TestLayerTreeImpl>(&client_, n);
auto weak_frame_sink = SetupLayerTreeForDraw();
ASSERT_TRUE(weak_frame_sink);
// First begin frame should submit.
BeginFrame(weak_frame_sink);
EXPECT_TRUE(weak_frame_sink->GetDidSubmitAndReset());
EXPECT_FALSE(weak_frame_sink->GetDidNotProduceFrameAndReset());
weak_frame_sink->DidReceiveCompositorFrameAck({});
EXPECT_TRUE(weak_frame_sink->needs_begin_frames());
// All begin frame up to one less should not submit but keep requesting
// begin frames.
for (uint32_t i = 0; i < n - 1; ++i) {
BeginFrame(weak_frame_sink);
EXPECT_FALSE(weak_frame_sink->GetDidSubmitAndReset());
EXPECT_TRUE(weak_frame_sink->GetDidNotProduceFrameAndReset());
EXPECT_TRUE(weak_frame_sink->needs_begin_frames());
}
// Should stop requesting begin frame after last one.
BeginFrame(weak_frame_sink);
EXPECT_FALSE(weak_frame_sink->GetDidSubmitAndReset());
EXPECT_TRUE(weak_frame_sink->GetDidNotProduceFrameAndReset());
EXPECT_FALSE(weak_frame_sink->needs_begin_frames());
}
TEST_F(SlimLayerTreeTest, DeferBeginFrame) {
auto defer_runnable = layer_tree_->DeferBeginFrame();
layer_tree_->SetVisible(true);
auto frame_sink = TestFrameSinkImpl::Create();
auto weak_frame_sink = frame_sink->GetWeakPtr();
layer_tree_->SetFrameSink(std::move(frame_sink));
ASSERT_TRUE(weak_frame_sink);
EXPECT_FALSE(layer_tree_->NeedsBeginFrames());
EXPECT_FALSE(weak_frame_sink->needs_begin_frames());
layer_tree_->set_background_color(SkColors::kGreen);
EXPECT_FALSE(layer_tree_->NeedsBeginFrames());
EXPECT_FALSE(weak_frame_sink->needs_begin_frames());
std::move(defer_runnable).Run();
EXPECT_TRUE(layer_tree_->NeedsBeginFrames());
EXPECT_TRUE(weak_frame_sink->needs_begin_frames());
}
TEST_F(SlimLayerTreeTest, MaxPendingFrame) {
auto weak_frame_sink = SetupLayerTreeForDraw();
ASSERT_TRUE(weak_frame_sink);
BeginFrame(weak_frame_sink);
EXPECT_TRUE(weak_frame_sink->GetDidSubmitAndReset());
EXPECT_FALSE(weak_frame_sink->GetDidNotProduceFrameAndReset());
layer_tree_->SetNeedsAnimate();
BeginFrame(weak_frame_sink);
EXPECT_FALSE(weak_frame_sink->GetDidSubmitAndReset());
EXPECT_TRUE(weak_frame_sink->GetDidNotProduceFrameAndReset());
weak_frame_sink->DidReceiveCompositorFrameAck({});
BeginFrame(weak_frame_sink);
EXPECT_TRUE(weak_frame_sink->GetDidSubmitAndReset());
EXPECT_FALSE(weak_frame_sink->GetDidNotProduceFrameAndReset());
}
TEST_F(SlimLayerTreeTest, MaxPendingResetWithFrameSink) {
auto weak_frame_sink = SetupLayerTreeForDraw();
ASSERT_TRUE(weak_frame_sink);
BeginFrame(weak_frame_sink);
EXPECT_TRUE(weak_frame_sink->GetDidSubmitAndReset());
EXPECT_FALSE(weak_frame_sink->GetDidNotProduceFrameAndReset());
layer_tree_->SetNeedsAnimate();
BeginFrame(weak_frame_sink);
EXPECT_FALSE(weak_frame_sink->GetDidSubmitAndReset());
EXPECT_TRUE(weak_frame_sink->GetDidNotProduceFrameAndReset());
// Release sink without ack-ing the previous frame.
layer_tree_->SetVisible(false);
layer_tree_->ReleaseLayerTreeFrameSink();
EXPECT_FALSE(weak_frame_sink);
layer_tree_->SetVisible(true);
auto frame_sink = TestFrameSinkImpl::Create();
weak_frame_sink = frame_sink->GetWeakPtr();
layer_tree_->SetFrameSink(std::move(frame_sink));
// Should allow producing frames with new sink.
BeginFrame(weak_frame_sink);
EXPECT_TRUE(weak_frame_sink->GetDidSubmitAndReset());
EXPECT_FALSE(weak_frame_sink->GetDidNotProduceFrameAndReset());
}
TEST_F(SlimLayerTreeTest, ReferencedSurfaceRange) {
scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create();
base::UnguessableToken token = base::UnguessableToken::Create();
viz::SurfaceId start(viz::FrameSinkId(1u, 2u),
viz::LocalSurfaceId(3u, 4u, token));
viz::SurfaceId end(viz::FrameSinkId(1u, 2u),
viz::LocalSurfaceId(5u, 6u, token));
layer->SetOldestAcceptableFallback(start);
layer->SetSurfaceId(end, cc::DeadlinePolicy::UseDefaultDeadline());
layer_tree_->SetRoot(layer);
EXPECT_THAT(layer_tree_->referenced_surfaces(),
testing::UnorderedElementsAre(
std::make_pair(viz::SurfaceRange(start, end), 1)));
viz::SurfaceId new_end(viz::FrameSinkId(1u, 2u),
viz::LocalSurfaceId(7u, 8u, token));
layer->SetSurfaceId(new_end, cc::DeadlinePolicy::UseDefaultDeadline());
EXPECT_THAT(layer_tree_->referenced_surfaces(),
testing::UnorderedElementsAre(
std::make_pair(viz::SurfaceRange(start, new_end), 1)));
layer_tree_->SetRoot(nullptr);
EXPECT_TRUE(layer_tree_->referenced_surfaces().empty());
}
TEST_F(SlimLayerTreeTest, DestroyTreeBeforeLayer) {
// Regression test for use after free.
auto root_layer = Layer::Create();
// Use SurfaceLayer here because it accesses LayerTreeImpl pointer in
// SetLayerTree.
auto surface_layer = SurfaceLayer::Create();
root_layer->AddChild(surface_layer);
base::UnguessableToken token = base::UnguessableToken::Create();
viz::SurfaceId end(viz::FrameSinkId(1u, 2u),
viz::LocalSurfaceId(5u, 6u, token));
surface_layer->SetSurfaceId(end, cc::DeadlinePolicy::UseDefaultDeadline());
layer_tree_->SetRoot(root_layer);
layer_tree_.reset();
EXPECT_EQ(root_layer->layer_tree(), nullptr);
EXPECT_EQ(surface_layer->layer_tree(), nullptr);
}
TEST_F(SlimLayerTreeTest, NewLocalSurfaceIdForNewSink) {
auto weak_frame_sink = SetupLayerTreeForDraw();
viz::LocalSurfaceId old_id = weak_frame_sink->GetCurrentLocalSurfaceId();
auto frame_sink = TestFrameSinkImpl::Create();
weak_frame_sink = frame_sink->GetWeakPtr();
layer_tree_->SetFrameSink(std::move(frame_sink));
EXPECT_TRUE(weak_frame_sink);
viz::LocalSurfaceId new_id = weak_frame_sink->GetCurrentLocalSurfaceId();
EXPECT_NE(old_id, new_id);
EXPECT_TRUE(new_id.IsNewerThan(old_id));
}
} // namespace
} // namespace cc::slim