0
Files
src/cc/layers/mirror_layer_unittest.cc
Khushal Sagar 1b51eba0e7 content/cc: Safely drop stale callbacks with RenderDocument + CC reuse
Since LayerTreeHost is threaded, callbacks tied to a frame submitted by
the main thread are posted asynchronously. This means when the
compositor is swapped between widgets (for RenderDocument), the new
widget could receive callbacks tied to content submitted by the
previous widget resulting in errors.

This change avoids this by adding a source_frame_number to such
callbacks. The source_frame_number is 1:1 with main frames and as such
can be used to tie callbacks to a particular frame. The LayerTreeView
can then safely ignore callbacks for main frames submitted by a
previous widget.

Bug: 1464791
Change-Id: I343b75474c7c2bf7a7c050ab949d2ccf328bbe80
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4993439
Reviewed-by: Vladimir Levin <vmpstr@chromium.org>
Reviewed-by: Rakina Zata Amni <rakina@chromium.org>
Auto-Submit: Khushal Sagar <khushalsagar@chromium.org>
Commit-Queue: Khushal Sagar <khushalsagar@chromium.org>
Reviewed-by: Ian Vollick <vollick@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1218442}
2023-11-01 21:16:54 +00:00

149 lines
5.6 KiB
C++

// Copyright 2019 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 "cc/animation/animation_host.h"
#include "cc/layers/mirror_layer.h"
#include "cc/layers/mirror_layer_impl.h"
#include "cc/test/fake_impl_task_runner_provider.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/tree_synchronizer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
class MirrorLayerTest : public testing::Test {
public:
MirrorLayerTest() : host_impl_(&task_runner_provider_, &task_graph_runner_) {}
// Synchronizes |layer_tree_host_| and |host_impl_| and pushes surface ids.
void SynchronizeTrees() {
TreeSynchronizer::PushLayerProperties(
*layer_tree_host_->GetPendingCommitState(),
layer_tree_host_->GetThreadUnsafeCommitState(),
host_impl_.pending_tree());
}
protected:
void SetUp() override {
animation_host_ = AnimationHost::CreateForTesting(ThreadInstance::kMain);
layer_tree_host_ = FakeLayerTreeHost::Create(
&fake_client_, &task_graph_runner_, animation_host_.get());
layer_tree_host_->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f,
viz::LocalSurfaceId());
host_impl_.CreatePendingTree();
}
void TearDown() override {
layer_tree_host_->SetRootLayer(nullptr);
layer_tree_host_ = nullptr;
}
FakeLayerTreeHostClient fake_client_;
FakeImplTaskRunnerProvider task_runner_provider_;
TestTaskGraphRunner task_graph_runner_;
std::unique_ptr<AnimationHost> animation_host_;
std::unique_ptr<FakeLayerTreeHost> layer_tree_host_;
FakeLayerTreeHostImpl host_impl_;
};
// This test verifies that MirrorLayer properties are pushed across to
// MirrorLayerImpl.
TEST_F(MirrorLayerTest, PushProperties) {
auto root = Layer::Create();
layer_tree_host_->SetRootLayer(root);
auto mirrored = Layer::Create();
root->AddChild(mirrored);
auto mirror = MirrorLayer::Create(mirrored);
root->AddChild(mirror);
EXPECT_EQ(1, mirrored->mirror_count());
EXPECT_EQ(mirrored.get(), mirror->mirrored_layer());
auto root_impl = LayerImpl::Create(host_impl_.pending_tree(), root->id());
auto mirrored_impl =
LayerImpl::Create(host_impl_.pending_tree(), mirrored->id());
auto mirror_impl =
MirrorLayerImpl::Create(host_impl_.pending_tree(), mirror->id());
// Verify that impl layers have default property values.
EXPECT_EQ(0, mirror_impl->mirrored_layer_id());
SynchronizeTrees();
// Verify that property values are pushed to impl layers.
EXPECT_EQ(mirrored_impl->id(), mirror_impl->mirrored_layer_id());
}
// This test verifies adding/removing mirror layers updates mirror count
// properly and sets appropriate bits on the layer tree host.
TEST_F(MirrorLayerTest, MirrorCount) {
auto mirrored = Layer::Create();
mirrored->SetLayerTreeHost(layer_tree_host_.get());
auto commit_state = layer_tree_host_->WillCommit(/*completion_event=*/nullptr,
/*has_updates=*/true);
layer_tree_host_->CommitComplete(commit_state->source_frame_number,
{base::TimeTicks(), base::TimeTicks::Now()});
layer_tree_host_->property_trees()->set_needs_rebuild(false);
EXPECT_EQ(0, mirrored->mirror_count());
// Creating the first mirror layer should trigger property trees rebuild.
auto mirror1 = MirrorLayer::Create(mirrored);
EXPECT_EQ(1, mirrored->mirror_count());
EXPECT_EQ(mirrored.get(), mirror1->mirrored_layer());
EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild());
EXPECT_TRUE(
const_cast<const FakeLayerTreeHost*>(layer_tree_host_.get())
->pending_commit_state()
->layers_that_should_push_properties.contains(mirrored.get()));
layer_tree_host_->property_trees()->set_needs_rebuild(false);
// Creating a second mirror layer should not trigger property trees rebuild.
auto mirror2 = MirrorLayer::Create(mirrored);
EXPECT_EQ(2, mirrored->mirror_count());
EXPECT_EQ(mirrored.get(), mirror2->mirrored_layer());
EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild());
EXPECT_TRUE(
const_cast<const FakeLayerTreeHost*>(layer_tree_host_.get())
->pending_commit_state()
->layers_that_should_push_properties.contains(mirrored.get()));
layer_tree_host_->property_trees()->set_needs_rebuild(false);
// Destroying one of the mirror layers should not trigger property trees
// rebuild.
mirror1->RemoveFromParent();
mirror1 = nullptr;
EXPECT_EQ(1, mirrored->mirror_count());
EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild());
EXPECT_EQ(1u, const_cast<const FakeLayerTreeHost*>(layer_tree_host_.get())
->pending_commit_state()
->layers_that_should_push_properties.size());
layer_tree_host_->property_trees()->set_needs_rebuild(false);
// Destroying the only remaining mirror layer should trigger property trees
// rebuild.
mirror2->RemoveFromParent();
mirror2 = nullptr;
EXPECT_EQ(0, mirrored->mirror_count());
EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild());
EXPECT_TRUE(
const_cast<const FakeLayerTreeHost*>(layer_tree_host_.get())
->pending_commit_state()
->layers_that_should_push_properties.contains(mirrored.get()));
layer_tree_host_->property_trees()->set_needs_rebuild(false);
mirrored->SetLayerTreeHost(nullptr);
}
} // namespace
} // namespace cc