blob: bf50fd0038ccf5ebf0385a9d4a925028ef85802c [file] [log] [blame]
Avi Drissman3f7a9d82022-09-08 20:55:421// Copyright 2013 The Chromium Authors
[email protected]efbdb3a2013-10-04 00:35:132// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cc/layers/ui_resource_layer.h"
6
loyso2cb3f32f2016-11-08 07:08:347#include "cc/animation/animation_host.h"
[email protected]efbdb3a2013-10-04 00:35:138#include "cc/resources/scoped_ui_resource.h"
Xiyuan Xiae50a2882022-08-23 20:04:199#include "cc/resources/ui_resource_manager.h"
[email protected]943528e2013-11-07 05:01:3210#include "cc/test/fake_layer_tree_host.h"
Xianzhu Wang66e13e02019-09-18 20:39:1211#include "cc/test/layer_tree_impl_test_base.h"
danakjffc181a2016-07-22 22:48:4312#include "cc/test/stub_layer_tree_host_single_thread_client.h"
[email protected]efbdb3a2013-10-04 00:35:1313#include "cc/trees/single_thread_proxy.h"
14#include "testing/gmock/include/gmock/gmock.h"
15#include "testing/gtest/include/gtest/gtest.h"
16#include "third_party/skia/include/core/SkBitmap.h"
17
18using ::testing::Mock;
19using ::testing::_;
20using ::testing::AtLeast;
21using ::testing::AnyNumber;
22
23namespace cc {
24namespace {
25
changwan8a519762014-11-20 23:06:5626class TestUIResourceLayer : public UIResourceLayer {
27 public:
loyso0940d412016-03-14 01:30:3128 static scoped_refptr<TestUIResourceLayer> Create() {
kylechar973a0412017-09-26 18:40:2929 return base::WrapRefCounted(new TestUIResourceLayer());
changwan8a519762014-11-20 23:06:5630 }
31
estade68ce2eb2017-01-24 20:09:3732 using UIResourceLayer::resource_id;
33 using UIResourceLayer::HasDrawableContent;
changwan8a519762014-11-20 23:06:5634
35 protected:
loyso0940d412016-03-14 01:30:3136 TestUIResourceLayer() : UIResourceLayer() { SetIsDrawable(true); }
Chris Watkinsf6353292017-12-04 02:36:0537 ~TestUIResourceLayer() override = default;
changwan8a519762014-11-20 23:06:5638};
39
[email protected]efbdb3a2013-10-04 00:35:1340class UIResourceLayerTest : public testing::Test {
[email protected]efbdb3a2013-10-04 00:35:1341 protected:
changwan8a519762014-11-20 23:06:5642 void TearDown() override {
estade68ce2eb2017-01-24 20:09:3743 Mock::VerifyAndClearExpectations(layer_tree_host());
[email protected]efbdb3a2013-10-04 00:35:1344 }
45
estade68ce2eb2017-01-24 20:09:3746 FakeLayerTreeHost* layer_tree_host() { return layer_impl_test_.host(); }
47
48 private:
Xianzhu Wang66e13e02019-09-18 20:39:1249 LayerTreeImplTestBase layer_impl_test_;
[email protected]efbdb3a2013-10-04 00:35:1350};
51
52TEST_F(UIResourceLayerTest, SetBitmap) {
loyso0940d412016-03-14 01:30:3153 scoped_refptr<UIResourceLayer> test_layer = TestUIResourceLayer::Create();
[email protected]efbdb3a2013-10-04 00:35:1354 ASSERT_TRUE(test_layer.get());
[email protected]efbdb3a2013-10-04 00:35:1355 test_layer->SetBounds(gfx::Size(100, 100));
56
estade68ce2eb2017-01-24 20:09:3757 layer_tree_host()->SetRootLayer(test_layer);
58 Mock::VerifyAndClearExpectations(layer_tree_host());
danakj17ff2d42018-06-13 21:41:0059 EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host());
[email protected]efbdb3a2013-10-04 00:35:1360
danakj5f46636a2015-06-19 00:01:4061 test_layer->Update();
[email protected]efbdb3a2013-10-04 00:35:1362
Stefan Zager2cec2682022-01-27 18:00:1963 EXPECT_FALSE(test_layer->draws_content());
[email protected]efbdb3a2013-10-04 00:35:1364
65 SkBitmap bitmap;
[email protected]0046982c2014-03-25 22:00:5166 bitmap.allocN32Pixels(10, 10);
[email protected]efbdb3a2013-10-04 00:35:1367 bitmap.setImmutable();
68
69 test_layer->SetBitmap(bitmap);
danakj5f46636a2015-06-19 00:01:4070 test_layer->Update();
[email protected]efbdb3a2013-10-04 00:35:1371
Stefan Zager2cec2682022-01-27 18:00:1972 EXPECT_TRUE(test_layer->draws_content());
[email protected]efbdb3a2013-10-04 00:35:1373}
74
75TEST_F(UIResourceLayerTest, SetUIResourceId) {
loyso0940d412016-03-14 01:30:3176 scoped_refptr<TestUIResourceLayer> test_layer = TestUIResourceLayer::Create();
[email protected]efbdb3a2013-10-04 00:35:1377 ASSERT_TRUE(test_layer.get());
[email protected]efbdb3a2013-10-04 00:35:1378 test_layer->SetBounds(gfx::Size(100, 100));
79
estade68ce2eb2017-01-24 20:09:3780 layer_tree_host()->SetRootLayer(test_layer);
81 Mock::VerifyAndClearExpectations(layer_tree_host());
danakj17ff2d42018-06-13 21:41:0082 EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host());
[email protected]efbdb3a2013-10-04 00:35:1383
danakj5f46636a2015-06-19 00:01:4084 test_layer->Update();
[email protected]efbdb3a2013-10-04 00:35:1385
Stefan Zager2cec2682022-01-27 18:00:1986 EXPECT_FALSE(test_layer->draws_content());
[email protected]efbdb3a2013-10-04 00:35:1387
[email protected]0046982c2014-03-25 22:00:5188 bool is_opaque = false;
khushalsagar8ec07402016-09-10 03:13:1989 std::unique_ptr<ScopedUIResource> resource =
estade68ce2eb2017-01-24 20:09:3790 ScopedUIResource::Create(layer_tree_host()->GetUIResourceManager(),
khushalsagar8ec07402016-09-10 03:13:1991 UIResourceBitmap(gfx::Size(10, 10), is_opaque));
[email protected]efbdb3a2013-10-04 00:35:1392 test_layer->SetUIResourceId(resource->id());
danakj5f46636a2015-06-19 00:01:4093 test_layer->Update();
[email protected]efbdb3a2013-10-04 00:35:1394
Stefan Zager2cec2682022-01-27 18:00:1995 EXPECT_TRUE(test_layer->draws_content());
changwan8a519762014-11-20 23:06:5696
97 // ID is preserved even when you set ID first and attach it to the tree.
estade68ce2eb2017-01-24 20:09:3798 layer_tree_host()->SetRootLayer(nullptr);
khushalsagar8ec07402016-09-10 03:13:1999 std::unique_ptr<ScopedUIResource> shared_resource =
estade68ce2eb2017-01-24 20:09:37100 ScopedUIResource::Create(layer_tree_host()->GetUIResourceManager(),
khushalsagar8ec07402016-09-10 03:13:19101 UIResourceBitmap(gfx::Size(5, 5), is_opaque));
changwan8a519762014-11-20 23:06:56102 test_layer->SetUIResourceId(shared_resource->id());
estade68ce2eb2017-01-24 20:09:37103 layer_tree_host()->SetRootLayer(test_layer);
104 EXPECT_EQ(shared_resource->id(), test_layer->resource_id());
Stefan Zager2cec2682022-01-27 18:00:19105 EXPECT_TRUE(test_layer->draws_content());
[email protected]efbdb3a2013-10-04 00:35:13106}
107
jdduke838114812014-12-18 19:31:44108TEST_F(UIResourceLayerTest, BitmapClearedOnSetUIResourceId) {
estade68ce2eb2017-01-24 20:09:37109 scoped_refptr<TestUIResourceLayer> test_layer = TestUIResourceLayer::Create();
jdduke838114812014-12-18 19:31:44110 ASSERT_TRUE(test_layer.get());
111 test_layer->SetBounds(gfx::Size(100, 100));
estade68ce2eb2017-01-24 20:09:37112 EXPECT_FALSE(test_layer->HasDrawableContent());
jdduke838114812014-12-18 19:31:44113
114 SkBitmap bitmap;
115 bitmap.allocN32Pixels(10, 10);
116 bitmap.setImmutable();
117 ASSERT_FALSE(bitmap.isNull());
118 ASSERT_TRUE(bitmap.pixelRef()->unique());
119
estade68ce2eb2017-01-24 20:09:37120 // Without a layer tree, the only additional reference is in UIResourceLayer.
jdduke838114812014-12-18 19:31:44121 test_layer->SetBitmap(bitmap);
122 ASSERT_FALSE(bitmap.pixelRef()->unique());
estade68ce2eb2017-01-24 20:09:37123 // Also, there's no drawable content due to the lack of a LTH.
124 EXPECT_FALSE(test_layer->HasDrawableContent());
jdduke838114812014-12-18 19:31:44125
126 test_layer->SetUIResourceId(0);
127 EXPECT_TRUE(bitmap.pixelRef()->unique());
estade68ce2eb2017-01-24 20:09:37128 EXPECT_FALSE(test_layer->HasDrawableContent());
129
130 // Add to a layer tree; now the UIResourceManager holds onto a ref
131 // indefinitely.
132 {
Xianzhu Wang66e13e02019-09-18 20:39:12133 LayerTreeImplTestBase impl;
estade68ce2eb2017-01-24 20:09:37134 impl.host()->SetRootLayer(test_layer);
135
136 test_layer->SetBitmap(bitmap);
137 EXPECT_FALSE(bitmap.pixelRef()->unique());
138 EXPECT_TRUE(test_layer->HasDrawableContent());
139 test_layer->SetUIResourceId(0);
140 EXPECT_FALSE(bitmap.pixelRef()->unique());
141 EXPECT_FALSE(test_layer->HasDrawableContent());
142 }
143
144 // After the layer tree/resource manager are destroyed, refs are back to 1.
145 test_layer->SetUIResourceId(0);
146 EXPECT_TRUE(bitmap.pixelRef()->unique());
147 EXPECT_FALSE(test_layer->HasDrawableContent());
148}
149
150TEST_F(UIResourceLayerTest, SharedBitmap) {
151 SkBitmap bitmap;
152 bitmap.allocN32Pixels(10, 10);
153 bitmap.setImmutable();
154 // The SkPixelRef is what's important, not the SkBitmap itself.
155 SkBitmap bitmap_copy = bitmap;
156
157 scoped_refptr<TestUIResourceLayer> layer1 = TestUIResourceLayer::Create();
158 layer_tree_host()->SetRootLayer(layer1);
159 layer1->SetBitmap(bitmap);
160 bitmap.reset();
estade68ce2eb2017-01-24 20:09:37161 layer1->Update();
Stefan Zager2cec2682022-01-27 18:00:19162 EXPECT_TRUE(layer1->draws_content());
estade68ce2eb2017-01-24 20:09:37163 const auto resource_id = layer1->resource_id();
164
165 // Second layer, same LTH. Resource is shared (has same ID).
166 scoped_refptr<TestUIResourceLayer> layer2 = TestUIResourceLayer::Create();
167 layer_tree_host()->SetRootLayer(layer2);
168 layer2->SetBitmap(bitmap_copy);
estade68ce2eb2017-01-24 20:09:37169 layer2->Update();
Stefan Zager2cec2682022-01-27 18:00:19170 EXPECT_TRUE(layer2->draws_content());
estade68ce2eb2017-01-24 20:09:37171 EXPECT_EQ(resource_id, layer2->resource_id());
172
173 // Change bitmap, different resource id.
174 SkBitmap other_bitmap;
175 other_bitmap.allocN32Pixels(12, 12);
176 other_bitmap.setImmutable();
177 layer2->SetBitmap(other_bitmap);
178 EXPECT_NE(resource_id, layer2->resource_id());
179
180 // Switch layer to different LTH. ID is in a new namespace (LTH), so it may
181 // still be the same. We can make sure it's using the same shared bitmap by
182 // verifying that whatever ID it has, it changes away from and back to when we
183 // change the shared bitmap to something else then back to the original.
Xianzhu Wang66e13e02019-09-18 20:39:12184 LayerTreeImplTestBase impl;
estade68ce2eb2017-01-24 20:09:37185 impl.host()->SetRootLayer(layer1);
estade68ce2eb2017-01-24 20:09:37186 layer1->Update();
Stefan Zager2cec2682022-01-27 18:00:19187 EXPECT_TRUE(layer1->draws_content());
estade68ce2eb2017-01-24 20:09:37188 const auto other_lth_resource_id = layer1->resource_id();
189 layer1->SetBitmap(other_bitmap);
190 EXPECT_NE(other_lth_resource_id, layer1->resource_id());
191 layer1->SetBitmap(bitmap_copy);
192 EXPECT_EQ(other_lth_resource_id, layer1->resource_id());
jdduke838114812014-12-18 19:31:44193}
194
Xiyuan Xiae50a2882022-08-23 20:04:19195TEST_F(UIResourceLayerTest, SharedBitmapCacheSizeLimit) {
196 scoped_refptr<TestUIResourceLayer> layer = TestUIResourceLayer::Create();
197 layer_tree_host()->SetRootLayer(layer);
198
199 // Number of bitmaps that are created then get their references dropped.
200 constexpr size_t kDroppedResources = 100u;
201
202 // Populate the shared bitmap cache.
203 auto* manager = layer_tree_host()->GetUIResourceManager();
204 while (manager->owned_shared_resources_size_for_test() < kDroppedResources) {
205 SkBitmap bitmap;
206 bitmap.allocN32Pixels(10, 10);
207 bitmap.setImmutable();
208 layer->SetBitmap(bitmap);
209 }
210
211 // No eviction because bitmaps are references by UIResourcesRequests.
212 EXPECT_EQ(manager->owned_shared_resources_size_for_test(), kDroppedResources);
213
214 // Pretend UIResourcesRequests are processed to drop bitmap references.
215 manager->TakeUIResourcesRequests();
216
217 // Create one more shared bitmap resource and the eviction happens.
218 SkBitmap bitmap;
219 bitmap.allocN32Pixels(10, 10);
220 bitmap.setImmutable();
221 layer->SetBitmap(bitmap);
222
223 // The cache should trimmed down.
224 EXPECT_EQ(manager->owned_shared_resources_size_for_test(), 1u);
225}
226
[email protected]efbdb3a2013-10-04 00:35:13227} // namespace
228} // namespace cc