Add UMAs to measure Android tab state transition
[chromium-blink-merge.git] / cc / surfaces / surface_factory_unittest.cc
blobc2951aead48a7be2bebcd3f3c675957fff739e91
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/bind.h"
6 #include "cc/output/compositor_frame.h"
7 #include "cc/output/delegated_frame_data.h"
8 #include "cc/resources/resource_provider.h"
9 #include "cc/surfaces/surface.h"
10 #include "cc/surfaces/surface_factory.h"
11 #include "cc/surfaces/surface_factory_client.h"
12 #include "cc/surfaces/surface_manager.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "ui/gfx/geometry/size.h"
16 namespace cc {
17 namespace {
19 class TestSurfaceFactoryClient : public SurfaceFactoryClient {
20 public:
21 TestSurfaceFactoryClient() {}
22 ~TestSurfaceFactoryClient() override {}
24 void ReturnResources(const ReturnedResourceArray& resources) override {
25 returned_resources_.insert(
26 returned_resources_.end(), resources.begin(), resources.end());
29 const ReturnedResourceArray& returned_resources() const {
30 return returned_resources_;
33 void clear_returned_resources() { returned_resources_.clear(); }
35 private:
36 ReturnedResourceArray returned_resources_;
38 DISALLOW_COPY_AND_ASSIGN(TestSurfaceFactoryClient);
41 class SurfaceFactoryTest : public testing::Test {
42 public:
43 SurfaceFactoryTest() : factory_(&manager_, &client_), surface_id_(3) {
44 factory_.Create(surface_id_);
47 ~SurfaceFactoryTest() override {
48 if (!surface_id_.is_null())
49 factory_.Destroy(surface_id_);
52 void SubmitFrameWithResources(ResourceId* resource_ids,
53 size_t num_resource_ids) {
54 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
55 for (size_t i = 0u; i < num_resource_ids; ++i) {
56 TransferableResource resource;
57 resource.id = resource_ids[i];
58 resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
59 frame_data->resource_list.push_back(resource);
61 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
62 frame->delegated_frame_data = frame_data.Pass();
63 factory_.SubmitFrame(surface_id_, frame.Pass(),
64 SurfaceFactory::DrawCallback());
67 void UnrefResources(ResourceId* ids_to_unref,
68 int* counts_to_unref,
69 size_t num_ids_to_unref) {
70 ReturnedResourceArray unref_array;
71 for (size_t i = 0; i < num_ids_to_unref; ++i) {
72 ReturnedResource resource;
73 resource.id = ids_to_unref[i];
74 resource.count = counts_to_unref[i];
75 unref_array.push_back(resource);
77 factory_.UnrefResources(unref_array);
80 void CheckReturnedResourcesMatchExpected(ResourceId* expected_returned_ids,
81 int* expected_returned_counts,
82 size_t expected_resources) {
83 const ReturnedResourceArray& actual_resources =
84 client_.returned_resources();
85 ASSERT_EQ(expected_resources, actual_resources.size());
86 for (size_t i = 0; i < expected_resources; ++i) {
87 ReturnedResource resource = actual_resources[i];
88 EXPECT_EQ(expected_returned_ids[i], resource.id);
89 EXPECT_EQ(expected_returned_counts[i], resource.count);
91 client_.clear_returned_resources();
94 void RefCurrentFrameResources() {
95 Surface* surface = manager_.GetSurfaceForId(surface_id_);
96 factory_.RefResources(
97 surface->GetEligibleFrame()->delegated_frame_data->resource_list);
100 protected:
101 SurfaceManager manager_;
102 TestSurfaceFactoryClient client_;
103 SurfaceFactory factory_;
104 SurfaceId surface_id_;
107 // Tests submitting a frame with resources followed by one with no resources
108 // with no resource provider action in between.
109 TEST_F(SurfaceFactoryTest, ResourceLifetimeSimple) {
110 ResourceId first_frame_ids[] = {1, 2, 3};
111 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
113 // All of the resources submitted in the first frame are still in use at this
114 // time by virtue of being in the pending frame, so none can be returned to
115 // the client yet.
116 EXPECT_EQ(0u, client_.returned_resources().size());
117 client_.clear_returned_resources();
119 // The second frame references no resources and thus should make all resources
120 // available to be returned.
121 SubmitFrameWithResources(NULL, 0);
123 ResourceId expected_returned_ids[] = {1, 2, 3};
124 int expected_returned_counts[] = {1, 1, 1};
125 CheckReturnedResourcesMatchExpected(expected_returned_ids,
126 expected_returned_counts,
127 arraysize(expected_returned_counts));
130 // Tests submitting a frame with resources followed by one with no resources
131 // with the resource provider holding everything alive.
132 TEST_F(SurfaceFactoryTest, ResourceLifetimeSimpleWithProviderHoldingAlive) {
133 ResourceId first_frame_ids[] = {1, 2, 3};
134 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
136 // All of the resources submitted in the first frame are still in use at this
137 // time by virtue of being in the pending frame, so none can be returned to
138 // the client yet.
139 EXPECT_EQ(0u, client_.returned_resources().size());
140 client_.clear_returned_resources();
142 // Hold on to everything.
143 RefCurrentFrameResources();
145 // The second frame references no resources and thus should make all resources
146 // available to be returned as soon as the resource provider releases them.
147 SubmitFrameWithResources(NULL, 0);
149 EXPECT_EQ(0u, client_.returned_resources().size());
150 client_.clear_returned_resources();
152 int release_counts[] = {1, 1, 1};
153 UnrefResources(first_frame_ids, release_counts, arraysize(first_frame_ids));
155 ResourceId expected_returned_ids[] = {1, 2, 3};
156 int expected_returned_counts[] = {1, 1, 1};
157 CheckReturnedResourcesMatchExpected(expected_returned_ids,
158 expected_returned_counts,
159 arraysize(expected_returned_counts));
162 // Tests referencing a resource, unref'ing it to zero, then using it again
163 // before returning it to the client.
164 TEST_F(SurfaceFactoryTest, ResourceReusedBeforeReturn) {
165 ResourceId first_frame_ids[] = {7};
166 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
168 // This removes all references to resource id 7.
169 SubmitFrameWithResources(NULL, 0);
171 // This references id 7 again.
172 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
174 // This removes it again.
175 SubmitFrameWithResources(NULL, 0);
177 // Now it should be returned.
178 // We don't care how many entries are in the returned array for 7, so long as
179 // the total returned count matches the submitted count.
180 const ReturnedResourceArray& returned = client_.returned_resources();
181 size_t return_count = 0;
182 for (size_t i = 0; i < returned.size(); ++i) {
183 EXPECT_EQ(7u, returned[i].id);
184 return_count += returned[i].count;
186 EXPECT_EQ(2u, return_count);
189 // Tests having resources referenced multiple times, as if referenced by
190 // multiple providers.
191 TEST_F(SurfaceFactoryTest, ResourceRefMultipleTimes) {
192 ResourceId first_frame_ids[] = {3, 4};
193 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
195 // Ref resources from the first frame twice.
196 RefCurrentFrameResources();
197 RefCurrentFrameResources();
199 ResourceId second_frame_ids[] = {4, 5};
200 SubmitFrameWithResources(second_frame_ids, arraysize(second_frame_ids));
202 // Ref resources from the second frame 3 times.
203 RefCurrentFrameResources();
204 RefCurrentFrameResources();
205 RefCurrentFrameResources();
207 // Submit a frame with no resources to remove all current frame refs from
208 // submitted resources.
209 SubmitFrameWithResources(NULL, 0);
211 EXPECT_EQ(0u, client_.returned_resources().size());
212 client_.clear_returned_resources();
214 // Expected current refs:
215 // 3 -> 2
216 // 4 -> 2 + 3 = 5
217 // 5 -> 3
219 SCOPED_TRACE("unref all 3");
220 ResourceId ids_to_unref[] = {3, 4, 5};
221 int counts[] = {1, 1, 1};
222 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
224 EXPECT_EQ(0u, client_.returned_resources().size());
225 client_.clear_returned_resources();
227 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
229 ResourceId expected_returned_ids[] = {3};
230 int expected_returned_counts[] = {1};
231 CheckReturnedResourcesMatchExpected(expected_returned_ids,
232 expected_returned_counts,
233 arraysize(expected_returned_counts));
236 // Expected refs remaining:
237 // 4 -> 3
238 // 5 -> 1
240 SCOPED_TRACE("unref 4 and 5");
241 ResourceId ids_to_unref[] = {4, 5};
242 int counts[] = {1, 1};
243 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
245 ResourceId expected_returned_ids[] = {5};
246 int expected_returned_counts[] = {1};
247 CheckReturnedResourcesMatchExpected(expected_returned_ids,
248 expected_returned_counts,
249 arraysize(expected_returned_counts));
252 // Now, just 2 refs remaining on resource 4. Unref both at once and make sure
253 // the returned count is correct.
255 SCOPED_TRACE("unref only 4");
256 ResourceId ids_to_unref[] = {4};
257 int counts[] = {2};
258 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
260 ResourceId expected_returned_ids[] = {4};
261 int expected_returned_counts[] = {2};
262 CheckReturnedResourcesMatchExpected(expected_returned_ids,
263 expected_returned_counts,
264 arraysize(expected_returned_counts));
268 TEST_F(SurfaceFactoryTest, ResourceLifetime) {
269 ResourceId first_frame_ids[] = {1, 2, 3};
270 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
272 // All of the resources submitted in the first frame are still in use at this
273 // time by virtue of being in the pending frame, so none can be returned to
274 // the client yet.
275 EXPECT_EQ(0u, client_.returned_resources().size());
276 client_.clear_returned_resources();
278 // The second frame references some of the same resources, but some different
279 // ones. We expect to receive back resource 1 with a count of 1 since it was
280 // only referenced by the first frame.
281 ResourceId second_frame_ids[] = {2, 3, 4};
282 SubmitFrameWithResources(second_frame_ids, arraysize(second_frame_ids));
285 SCOPED_TRACE("second frame");
286 ResourceId expected_returned_ids[] = {1};
287 int expected_returned_counts[] = {1};
288 CheckReturnedResourcesMatchExpected(expected_returned_ids,
289 expected_returned_counts,
290 arraysize(expected_returned_counts));
293 // The third frame references a disjoint set of resources, so we expect to
294 // receive back all resources from the first and second frames. Resource IDs 2
295 // and 3 will have counts of 2, since they were used in both frames, and
296 // resource ID 4 will have a count of 1.
297 ResourceId third_frame_ids[] = {10, 11, 12, 13};
298 SubmitFrameWithResources(third_frame_ids, arraysize(third_frame_ids));
301 SCOPED_TRACE("third frame");
302 ResourceId expected_returned_ids[] = {2, 3, 4};
303 int expected_returned_counts[] = {2, 2, 1};
304 CheckReturnedResourcesMatchExpected(expected_returned_ids,
305 expected_returned_counts,
306 arraysize(expected_returned_counts));
309 // Simulate a ResourceProvider taking a ref on all of the resources.
310 RefCurrentFrameResources();
312 ResourceId fourth_frame_ids[] = {12, 13};
313 SubmitFrameWithResources(fourth_frame_ids, arraysize(fourth_frame_ids));
315 EXPECT_EQ(0u, client_.returned_resources().size());
317 RefCurrentFrameResources();
319 // All resources are still being used by the external reference, so none can
320 // be returned to the client.
321 EXPECT_EQ(0u, client_.returned_resources().size());
323 // Release resources associated with the first RefCurrentFrameResources() call
324 // first.
326 ResourceId ids_to_unref[] = {10, 11, 12, 13};
327 int counts[] = {1, 1, 1, 1};
328 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
332 SCOPED_TRACE("fourth frame, first unref");
333 ResourceId expected_returned_ids[] = {10, 11};
334 int expected_returned_counts[] = {1, 1};
335 CheckReturnedResourcesMatchExpected(expected_returned_ids,
336 expected_returned_counts,
337 arraysize(expected_returned_counts));
341 ResourceId ids_to_unref[] = {12, 13};
342 int counts[] = {1, 1};
343 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
346 // Resources 12 and 13 are still in use by the current frame, so they
347 // shouldn't be available to be returned.
348 EXPECT_EQ(0u, client_.returned_resources().size());
350 // If we submit an empty frame, however, they should become available.
351 SubmitFrameWithResources(NULL, 0u);
354 SCOPED_TRACE("fourth frame, second unref");
355 ResourceId expected_returned_ids[] = {12, 13};
356 int expected_returned_counts[] = {2, 2};
357 CheckReturnedResourcesMatchExpected(expected_returned_ids,
358 expected_returned_counts,
359 arraysize(expected_returned_counts));
363 TEST_F(SurfaceFactoryTest, BlankNoIndexIncrement) {
364 SurfaceId surface_id(6);
365 factory_.Create(surface_id);
366 Surface* surface = manager_.GetSurfaceForId(surface_id);
367 ASSERT_NE(nullptr, surface);
368 EXPECT_EQ(2, surface->frame_index());
369 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
370 frame->delegated_frame_data.reset(new DelegatedFrameData);
372 factory_.SubmitFrame(surface_id, frame.Pass(),
373 SurfaceFactory::DrawCallback());
374 EXPECT_EQ(2, surface->frame_index());
375 factory_.Destroy(surface_id);
378 void DrawCallback(uint32* execute_count,
379 SurfaceDrawStatus* result,
380 SurfaceDrawStatus drawn) {
381 *execute_count += 1;
382 *result = drawn;
385 // Tests doing a DestroyAll before shutting down the factory;
386 TEST_F(SurfaceFactoryTest, DestroyAll) {
387 SurfaceId id(7);
388 factory_.Create(id);
390 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
391 TransferableResource resource;
392 resource.id = 1;
393 resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
394 frame_data->resource_list.push_back(resource);
395 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
396 frame->delegated_frame_data = frame_data.Pass();
397 uint32 execute_count = 0;
398 SurfaceDrawStatus drawn = SurfaceDrawStatus::DRAW_SKIPPED;
400 factory_.SubmitFrame(id, frame.Pass(),
401 base::Bind(&DrawCallback, &execute_count, &drawn));
403 surface_id_ = SurfaceId();
404 factory_.DestroyAll();
405 EXPECT_EQ(1u, execute_count);
406 EXPECT_EQ(SurfaceDrawStatus::DRAW_SKIPPED, drawn);
409 TEST_F(SurfaceFactoryTest, DestroySequence) {
410 SurfaceId id2(5);
411 factory_.Create(id2);
413 manager_.RegisterSurfaceIdNamespace(0);
415 // Check that waiting before the sequence is satisfied works.
416 manager_.GetSurfaceForId(id2)
417 ->AddDestructionDependency(SurfaceSequence(0, 4));
418 factory_.Destroy(id2);
420 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
421 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
422 frame->metadata.satisfies_sequences.push_back(6);
423 frame->metadata.satisfies_sequences.push_back(4);
424 frame->delegated_frame_data = frame_data.Pass();
425 DCHECK(manager_.GetSurfaceForId(id2));
426 factory_.SubmitFrame(surface_id_, frame.Pass(),
427 SurfaceFactory::DrawCallback());
428 DCHECK(!manager_.GetSurfaceForId(id2));
430 // Check that waiting after the sequence is satisfied works.
431 factory_.Create(id2);
432 DCHECK(manager_.GetSurfaceForId(id2));
433 manager_.GetSurfaceForId(id2)
434 ->AddDestructionDependency(SurfaceSequence(0, 6));
435 factory_.Destroy(id2);
436 DCHECK(!manager_.GetSurfaceForId(id2));
439 // Tests that Surface ID namespace invalidation correctly allows
440 // Sequences to be ignored.
441 TEST_F(SurfaceFactoryTest, InvalidIdNamespace) {
442 uint32_t id_namespace = 9u;
443 SurfaceId id(5);
444 factory_.Create(id);
446 manager_.RegisterSurfaceIdNamespace(id_namespace);
447 manager_.GetSurfaceForId(id)
448 ->AddDestructionDependency(SurfaceSequence(id_namespace, 4));
449 factory_.Destroy(id);
451 // Verify the dependency has prevented the surface from getting destroyed.
452 EXPECT_TRUE(manager_.GetSurfaceForId(id));
454 manager_.InvalidateSurfaceIdNamespace(id_namespace);
456 // Verify that the invalidated namespace caused the unsatisfied sequence
457 // to be ignored.
458 EXPECT_FALSE(manager_.GetSurfaceForId(id));
461 TEST_F(SurfaceFactoryTest, DestroyCycle) {
462 SurfaceId id2(5);
463 factory_.Create(id2);
465 manager_.RegisterSurfaceIdNamespace(0);
467 manager_.GetSurfaceForId(id2)
468 ->AddDestructionDependency(SurfaceSequence(0, 4));
470 // Give id2 a frame that references surface_id_.
472 scoped_ptr<RenderPass> render_pass(RenderPass::Create());
473 render_pass->referenced_surfaces.push_back(surface_id_);
474 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
475 frame_data->render_pass_list.push_back(render_pass.Pass());
476 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
477 frame->delegated_frame_data = frame_data.Pass();
478 factory_.SubmitFrame(id2, frame.Pass(), SurfaceFactory::DrawCallback());
480 factory_.Destroy(id2);
482 // Give surface_id_ a frame that references id2.
484 scoped_ptr<RenderPass> render_pass(RenderPass::Create());
485 render_pass->referenced_surfaces.push_back(id2);
486 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
487 frame_data->render_pass_list.push_back(render_pass.Pass());
488 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
489 frame->delegated_frame_data = frame_data.Pass();
490 factory_.SubmitFrame(surface_id_, frame.Pass(),
491 SurfaceFactory::DrawCallback());
493 factory_.Destroy(surface_id_);
494 EXPECT_TRUE(manager_.GetSurfaceForId(id2));
495 // surface_id_ should be retained by reference from id2.
496 EXPECT_TRUE(manager_.GetSurfaceForId(surface_id_));
498 // Satisfy last destruction dependency for id2.
499 std::vector<uint32_t> to_satisfy;
500 to_satisfy.push_back(4);
501 manager_.DidSatisfySequences(0, &to_satisfy);
503 // id2 and surface_id_ are in a reference cycle that has no surface
504 // sequences holding on to it, so they should be destroyed.
505 EXPECT_TRUE(!manager_.GetSurfaceForId(id2));
506 EXPECT_TRUE(!manager_.GetSurfaceForId(surface_id_));
508 surface_id_ = SurfaceId();
511 } // namespace
512 } // namespace cc