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 "cc/output/compositor_frame.h"
6 #include "cc/output/delegated_frame_data.h"
7 #include "cc/surfaces/surface.h"
8 #include "cc/surfaces/surface_factory.h"
9 #include "cc/surfaces/surface_factory_client.h"
10 #include "cc/surfaces/surface_manager.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/gfx/geometry/size.h"
17 class TestSurfaceFactoryClient
: public SurfaceFactoryClient
{
19 TestSurfaceFactoryClient() {}
20 ~TestSurfaceFactoryClient() override
{}
22 void ReturnResources(const ReturnedResourceArray
& resources
) override
{
23 returned_resources_
.insert(
24 returned_resources_
.end(), resources
.begin(), resources
.end());
27 const ReturnedResourceArray
& returned_resources() const {
28 return returned_resources_
;
31 void clear_returned_resources() { returned_resources_
.clear(); }
34 ReturnedResourceArray returned_resources_
;
36 DISALLOW_COPY_AND_ASSIGN(TestSurfaceFactoryClient
);
39 class SurfaceFactoryTest
: public testing::Test
{
41 SurfaceFactoryTest() : factory_(&manager_
, &client_
), surface_id_(3) {
42 factory_
.Create(surface_id_
, gfx::Size(5, 5));
45 virtual ~SurfaceFactoryTest() {
46 if (!surface_id_
.is_null())
47 factory_
.Destroy(surface_id_
);
50 void SubmitFrameWithResources(ResourceProvider::ResourceId
* resource_ids
,
51 size_t num_resource_ids
) {
52 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
53 for (size_t i
= 0u; i
< num_resource_ids
; ++i
) {
54 TransferableResource resource
;
55 resource
.id
= resource_ids
[i
];
56 resource
.mailbox_holder
.texture_target
= GL_TEXTURE_2D
;
57 frame_data
->resource_list
.push_back(resource
);
59 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
60 frame
->delegated_frame_data
= frame_data
.Pass();
61 factory_
.SubmitFrame(surface_id_
, frame
.Pass(), base::Closure());
64 void UnrefResources(ResourceProvider::ResourceId
* ids_to_unref
,
66 size_t num_ids_to_unref
) {
67 ReturnedResourceArray unref_array
;
68 for (size_t i
= 0; i
< num_ids_to_unref
; ++i
) {
69 ReturnedResource resource
;
70 resource
.id
= ids_to_unref
[i
];
71 resource
.count
= counts_to_unref
[i
];
72 unref_array
.push_back(resource
);
74 factory_
.UnrefResources(unref_array
);
77 void CheckReturnedResourcesMatchExpected(
78 ResourceProvider::ResourceId
* expected_returned_ids
,
79 int* expected_returned_counts
,
80 size_t expected_resources
) {
81 const ReturnedResourceArray
& actual_resources
=
82 client_
.returned_resources();
83 ASSERT_EQ(expected_resources
, actual_resources
.size());
84 for (size_t i
= 0; i
< expected_resources
; ++i
) {
85 ReturnedResource resource
= actual_resources
[i
];
86 EXPECT_EQ(expected_returned_ids
[i
], resource
.id
);
87 EXPECT_EQ(expected_returned_counts
[i
], resource
.count
);
89 client_
.clear_returned_resources();
92 void RefCurrentFrameResources() {
93 Surface
* surface
= manager_
.GetSurfaceForId(surface_id_
);
94 factory_
.RefResources(
95 surface
->GetEligibleFrame()->delegated_frame_data
->resource_list
);
99 SurfaceManager manager_
;
100 TestSurfaceFactoryClient client_
;
101 SurfaceFactory factory_
;
102 SurfaceId surface_id_
;
105 // Tests submitting a frame with resources followed by one with no resources
106 // with no resource provider action in between.
107 TEST_F(SurfaceFactoryTest
, ResourceLifetimeSimple
) {
108 ResourceProvider::ResourceId first_frame_ids
[] = {1, 2, 3};
109 SubmitFrameWithResources(first_frame_ids
, arraysize(first_frame_ids
));
111 // All of the resources submitted in the first frame are still in use at this
112 // time by virtue of being in the pending frame, so none can be returned to
114 EXPECT_EQ(0u, client_
.returned_resources().size());
115 client_
.clear_returned_resources();
117 // The second frame references no resources and thus should make all resources
118 // available to be returned.
119 SubmitFrameWithResources(NULL
, 0);
121 ResourceProvider::ResourceId expected_returned_ids
[] = {1, 2, 3};
122 int expected_returned_counts
[] = {1, 1, 1};
123 CheckReturnedResourcesMatchExpected(expected_returned_ids
,
124 expected_returned_counts
,
125 arraysize(expected_returned_counts
));
128 // Tests submitting a frame with resources followed by one with no resources
129 // with the resource provider holding everything alive.
130 TEST_F(SurfaceFactoryTest
, ResourceLifetimeSimpleWithProviderHoldingAlive
) {
131 ResourceProvider::ResourceId first_frame_ids
[] = {1, 2, 3};
132 SubmitFrameWithResources(first_frame_ids
, arraysize(first_frame_ids
));
134 // All of the resources submitted in the first frame are still in use at this
135 // time by virtue of being in the pending frame, so none can be returned to
137 EXPECT_EQ(0u, client_
.returned_resources().size());
138 client_
.clear_returned_resources();
140 // Hold on to everything.
141 RefCurrentFrameResources();
143 // The second frame references no resources and thus should make all resources
144 // available to be returned as soon as the resource provider releases them.
145 SubmitFrameWithResources(NULL
, 0);
147 EXPECT_EQ(0u, client_
.returned_resources().size());
148 client_
.clear_returned_resources();
150 int release_counts
[] = {1, 1, 1};
151 UnrefResources(first_frame_ids
, release_counts
, arraysize(first_frame_ids
));
153 ResourceProvider::ResourceId expected_returned_ids
[] = {1, 2, 3};
154 int expected_returned_counts
[] = {1, 1, 1};
155 CheckReturnedResourcesMatchExpected(expected_returned_ids
,
156 expected_returned_counts
,
157 arraysize(expected_returned_counts
));
160 // Tests referencing a resource, unref'ing it to zero, then using it again
161 // before returning it to the client.
162 TEST_F(SurfaceFactoryTest
, ResourceReusedBeforeReturn
) {
163 ResourceProvider::ResourceId first_frame_ids
[] = {7};
164 SubmitFrameWithResources(first_frame_ids
, arraysize(first_frame_ids
));
166 // This removes all references to resource id 7.
167 SubmitFrameWithResources(NULL
, 0);
169 // This references id 7 again.
170 SubmitFrameWithResources(first_frame_ids
, arraysize(first_frame_ids
));
172 // This removes it again.
173 SubmitFrameWithResources(NULL
, 0);
175 // Now it should be returned.
176 // We don't care how many entries are in the returned array for 7, so long as
177 // the total returned count matches the submitted count.
178 const ReturnedResourceArray
& returned
= client_
.returned_resources();
179 size_t return_count
= 0;
180 for (size_t i
= 0; i
< returned
.size(); ++i
) {
181 EXPECT_EQ(7u, returned
[i
].id
);
182 return_count
+= returned
[i
].count
;
184 EXPECT_EQ(2u, return_count
);
187 // Tests having resources referenced multiple times, as if referenced by
188 // multiple providers.
189 TEST_F(SurfaceFactoryTest
, ResourceRefMultipleTimes
) {
190 ResourceProvider::ResourceId first_frame_ids
[] = {3, 4};
191 SubmitFrameWithResources(first_frame_ids
, arraysize(first_frame_ids
));
193 // Ref resources from the first frame twice.
194 RefCurrentFrameResources();
195 RefCurrentFrameResources();
197 ResourceProvider::ResourceId second_frame_ids
[] = {4, 5};
198 SubmitFrameWithResources(second_frame_ids
, arraysize(second_frame_ids
));
200 // Ref resources from the second frame 3 times.
201 RefCurrentFrameResources();
202 RefCurrentFrameResources();
203 RefCurrentFrameResources();
205 // Submit a frame with no resources to remove all current frame refs from
206 // submitted resources.
207 SubmitFrameWithResources(NULL
, 0);
209 EXPECT_EQ(0u, client_
.returned_resources().size());
210 client_
.clear_returned_resources();
212 // Expected current refs:
217 SCOPED_TRACE("unref all 3");
218 ResourceProvider::ResourceId ids_to_unref
[] = {3, 4, 5};
219 int counts
[] = {1, 1, 1};
220 UnrefResources(ids_to_unref
, counts
, arraysize(ids_to_unref
));
222 EXPECT_EQ(0u, client_
.returned_resources().size());
223 client_
.clear_returned_resources();
225 UnrefResources(ids_to_unref
, counts
, arraysize(ids_to_unref
));
227 ResourceProvider::ResourceId expected_returned_ids
[] = {3};
228 int expected_returned_counts
[] = {1};
229 CheckReturnedResourcesMatchExpected(expected_returned_ids
,
230 expected_returned_counts
,
231 arraysize(expected_returned_counts
));
234 // Expected refs remaining:
238 SCOPED_TRACE("unref 4 and 5");
239 ResourceProvider::ResourceId ids_to_unref
[] = {4, 5};
240 int counts
[] = {1, 1};
241 UnrefResources(ids_to_unref
, counts
, arraysize(ids_to_unref
));
243 ResourceProvider::ResourceId expected_returned_ids
[] = {5};
244 int expected_returned_counts
[] = {1};
245 CheckReturnedResourcesMatchExpected(expected_returned_ids
,
246 expected_returned_counts
,
247 arraysize(expected_returned_counts
));
250 // Now, just 2 refs remaining on resource 4. Unref both at once and make sure
251 // the returned count is correct.
253 SCOPED_TRACE("unref only 4");
254 ResourceProvider::ResourceId ids_to_unref
[] = {4};
256 UnrefResources(ids_to_unref
, counts
, arraysize(ids_to_unref
));
258 ResourceProvider::ResourceId expected_returned_ids
[] = {4};
259 int expected_returned_counts
[] = {2};
260 CheckReturnedResourcesMatchExpected(expected_returned_ids
,
261 expected_returned_counts
,
262 arraysize(expected_returned_counts
));
266 TEST_F(SurfaceFactoryTest
, ResourceLifetime
) {
267 ResourceProvider::ResourceId first_frame_ids
[] = {1, 2, 3};
268 SubmitFrameWithResources(first_frame_ids
, arraysize(first_frame_ids
));
270 // All of the resources submitted in the first frame are still in use at this
271 // time by virtue of being in the pending frame, so none can be returned to
273 EXPECT_EQ(0u, client_
.returned_resources().size());
274 client_
.clear_returned_resources();
276 // The second frame references some of the same resources, but some different
277 // ones. We expect to receive back resource 1 with a count of 1 since it was
278 // only referenced by the first frame.
279 ResourceProvider::ResourceId second_frame_ids
[] = {2, 3, 4};
280 SubmitFrameWithResources(second_frame_ids
, arraysize(second_frame_ids
));
283 SCOPED_TRACE("second frame");
284 ResourceProvider::ResourceId expected_returned_ids
[] = {1};
285 int expected_returned_counts
[] = {1};
286 CheckReturnedResourcesMatchExpected(expected_returned_ids
,
287 expected_returned_counts
,
288 arraysize(expected_returned_counts
));
291 // The third frame references a disjoint set of resources, so we expect to
292 // receive back all resources from the first and second frames. Resource IDs 2
293 // and 3 will have counts of 2, since they were used in both frames, and
294 // resource ID 4 will have a count of 1.
295 ResourceProvider::ResourceId third_frame_ids
[] = {10, 11, 12, 13};
296 SubmitFrameWithResources(third_frame_ids
, arraysize(third_frame_ids
));
299 SCOPED_TRACE("third frame");
300 ResourceProvider::ResourceId expected_returned_ids
[] = {2, 3, 4};
301 int expected_returned_counts
[] = {2, 2, 1};
302 CheckReturnedResourcesMatchExpected(expected_returned_ids
,
303 expected_returned_counts
,
304 arraysize(expected_returned_counts
));
307 // Simulate a ResourceProvider taking a ref on all of the resources.
308 RefCurrentFrameResources();
310 ResourceProvider::ResourceId fourth_frame_ids
[] = {12, 13};
311 SubmitFrameWithResources(fourth_frame_ids
, arraysize(fourth_frame_ids
));
313 EXPECT_EQ(0u, client_
.returned_resources().size());
315 RefCurrentFrameResources();
317 // All resources are still being used by the external reference, so none can
318 // be returned to the client.
319 EXPECT_EQ(0u, client_
.returned_resources().size());
321 // Release resources associated with the first RefCurrentFrameResources() call
324 ResourceProvider::ResourceId ids_to_unref
[] = {10, 11, 12, 13};
325 int counts
[] = {1, 1, 1, 1};
326 UnrefResources(ids_to_unref
, counts
, arraysize(ids_to_unref
));
330 SCOPED_TRACE("fourth frame, first unref");
331 ResourceProvider::ResourceId expected_returned_ids
[] = {10, 11};
332 int expected_returned_counts
[] = {1, 1};
333 CheckReturnedResourcesMatchExpected(expected_returned_ids
,
334 expected_returned_counts
,
335 arraysize(expected_returned_counts
));
339 ResourceProvider::ResourceId ids_to_unref
[] = {12, 13};
340 int counts
[] = {1, 1};
341 UnrefResources(ids_to_unref
, counts
, arraysize(ids_to_unref
));
344 // Resources 12 and 13 are still in use by the current frame, so they
345 // shouldn't be available to be returned.
346 EXPECT_EQ(0u, client_
.returned_resources().size());
348 // If we submit an empty frame, however, they should become available.
349 SubmitFrameWithResources(NULL
, 0u);
352 SCOPED_TRACE("fourth frame, second unref");
353 ResourceProvider::ResourceId expected_returned_ids
[] = {12, 13};
354 int expected_returned_counts
[] = {2, 2};
355 CheckReturnedResourcesMatchExpected(expected_returned_ids
,
356 expected_returned_counts
,
357 arraysize(expected_returned_counts
));
361 // Tests doing a DestroyAll before shutting down the factory;
362 TEST_F(SurfaceFactoryTest
, DestroyAll
) {
364 factory_
.Create(id
, gfx::Size(1, 1));
366 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
367 TransferableResource resource
;
369 resource
.mailbox_holder
.texture_target
= GL_TEXTURE_2D
;
370 frame_data
->resource_list
.push_back(resource
);
371 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
372 frame
->delegated_frame_data
= frame_data
.Pass();
373 factory_
.SubmitFrame(id
, frame
.Pass(), base::Closure());
375 surface_id_
= SurfaceId();
376 factory_
.DestroyAll();
379 TEST_F(SurfaceFactoryTest
, DestroySequence
) {
381 factory_
.Create(id2
, gfx::Size(5, 5));
383 // Check that waiting before the sequence is satisfied works.
384 std::set
<SurfaceSequence
> sequence
;
385 sequence
.insert(SurfaceSequence(0, 4));
386 factory_
.DestroyOnSequence(id2
, sequence
);
388 scoped_ptr
<DelegatedFrameData
> frame_data(new DelegatedFrameData
);
389 scoped_ptr
<CompositorFrame
> frame(new CompositorFrame
);
390 frame
->metadata
.satisfies_sequences
.push_back(6);
391 frame
->metadata
.satisfies_sequences
.push_back(4);
392 frame
->delegated_frame_data
= frame_data
.Pass();
393 DCHECK(manager_
.GetSurfaceForId(id2
));
394 factory_
.SubmitFrame(surface_id_
, frame
.Pass(), base::Closure());
395 DCHECK(!manager_
.GetSurfaceForId(id2
));
397 // Check that waiting after the sequence is satisfied works.
398 factory_
.Create(id2
, gfx::Size(5, 5));
400 sequence
.insert(SurfaceSequence(0, 6));
401 DCHECK(manager_
.GetSurfaceForId(id2
));
402 factory_
.DestroyOnSequence(id2
, sequence
);
403 DCHECK(!manager_
.GetSurfaceForId(id2
));