[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / cc / surfaces / surface_factory_unittest.cc
blobc7ce96403e2468ba29721fddf17aad21881c76ec
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 SubmitCompositorFrameWithResources(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_.SubmitCompositorFrame(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 SubmitCompositorFrameWithResources(first_frame_ids,
112 arraysize(first_frame_ids));
114 // All of the resources submitted in the first frame are still in use at this
115 // time by virtue of being in the pending frame, so none can be returned to
116 // the client yet.
117 EXPECT_EQ(0u, client_.returned_resources().size());
118 client_.clear_returned_resources();
120 // The second frame references no resources and thus should make all resources
121 // available to be returned.
122 SubmitCompositorFrameWithResources(NULL, 0);
124 ResourceId expected_returned_ids[] = {1, 2, 3};
125 int expected_returned_counts[] = {1, 1, 1};
126 CheckReturnedResourcesMatchExpected(expected_returned_ids,
127 expected_returned_counts,
128 arraysize(expected_returned_counts));
131 // Tests submitting a frame with resources followed by one with no resources
132 // with the resource provider holding everything alive.
133 TEST_F(SurfaceFactoryTest, ResourceLifetimeSimpleWithProviderHoldingAlive) {
134 ResourceId first_frame_ids[] = {1, 2, 3};
135 SubmitCompositorFrameWithResources(first_frame_ids,
136 arraysize(first_frame_ids));
138 // All of the resources submitted in the first frame are still in use at this
139 // time by virtue of being in the pending frame, so none can be returned to
140 // the client yet.
141 EXPECT_EQ(0u, client_.returned_resources().size());
142 client_.clear_returned_resources();
144 // Hold on to everything.
145 RefCurrentFrameResources();
147 // The second frame references no resources and thus should make all resources
148 // available to be returned as soon as the resource provider releases them.
149 SubmitCompositorFrameWithResources(NULL, 0);
151 EXPECT_EQ(0u, client_.returned_resources().size());
152 client_.clear_returned_resources();
154 int release_counts[] = {1, 1, 1};
155 UnrefResources(first_frame_ids, release_counts, arraysize(first_frame_ids));
157 ResourceId expected_returned_ids[] = {1, 2, 3};
158 int expected_returned_counts[] = {1, 1, 1};
159 CheckReturnedResourcesMatchExpected(expected_returned_ids,
160 expected_returned_counts,
161 arraysize(expected_returned_counts));
164 // Tests referencing a resource, unref'ing it to zero, then using it again
165 // before returning it to the client.
166 TEST_F(SurfaceFactoryTest, ResourceReusedBeforeReturn) {
167 ResourceId first_frame_ids[] = {7};
168 SubmitCompositorFrameWithResources(first_frame_ids,
169 arraysize(first_frame_ids));
171 // This removes all references to resource id 7.
172 SubmitCompositorFrameWithResources(NULL, 0);
174 // This references id 7 again.
175 SubmitCompositorFrameWithResources(first_frame_ids,
176 arraysize(first_frame_ids));
178 // This removes it again.
179 SubmitCompositorFrameWithResources(NULL, 0);
181 // Now it should be returned.
182 // We don't care how many entries are in the returned array for 7, so long as
183 // the total returned count matches the submitted count.
184 const ReturnedResourceArray& returned = client_.returned_resources();
185 size_t return_count = 0;
186 for (size_t i = 0; i < returned.size(); ++i) {
187 EXPECT_EQ(7u, returned[i].id);
188 return_count += returned[i].count;
190 EXPECT_EQ(2u, return_count);
193 // Tests having resources referenced multiple times, as if referenced by
194 // multiple providers.
195 TEST_F(SurfaceFactoryTest, ResourceRefMultipleTimes) {
196 ResourceId first_frame_ids[] = {3, 4};
197 SubmitCompositorFrameWithResources(first_frame_ids,
198 arraysize(first_frame_ids));
200 // Ref resources from the first frame twice.
201 RefCurrentFrameResources();
202 RefCurrentFrameResources();
204 ResourceId second_frame_ids[] = {4, 5};
205 SubmitCompositorFrameWithResources(second_frame_ids,
206 arraysize(second_frame_ids));
208 // Ref resources from the second frame 3 times.
209 RefCurrentFrameResources();
210 RefCurrentFrameResources();
211 RefCurrentFrameResources();
213 // Submit a frame with no resources to remove all current frame refs from
214 // submitted resources.
215 SubmitCompositorFrameWithResources(NULL, 0);
217 EXPECT_EQ(0u, client_.returned_resources().size());
218 client_.clear_returned_resources();
220 // Expected current refs:
221 // 3 -> 2
222 // 4 -> 2 + 3 = 5
223 // 5 -> 3
225 SCOPED_TRACE("unref all 3");
226 ResourceId ids_to_unref[] = {3, 4, 5};
227 int counts[] = {1, 1, 1};
228 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
230 EXPECT_EQ(0u, client_.returned_resources().size());
231 client_.clear_returned_resources();
233 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
235 ResourceId expected_returned_ids[] = {3};
236 int expected_returned_counts[] = {1};
237 CheckReturnedResourcesMatchExpected(expected_returned_ids,
238 expected_returned_counts,
239 arraysize(expected_returned_counts));
242 // Expected refs remaining:
243 // 4 -> 3
244 // 5 -> 1
246 SCOPED_TRACE("unref 4 and 5");
247 ResourceId ids_to_unref[] = {4, 5};
248 int counts[] = {1, 1};
249 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
251 ResourceId expected_returned_ids[] = {5};
252 int expected_returned_counts[] = {1};
253 CheckReturnedResourcesMatchExpected(expected_returned_ids,
254 expected_returned_counts,
255 arraysize(expected_returned_counts));
258 // Now, just 2 refs remaining on resource 4. Unref both at once and make sure
259 // the returned count is correct.
261 SCOPED_TRACE("unref only 4");
262 ResourceId ids_to_unref[] = {4};
263 int counts[] = {2};
264 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
266 ResourceId expected_returned_ids[] = {4};
267 int expected_returned_counts[] = {2};
268 CheckReturnedResourcesMatchExpected(expected_returned_ids,
269 expected_returned_counts,
270 arraysize(expected_returned_counts));
274 TEST_F(SurfaceFactoryTest, ResourceLifetime) {
275 ResourceId first_frame_ids[] = {1, 2, 3};
276 SubmitCompositorFrameWithResources(first_frame_ids,
277 arraysize(first_frame_ids));
279 // All of the resources submitted in the first frame are still in use at this
280 // time by virtue of being in the pending frame, so none can be returned to
281 // the client yet.
282 EXPECT_EQ(0u, client_.returned_resources().size());
283 client_.clear_returned_resources();
285 // The second frame references some of the same resources, but some different
286 // ones. We expect to receive back resource 1 with a count of 1 since it was
287 // only referenced by the first frame.
288 ResourceId second_frame_ids[] = {2, 3, 4};
289 SubmitCompositorFrameWithResources(second_frame_ids,
290 arraysize(second_frame_ids));
293 SCOPED_TRACE("second frame");
294 ResourceId expected_returned_ids[] = {1};
295 int expected_returned_counts[] = {1};
296 CheckReturnedResourcesMatchExpected(expected_returned_ids,
297 expected_returned_counts,
298 arraysize(expected_returned_counts));
301 // The third frame references a disjoint set of resources, so we expect to
302 // receive back all resources from the first and second frames. Resource IDs 2
303 // and 3 will have counts of 2, since they were used in both frames, and
304 // resource ID 4 will have a count of 1.
305 ResourceId third_frame_ids[] = {10, 11, 12, 13};
306 SubmitCompositorFrameWithResources(third_frame_ids,
307 arraysize(third_frame_ids));
310 SCOPED_TRACE("third frame");
311 ResourceId expected_returned_ids[] = {2, 3, 4};
312 int expected_returned_counts[] = {2, 2, 1};
313 CheckReturnedResourcesMatchExpected(expected_returned_ids,
314 expected_returned_counts,
315 arraysize(expected_returned_counts));
318 // Simulate a ResourceProvider taking a ref on all of the resources.
319 RefCurrentFrameResources();
321 ResourceId fourth_frame_ids[] = {12, 13};
322 SubmitCompositorFrameWithResources(fourth_frame_ids,
323 arraysize(fourth_frame_ids));
325 EXPECT_EQ(0u, client_.returned_resources().size());
327 RefCurrentFrameResources();
329 // All resources are still being used by the external reference, so none can
330 // be returned to the client.
331 EXPECT_EQ(0u, client_.returned_resources().size());
333 // Release resources associated with the first RefCurrentFrameResources() call
334 // first.
336 ResourceId ids_to_unref[] = {10, 11, 12, 13};
337 int counts[] = {1, 1, 1, 1};
338 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
342 SCOPED_TRACE("fourth frame, first unref");
343 ResourceId expected_returned_ids[] = {10, 11};
344 int expected_returned_counts[] = {1, 1};
345 CheckReturnedResourcesMatchExpected(expected_returned_ids,
346 expected_returned_counts,
347 arraysize(expected_returned_counts));
351 ResourceId ids_to_unref[] = {12, 13};
352 int counts[] = {1, 1};
353 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
356 // Resources 12 and 13 are still in use by the current frame, so they
357 // shouldn't be available to be returned.
358 EXPECT_EQ(0u, client_.returned_resources().size());
360 // If we submit an empty frame, however, they should become available.
361 SubmitCompositorFrameWithResources(NULL, 0u);
364 SCOPED_TRACE("fourth frame, second unref");
365 ResourceId expected_returned_ids[] = {12, 13};
366 int expected_returned_counts[] = {2, 2};
367 CheckReturnedResourcesMatchExpected(expected_returned_ids,
368 expected_returned_counts,
369 arraysize(expected_returned_counts));
373 TEST_F(SurfaceFactoryTest, BlankNoIndexIncrement) {
374 SurfaceId surface_id(6);
375 factory_.Create(surface_id);
376 Surface* surface = manager_.GetSurfaceForId(surface_id);
377 ASSERT_NE(nullptr, surface);
378 EXPECT_EQ(2, surface->frame_index());
379 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
380 frame->delegated_frame_data.reset(new DelegatedFrameData);
382 factory_.SubmitCompositorFrame(surface_id, frame.Pass(),
383 SurfaceFactory::DrawCallback());
384 EXPECT_EQ(2, surface->frame_index());
385 factory_.Destroy(surface_id);
388 void DrawCallback(uint32* execute_count,
389 SurfaceDrawStatus* result,
390 SurfaceDrawStatus drawn) {
391 *execute_count += 1;
392 *result = drawn;
395 // Tests doing a DestroyAll before shutting down the factory;
396 TEST_F(SurfaceFactoryTest, DestroyAll) {
397 SurfaceId id(7);
398 factory_.Create(id);
400 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
401 TransferableResource resource;
402 resource.id = 1;
403 resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
404 frame_data->resource_list.push_back(resource);
405 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
406 frame->delegated_frame_data = frame_data.Pass();
407 uint32 execute_count = 0;
408 SurfaceDrawStatus drawn = SurfaceDrawStatus::DRAW_SKIPPED;
410 factory_.SubmitCompositorFrame(
411 id, frame.Pass(), base::Bind(&DrawCallback, &execute_count, &drawn));
413 surface_id_ = SurfaceId();
414 factory_.DestroyAll();
415 EXPECT_EQ(1u, execute_count);
416 EXPECT_EQ(SurfaceDrawStatus::DRAW_SKIPPED, drawn);
419 TEST_F(SurfaceFactoryTest, DestroySequence) {
420 SurfaceId id2(5);
421 factory_.Create(id2);
423 manager_.RegisterSurfaceIdNamespace(0);
425 // Check that waiting before the sequence is satisfied works.
426 manager_.GetSurfaceForId(id2)
427 ->AddDestructionDependency(SurfaceSequence(0, 4));
428 factory_.Destroy(id2);
430 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
431 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
432 frame->metadata.satisfies_sequences.push_back(6);
433 frame->metadata.satisfies_sequences.push_back(4);
434 frame->delegated_frame_data = frame_data.Pass();
435 DCHECK(manager_.GetSurfaceForId(id2));
436 factory_.SubmitCompositorFrame(surface_id_, frame.Pass(),
437 SurfaceFactory::DrawCallback());
438 DCHECK(!manager_.GetSurfaceForId(id2));
440 // Check that waiting after the sequence is satisfied works.
441 factory_.Create(id2);
442 DCHECK(manager_.GetSurfaceForId(id2));
443 manager_.GetSurfaceForId(id2)
444 ->AddDestructionDependency(SurfaceSequence(0, 6));
445 factory_.Destroy(id2);
446 DCHECK(!manager_.GetSurfaceForId(id2));
449 // Tests that Surface ID namespace invalidation correctly allows
450 // Sequences to be ignored.
451 TEST_F(SurfaceFactoryTest, InvalidIdNamespace) {
452 uint32_t id_namespace = 9u;
453 SurfaceId id(5);
454 factory_.Create(id);
456 manager_.RegisterSurfaceIdNamespace(id_namespace);
457 manager_.GetSurfaceForId(id)
458 ->AddDestructionDependency(SurfaceSequence(id_namespace, 4));
459 factory_.Destroy(id);
461 // Verify the dependency has prevented the surface from getting destroyed.
462 EXPECT_TRUE(manager_.GetSurfaceForId(id));
464 manager_.InvalidateSurfaceIdNamespace(id_namespace);
466 // Verify that the invalidated namespace caused the unsatisfied sequence
467 // to be ignored.
468 EXPECT_FALSE(manager_.GetSurfaceForId(id));
471 TEST_F(SurfaceFactoryTest, DestroyCycle) {
472 SurfaceId id2(5);
473 factory_.Create(id2);
475 manager_.RegisterSurfaceIdNamespace(0);
477 manager_.GetSurfaceForId(id2)
478 ->AddDestructionDependency(SurfaceSequence(0, 4));
480 // Give id2 a frame that references surface_id_.
482 scoped_ptr<RenderPass> render_pass(RenderPass::Create());
483 render_pass->referenced_surfaces.push_back(surface_id_);
484 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
485 frame_data->render_pass_list.push_back(render_pass.Pass());
486 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
487 frame->delegated_frame_data = frame_data.Pass();
488 factory_.SubmitCompositorFrame(id2, frame.Pass(),
489 SurfaceFactory::DrawCallback());
491 factory_.Destroy(id2);
493 // Give surface_id_ a frame that references id2.
495 scoped_ptr<RenderPass> render_pass(RenderPass::Create());
496 render_pass->referenced_surfaces.push_back(id2);
497 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
498 frame_data->render_pass_list.push_back(render_pass.Pass());
499 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
500 frame->delegated_frame_data = frame_data.Pass();
501 factory_.SubmitCompositorFrame(surface_id_, frame.Pass(),
502 SurfaceFactory::DrawCallback());
504 factory_.Destroy(surface_id_);
505 EXPECT_TRUE(manager_.GetSurfaceForId(id2));
506 // surface_id_ should be retained by reference from id2.
507 EXPECT_TRUE(manager_.GetSurfaceForId(surface_id_));
509 // Satisfy last destruction dependency for id2.
510 std::vector<uint32_t> to_satisfy;
511 to_satisfy.push_back(4);
512 manager_.DidSatisfySequences(0, &to_satisfy);
514 // id2 and surface_id_ are in a reference cycle that has no surface
515 // sequences holding on to it, so they should be destroyed.
516 EXPECT_TRUE(!manager_.GetSurfaceForId(id2));
517 EXPECT_TRUE(!manager_.GetSurfaceForId(surface_id_));
519 surface_id_ = SurfaceId();
522 } // namespace
523 } // namespace cc