blob: 4e0865a23876e01d439e430d413e8ffbf7524ada [file] [log] [blame]
[email protected]387b59d2014-06-27 01:17:341// 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.
4
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"
heejin.r.chungd28506ba2014-10-23 16:36:2012#include "ui/gfx/geometry/size.h"
[email protected]387b59d2014-06-27 01:17:3413
14namespace cc {
15namespace {
16
17class TestSurfaceFactoryClient : public SurfaceFactoryClient {
18 public:
19 TestSurfaceFactoryClient() {}
dcheng716bedf2014-10-21 09:51:0820 ~TestSurfaceFactoryClient() override {}
[email protected]387b59d2014-06-27 01:17:3421
dcheng716bedf2014-10-21 09:51:0822 void ReturnResources(const ReturnedResourceArray& resources) override {
[email protected]387b59d2014-06-27 01:17:3423 returned_resources_.insert(
24 returned_resources_.end(), resources.begin(), resources.end());
25 }
26
27 const ReturnedResourceArray& returned_resources() const {
28 return returned_resources_;
29 }
30
31 void clear_returned_resources() { returned_resources_.clear(); }
32
33 private:
34 ReturnedResourceArray returned_resources_;
35
36 DISALLOW_COPY_AND_ASSIGN(TestSurfaceFactoryClient);
37};
38
39class SurfaceFactoryTest : public testing::Test {
40 public:
[email protected]cde792132014-07-02 06:52:4641 SurfaceFactoryTest() : factory_(&manager_, &client_), surface_id_(3) {
42 factory_.Create(surface_id_, gfx::Size(5, 5));
43 }
[email protected]387b59d2014-06-27 01:17:3444
45 virtual ~SurfaceFactoryTest() { factory_.Destroy(surface_id_); }
46
47 void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids,
48 size_t num_resource_ids) {
49 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
50 for (size_t i = 0u; i < num_resource_ids; ++i) {
51 TransferableResource resource;
52 resource.id = resource_ids[i];
53 resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
54 frame_data->resource_list.push_back(resource);
55 }
56 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
57 frame->delegated_frame_data = frame_data.Pass();
jbauman878e9532014-08-23 22:10:2358 factory_.SubmitFrame(surface_id_, frame.Pass(), base::Closure());
[email protected]387b59d2014-06-27 01:17:3459 }
60
61 void UnrefResources(ResourceProvider::ResourceId* ids_to_unref,
62 int* counts_to_unref,
63 size_t num_ids_to_unref) {
64 ReturnedResourceArray unref_array;
65 for (size_t i = 0; i < num_ids_to_unref; ++i) {
66 ReturnedResource resource;
67 resource.id = ids_to_unref[i];
68 resource.count = counts_to_unref[i];
69 unref_array.push_back(resource);
70 }
71 factory_.UnrefResources(unref_array);
72 }
73
74 void CheckReturnedResourcesMatchExpected(
75 ResourceProvider::ResourceId* expected_returned_ids,
76 int* expected_returned_counts,
77 size_t expected_resources) {
78 const ReturnedResourceArray& actual_resources =
79 client_.returned_resources();
80 ASSERT_EQ(expected_resources, actual_resources.size());
81 for (size_t i = 0; i < expected_resources; ++i) {
82 ReturnedResource resource = actual_resources[i];
83 EXPECT_EQ(expected_returned_ids[i], resource.id);
84 EXPECT_EQ(expected_returned_counts[i], resource.count);
85 }
86 client_.clear_returned_resources();
87 }
88
89 void RefCurrentFrameResources() {
90 Surface* surface = manager_.GetSurfaceForId(surface_id_);
91 factory_.RefResources(
92 surface->GetEligibleFrame()->delegated_frame_data->resource_list);
93 }
94
95 protected:
96 SurfaceManager manager_;
97 TestSurfaceFactoryClient client_;
98 SurfaceFactory factory_;
99 SurfaceId surface_id_;
100};
101
102// Tests submitting a frame with resources followed by one with no resources
103// with no resource provider action in between.
104TEST_F(SurfaceFactoryTest, ResourceLifetimeSimple) {
105 ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
106 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
107
108 // All of the resources submitted in the first frame are still in use at this
109 // time by virtue of being in the pending frame, so none can be returned to
110 // the client yet.
111 EXPECT_EQ(0u, client_.returned_resources().size());
112 client_.clear_returned_resources();
113
114 // The second frame references no resources and thus should make all resources
115 // available to be returned.
116 SubmitFrameWithResources(NULL, 0);
117
118 ResourceProvider::ResourceId expected_returned_ids[] = {1, 2, 3};
119 int expected_returned_counts[] = {1, 1, 1};
120 CheckReturnedResourcesMatchExpected(expected_returned_ids,
121 expected_returned_counts,
122 arraysize(expected_returned_counts));
123}
124
125// Tests submitting a frame with resources followed by one with no resources
126// with the resource provider holding everything alive.
127TEST_F(SurfaceFactoryTest, ResourceLifetimeSimpleWithProviderHoldingAlive) {
128 ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
129 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
130
131 // All of the resources submitted in the first frame are still in use at this
132 // time by virtue of being in the pending frame, so none can be returned to
133 // the client yet.
134 EXPECT_EQ(0u, client_.returned_resources().size());
135 client_.clear_returned_resources();
136
137 // Hold on to everything.
138 RefCurrentFrameResources();
139
140 // The second frame references no resources and thus should make all resources
141 // available to be returned as soon as the resource provider releases them.
142 SubmitFrameWithResources(NULL, 0);
143
144 EXPECT_EQ(0u, client_.returned_resources().size());
145 client_.clear_returned_resources();
146
147 int release_counts[] = {1, 1, 1};
148 UnrefResources(first_frame_ids, release_counts, arraysize(first_frame_ids));
149
150 ResourceProvider::ResourceId expected_returned_ids[] = {1, 2, 3};
151 int expected_returned_counts[] = {1, 1, 1};
152 CheckReturnedResourcesMatchExpected(expected_returned_ids,
153 expected_returned_counts,
154 arraysize(expected_returned_counts));
155}
156
157// Tests referencing a resource, unref'ing it to zero, then using it again
158// before returning it to the client.
159TEST_F(SurfaceFactoryTest, ResourceReusedBeforeReturn) {
160 ResourceProvider::ResourceId first_frame_ids[] = {7};
161 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
162
163 // This removes all references to resource id 7.
164 SubmitFrameWithResources(NULL, 0);
165
166 // This references id 7 again.
167 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
168
169 // This removes it again.
170 SubmitFrameWithResources(NULL, 0);
171
172 // Now it should be returned.
173 // We don't care how many entries are in the returned array for 7, so long as
174 // the total returned count matches the submitted count.
175 const ReturnedResourceArray& returned = client_.returned_resources();
176 size_t return_count = 0;
177 for (size_t i = 0; i < returned.size(); ++i) {
178 EXPECT_EQ(7u, returned[i].id);
179 return_count += returned[i].count;
180 }
181 EXPECT_EQ(2u, return_count);
182}
183
184// Tests having resources referenced multiple times, as if referenced by
185// multiple providers.
186TEST_F(SurfaceFactoryTest, ResourceRefMultipleTimes) {
187 ResourceProvider::ResourceId first_frame_ids[] = {3, 4};
188 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
189
190 // Ref resources from the first frame twice.
191 RefCurrentFrameResources();
192 RefCurrentFrameResources();
193
194 ResourceProvider::ResourceId second_frame_ids[] = {4, 5};
195 SubmitFrameWithResources(second_frame_ids, arraysize(second_frame_ids));
196
197 // Ref resources from the second frame 3 times.
198 RefCurrentFrameResources();
199 RefCurrentFrameResources();
200 RefCurrentFrameResources();
201
202 // Submit a frame with no resources to remove all current frame refs from
203 // submitted resources.
204 SubmitFrameWithResources(NULL, 0);
205
206 EXPECT_EQ(0u, client_.returned_resources().size());
207 client_.clear_returned_resources();
208
209 // Expected current refs:
210 // 3 -> 2
211 // 4 -> 2 + 3 = 5
212 // 5 -> 3
213 {
214 SCOPED_TRACE("unref all 3");
215 ResourceProvider::ResourceId ids_to_unref[] = {3, 4, 5};
216 int counts[] = {1, 1, 1};
217 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
218
219 EXPECT_EQ(0u, client_.returned_resources().size());
220 client_.clear_returned_resources();
221
222 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
223
224 ResourceProvider::ResourceId expected_returned_ids[] = {3};
225 int expected_returned_counts[] = {1};
226 CheckReturnedResourcesMatchExpected(expected_returned_ids,
227 expected_returned_counts,
228 arraysize(expected_returned_counts));
229 }
230
231 // Expected refs remaining:
232 // 4 -> 3
233 // 5 -> 1
234 {
235 SCOPED_TRACE("unref 4 and 5");
236 ResourceProvider::ResourceId ids_to_unref[] = {4, 5};
237 int counts[] = {1, 1};
238 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
239
240 ResourceProvider::ResourceId expected_returned_ids[] = {5};
241 int expected_returned_counts[] = {1};
242 CheckReturnedResourcesMatchExpected(expected_returned_ids,
243 expected_returned_counts,
244 arraysize(expected_returned_counts));
245 }
246
247 // Now, just 2 refs remaining on resource 4. Unref both at once and make sure
248 // the returned count is correct.
249 {
250 SCOPED_TRACE("unref only 4");
251 ResourceProvider::ResourceId ids_to_unref[] = {4};
252 int counts[] = {2};
253 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
254
255 ResourceProvider::ResourceId expected_returned_ids[] = {4};
256 int expected_returned_counts[] = {2};
257 CheckReturnedResourcesMatchExpected(expected_returned_ids,
258 expected_returned_counts,
259 arraysize(expected_returned_counts));
260 }
261}
262
263TEST_F(SurfaceFactoryTest, ResourceLifetime) {
264 ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
265 SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids));
266
267 // All of the resources submitted in the first frame are still in use at this
268 // time by virtue of being in the pending frame, so none can be returned to
269 // the client yet.
270 EXPECT_EQ(0u, client_.returned_resources().size());
271 client_.clear_returned_resources();
272
273 // The second frame references some of the same resources, but some different
274 // ones. We expect to receive back resource 1 with a count of 1 since it was
275 // only referenced by the first frame.
276 ResourceProvider::ResourceId second_frame_ids[] = {2, 3, 4};
277 SubmitFrameWithResources(second_frame_ids, arraysize(second_frame_ids));
278
279 {
280 SCOPED_TRACE("second frame");
281 ResourceProvider::ResourceId expected_returned_ids[] = {1};
282 int expected_returned_counts[] = {1};
283 CheckReturnedResourcesMatchExpected(expected_returned_ids,
284 expected_returned_counts,
285 arraysize(expected_returned_counts));
286 }
287
288 // The third frame references a disjoint set of resources, so we expect to
289 // receive back all resources from the first and second frames. Resource IDs 2
290 // and 3 will have counts of 2, since they were used in both frames, and
291 // resource ID 4 will have a count of 1.
292 ResourceProvider::ResourceId third_frame_ids[] = {10, 11, 12, 13};
293 SubmitFrameWithResources(third_frame_ids, arraysize(third_frame_ids));
294
295 {
296 SCOPED_TRACE("third frame");
297 ResourceProvider::ResourceId expected_returned_ids[] = {2, 3, 4};
298 int expected_returned_counts[] = {2, 2, 1};
299 CheckReturnedResourcesMatchExpected(expected_returned_ids,
300 expected_returned_counts,
301 arraysize(expected_returned_counts));
302 }
303
304 // Simulate a ResourceProvider taking a ref on all of the resources.
305 RefCurrentFrameResources();
306
307 ResourceProvider::ResourceId fourth_frame_ids[] = {12, 13};
308 SubmitFrameWithResources(fourth_frame_ids, arraysize(fourth_frame_ids));
309
310 EXPECT_EQ(0u, client_.returned_resources().size());
311
312 RefCurrentFrameResources();
313
314 // All resources are still being used by the external reference, so none can
315 // be returned to the client.
316 EXPECT_EQ(0u, client_.returned_resources().size());
317
318 // Release resources associated with the first RefCurrentFrameResources() call
319 // first.
320 {
321 ResourceProvider::ResourceId ids_to_unref[] = {10, 11, 12, 13};
322 int counts[] = {1, 1, 1, 1};
323 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
324 }
325
326 {
327 SCOPED_TRACE("fourth frame, first unref");
328 ResourceProvider::ResourceId expected_returned_ids[] = {10, 11};
329 int expected_returned_counts[] = {1, 1};
330 CheckReturnedResourcesMatchExpected(expected_returned_ids,
331 expected_returned_counts,
332 arraysize(expected_returned_counts));
333 }
334
335 {
336 ResourceProvider::ResourceId ids_to_unref[] = {12, 13};
337 int counts[] = {1, 1};
338 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
339 }
340
341 // Resources 12 and 13 are still in use by the current frame, so they
342 // shouldn't be available to be returned.
343 EXPECT_EQ(0u, client_.returned_resources().size());
344
345 // If we submit an empty frame, however, they should become available.
346 SubmitFrameWithResources(NULL, 0u);
347
348 {
349 SCOPED_TRACE("fourth frame, second unref");
350 ResourceProvider::ResourceId expected_returned_ids[] = {12, 13};
351 int expected_returned_counts[] = {2, 2};
352 CheckReturnedResourcesMatchExpected(expected_returned_ids,
353 expected_returned_counts,
354 arraysize(expected_returned_counts));
355 }
356}
357
jamesrdd9b6605c2014-09-24 19:25:11358// Tests shutting down the factory with a surface with outstanding refs still in
359// the map.
360TEST_F(SurfaceFactoryTest, DestroyWithResourceRefs) {
361 SurfaceId id(7);
362 factory_.Create(id, gfx::Size(1, 1));
363
364 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
365 TransferableResource resource;
366 resource.id = 1;
367 resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
368 frame_data->resource_list.push_back(resource);
369 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
370 frame->delegated_frame_data = frame_data.Pass();
371 factory_.SubmitFrame(id, frame.Pass(), base::Closure());
372}
373
jbaumanfdc3baa2014-10-10 00:22:09374TEST_F(SurfaceFactoryTest, DestroySequence) {
375 SurfaceId id2(5);
376 factory_.Create(id2, gfx::Size(5, 5));
377
378 // Check that waiting before the sequence is satisfied works.
379 std::set<SurfaceSequence> sequence;
380 sequence.insert(SurfaceSequence(0, 4));
381 factory_.DestroyOnSequence(id2, sequence);
382
383 scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
384 scoped_ptr<CompositorFrame> frame(new CompositorFrame);
385 frame->metadata.satisfies_sequences.push_back(6);
386 frame->metadata.satisfies_sequences.push_back(4);
387 frame->delegated_frame_data = frame_data.Pass();
388 DCHECK(manager_.GetSurfaceForId(id2));
389 factory_.SubmitFrame(surface_id_, frame.Pass(), base::Closure());
390 DCHECK(!manager_.GetSurfaceForId(id2));
391
392 // Check that waiting after the sequence is satisfied works.
393 factory_.Create(id2, gfx::Size(5, 5));
394 sequence.clear();
395 sequence.insert(SurfaceSequence(0, 6));
396 DCHECK(manager_.GetSurfaceForId(id2));
397 factory_.DestroyOnSequence(id2, sequence);
398 DCHECK(!manager_.GetSurfaceForId(id2));
399}
400
[email protected]387b59d2014-06-27 01:17:34401} // namespace
402} // namespace cc