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_client.h"
9 #include "cc/surfaces/surface_manager.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "ui/gfx/size.h"
16 TEST(SurfaceTest, SurfaceLifetime) {
17 SurfaceManager manager;
21 Surface surface(&manager, NULL, gfx::Size(5, 5));
22 surface_id = surface.surface_id();
23 EXPECT_TRUE(!surface_id.is_null());
24 EXPECT_EQ(&surface, manager.GetSurfaceForId(surface_id));
27 EXPECT_EQ(NULL, manager.GetSurfaceForId(surface_id));
30 class TestSurfaceClient : public SurfaceClient {
32 TestSurfaceClient() {}
33 virtual ~TestSurfaceClient() {}
35 virtual void ReturnResources(
36 const ReturnedResourceArray& resources) OVERRIDE {
37 returned_resources_ = resources;
40 const ReturnedResourceArray& returned_resources() const {
41 return returned_resources_;
44 void clear_returned_resources() { returned_resources_.clear(); }
47 ReturnedResourceArray returned_resources_;
49 DISALLOW_COPY_AND_ASSIGN(TestSurfaceClient);
52 void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids,
53 size_t num_resource_ids,
55 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
56 for (size_t i = 0u; i < num_resource_ids; ++i) {
57 TransferableResource resource;
58 resource.id = resource_ids[i];
59 resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
60 frame_data->resource_list.push_back(resource);
62 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
63 frame->delegated_frame_data = frame_data.Pass();
64 surface->QueueFrame(frame.Pass());
67 void CheckReturnedResourcesMatchExpected(
68 ResourceProvider::ResourceId* expected_returned_ids,
69 int* expected_returned_counts,
70 size_t expected_resources,
71 const ReturnedResourceArray& actual_resources) {
72 ASSERT_EQ(expected_resources, actual_resources.size());
73 for (size_t i = 0; i < expected_resources; ++i) {
74 ReturnedResource resource = actual_resources[i];
75 EXPECT_EQ(expected_returned_ids[i], resource.id);
76 EXPECT_EQ(expected_returned_counts[i], resource.count);
80 void UnrefResources(ResourceProvider::ResourceId* ids_to_unref,
82 size_t num_ids_to_unref,
84 ReturnedResourceArray unref_array;
85 for (size_t i = 0; i < num_ids_to_unref; ++i) {
86 ReturnedResource resource;
87 resource.id = ids_to_unref[i];
88 resource.count = counts_to_unref[i];
89 unref_array.push_back(resource);
91 surface->UnrefResources(unref_array);
94 // Tests submitting a frame with resources followed by one with no resources
95 // with no resource provider action in between.
96 TEST(SurfaceTest, ResourceLifetimeSimple) {
97 SurfaceManager manager;
98 TestSurfaceClient client;
99 Surface surface(&manager, &client, gfx::Size(5, 5));
101 ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
102 SubmitFrameWithResources(
103 first_frame_ids, arraysize(first_frame_ids), &surface);
105 // All of the resources submitted in the first frame are still in use at this
106 // time by virtue of being in the pending frame, so none can be returned to
108 surface.ReturnUnusedResourcesToClient();
109 EXPECT_EQ(0u, client.returned_resources().size());
110 client.clear_returned_resources();
112 // The second frame references no resources and thus should make all resources
113 // available to be returned.
114 SubmitFrameWithResources(NULL, 0, &surface);
116 surface.ReturnUnusedResourcesToClient();
117 ResourceProvider::ResourceId expected_returned_ids[] = {1, 2, 3};
118 int expected_returned_counts[] = {1, 1, 1};
119 CheckReturnedResourcesMatchExpected(expected_returned_ids,
120 expected_returned_counts,
121 arraysize(expected_returned_counts),
122 client.returned_resources());
125 // Tests submitting a frame with resources followed by one with no resources
126 // with the resource provider holding everything alive.
127 TEST(SurfaceTest, ResourceLifetimeSimpleWithProviderHoldingAlive) {
128 SurfaceManager manager;
129 TestSurfaceClient client;
130 Surface surface(&manager, &client, gfx::Size(5, 5));
132 ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
133 SubmitFrameWithResources(
134 first_frame_ids, arraysize(first_frame_ids), &surface);
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
139 surface.ReturnUnusedResourcesToClient();
140 EXPECT_EQ(0u, client.returned_resources().size());
141 client.clear_returned_resources();
143 // Hold on to everything.
144 surface.RefCurrentFrameResources();
146 // The second frame references no resources and thus should make all resources
147 // available to be returned as soon as the resource provider releases them.
148 SubmitFrameWithResources(NULL, 0, &surface);
150 surface.ReturnUnusedResourcesToClient();
151 EXPECT_EQ(0u, client.returned_resources().size());
152 client.clear_returned_resources();
154 int release_counts[] = {1, 1, 1};
156 first_frame_ids, release_counts, arraysize(first_frame_ids), &surface);
158 surface.ReturnUnusedResourcesToClient();
159 ResourceProvider::ResourceId expected_returned_ids[] = {1, 2, 3};
160 int expected_returned_counts[] = {1, 1, 1};
161 CheckReturnedResourcesMatchExpected(expected_returned_ids,
162 expected_returned_counts,
163 arraysize(expected_returned_counts),
164 client.returned_resources());
167 // Tests referencing a resource, unref'ing it to zero, then using it again
168 // before returning it to the client.
169 TEST(SurfaceTest, ResourceReusedBeforeReturn) {
170 SurfaceManager manager;
171 TestSurfaceClient client;
172 Surface surface(&manager, &client, gfx::Size(5, 5));
174 ResourceProvider::ResourceId first_frame_ids[] = {7};
175 SubmitFrameWithResources(
176 first_frame_ids, arraysize(first_frame_ids), &surface);
178 // This removes all references to resource id 7.
179 SubmitFrameWithResources(NULL, 0, &surface);
181 // This references id 7 again.
182 SubmitFrameWithResources(
183 first_frame_ids, arraysize(first_frame_ids), &surface);
185 // This removes it again.
186 SubmitFrameWithResources(NULL, 0, &surface);
188 // Now it should be returned.
189 surface.ReturnUnusedResourcesToClient();
191 // We don't care how many entries are in the returned array for 7, so long as
192 // the total returned count matches the submitted count.
193 const ReturnedResourceArray& returned = client.returned_resources();
194 size_t return_count = 0;
195 for (size_t i = 0; i < returned.size(); ++i) {
196 EXPECT_EQ(7u, returned[i].id);
197 return_count += returned[i].count;
199 EXPECT_EQ(2u, return_count);
202 // Tests having resources referenced multiple times, as if referenced by
203 // multiple providers.
204 TEST(SurfaceTest, ResourceRefMultipleTimes) {
205 SurfaceManager manager;
206 TestSurfaceClient client;
207 Surface surface(&manager, &client, gfx::Size(5, 5));
209 ResourceProvider::ResourceId first_frame_ids[] = {3, 4};
210 SubmitFrameWithResources(
211 first_frame_ids, arraysize(first_frame_ids), &surface);
213 // Ref resources from the first frame twice.
214 surface.RefCurrentFrameResources();
215 surface.RefCurrentFrameResources();
217 ResourceProvider::ResourceId second_frame_ids[] = {4, 5};
218 SubmitFrameWithResources(
219 second_frame_ids, arraysize(second_frame_ids), &surface);
221 // Ref resources from the second frame 3 times.
222 surface.RefCurrentFrameResources();
223 surface.RefCurrentFrameResources();
224 surface.RefCurrentFrameResources();
226 // Submit a frame with no resources to remove all current frame refs from
227 // submitted resources.
228 SubmitFrameWithResources(NULL, 0, &surface);
230 surface.ReturnUnusedResourcesToClient();
231 EXPECT_EQ(0u, client.returned_resources().size());
232 client.clear_returned_resources();
234 // Expected current refs:
239 SCOPED_TRACE("unref all 3");
240 ResourceProvider::ResourceId ids_to_unref[] = {3, 4, 5};
241 int counts[] = {1, 1, 1};
242 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
244 surface.ReturnUnusedResourcesToClient();
245 EXPECT_EQ(0u, client.returned_resources().size());
246 client.clear_returned_resources();
248 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
250 surface.ReturnUnusedResourcesToClient();
251 ResourceProvider::ResourceId expected_returned_ids[] = {3};
252 int expected_returned_counts[] = {1};
253 CheckReturnedResourcesMatchExpected(expected_returned_ids,
254 expected_returned_counts,
255 arraysize(expected_returned_counts),
256 client.returned_resources());
259 // Expected refs remaining:
263 SCOPED_TRACE("unref 4 and 5");
264 ResourceProvider::ResourceId ids_to_unref[] = {4, 5};
265 int counts[] = {1, 1};
266 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
268 surface.ReturnUnusedResourcesToClient();
269 ResourceProvider::ResourceId expected_returned_ids[] = {5};
270 int expected_returned_counts[] = {1};
271 CheckReturnedResourcesMatchExpected(expected_returned_ids,
272 expected_returned_counts,
273 arraysize(expected_returned_counts),
274 client.returned_resources());
277 // Now, just 2 refs remaining on resource 4. Unref both at once and make sure
278 // the returned count is correct.
280 SCOPED_TRACE("unref only 4");
281 ResourceProvider::ResourceId ids_to_unref[] = {4};
283 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
285 surface.ReturnUnusedResourcesToClient();
286 ResourceProvider::ResourceId expected_returned_ids[] = {4};
287 int expected_returned_counts[] = {2};
288 CheckReturnedResourcesMatchExpected(expected_returned_ids,
289 expected_returned_counts,
290 arraysize(expected_returned_counts),
291 client.returned_resources());
295 TEST(SurfaceTest, ResourceLifetime) {
296 SurfaceManager manager;
297 TestSurfaceClient client;
298 Surface surface(&manager, &client, gfx::Size(5, 5));
300 ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
301 SubmitFrameWithResources(
302 first_frame_ids, arraysize(first_frame_ids), &surface);
304 // All of the resources submitted in the first frame are still in use at this
305 // time by virtue of being in the pending frame, so none can be returned to
307 surface.ReturnUnusedResourcesToClient();
308 EXPECT_EQ(0u, client.returned_resources().size());
309 client.clear_returned_resources();
311 // The second frame references some of the same resources, but some different
312 // ones. We expect to receive back resource 1 with a count of 1 since it was
313 // only referenced by the first frame.
314 ResourceProvider::ResourceId second_frame_ids[] = {2, 3, 4};
315 SubmitFrameWithResources(
316 second_frame_ids, arraysize(second_frame_ids), &surface);
318 surface.ReturnUnusedResourcesToClient();
320 SCOPED_TRACE("second frame");
321 ResourceProvider::ResourceId expected_returned_ids[] = {1};
322 int expected_returned_counts[] = {1};
323 CheckReturnedResourcesMatchExpected(expected_returned_ids,
324 expected_returned_counts,
325 arraysize(expected_returned_counts),
326 client.returned_resources());
329 // The third frame references a disjoint set of resources, so we expect to
330 // receive back all resources from the first and second frames. Resource IDs 2
331 // and 3 will have counts of 2, since they were used in both frames, and
332 // resource ID 4 will have a count of 1.
333 ResourceProvider::ResourceId third_frame_ids[] = {10, 11, 12, 13};
334 SubmitFrameWithResources(
335 third_frame_ids, arraysize(third_frame_ids), &surface);
337 surface.ReturnUnusedResourcesToClient();
339 SCOPED_TRACE("third frame");
340 ResourceProvider::ResourceId expected_returned_ids[] = {2, 3, 4};
341 int expected_returned_counts[] = {2, 2, 1};
342 CheckReturnedResourcesMatchExpected(expected_returned_ids,
343 expected_returned_counts,
344 arraysize(expected_returned_counts),
345 client.returned_resources());
348 // Simulate a ResourceProvider taking a ref on all of the resources.
349 surface.RefCurrentFrameResources();
351 ResourceProvider::ResourceId fourth_frame_ids[] = {12, 13};
352 SubmitFrameWithResources(
353 fourth_frame_ids, arraysize(fourth_frame_ids), &surface);
355 surface.ReturnUnusedResourcesToClient();
356 EXPECT_EQ(0u, client.returned_resources().size());
358 surface.RefCurrentFrameResources();
360 // All resources are still being used by the external reference, so none can
361 // be returned to the client.
362 surface.ReturnUnusedResourcesToClient();
363 EXPECT_EQ(0u, client.returned_resources().size());
365 // Release resources associated with the first RefCurrentFrameResources() call
368 ResourceProvider::ResourceId ids_to_unref[] = {10, 11, 12, 13};
369 int counts[] = {1, 1, 1, 1};
370 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
373 surface.ReturnUnusedResourcesToClient();
375 SCOPED_TRACE("fourth frame, first unref");
376 ResourceProvider::ResourceId expected_returned_ids[] = {10, 11};
377 int expected_returned_counts[] = {1, 1};
378 CheckReturnedResourcesMatchExpected(expected_returned_ids,
379 expected_returned_counts,
380 arraysize(expected_returned_counts),
381 client.returned_resources());
385 ResourceProvider::ResourceId ids_to_unref[] = {12, 13};
386 int counts[] = {1, 1};
387 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
390 // Resources 12 and 13 are still in use by the current frame, so they
391 // shouldn't be available to be returned.
392 surface.ReturnUnusedResourcesToClient();
393 EXPECT_EQ(0u, client.returned_resources().size());
395 // If we submit an empty frame, however, they should become available.
396 SubmitFrameWithResources(NULL, 0u, &surface);
398 surface.ReturnUnusedResourcesToClient();
400 SCOPED_TRACE("fourth frame, second unref");
401 ResourceProvider::ResourceId expected_returned_ids[] = {12, 13};
402 int expected_returned_counts[] = {2, 2};
403 CheckReturnedResourcesMatchExpected(expected_returned_ids,
404 expected_returned_counts,
405 arraysize(expected_returned_counts),
406 client.returned_resources());