66890c4213d1207a47e53646f1fd343400dc810b
[platform/framework/web/crosswalk.git] / src / cc / surfaces / surface_unittest.cc
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.
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_client.h"
9 #include "cc/surfaces/surface_manager.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "ui/gfx/size.h"
12
13 namespace cc {
14 namespace {
15
16 TEST(SurfaceTest, SurfaceLifetime) {
17   SurfaceManager manager;
18
19   SurfaceId surface_id;
20   {
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));
25   }
26
27   EXPECT_EQ(NULL, manager.GetSurfaceForId(surface_id));
28 }
29
30 class TestSurfaceClient : public SurfaceClient {
31  public:
32   TestSurfaceClient() {}
33   virtual ~TestSurfaceClient() {}
34
35   virtual void ReturnResources(
36       const ReturnedResourceArray& resources) OVERRIDE {
37     returned_resources_ = resources;
38   }
39
40   const ReturnedResourceArray& returned_resources() const {
41     return returned_resources_;
42   }
43
44   void clear_returned_resources() { returned_resources_.clear(); }
45
46  private:
47   ReturnedResourceArray returned_resources_;
48
49   DISALLOW_COPY_AND_ASSIGN(TestSurfaceClient);
50 };
51
52 void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids,
53                               size_t num_resource_ids,
54                               Surface* surface) {
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);
61   }
62   scoped_ptr<CompositorFrame> frame(new CompositorFrame);
63   frame->delegated_frame_data = frame_data.Pass();
64   surface->QueueFrame(frame.Pass());
65 }
66
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);
77   }
78 }
79
80 void UnrefResources(ResourceProvider::ResourceId* ids_to_unref,
81                     int* counts_to_unref,
82                     size_t num_ids_to_unref,
83                     Surface* surface) {
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);
90   }
91   surface->UnrefResources(unref_array);
92 }
93
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));
100
101   ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
102   SubmitFrameWithResources(
103       first_frame_ids, arraysize(first_frame_ids), &surface);
104
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
107   // the client yet.
108   surface.ReturnUnusedResourcesToClient();
109   EXPECT_EQ(0u, client.returned_resources().size());
110   client.clear_returned_resources();
111
112   // The second frame references no resources and thus should make all resources
113   // available to be returned.
114   SubmitFrameWithResources(NULL, 0, &surface);
115
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());
123 }
124
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));
131
132   ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
133   SubmitFrameWithResources(
134       first_frame_ids, arraysize(first_frame_ids), &surface);
135
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   surface.ReturnUnusedResourcesToClient();
140   EXPECT_EQ(0u, client.returned_resources().size());
141   client.clear_returned_resources();
142
143   // Hold on to everything.
144   surface.RefCurrentFrameResources();
145
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);
149
150   surface.ReturnUnusedResourcesToClient();
151   EXPECT_EQ(0u, client.returned_resources().size());
152   client.clear_returned_resources();
153
154   int release_counts[] = {1, 1, 1};
155   UnrefResources(
156       first_frame_ids, release_counts, arraysize(first_frame_ids), &surface);
157
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());
165 }
166
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));
173
174   ResourceProvider::ResourceId first_frame_ids[] = {7};
175   SubmitFrameWithResources(
176       first_frame_ids, arraysize(first_frame_ids), &surface);
177
178   // This removes all references to resource id 7.
179   SubmitFrameWithResources(NULL, 0, &surface);
180
181   // This references id 7 again.
182   SubmitFrameWithResources(
183       first_frame_ids, arraysize(first_frame_ids), &surface);
184
185   // This removes it again.
186   SubmitFrameWithResources(NULL, 0, &surface);
187
188   // Now it should be returned.
189   surface.ReturnUnusedResourcesToClient();
190
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;
198   }
199   EXPECT_EQ(2u, return_count);
200 }
201
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));
208
209   ResourceProvider::ResourceId first_frame_ids[] = {3, 4};
210   SubmitFrameWithResources(
211       first_frame_ids, arraysize(first_frame_ids), &surface);
212
213   // Ref resources from the first frame twice.
214   surface.RefCurrentFrameResources();
215   surface.RefCurrentFrameResources();
216
217   ResourceProvider::ResourceId second_frame_ids[] = {4, 5};
218   SubmitFrameWithResources(
219       second_frame_ids, arraysize(second_frame_ids), &surface);
220
221   // Ref resources from the second frame 3 times.
222   surface.RefCurrentFrameResources();
223   surface.RefCurrentFrameResources();
224   surface.RefCurrentFrameResources();
225
226   // Submit a frame with no resources to remove all current frame refs from
227   // submitted resources.
228   SubmitFrameWithResources(NULL, 0, &surface);
229
230   surface.ReturnUnusedResourcesToClient();
231   EXPECT_EQ(0u, client.returned_resources().size());
232   client.clear_returned_resources();
233
234   // Expected current refs:
235   //  3 -> 2
236   //  4 -> 2 + 3 = 5
237   //  5 -> 3
238   {
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);
243
244     surface.ReturnUnusedResourcesToClient();
245     EXPECT_EQ(0u, client.returned_resources().size());
246     client.clear_returned_resources();
247
248     UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
249
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());
257   }
258
259   // Expected refs remaining:
260   //  4 -> 3
261   //  5 -> 1
262   {
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);
267
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());
275   }
276
277   // Now, just 2 refs remaining on resource 4. Unref both at once and make sure
278   // the returned count is correct.
279   {
280     SCOPED_TRACE("unref only 4");
281     ResourceProvider::ResourceId ids_to_unref[] = {4};
282     int counts[] = {2};
283     UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
284
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());
292   }
293 }
294
295 TEST(SurfaceTest, ResourceLifetime) {
296   SurfaceManager manager;
297   TestSurfaceClient client;
298   Surface surface(&manager, &client, gfx::Size(5, 5));
299
300   ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
301   SubmitFrameWithResources(
302       first_frame_ids, arraysize(first_frame_ids), &surface);
303
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
306   // the client yet.
307   surface.ReturnUnusedResourcesToClient();
308   EXPECT_EQ(0u, client.returned_resources().size());
309   client.clear_returned_resources();
310
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);
317
318   surface.ReturnUnusedResourcesToClient();
319   {
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());
327   }
328
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);
336
337   surface.ReturnUnusedResourcesToClient();
338   {
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());
346   }
347
348   // Simulate a ResourceProvider taking a ref on all of the resources.
349   surface.RefCurrentFrameResources();
350
351   ResourceProvider::ResourceId fourth_frame_ids[] = {12, 13};
352   SubmitFrameWithResources(
353       fourth_frame_ids, arraysize(fourth_frame_ids), &surface);
354
355   surface.ReturnUnusedResourcesToClient();
356   EXPECT_EQ(0u, client.returned_resources().size());
357
358   surface.RefCurrentFrameResources();
359
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());
364
365   // Release resources associated with the first RefCurrentFrameResources() call
366   // first.
367   {
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);
371   }
372
373   surface.ReturnUnusedResourcesToClient();
374   {
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());
382   }
383
384   {
385     ResourceProvider::ResourceId ids_to_unref[] = {12, 13};
386     int counts[] = {1, 1};
387     UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
388   }
389
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());
394
395   // If we submit an empty frame, however, they should become available.
396   SubmitFrameWithResources(NULL, 0u, &surface);
397
398   surface.ReturnUnusedResourcesToClient();
399   {
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());
407   }
408 }
409
410 }  // namespace
411 }  // namespace cc