OLD | NEW |
| (Empty) |
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/surfaces/surface_factory.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 | |
10 #include <utility> | |
11 #include <vector> | |
12 | |
13 #include "base/bind.h" | |
14 #include "base/macros.h" | |
15 #include "cc/output/compositor_frame.h" | |
16 #include "cc/output/copy_output_request.h" | |
17 #include "cc/output/copy_output_result.h" | |
18 #include "cc/resources/resource_provider.h" | |
19 #include "cc/surfaces/frame_sink_manager_client.h" | |
20 #include "cc/surfaces/surface.h" | |
21 #include "cc/surfaces/surface_factory_client.h" | |
22 #include "cc/surfaces/surface_info.h" | |
23 #include "cc/surfaces/surface_manager.h" | |
24 #include "cc/surfaces/surface_resource_holder_client.h" | |
25 #include "cc/test/fake_surface_resource_holder_client.h" | |
26 #include "cc/test/scheduler_test_common.h" | |
27 #include "cc/test/stub_surface_factory_client.h" | |
28 #include "testing/gtest/include/gtest/gtest.h" | |
29 #include "ui/gfx/geometry/size.h" | |
30 | |
31 namespace cc { | |
32 namespace { | |
33 | |
34 static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1); | |
35 static constexpr FrameSinkId kAnotherArbitraryFrameSinkId(2, 2); | |
36 static const base::UnguessableToken kArbitraryToken = | |
37 base::UnguessableToken::Create(); | |
38 static auto kArbitrarySourceId1 = | |
39 base::UnguessableToken::Deserialize(0xdead, 0xbeef); | |
40 static auto kArbitrarySourceId2 = | |
41 base::UnguessableToken::Deserialize(0xdead, 0xbee0); | |
42 | |
43 gpu::SyncToken GenTestSyncToken(int id) { | |
44 gpu::SyncToken token; | |
45 token.Set(gpu::CommandBufferNamespace::GPU_IO, 0, | |
46 gpu::CommandBufferId::FromUnsafeValue(id), 1); | |
47 return token; | |
48 } | |
49 | |
50 class SurfaceFactoryTest : public testing::Test, public SurfaceObserver { | |
51 public: | |
52 SurfaceFactoryTest() | |
53 : factory_(new SurfaceFactory(kArbitraryFrameSinkId, | |
54 &manager_, | |
55 &stub_surface_factory_client_, | |
56 &fake_surface_resource_holder_client_)), | |
57 local_surface_id_(3, kArbitraryToken), | |
58 frame_sync_token_(GenTestSyncToken(4)), | |
59 consumer_sync_token_(GenTestSyncToken(5)) { | |
60 manager_.AddObserver(this); | |
61 } | |
62 | |
63 const SurfaceId& last_created_surface_id() const { | |
64 return last_created_surface_id_; | |
65 } | |
66 | |
67 // SurfaceObserver implementation. | |
68 void OnSurfaceCreated(const SurfaceInfo& surface_info) override { | |
69 EXPECT_EQ(kArbitraryFrameSinkId, surface_info.id().frame_sink_id()); | |
70 last_created_surface_id_ = surface_info.id(); | |
71 last_surface_info_ = surface_info; | |
72 } | |
73 | |
74 void OnSurfaceDamaged(const SurfaceId& id, bool* changed) override { | |
75 *changed = true; | |
76 } | |
77 | |
78 ~SurfaceFactoryTest() override { | |
79 manager_.RemoveObserver(this); | |
80 factory_->EvictSurface(); | |
81 } | |
82 | |
83 void SubmitCompositorFrameWithResources(ResourceId* resource_ids, | |
84 size_t num_resource_ids) { | |
85 CompositorFrame frame; | |
86 for (size_t i = 0u; i < num_resource_ids; ++i) { | |
87 TransferableResource resource; | |
88 resource.id = resource_ids[i]; | |
89 resource.mailbox_holder.texture_target = GL_TEXTURE_2D; | |
90 resource.mailbox_holder.sync_token = frame_sync_token_; | |
91 frame.resource_list.push_back(resource); | |
92 } | |
93 factory_->SubmitCompositorFrame(local_surface_id_, std::move(frame), | |
94 SurfaceFactory::DrawCallback(), | |
95 SurfaceFactory::WillDrawCallback()); | |
96 EXPECT_EQ(last_created_surface_id_.local_surface_id(), local_surface_id_); | |
97 } | |
98 | |
99 void UnrefResources(ResourceId* ids_to_unref, | |
100 int* counts_to_unref, | |
101 size_t num_ids_to_unref) { | |
102 ReturnedResourceArray unref_array; | |
103 for (size_t i = 0; i < num_ids_to_unref; ++i) { | |
104 ReturnedResource resource; | |
105 resource.sync_token = consumer_sync_token_; | |
106 resource.id = ids_to_unref[i]; | |
107 resource.count = counts_to_unref[i]; | |
108 unref_array.push_back(resource); | |
109 } | |
110 factory_->UnrefResources(unref_array); | |
111 } | |
112 | |
113 void CheckReturnedResourcesMatchExpected(ResourceId* expected_returned_ids, | |
114 int* expected_returned_counts, | |
115 size_t expected_resources, | |
116 gpu::SyncToken expected_sync_token) { | |
117 const ReturnedResourceArray& actual_resources = | |
118 fake_surface_resource_holder_client_.returned_resources(); | |
119 ASSERT_EQ(expected_resources, actual_resources.size()); | |
120 for (size_t i = 0; i < expected_resources; ++i) { | |
121 ReturnedResource resource = actual_resources[i]; | |
122 EXPECT_EQ(expected_sync_token, resource.sync_token); | |
123 EXPECT_EQ(expected_returned_ids[i], resource.id); | |
124 EXPECT_EQ(expected_returned_counts[i], resource.count); | |
125 } | |
126 fake_surface_resource_holder_client_.clear_returned_resources(); | |
127 } | |
128 | |
129 void RefCurrentFrameResources() { | |
130 Surface* surface = manager_.GetSurfaceForId( | |
131 SurfaceId(factory_->frame_sink_id(), local_surface_id_)); | |
132 factory_->RefResources(surface->GetActiveFrame().resource_list); | |
133 } | |
134 | |
135 protected: | |
136 SurfaceManager manager_; | |
137 StubSurfaceFactoryClient stub_surface_factory_client_; | |
138 FakeSurfaceResourceHolderClient fake_surface_resource_holder_client_; | |
139 std::unique_ptr<SurfaceFactory> factory_; | |
140 LocalSurfaceId local_surface_id_; | |
141 SurfaceId last_created_surface_id_; | |
142 SurfaceInfo last_surface_info_; | |
143 | |
144 // This is the sync token submitted with the frame. It should never be | |
145 // returned to the client. | |
146 const gpu::SyncToken frame_sync_token_; | |
147 | |
148 // This is the sync token returned by the consumer. It should always be | |
149 // returned to the client. | |
150 const gpu::SyncToken consumer_sync_token_; | |
151 }; | |
152 | |
153 // Tests submitting a frame with resources followed by one with no resources | |
154 // with no resource provider action in between. | |
155 TEST_F(SurfaceFactoryTest, ResourceLifetimeSimple) { | |
156 ResourceId first_frame_ids[] = {1, 2, 3}; | |
157 SubmitCompositorFrameWithResources(first_frame_ids, | |
158 arraysize(first_frame_ids)); | |
159 | |
160 // All of the resources submitted in the first frame are still in use at this | |
161 // time by virtue of being in the pending frame, so none can be returned to | |
162 // the client yet. | |
163 EXPECT_EQ(0u, | |
164 fake_surface_resource_holder_client_.returned_resources().size()); | |
165 fake_surface_resource_holder_client_.clear_returned_resources(); | |
166 | |
167 // The second frame references no resources of first frame and thus should | |
168 // make all resources of first frame available to be returned. | |
169 SubmitCompositorFrameWithResources(NULL, 0); | |
170 | |
171 ResourceId expected_returned_ids[] = {1, 2, 3}; | |
172 int expected_returned_counts[] = {1, 1, 1}; | |
173 // Resources were never consumed so no sync token should be set. | |
174 CheckReturnedResourcesMatchExpected( | |
175 expected_returned_ids, expected_returned_counts, | |
176 arraysize(expected_returned_counts), gpu::SyncToken()); | |
177 | |
178 ResourceId third_frame_ids[] = {4, 5, 6}; | |
179 SubmitCompositorFrameWithResources(third_frame_ids, | |
180 arraysize(third_frame_ids)); | |
181 | |
182 // All of the resources submitted in the third frame are still in use at this | |
183 // time by virtue of being in the pending frame, so none can be returned to | |
184 // the client yet. | |
185 EXPECT_EQ(0u, | |
186 fake_surface_resource_holder_client_.returned_resources().size()); | |
187 fake_surface_resource_holder_client_.clear_returned_resources(); | |
188 | |
189 // The forth frame references no resources of third frame and thus should | |
190 // make all resources of third frame available to be returned. | |
191 ResourceId forth_frame_ids[] = {7, 8, 9}; | |
192 SubmitCompositorFrameWithResources(forth_frame_ids, | |
193 arraysize(forth_frame_ids)); | |
194 | |
195 ResourceId forth_expected_returned_ids[] = {4, 5, 6}; | |
196 int forth_expected_returned_counts[] = {1, 1, 1}; | |
197 // Resources were never consumed so no sync token should be set. | |
198 CheckReturnedResourcesMatchExpected( | |
199 forth_expected_returned_ids, forth_expected_returned_counts, | |
200 arraysize(forth_expected_returned_counts), gpu::SyncToken()); | |
201 } | |
202 | |
203 // Tests submitting a frame with resources followed by one with no resources | |
204 // with the resource provider holding everything alive. | |
205 TEST_F(SurfaceFactoryTest, ResourceLifetimeSimpleWithProviderHoldingAlive) { | |
206 ResourceId first_frame_ids[] = {1, 2, 3}; | |
207 SubmitCompositorFrameWithResources(first_frame_ids, | |
208 arraysize(first_frame_ids)); | |
209 | |
210 // All of the resources submitted in the first frame are still in use at this | |
211 // time by virtue of being in the pending frame, so none can be returned to | |
212 // the client yet. | |
213 EXPECT_EQ(0u, | |
214 fake_surface_resource_holder_client_.returned_resources().size()); | |
215 fake_surface_resource_holder_client_.clear_returned_resources(); | |
216 | |
217 // Hold on to everything. | |
218 RefCurrentFrameResources(); | |
219 | |
220 // The second frame references no resources and thus should make all resources | |
221 // available to be returned as soon as the resource provider releases them. | |
222 SubmitCompositorFrameWithResources(NULL, 0); | |
223 | |
224 EXPECT_EQ(0u, | |
225 fake_surface_resource_holder_client_.returned_resources().size()); | |
226 fake_surface_resource_holder_client_.clear_returned_resources(); | |
227 | |
228 int release_counts[] = {1, 1, 1}; | |
229 UnrefResources(first_frame_ids, release_counts, arraysize(first_frame_ids)); | |
230 | |
231 ResourceId expected_returned_ids[] = {1, 2, 3}; | |
232 int expected_returned_counts[] = {1, 1, 1}; | |
233 CheckReturnedResourcesMatchExpected( | |
234 expected_returned_ids, expected_returned_counts, | |
235 arraysize(expected_returned_counts), consumer_sync_token_); | |
236 } | |
237 | |
238 // Tests referencing a resource, unref'ing it to zero, then using it again | |
239 // before returning it to the client. | |
240 TEST_F(SurfaceFactoryTest, ResourceReusedBeforeReturn) { | |
241 ResourceId first_frame_ids[] = {7}; | |
242 SubmitCompositorFrameWithResources(first_frame_ids, | |
243 arraysize(first_frame_ids)); | |
244 | |
245 // This removes all references to resource id 7. | |
246 SubmitCompositorFrameWithResources(NULL, 0); | |
247 | |
248 // This references id 7 again. | |
249 SubmitCompositorFrameWithResources(first_frame_ids, | |
250 arraysize(first_frame_ids)); | |
251 | |
252 // This removes it again. | |
253 SubmitCompositorFrameWithResources(NULL, 0); | |
254 | |
255 // Now it should be returned. | |
256 // We don't care how many entries are in the returned array for 7, so long as | |
257 // the total returned count matches the submitted count. | |
258 const ReturnedResourceArray& returned = | |
259 fake_surface_resource_holder_client_.returned_resources(); | |
260 size_t return_count = 0; | |
261 for (size_t i = 0; i < returned.size(); ++i) { | |
262 EXPECT_EQ(7u, returned[i].id); | |
263 return_count += returned[i].count; | |
264 } | |
265 EXPECT_EQ(2u, return_count); | |
266 } | |
267 | |
268 // Tests having resources referenced multiple times, as if referenced by | |
269 // multiple providers. | |
270 TEST_F(SurfaceFactoryTest, ResourceRefMultipleTimes) { | |
271 ResourceId first_frame_ids[] = {3, 4}; | |
272 SubmitCompositorFrameWithResources(first_frame_ids, | |
273 arraysize(first_frame_ids)); | |
274 | |
275 // Ref resources from the first frame twice. | |
276 RefCurrentFrameResources(); | |
277 RefCurrentFrameResources(); | |
278 | |
279 ResourceId second_frame_ids[] = {4, 5}; | |
280 SubmitCompositorFrameWithResources(second_frame_ids, | |
281 arraysize(second_frame_ids)); | |
282 | |
283 // Ref resources from the second frame 3 times. | |
284 RefCurrentFrameResources(); | |
285 RefCurrentFrameResources(); | |
286 RefCurrentFrameResources(); | |
287 | |
288 // Submit a frame with no resources to remove all current frame refs from | |
289 // submitted resources. | |
290 SubmitCompositorFrameWithResources(NULL, 0); | |
291 | |
292 EXPECT_EQ(0u, | |
293 fake_surface_resource_holder_client_.returned_resources().size()); | |
294 fake_surface_resource_holder_client_.clear_returned_resources(); | |
295 | |
296 // Expected current refs: | |
297 // 3 -> 2 | |
298 // 4 -> 2 + 3 = 5 | |
299 // 5 -> 3 | |
300 { | |
301 SCOPED_TRACE("unref all 3"); | |
302 ResourceId ids_to_unref[] = {3, 4, 5}; | |
303 int counts[] = {1, 1, 1}; | |
304 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); | |
305 | |
306 EXPECT_EQ(0u, | |
307 fake_surface_resource_holder_client_.returned_resources().size()); | |
308 fake_surface_resource_holder_client_.clear_returned_resources(); | |
309 | |
310 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); | |
311 | |
312 ResourceId expected_returned_ids[] = {3}; | |
313 int expected_returned_counts[] = {1}; | |
314 CheckReturnedResourcesMatchExpected( | |
315 expected_returned_ids, expected_returned_counts, | |
316 arraysize(expected_returned_counts), consumer_sync_token_); | |
317 } | |
318 | |
319 // Expected refs remaining: | |
320 // 4 -> 3 | |
321 // 5 -> 1 | |
322 { | |
323 SCOPED_TRACE("unref 4 and 5"); | |
324 ResourceId ids_to_unref[] = {4, 5}; | |
325 int counts[] = {1, 1}; | |
326 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); | |
327 | |
328 ResourceId expected_returned_ids[] = {5}; | |
329 int expected_returned_counts[] = {1}; | |
330 CheckReturnedResourcesMatchExpected( | |
331 expected_returned_ids, expected_returned_counts, | |
332 arraysize(expected_returned_counts), consumer_sync_token_); | |
333 } | |
334 | |
335 // Now, just 2 refs remaining on resource 4. Unref both at once and make sure | |
336 // the returned count is correct. | |
337 { | |
338 SCOPED_TRACE("unref only 4"); | |
339 ResourceId ids_to_unref[] = {4}; | |
340 int counts[] = {2}; | |
341 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); | |
342 | |
343 ResourceId expected_returned_ids[] = {4}; | |
344 int expected_returned_counts[] = {2}; | |
345 CheckReturnedResourcesMatchExpected( | |
346 expected_returned_ids, expected_returned_counts, | |
347 arraysize(expected_returned_counts), consumer_sync_token_); | |
348 } | |
349 } | |
350 | |
351 TEST_F(SurfaceFactoryTest, ResourceLifetime) { | |
352 ResourceId first_frame_ids[] = {1, 2, 3}; | |
353 SubmitCompositorFrameWithResources(first_frame_ids, | |
354 arraysize(first_frame_ids)); | |
355 | |
356 // All of the resources submitted in the first frame are still in use at this | |
357 // time by virtue of being in the pending frame, so none can be returned to | |
358 // the client yet. | |
359 EXPECT_EQ(0u, | |
360 fake_surface_resource_holder_client_.returned_resources().size()); | |
361 fake_surface_resource_holder_client_.clear_returned_resources(); | |
362 | |
363 // The second frame references some of the same resources, but some different | |
364 // ones. We expect to receive back resource 1 with a count of 1 since it was | |
365 // only referenced by the first frame. | |
366 ResourceId second_frame_ids[] = {2, 3, 4}; | |
367 SubmitCompositorFrameWithResources(second_frame_ids, | |
368 arraysize(second_frame_ids)); | |
369 | |
370 { | |
371 SCOPED_TRACE("second frame"); | |
372 ResourceId expected_returned_ids[] = {1}; | |
373 int expected_returned_counts[] = {1}; | |
374 CheckReturnedResourcesMatchExpected( | |
375 expected_returned_ids, expected_returned_counts, | |
376 arraysize(expected_returned_counts), gpu::SyncToken()); | |
377 } | |
378 | |
379 // The third frame references a disjoint set of resources, so we expect to | |
380 // receive back all resources from the first and second frames. Resource IDs 2 | |
381 // and 3 will have counts of 2, since they were used in both frames, and | |
382 // resource ID 4 will have a count of 1. | |
383 ResourceId third_frame_ids[] = {10, 11, 12, 13}; | |
384 SubmitCompositorFrameWithResources(third_frame_ids, | |
385 arraysize(third_frame_ids)); | |
386 | |
387 { | |
388 SCOPED_TRACE("third frame"); | |
389 ResourceId expected_returned_ids[] = {2, 3, 4}; | |
390 int expected_returned_counts[] = {2, 2, 1}; | |
391 CheckReturnedResourcesMatchExpected( | |
392 expected_returned_ids, expected_returned_counts, | |
393 arraysize(expected_returned_counts), gpu::SyncToken()); | |
394 } | |
395 | |
396 // Simulate a ResourceProvider taking a ref on all of the resources. | |
397 RefCurrentFrameResources(); | |
398 | |
399 ResourceId fourth_frame_ids[] = {12, 13}; | |
400 SubmitCompositorFrameWithResources(fourth_frame_ids, | |
401 arraysize(fourth_frame_ids)); | |
402 | |
403 EXPECT_EQ(0u, | |
404 fake_surface_resource_holder_client_.returned_resources().size()); | |
405 | |
406 RefCurrentFrameResources(); | |
407 | |
408 // All resources are still being used by the external reference, so none can | |
409 // be returned to the client. | |
410 EXPECT_EQ(0u, | |
411 fake_surface_resource_holder_client_.returned_resources().size()); | |
412 | |
413 // Release resources associated with the first RefCurrentFrameResources() call | |
414 // first. | |
415 { | |
416 ResourceId ids_to_unref[] = {10, 11, 12, 13}; | |
417 int counts[] = {1, 1, 1, 1}; | |
418 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); | |
419 } | |
420 | |
421 { | |
422 SCOPED_TRACE("fourth frame, first unref"); | |
423 ResourceId expected_returned_ids[] = {10, 11}; | |
424 int expected_returned_counts[] = {1, 1}; | |
425 CheckReturnedResourcesMatchExpected( | |
426 expected_returned_ids, expected_returned_counts, | |
427 arraysize(expected_returned_counts), consumer_sync_token_); | |
428 } | |
429 | |
430 { | |
431 ResourceId ids_to_unref[] = {12, 13}; | |
432 int counts[] = {1, 1}; | |
433 UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); | |
434 } | |
435 | |
436 // Resources 12 and 13 are still in use by the current frame, so they | |
437 // shouldn't be available to be returned. | |
438 EXPECT_EQ(0u, | |
439 fake_surface_resource_holder_client_.returned_resources().size()); | |
440 | |
441 // If we submit an empty frame, however, they should become available. | |
442 SubmitCompositorFrameWithResources(NULL, 0u); | |
443 | |
444 { | |
445 SCOPED_TRACE("fourth frame, second unref"); | |
446 ResourceId expected_returned_ids[] = {12, 13}; | |
447 int expected_returned_counts[] = {2, 2}; | |
448 CheckReturnedResourcesMatchExpected( | |
449 expected_returned_ids, expected_returned_counts, | |
450 arraysize(expected_returned_counts), consumer_sync_token_); | |
451 } | |
452 } | |
453 | |
454 TEST_F(SurfaceFactoryTest, BlankNoIndexIncrement) { | |
455 LocalSurfaceId local_surface_id(6, kArbitraryToken); | |
456 SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id); | |
457 factory_->SubmitCompositorFrame(local_surface_id, CompositorFrame(), | |
458 SurfaceFactory::DrawCallback(), | |
459 SurfaceFactory::WillDrawCallback()); | |
460 Surface* surface = manager_.GetSurfaceForId(surface_id); | |
461 ASSERT_NE(nullptr, surface); | |
462 EXPECT_EQ(2, surface->frame_index()); | |
463 EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id); | |
464 } | |
465 | |
466 void CreateSurfaceDrawCallback(SurfaceFactory* factory, | |
467 uint32_t* execute_count) { | |
468 LocalSurfaceId new_id(7, base::UnguessableToken::Create()); | |
469 factory->SubmitCompositorFrame(new_id, CompositorFrame(), | |
470 SurfaceFactory::DrawCallback(), | |
471 SurfaceFactory::WillDrawCallback()); | |
472 factory->EvictSurface(); | |
473 *execute_count += 1; | |
474 } | |
475 | |
476 TEST_F(SurfaceFactoryTest, AddDuringEviction) { | |
477 LocalSurfaceId local_surface_id(6, kArbitraryToken); | |
478 | |
479 uint32_t execute_count = 0; | |
480 factory_->SubmitCompositorFrame( | |
481 local_surface_id, CompositorFrame(), | |
482 base::Bind(&CreateSurfaceDrawCallback, base::Unretained(factory_.get()), | |
483 &execute_count), | |
484 SurfaceFactory::WillDrawCallback()); | |
485 EXPECT_EQ(0u, execute_count); | |
486 factory_->EvictSurface(); | |
487 EXPECT_EQ(1u, execute_count); | |
488 } | |
489 | |
490 void DrawCallback(uint32_t* execute_count) { | |
491 *execute_count += 1; | |
492 } | |
493 | |
494 // Tests doing an EvictSurface before shutting down the factory. | |
495 TEST_F(SurfaceFactoryTest, EvictSurface) { | |
496 LocalSurfaceId local_surface_id(7, kArbitraryToken); | |
497 SurfaceId id(kArbitraryFrameSinkId, local_surface_id); | |
498 | |
499 TransferableResource resource; | |
500 resource.id = 1; | |
501 resource.mailbox_holder.texture_target = GL_TEXTURE_2D; | |
502 CompositorFrame frame; | |
503 frame.resource_list.push_back(resource); | |
504 uint32_t execute_count = 0; | |
505 factory_->SubmitCompositorFrame(local_surface_id, std::move(frame), | |
506 base::Bind(&DrawCallback, &execute_count), | |
507 SurfaceFactory::WillDrawCallback()); | |
508 EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id); | |
509 local_surface_id_ = LocalSurfaceId(); | |
510 | |
511 EXPECT_TRUE(manager_.GetSurfaceForId(id)); | |
512 EXPECT_TRUE( | |
513 fake_surface_resource_holder_client_.returned_resources().empty()); | |
514 factory_->EvictSurface(); | |
515 EXPECT_FALSE(manager_.GetSurfaceForId(id)); | |
516 EXPECT_FALSE( | |
517 fake_surface_resource_holder_client_.returned_resources().empty()); | |
518 EXPECT_EQ(1u, execute_count); | |
519 } | |
520 | |
521 // Tests doing an EvictSurface which has unregistered dependency. | |
522 TEST_F(SurfaceFactoryTest, EvictSurfaceDependencyUnRegistered) { | |
523 LocalSurfaceId local_surface_id(7, kArbitraryToken); | |
524 | |
525 TransferableResource resource; | |
526 resource.id = 1; | |
527 resource.mailbox_holder.texture_target = GL_TEXTURE_2D; | |
528 CompositorFrame frame; | |
529 frame.resource_list.push_back(resource); | |
530 uint32_t execute_count = 0; | |
531 factory_->SubmitCompositorFrame(local_surface_id, std::move(frame), | |
532 base::Bind(&DrawCallback, &execute_count), | |
533 SurfaceFactory::WillDrawCallback()); | |
534 EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id); | |
535 local_surface_id_ = LocalSurfaceId(); | |
536 | |
537 SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id); | |
538 Surface* surface = manager_.GetSurfaceForId(surface_id); | |
539 surface->AddDestructionDependency( | |
540 SurfaceSequence(kAnotherArbitraryFrameSinkId, 4)); | |
541 | |
542 EXPECT_TRUE(manager_.GetSurfaceForId(surface_id)); | |
543 EXPECT_TRUE( | |
544 fake_surface_resource_holder_client_.returned_resources().empty()); | |
545 factory_->EvictSurface(); | |
546 EXPECT_FALSE(manager_.GetSurfaceForId(surface_id)); | |
547 EXPECT_FALSE( | |
548 fake_surface_resource_holder_client_.returned_resources().empty()); | |
549 EXPECT_EQ(1u, execute_count); | |
550 } | |
551 | |
552 // Tests doing an EvictSurface which has registered dependency. | |
553 TEST_F(SurfaceFactoryTest, EvictSurfaceDependencyRegistered) { | |
554 LocalSurfaceId local_surface_id(7, kArbitraryToken); | |
555 | |
556 TransferableResource resource; | |
557 resource.id = 1; | |
558 resource.mailbox_holder.texture_target = GL_TEXTURE_2D; | |
559 CompositorFrame frame; | |
560 frame.resource_list.push_back(resource); | |
561 uint32_t execute_count = 0; | |
562 factory_->SubmitCompositorFrame(local_surface_id, std::move(frame), | |
563 base::Bind(&DrawCallback, &execute_count), | |
564 SurfaceFactory::WillDrawCallback()); | |
565 EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id); | |
566 local_surface_id_ = LocalSurfaceId(); | |
567 | |
568 manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId); | |
569 | |
570 SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id); | |
571 Surface* surface = manager_.GetSurfaceForId(surface_id); | |
572 surface->AddDestructionDependency( | |
573 SurfaceSequence(kAnotherArbitraryFrameSinkId, 4)); | |
574 | |
575 EXPECT_TRUE(manager_.GetSurfaceForId(surface_id)); | |
576 EXPECT_TRUE( | |
577 fake_surface_resource_holder_client_.returned_resources().empty()); | |
578 factory_->EvictSurface(); | |
579 EXPECT_TRUE(manager_.GetSurfaceForId(surface_id)); | |
580 EXPECT_TRUE( | |
581 fake_surface_resource_holder_client_.returned_resources().empty()); | |
582 EXPECT_EQ(0u, execute_count); | |
583 | |
584 manager_.SatisfySequence(SurfaceSequence(kAnotherArbitraryFrameSinkId, 4)); | |
585 EXPECT_FALSE(manager_.GetSurfaceForId(surface_id)); | |
586 EXPECT_FALSE( | |
587 fake_surface_resource_holder_client_.returned_resources().empty()); | |
588 } | |
589 | |
590 TEST_F(SurfaceFactoryTest, DestroySequence) { | |
591 LocalSurfaceId local_surface_id2(5, kArbitraryToken); | |
592 std::unique_ptr<SurfaceFactory> factory2(new SurfaceFactory( | |
593 kArbitraryFrameSinkId, &manager_, &stub_surface_factory_client_, | |
594 &fake_surface_resource_holder_client_)); | |
595 SurfaceId id2(kArbitraryFrameSinkId, local_surface_id2); | |
596 factory2->SubmitCompositorFrame(local_surface_id2, CompositorFrame(), | |
597 SurfaceFactory::DrawCallback(), | |
598 SurfaceFactory::WillDrawCallback()); | |
599 | |
600 manager_.RegisterFrameSinkId(kArbitraryFrameSinkId); | |
601 | |
602 // Check that waiting before the sequence is satisfied works. | |
603 manager_.GetSurfaceForId(id2)->AddDestructionDependency( | |
604 SurfaceSequence(kArbitraryFrameSinkId, 4)); | |
605 factory2->EvictSurface(); | |
606 | |
607 DCHECK(manager_.GetSurfaceForId(id2)); | |
608 manager_.SatisfySequence(SurfaceSequence(kArbitraryFrameSinkId, 4)); | |
609 manager_.SatisfySequence(SurfaceSequence(kArbitraryFrameSinkId, 6)); | |
610 DCHECK(!manager_.GetSurfaceForId(id2)); | |
611 | |
612 // Check that waiting after the sequence is satisfied works. | |
613 factory2->SubmitCompositorFrame(local_surface_id2, CompositorFrame(), | |
614 SurfaceFactory::DrawCallback(), | |
615 SurfaceFactory::WillDrawCallback()); | |
616 DCHECK(manager_.GetSurfaceForId(id2)); | |
617 manager_.GetSurfaceForId(id2)->AddDestructionDependency( | |
618 SurfaceSequence(kAnotherArbitraryFrameSinkId, 6)); | |
619 factory2->EvictSurface(); | |
620 DCHECK(!manager_.GetSurfaceForId(id2)); | |
621 } | |
622 | |
623 // Tests that Surface ID namespace invalidation correctly allows | |
624 // Sequences to be ignored. | |
625 TEST_F(SurfaceFactoryTest, InvalidFrameSinkId) { | |
626 FrameSinkId frame_sink_id(1234, 5678); | |
627 | |
628 LocalSurfaceId local_surface_id(5, kArbitraryToken); | |
629 SurfaceId id(factory_->frame_sink_id(), local_surface_id); | |
630 factory_->SubmitCompositorFrame(local_surface_id, CompositorFrame(), | |
631 SurfaceFactory::DrawCallback(), | |
632 SurfaceFactory::WillDrawCallback()); | |
633 | |
634 manager_.RegisterFrameSinkId(frame_sink_id); | |
635 manager_.GetSurfaceForId(id)->AddDestructionDependency( | |
636 SurfaceSequence(frame_sink_id, 4)); | |
637 | |
638 factory_->EvictSurface(); | |
639 | |
640 // Verify the dependency has prevented the surface from getting destroyed. | |
641 EXPECT_TRUE(manager_.GetSurfaceForId(id)); | |
642 | |
643 manager_.InvalidateFrameSinkId(frame_sink_id); | |
644 | |
645 // Verify that the invalidated namespace caused the unsatisfied sequence | |
646 // to be ignored. | |
647 EXPECT_FALSE(manager_.GetSurfaceForId(id)); | |
648 } | |
649 | |
650 TEST_F(SurfaceFactoryTest, DestroyCycle) { | |
651 LocalSurfaceId local_surface_id2(5, kArbitraryToken); | |
652 SurfaceId id2(kArbitraryFrameSinkId, local_surface_id2); | |
653 std::unique_ptr<SurfaceFactory> factory2(new SurfaceFactory( | |
654 kArbitraryFrameSinkId, &manager_, &stub_surface_factory_client_, | |
655 &fake_surface_resource_holder_client_)); | |
656 manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId); | |
657 // Give id2 a frame that references local_surface_id_. | |
658 { | |
659 std::unique_ptr<RenderPass> render_pass(RenderPass::Create()); | |
660 CompositorFrame frame; | |
661 frame.render_pass_list.push_back(std::move(render_pass)); | |
662 frame.metadata.referenced_surfaces.push_back( | |
663 SurfaceId(factory_->frame_sink_id(), local_surface_id_)); | |
664 factory2->SubmitCompositorFrame(local_surface_id2, std::move(frame), | |
665 SurfaceFactory::DrawCallback(), | |
666 SurfaceFactory::WillDrawCallback()); | |
667 EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id2); | |
668 } | |
669 manager_.GetSurfaceForId(id2)->AddDestructionDependency( | |
670 SurfaceSequence(kAnotherArbitraryFrameSinkId, 4)); | |
671 factory2->EvictSurface(); | |
672 // Give local_surface_id_ a frame that references id2. | |
673 { | |
674 std::unique_ptr<RenderPass> render_pass(RenderPass::Create()); | |
675 CompositorFrame frame; | |
676 frame.render_pass_list.push_back(std::move(render_pass)); | |
677 frame.metadata.referenced_surfaces.push_back(id2); | |
678 factory_->SubmitCompositorFrame(local_surface_id_, std::move(frame), | |
679 SurfaceFactory::DrawCallback(), | |
680 SurfaceFactory::WillDrawCallback()); | |
681 } | |
682 factory_->EvictSurface(); | |
683 EXPECT_TRUE(manager_.GetSurfaceForId(id2)); | |
684 // local_surface_id_ should be retained by reference from id2. | |
685 EXPECT_TRUE(manager_.GetSurfaceForId( | |
686 SurfaceId(factory_->frame_sink_id(), local_surface_id_))); | |
687 | |
688 // Satisfy last destruction dependency for id2. | |
689 manager_.SatisfySequence(SurfaceSequence(kAnotherArbitraryFrameSinkId, 4)); | |
690 | |
691 // id2 and local_surface_id_ are in a reference cycle that has no surface | |
692 // sequences holding on to it, so they should be destroyed. | |
693 EXPECT_TRUE(!manager_.GetSurfaceForId(id2)); | |
694 EXPECT_TRUE(!manager_.GetSurfaceForId( | |
695 SurfaceId(factory_->frame_sink_id(), local_surface_id_))); | |
696 | |
697 local_surface_id_ = LocalSurfaceId(); | |
698 } | |
699 | |
700 void CopyRequestTestCallback(bool* called, | |
701 std::unique_ptr<CopyOutputResult> result) { | |
702 *called = true; | |
703 } | |
704 | |
705 TEST_F(SurfaceFactoryTest, DuplicateCopyRequest) { | |
706 { | |
707 std::unique_ptr<RenderPass> render_pass(RenderPass::Create()); | |
708 CompositorFrame frame; | |
709 frame.render_pass_list.push_back(std::move(render_pass)); | |
710 frame.metadata.referenced_surfaces.push_back( | |
711 SurfaceId(factory_->frame_sink_id(), local_surface_id_)); | |
712 factory_->SubmitCompositorFrame(local_surface_id_, std::move(frame), | |
713 SurfaceFactory::DrawCallback(), | |
714 SurfaceFactory::WillDrawCallback()); | |
715 EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id_); | |
716 } | |
717 | |
718 bool called1 = false; | |
719 std::unique_ptr<CopyOutputRequest> request; | |
720 request = CopyOutputRequest::CreateRequest( | |
721 base::Bind(&CopyRequestTestCallback, &called1)); | |
722 request->set_source(kArbitrarySourceId1); | |
723 | |
724 factory_->RequestCopyOfSurface(std::move(request)); | |
725 EXPECT_FALSE(called1); | |
726 | |
727 bool called2 = false; | |
728 request = CopyOutputRequest::CreateRequest( | |
729 base::Bind(&CopyRequestTestCallback, &called2)); | |
730 request->set_source(kArbitrarySourceId2); | |
731 | |
732 factory_->RequestCopyOfSurface(std::move(request)); | |
733 // Callbacks have different sources so neither should be called. | |
734 EXPECT_FALSE(called1); | |
735 EXPECT_FALSE(called2); | |
736 | |
737 bool called3 = false; | |
738 request = CopyOutputRequest::CreateRequest( | |
739 base::Bind(&CopyRequestTestCallback, &called3)); | |
740 request->set_source(kArbitrarySourceId1); | |
741 | |
742 factory_->RequestCopyOfSurface(std::move(request)); | |
743 // Two callbacks are from source1, so the first should be called. | |
744 EXPECT_TRUE(called1); | |
745 EXPECT_FALSE(called2); | |
746 EXPECT_FALSE(called3); | |
747 | |
748 factory_->EvictSurface(); | |
749 local_surface_id_ = LocalSurfaceId(); | |
750 EXPECT_TRUE(called1); | |
751 EXPECT_TRUE(called2); | |
752 EXPECT_TRUE(called3); | |
753 } | |
754 | |
755 // Check whether the SurfaceInfo object is created and populated correctly | |
756 // after the frame submission. | |
757 TEST_F(SurfaceFactoryTest, SurfaceInfo) { | |
758 CompositorFrame frame; | |
759 | |
760 auto render_pass = RenderPass::Create(); | |
761 render_pass->SetNew(1, gfx::Rect(5, 6), gfx::Rect(), gfx::Transform()); | |
762 frame.render_pass_list.push_back(std::move(render_pass)); | |
763 | |
764 render_pass = RenderPass::Create(); | |
765 render_pass->SetNew(2, gfx::Rect(7, 8), gfx::Rect(), gfx::Transform()); | |
766 frame.render_pass_list.push_back(std::move(render_pass)); | |
767 | |
768 frame.metadata.device_scale_factor = 2.5f; | |
769 | |
770 factory_->SubmitCompositorFrame(local_surface_id_, std::move(frame), | |
771 SurfaceFactory::DrawCallback(), | |
772 SurfaceFactory::WillDrawCallback()); | |
773 SurfaceId expected_surface_id(factory_->frame_sink_id(), local_surface_id_); | |
774 EXPECT_EQ(expected_surface_id, last_surface_info_.id()); | |
775 EXPECT_EQ(2.5f, last_surface_info_.device_scale_factor()); | |
776 EXPECT_EQ(gfx::Size(7, 8), last_surface_info_.size_in_pixels()); | |
777 } | |
778 | |
779 } // namespace | |
780 } // namespace cc | |
OLD | NEW |