OLD | NEW |
| (Empty) |
1 // Copyright 2012 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/resource_update_controller.h" | |
6 | |
7 #include "cc/prioritized_resource_manager.h" | |
8 #include "cc/test/fake_output_surface.h" | |
9 #include "cc/test/fake_proxy.h" | |
10 #include "cc/test/scheduler_test_common.h" | |
11 #include "cc/test/test_web_graphics_context_3d.h" | |
12 #include "cc/test/tiled_layer_test_common.h" | |
13 #include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 #include "third_party/khronos/GLES2/gl2ext.h" | |
16 | |
17 using namespace WebKit; | |
18 using testing::Test; | |
19 | |
20 namespace cc { | |
21 namespace { | |
22 | |
23 const int kFlushPeriodFull = 4; | |
24 const int kFlushPeriodPartial = kFlushPeriodFull; | |
25 | |
26 class ResourceUpdateControllerTest; | |
27 | |
28 class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D { | |
29 public: | |
30 WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest *test) | |
31 : m_test(test) | |
32 , m_supportShallowFlush(true) | |
33 { } | |
34 | |
35 virtual void flush(void); | |
36 virtual void shallowFlushCHROMIUM(void); | |
37 virtual void texSubImage2D(WGC3Denum target, | |
38 WGC3Dint level, | |
39 WGC3Dint xoffset, | |
40 WGC3Dint yoffset, | |
41 WGC3Dsizei width, | |
42 WGC3Dsizei height, | |
43 WGC3Denum format, | |
44 WGC3Denum type, | |
45 const void* pixels); | |
46 virtual GrGLInterface* onCreateGrGLInterface() { return 0; } | |
47 | |
48 virtual WebString getString(WGC3Denum name) | |
49 { | |
50 if (m_supportShallowFlush) | |
51 return WebString("GL_CHROMIUM_shallow_flush"); | |
52 return WebString(""); | |
53 } | |
54 | |
55 virtual void getQueryObjectuivEXT(WebGLId, WGC3Denum, WGC3Duint*); | |
56 | |
57 private: | |
58 ResourceUpdateControllerTest* m_test; | |
59 bool m_supportShallowFlush; | |
60 }; | |
61 | |
62 | |
63 class ResourceUpdateControllerTest : public Test { | |
64 public: | |
65 ResourceUpdateControllerTest() | |
66 : m_proxy(scoped_ptr<Thread>(NULL)) | |
67 , m_queue(make_scoped_ptr(new ResourceUpdateQueue)) | |
68 , m_resourceManager(PrioritizedResourceManager::create(&m_proxy)) | |
69 , m_fullUploadCountExpected(0) | |
70 , m_partialCountExpected(0) | |
71 , m_totalUploadCountExpected(0) | |
72 , m_maxUploadCountPerUpdate(0) | |
73 , m_numConsecutiveFlushes(0) | |
74 , m_numDanglingUploads(0) | |
75 , m_numTotalUploads(0) | |
76 , m_numTotalFlushes(0) | |
77 , m_queryResultsAvailable(0) | |
78 { | |
79 } | |
80 | |
81 virtual ~ResourceUpdateControllerTest() | |
82 { | |
83 DebugScopedSetImplThreadAndMainThreadBlocked | |
84 implThreadAndMainThreadBlocked(&m_proxy); | |
85 m_resourceManager->clearAllMemory(m_resourceProvider.get()); | |
86 } | |
87 | |
88 public: | |
89 void onFlush() | |
90 { | |
91 // Check for back-to-back flushes. | |
92 EXPECT_EQ(0, m_numConsecutiveFlushes) << "Back-to-back flushes detected.
"; | |
93 | |
94 m_numDanglingUploads = 0; | |
95 m_numConsecutiveFlushes++; | |
96 m_numTotalFlushes++; | |
97 } | |
98 | |
99 void onUpload() | |
100 { | |
101 // Check for too many consecutive uploads | |
102 if (m_numTotalUploads < m_fullUploadCountExpected) | |
103 EXPECT_LT(m_numDanglingUploads, kFlushPeriodFull) << "Too many conse
cutive full uploads detected."; | |
104 else | |
105 EXPECT_LT(m_numDanglingUploads, kFlushPeriodPartial) << "Too many co
nsecutive partial uploads detected."; | |
106 | |
107 m_numConsecutiveFlushes = 0; | |
108 m_numDanglingUploads++; | |
109 m_numTotalUploads++; | |
110 } | |
111 | |
112 bool isQueryResultAvailable() | |
113 { | |
114 if (!m_queryResultsAvailable) | |
115 return false; | |
116 | |
117 m_queryResultsAvailable--; | |
118 return true; | |
119 } | |
120 | |
121 protected: | |
122 virtual void SetUp() | |
123 { | |
124 m_outputSurface = FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGrap
hicsContext3D>(new WebGraphicsContext3DForUploadTest(this))); | |
125 m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 300, 150); | |
126 m_bitmap.allocPixels(); | |
127 | |
128 for (int i = 0; i < 4; i++) { | |
129 m_textures[i] = PrioritizedResource::create( | |
130 m_resourceManager.get(), gfx::Size(300, 150), GL_RGBA); | |
131 m_textures[i]->setRequestPriority( | |
132 PriorityCalculator::VisiblePriority(true)); | |
133 } | |
134 m_resourceManager->prioritizeTextures(); | |
135 | |
136 m_resourceProvider = ResourceProvider::Create(m_outputSurface.get()); | |
137 } | |
138 | |
139 | |
140 void appendFullUploadsOfIndexedTextureToUpdateQueue(int count, int textureIn
dex) | |
141 { | |
142 m_fullUploadCountExpected += count; | |
143 m_totalUploadCountExpected += count; | |
144 | |
145 const gfx::Rect rect(0, 0, 300, 150); | |
146 const ResourceUpdate upload = ResourceUpdate::Create( | |
147 m_textures[textureIndex].get(), &m_bitmap, rect, rect, gfx::Vector2d
()); | |
148 for (int i = 0; i < count; i++) | |
149 m_queue->appendFullUpload(upload); | |
150 } | |
151 | |
152 void appendFullUploadsToUpdateQueue(int count) | |
153 { | |
154 appendFullUploadsOfIndexedTextureToUpdateQueue(count, 0); | |
155 } | |
156 | |
157 void appendPartialUploadsOfIndexedTextureToUpdateQueue(int count, int textur
eIndex) | |
158 { | |
159 m_partialCountExpected += count; | |
160 m_totalUploadCountExpected += count; | |
161 | |
162 const gfx::Rect rect(0, 0, 100, 100); | |
163 const ResourceUpdate upload = ResourceUpdate::Create( | |
164 m_textures[textureIndex].get(), &m_bitmap, rect, rect, gfx::Vector2d
()); | |
165 for (int i = 0; i < count; i++) | |
166 m_queue->appendPartialUpload(upload); | |
167 } | |
168 | |
169 void appendPartialUploadsToUpdateQueue(int count) | |
170 { | |
171 appendPartialUploadsOfIndexedTextureToUpdateQueue(count, 0); | |
172 } | |
173 | |
174 void setMaxUploadCountPerUpdate(int count) | |
175 { | |
176 m_maxUploadCountPerUpdate = count; | |
177 } | |
178 | |
179 void updateTextures() | |
180 { | |
181 DebugScopedSetImplThreadAndMainThreadBlocked | |
182 implThreadAndMainThreadBlocked(&m_proxy); | |
183 scoped_ptr<ResourceUpdateController> updateController = | |
184 ResourceUpdateController::Create( | |
185 NULL, | |
186 m_proxy.ImplThread(), | |
187 m_queue.Pass(), | |
188 m_resourceProvider.get()); | |
189 updateController->Finalize(); | |
190 } | |
191 | |
192 void makeQueryResultAvailable() | |
193 { | |
194 m_queryResultsAvailable++; | |
195 } | |
196 | |
197 protected: | |
198 // Classes required to interact and test the ResourceUpdateController | |
199 FakeProxy m_proxy; | |
200 scoped_ptr<OutputSurface> m_outputSurface; | |
201 scoped_ptr<ResourceProvider> m_resourceProvider; | |
202 scoped_ptr<ResourceUpdateQueue> m_queue; | |
203 scoped_ptr<PrioritizedResource> m_textures[4]; | |
204 scoped_ptr<PrioritizedResourceManager> m_resourceManager; | |
205 SkBitmap m_bitmap; | |
206 int m_queryResultsAvailable; | |
207 | |
208 // Properties / expectations of this test | |
209 int m_fullUploadCountExpected; | |
210 int m_partialCountExpected; | |
211 int m_totalUploadCountExpected; | |
212 int m_maxUploadCountPerUpdate; | |
213 | |
214 // Dynamic properties of this test | |
215 int m_numConsecutiveFlushes; | |
216 int m_numDanglingUploads; | |
217 int m_numTotalUploads; | |
218 int m_numTotalFlushes; | |
219 }; | |
220 | |
221 void WebGraphicsContext3DForUploadTest::flush(void) | |
222 { | |
223 m_test->onFlush(); | |
224 } | |
225 | |
226 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM(void) | |
227 { | |
228 m_test->onFlush(); | |
229 } | |
230 | |
231 void WebGraphicsContext3DForUploadTest::texSubImage2D(WGC3Denum target, | |
232 WGC3Dint level, | |
233 WGC3Dint xoffset, | |
234 WGC3Dint yoffset, | |
235 WGC3Dsizei width, | |
236 WGC3Dsizei height, | |
237 WGC3Denum format, | |
238 WGC3Denum type, | |
239 const void* pixels) | |
240 { | |
241 m_test->onUpload(); | |
242 } | |
243 | |
244 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT( | |
245 WebGLId, | |
246 WGC3Denum pname, | |
247 WGC3Duint* params) { | |
248 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT) | |
249 *params = m_test->isQueryResultAvailable(); | |
250 } | |
251 | |
252 // ZERO UPLOADS TESTS | |
253 TEST_F(ResourceUpdateControllerTest, ZeroUploads) | |
254 { | |
255 appendFullUploadsToUpdateQueue(0); | |
256 appendPartialUploadsToUpdateQueue(0); | |
257 updateTextures(); | |
258 | |
259 EXPECT_EQ(0, m_numTotalFlushes); | |
260 EXPECT_EQ(0, m_numTotalUploads); | |
261 } | |
262 | |
263 | |
264 // ONE UPLOAD TESTS | |
265 TEST_F(ResourceUpdateControllerTest, OneFullUpload) | |
266 { | |
267 appendFullUploadsToUpdateQueue(1); | |
268 appendPartialUploadsToUpdateQueue(0); | |
269 updateTextures(); | |
270 | |
271 EXPECT_EQ(1, m_numTotalFlushes); | |
272 EXPECT_EQ(1, m_numTotalUploads); | |
273 EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flus
h."; | |
274 } | |
275 | |
276 TEST_F(ResourceUpdateControllerTest, OnePartialUpload) | |
277 { | |
278 appendFullUploadsToUpdateQueue(0); | |
279 appendPartialUploadsToUpdateQueue(1); | |
280 updateTextures(); | |
281 | |
282 EXPECT_EQ(1, m_numTotalFlushes); | |
283 EXPECT_EQ(1, m_numTotalUploads); | |
284 EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flus
h."; | |
285 } | |
286 | |
287 TEST_F(ResourceUpdateControllerTest, OneFullOnePartialUpload) | |
288 { | |
289 appendFullUploadsToUpdateQueue(1); | |
290 appendPartialUploadsToUpdateQueue(1); | |
291 updateTextures(); | |
292 | |
293 EXPECT_EQ(1, m_numTotalFlushes); | |
294 EXPECT_EQ(2, m_numTotalUploads); | |
295 EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flus
h."; | |
296 } | |
297 | |
298 | |
299 // This class of tests upload a number of textures that is a multiple of the flu
sh period. | |
300 const int fullUploadFlushMultipler = 7; | |
301 const int fullCount = fullUploadFlushMultipler * kFlushPeriodFull; | |
302 | |
303 const int partialUploadFlushMultipler = 11; | |
304 const int partialCount = partialUploadFlushMultipler * kFlushPeriodPartial; | |
305 | |
306 TEST_F(ResourceUpdateControllerTest, ManyFullUploads) | |
307 { | |
308 appendFullUploadsToUpdateQueue(fullCount); | |
309 appendPartialUploadsToUpdateQueue(0); | |
310 updateTextures(); | |
311 | |
312 EXPECT_EQ(fullUploadFlushMultipler, m_numTotalFlushes); | |
313 EXPECT_EQ(fullCount, m_numTotalUploads); | |
314 EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flus
h."; | |
315 } | |
316 | |
317 TEST_F(ResourceUpdateControllerTest, ManyPartialUploads) | |
318 { | |
319 appendFullUploadsToUpdateQueue(0); | |
320 appendPartialUploadsToUpdateQueue(partialCount); | |
321 updateTextures(); | |
322 | |
323 EXPECT_EQ(partialUploadFlushMultipler, m_numTotalFlushes); | |
324 EXPECT_EQ(partialCount, m_numTotalUploads); | |
325 EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flus
h."; | |
326 } | |
327 | |
328 TEST_F(ResourceUpdateControllerTest, ManyFullManyPartialUploads) | |
329 { | |
330 appendFullUploadsToUpdateQueue(fullCount); | |
331 appendPartialUploadsToUpdateQueue(partialCount); | |
332 updateTextures(); | |
333 | |
334 EXPECT_EQ(fullUploadFlushMultipler + partialUploadFlushMultipler, m_numTotal
Flushes); | |
335 EXPECT_EQ(fullCount + partialCount, m_numTotalUploads); | |
336 EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flus
h."; | |
337 } | |
338 | |
339 class FakeResourceUpdateControllerClient : public cc::ResourceUpdateControllerCl
ient { | |
340 public: | |
341 FakeResourceUpdateControllerClient() { reset(); } | |
342 void reset() { m_readyToFinalizeCalled = false; } | |
343 bool readyToFinalizeCalled() const { return m_readyToFinalizeCalled; } | |
344 | |
345 virtual void ReadyToFinalizeTextureUpdates() OVERRIDE { m_readyToFinalizeCal
led = true; } | |
346 | |
347 protected: | |
348 bool m_readyToFinalizeCalled; | |
349 }; | |
350 | |
351 class FakeResourceUpdateController : public cc::ResourceUpdateController { | |
352 public: | |
353 static scoped_ptr<FakeResourceUpdateController> Create(cc::ResourceUpdateCon
trollerClient* client, cc::Thread* thread, scoped_ptr<ResourceUpdateQueue> queue
, ResourceProvider* resourceProvider) | |
354 { | |
355 return make_scoped_ptr(new FakeResourceUpdateController(client, thread,
queue.Pass(), resourceProvider)); | |
356 } | |
357 | |
358 void setNow(base::TimeTicks time) { m_now = time; } | |
359 virtual base::TimeTicks Now() const OVERRIDE { return m_now; } | |
360 void setUpdateMoreTexturesTime(base::TimeDelta time) { m_updateMoreTexturesT
ime = time; } | |
361 virtual base::TimeDelta UpdateMoreTexturesTime() const OVERRIDE { return m_u
pdateMoreTexturesTime; } | |
362 void setUpdateMoreTexturesSize(size_t size) { m_updateMoreTexturesSize = siz
e; } | |
363 virtual size_t UpdateMoreTexturesSize() const OVERRIDE { return m_updateMore
TexturesSize; } | |
364 | |
365 protected: | |
366 FakeResourceUpdateController(cc::ResourceUpdateControllerClient* client, cc:
:Thread* thread, scoped_ptr<ResourceUpdateQueue> queue, ResourceProvider* resour
ceProvider) | |
367 : cc::ResourceUpdateController(client, thread, queue.Pass(), resourcePro
vider) | |
368 , m_updateMoreTexturesSize(0) { } | |
369 | |
370 base::TimeTicks m_now; | |
371 base::TimeDelta m_updateMoreTexturesTime; | |
372 size_t m_updateMoreTexturesSize; | |
373 }; | |
374 | |
375 static void runPendingTask(FakeThread* thread, FakeResourceUpdateController* con
troller) | |
376 { | |
377 EXPECT_TRUE(thread->hasPendingTask()); | |
378 controller->setNow(controller->Now() + base::TimeDelta::FromMilliseconds(thr
ead->pendingDelayMs())); | |
379 thread->runPendingTask(); | |
380 } | |
381 | |
382 TEST_F(ResourceUpdateControllerTest, UpdateMoreTextures) | |
383 { | |
384 FakeResourceUpdateControllerClient client; | |
385 FakeThread thread; | |
386 | |
387 setMaxUploadCountPerUpdate(1); | |
388 appendFullUploadsToUpdateQueue(3); | |
389 appendPartialUploadsToUpdateQueue(0); | |
390 | |
391 DebugScopedSetImplThreadAndMainThreadBlocked | |
392 implThreadAndMainThreadBlocked(&m_proxy); | |
393 scoped_ptr<FakeResourceUpdateController> controller(FakeResourceUpdateContro
ller::Create(&client, &thread, m_queue.Pass(), m_resourceProvider.get())); | |
394 | |
395 controller->setNow( | |
396 controller->Now() + base::TimeDelta::FromMilliseconds(1)); | |
397 controller->setUpdateMoreTexturesTime( | |
398 base::TimeDelta::FromMilliseconds(100)); | |
399 controller->setUpdateMoreTexturesSize(1); | |
400 // Not enough time for any updates. | |
401 controller->PerformMoreUpdates( | |
402 controller->Now() + base::TimeDelta::FromMilliseconds(90)); | |
403 EXPECT_FALSE(thread.hasPendingTask()); | |
404 | |
405 controller->setUpdateMoreTexturesTime( | |
406 base::TimeDelta::FromMilliseconds(100)); | |
407 controller->setUpdateMoreTexturesSize(1); | |
408 // Only enough time for 1 update. | |
409 controller->PerformMoreUpdates( | |
410 controller->Now() + base::TimeDelta::FromMilliseconds(120)); | |
411 EXPECT_FALSE(thread.hasPendingTask()); | |
412 EXPECT_EQ(1, m_numTotalUploads); | |
413 | |
414 // Complete one upload. | |
415 makeQueryResultAvailable(); | |
416 | |
417 controller->setUpdateMoreTexturesTime( | |
418 base::TimeDelta::FromMilliseconds(100)); | |
419 controller->setUpdateMoreTexturesSize(1); | |
420 // Enough time for 2 updates. | |
421 controller->PerformMoreUpdates( | |
422 controller->Now() + base::TimeDelta::FromMilliseconds(220)); | |
423 runPendingTask(&thread, controller.get()); | |
424 EXPECT_FALSE(thread.hasPendingTask()); | |
425 EXPECT_TRUE(client.readyToFinalizeCalled()); | |
426 EXPECT_EQ(3, m_numTotalUploads); | |
427 } | |
428 | |
429 TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) | |
430 { | |
431 FakeResourceUpdateControllerClient client; | |
432 FakeThread thread; | |
433 | |
434 setMaxUploadCountPerUpdate(1); | |
435 appendFullUploadsToUpdateQueue(2); | |
436 appendPartialUploadsToUpdateQueue(0); | |
437 | |
438 DebugScopedSetImplThreadAndMainThreadBlocked | |
439 implThreadAndMainThreadBlocked(&m_proxy); | |
440 scoped_ptr<FakeResourceUpdateController> controller(FakeResourceUpdateContro
ller::Create(&client, &thread, m_queue.Pass(), m_resourceProvider.get())); | |
441 | |
442 controller->setNow( | |
443 controller->Now() + base::TimeDelta::FromMilliseconds(1)); | |
444 controller->setUpdateMoreTexturesTime( | |
445 base::TimeDelta::FromMilliseconds(100)); | |
446 controller->setUpdateMoreTexturesSize(1); | |
447 // Enough time for 3 updates but only 2 necessary. | |
448 controller->PerformMoreUpdates( | |
449 controller->Now() + base::TimeDelta::FromMilliseconds(310)); | |
450 runPendingTask(&thread, controller.get()); | |
451 EXPECT_FALSE(thread.hasPendingTask()); | |
452 EXPECT_TRUE(client.readyToFinalizeCalled()); | |
453 EXPECT_EQ(2, m_numTotalUploads); | |
454 | |
455 controller->setUpdateMoreTexturesTime( | |
456 base::TimeDelta::FromMilliseconds(100)); | |
457 controller->setUpdateMoreTexturesSize(1); | |
458 // Enough time for updates but no more updates left. | |
459 controller->PerformMoreUpdates( | |
460 controller->Now() + base::TimeDelta::FromMilliseconds(310)); | |
461 // 0-delay task used to call readyToFinalizeTextureUpdates(). | |
462 runPendingTask(&thread, controller.get()); | |
463 EXPECT_FALSE(thread.hasPendingTask()); | |
464 EXPECT_TRUE(client.readyToFinalizeCalled()); | |
465 EXPECT_EQ(2, m_numTotalUploads); | |
466 } | |
467 | |
468 TEST_F(ResourceUpdateControllerTest, UpdatesCompleteInFiniteTime) | |
469 { | |
470 FakeResourceUpdateControllerClient client; | |
471 FakeThread thread; | |
472 | |
473 setMaxUploadCountPerUpdate(1); | |
474 appendFullUploadsToUpdateQueue(2); | |
475 appendPartialUploadsToUpdateQueue(0); | |
476 | |
477 DebugScopedSetImplThreadAndMainThreadBlocked | |
478 implThreadAndMainThreadBlocked(&m_proxy); | |
479 scoped_ptr<FakeResourceUpdateController> controller(FakeResourceUpdateContro
ller::Create(&client, &thread, m_queue.Pass(), m_resourceProvider.get())); | |
480 | |
481 controller->setNow( | |
482 controller->Now() + base::TimeDelta::FromMilliseconds(1)); | |
483 controller->setUpdateMoreTexturesTime( | |
484 base::TimeDelta::FromMilliseconds(500)); | |
485 controller->setUpdateMoreTexturesSize(1); | |
486 | |
487 for (int i = 0; i < 100; i++) { | |
488 if (client.readyToFinalizeCalled()) | |
489 break; | |
490 | |
491 // Not enough time for any updates. | |
492 controller->PerformMoreUpdates( | |
493 controller->Now() + base::TimeDelta::FromMilliseconds(400)); | |
494 | |
495 if (thread.hasPendingTask()) | |
496 runPendingTask(&thread, controller.get()); | |
497 } | |
498 | |
499 EXPECT_FALSE(thread.hasPendingTask()); | |
500 EXPECT_TRUE(client.readyToFinalizeCalled()); | |
501 EXPECT_EQ(2, m_numTotalUploads); | |
502 } | |
503 | |
504 } // namespace | |
505 } // namespace cc | |
OLD | NEW |