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.
5 #include "cc/resource_update_controller.h"
7 #include "cc/single_thread_proxy.h" // For DebugScopedSetImplThread
8 #include "cc/test/fake_proxy.h"
9 #include "cc/test/fake_web_compositor_output_surface.h"
10 #include "cc/test/fake_web_graphics_context_3d.h"
11 #include "cc/test/scheduler_test_common.h"
12 #include "cc/test/tiled_layer_test_common.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/khronos/GLES2/gl2ext.h"
16 using namespace WebKit
;
17 using namespace WebKitTests
;
23 const int kFlushPeriodFull
= 4;
24 const int kFlushPeriodPartial
= kFlushPeriodFull
;
26 class ResourceUpdateControllerTest
;
28 class WebGraphicsContext3DForUploadTest
: public FakeWebGraphicsContext3D
{
30 WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest
*test
)
32 , m_supportShallowFlush(true)
35 virtual void flush(void);
36 virtual void shallowFlushCHROMIUM(void);
37 virtual void texSubImage2D(WGC3Denum target
,
46 virtual GrGLInterface
* onCreateGrGLInterface() { return 0; }
48 virtual WebString
getString(WGC3Denum name
)
50 if (m_supportShallowFlush
)
51 return WebString("GL_CHROMIUM_shallow_flush");
55 virtual void getQueryObjectuivEXT(WebGLId
, WGC3Denum
, WGC3Duint
*);
58 ResourceUpdateControllerTest
* m_test
;
59 bool m_supportShallowFlush
;
63 class ResourceUpdateControllerTest
: public Test
{
65 ResourceUpdateControllerTest()
66 : m_proxy(scoped_ptr
<Thread
>(NULL
))
67 , m_queue(make_scoped_ptr(new ResourceUpdateQueue
))
68 , m_resourceManager(PrioritizedResourceManager::create(Renderer::ContentPool
, &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)
81 ~ResourceUpdateControllerTest()
83 DebugScopedSetImplThreadAndMainThreadBlocked
84 implThreadAndMainThreadBlocked(&m_proxy
);
85 m_resourceManager
->clearAllMemory(m_resourceProvider
.get());
91 // Check for back-to-back flushes.
92 EXPECT_EQ(0, m_numConsecutiveFlushes
) << "Back-to-back flushes detected.";
94 m_numDanglingUploads
= 0;
95 m_numConsecutiveFlushes
++;
101 // Check for too many consecutive uploads
102 if (m_numTotalUploads
< m_fullUploadCountExpected
)
103 EXPECT_LT(m_numDanglingUploads
, kFlushPeriodFull
) << "Too many consecutive full uploads detected.";
105 EXPECT_LT(m_numDanglingUploads
, kFlushPeriodPartial
) << "Too many consecutive partial uploads detected.";
107 m_numConsecutiveFlushes
= 0;
108 m_numDanglingUploads
++;
112 bool isQueryResultAvailable()
114 if (!m_queryResultsAvailable
)
117 m_queryResultsAvailable
--;
124 m_context
= FakeWebCompositorOutputSurface::create(scoped_ptr
<WebKit::WebGraphicsContext3D
>(new WebGraphicsContext3DForUploadTest(this)));
125 m_bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 300, 150);
126 m_bitmap
.allocPixels();
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));
134 m_resourceManager
->prioritizeTextures();
136 m_resourceProvider
= ResourceProvider::create(m_context
.get());
140 void appendFullUploadsOfIndexedTextureToUpdateQueue(int count
, int textureIndex
)
142 m_fullUploadCountExpected
+= count
;
143 m_totalUploadCountExpected
+= count
;
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
);
152 void appendFullUploadsToUpdateQueue(int count
)
154 appendFullUploadsOfIndexedTextureToUpdateQueue(count
, 0);
157 void appendPartialUploadsOfIndexedTextureToUpdateQueue(int count
, int textureIndex
)
159 m_partialCountExpected
+= count
;
160 m_totalUploadCountExpected
+= count
;
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
);
169 void appendPartialUploadsToUpdateQueue(int count
)
171 appendPartialUploadsOfIndexedTextureToUpdateQueue(count
, 0);
174 void setMaxUploadCountPerUpdate(int count
)
176 m_maxUploadCountPerUpdate
= count
;
179 void updateTextures()
181 DebugScopedSetImplThreadAndMainThreadBlocked
182 implThreadAndMainThreadBlocked(&m_proxy
);
183 scoped_ptr
<ResourceUpdateController
> updateController
=
184 ResourceUpdateController::create(
186 m_proxy
.implThread(),
188 m_resourceProvider
.get(),
189 m_proxy
.hasImplThread());
190 updateController
->finalize();
193 void makeQueryResultAvailable()
195 m_queryResultsAvailable
++;
199 // Classes required to interact and test the ResourceUpdateController
201 scoped_ptr
<GraphicsContext
> m_context
;
202 scoped_ptr
<ResourceProvider
> m_resourceProvider
;
203 scoped_ptr
<ResourceUpdateQueue
> m_queue
;
204 scoped_ptr
<PrioritizedResource
> m_textures
[4];
205 scoped_ptr
<PrioritizedResourceManager
> m_resourceManager
;
207 int m_queryResultsAvailable
;
209 // Properties / expectations of this test
210 int m_fullUploadCountExpected
;
211 int m_partialCountExpected
;
212 int m_totalUploadCountExpected
;
213 int m_maxUploadCountPerUpdate
;
215 // Dynamic properties of this test
216 int m_numConsecutiveFlushes
;
217 int m_numDanglingUploads
;
218 int m_numTotalUploads
;
219 int m_numTotalFlushes
;
222 void WebGraphicsContext3DForUploadTest::flush(void)
227 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM(void)
232 void WebGraphicsContext3DForUploadTest::texSubImage2D(WGC3Denum target
,
245 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(
249 if (pname
== GL_QUERY_RESULT_AVAILABLE_EXT
)
250 *params
= m_test
->isQueryResultAvailable();
253 // ZERO UPLOADS TESTS
254 TEST_F(ResourceUpdateControllerTest
, ZeroUploads
)
256 appendFullUploadsToUpdateQueue(0);
257 appendPartialUploadsToUpdateQueue(0);
260 EXPECT_EQ(0, m_numTotalFlushes
);
261 EXPECT_EQ(0, m_numTotalUploads
);
266 TEST_F(ResourceUpdateControllerTest
, OneFullUpload
)
268 appendFullUploadsToUpdateQueue(1);
269 appendPartialUploadsToUpdateQueue(0);
272 EXPECT_EQ(1, m_numTotalFlushes
);
273 EXPECT_EQ(1, m_numTotalUploads
);
274 EXPECT_EQ(0, m_numDanglingUploads
) << "Last upload wasn't followed by a flush.";
277 TEST_F(ResourceUpdateControllerTest
, OnePartialUpload
)
279 appendFullUploadsToUpdateQueue(0);
280 appendPartialUploadsToUpdateQueue(1);
283 EXPECT_EQ(1, m_numTotalFlushes
);
284 EXPECT_EQ(1, m_numTotalUploads
);
285 EXPECT_EQ(0, m_numDanglingUploads
) << "Last upload wasn't followed by a flush.";
288 TEST_F(ResourceUpdateControllerTest
, OneFullOnePartialUpload
)
290 appendFullUploadsToUpdateQueue(1);
291 appendPartialUploadsToUpdateQueue(1);
294 EXPECT_EQ(1, m_numTotalFlushes
);
295 EXPECT_EQ(2, m_numTotalUploads
);
296 EXPECT_EQ(0, m_numDanglingUploads
) << "Last upload wasn't followed by a flush.";
300 // This class of tests upload a number of textures that is a multiple of the flush period.
301 const int fullUploadFlushMultipler
= 7;
302 const int fullCount
= fullUploadFlushMultipler
* kFlushPeriodFull
;
304 const int partialUploadFlushMultipler
= 11;
305 const int partialCount
= partialUploadFlushMultipler
* kFlushPeriodPartial
;
307 TEST_F(ResourceUpdateControllerTest
, ManyFullUploads
)
309 appendFullUploadsToUpdateQueue(fullCount
);
310 appendPartialUploadsToUpdateQueue(0);
313 EXPECT_EQ(fullUploadFlushMultipler
, m_numTotalFlushes
);
314 EXPECT_EQ(fullCount
, m_numTotalUploads
);
315 EXPECT_EQ(0, m_numDanglingUploads
) << "Last upload wasn't followed by a flush.";
318 TEST_F(ResourceUpdateControllerTest
, ManyPartialUploads
)
320 appendFullUploadsToUpdateQueue(0);
321 appendPartialUploadsToUpdateQueue(partialCount
);
324 EXPECT_EQ(partialUploadFlushMultipler
, m_numTotalFlushes
);
325 EXPECT_EQ(partialCount
, m_numTotalUploads
);
326 EXPECT_EQ(0, m_numDanglingUploads
) << "Last upload wasn't followed by a flush.";
329 TEST_F(ResourceUpdateControllerTest
, ManyFullManyPartialUploads
)
331 appendFullUploadsToUpdateQueue(fullCount
);
332 appendPartialUploadsToUpdateQueue(partialCount
);
335 EXPECT_EQ(fullUploadFlushMultipler
+ partialUploadFlushMultipler
, m_numTotalFlushes
);
336 EXPECT_EQ(fullCount
+ partialCount
, m_numTotalUploads
);
337 EXPECT_EQ(0, m_numDanglingUploads
) << "Last upload wasn't followed by a flush.";
340 class FakeResourceUpdateControllerClient
: public cc::ResourceUpdateControllerClient
{
342 FakeResourceUpdateControllerClient() { reset(); }
343 void reset() { m_readyToFinalizeCalled
= false; }
344 bool readyToFinalizeCalled() const { return m_readyToFinalizeCalled
; }
346 virtual void readyToFinalizeTextureUpdates() OVERRIDE
{ m_readyToFinalizeCalled
= true; }
349 bool m_readyToFinalizeCalled
;
352 class FakeResourceUpdateController
: public cc::ResourceUpdateController
{
354 static scoped_ptr
<FakeResourceUpdateController
> create(cc::ResourceUpdateControllerClient
* client
, cc::Thread
* thread
, scoped_ptr
<ResourceUpdateQueue
> queue
, ResourceProvider
* resourceProvider
)
356 return make_scoped_ptr(new FakeResourceUpdateController(client
, thread
, queue
.Pass(), resourceProvider
));
359 void setNow(base::TimeTicks time
) { m_now
= time
; }
360 virtual base::TimeTicks
now() const OVERRIDE
{ return m_now
; }
361 void setUpdateMoreTexturesTime(base::TimeDelta time
) { m_updateMoreTexturesTime
= time
; }
362 virtual base::TimeDelta
updateMoreTexturesTime() const OVERRIDE
{ return m_updateMoreTexturesTime
; }
363 void setUpdateMoreTexturesSize(size_t size
) { m_updateMoreTexturesSize
= size
; }
364 virtual size_t updateMoreTexturesSize() const OVERRIDE
{ return m_updateMoreTexturesSize
; }
367 FakeResourceUpdateController(cc::ResourceUpdateControllerClient
* client
, cc::Thread
* thread
, scoped_ptr
<ResourceUpdateQueue
> queue
, ResourceProvider
* resourceProvider
)
368 : cc::ResourceUpdateController(client
, thread
, queue
.Pass(), resourceProvider
, false)
369 , m_updateMoreTexturesSize(0) { }
371 base::TimeTicks m_now
;
372 base::TimeDelta m_updateMoreTexturesTime
;
373 size_t m_updateMoreTexturesSize
;
376 static void runPendingTask(FakeThread
* thread
, FakeResourceUpdateController
* controller
)
378 EXPECT_TRUE(thread
->hasPendingTask());
379 controller
->setNow(controller
->now() + base::TimeDelta::FromMilliseconds(thread
->pendingDelayMs()));
380 thread
->runPendingTask();
383 TEST_F(ResourceUpdateControllerTest
, UpdateMoreTextures
)
385 FakeResourceUpdateControllerClient client
;
388 setMaxUploadCountPerUpdate(1);
389 appendFullUploadsToUpdateQueue(3);
390 appendPartialUploadsToUpdateQueue(0);
392 DebugScopedSetImplThreadAndMainThreadBlocked
393 implThreadAndMainThreadBlocked(&m_proxy
);
394 scoped_ptr
<FakeResourceUpdateController
> controller(FakeResourceUpdateController::create(&client
, &thread
, m_queue
.Pass(), m_resourceProvider
.get()));
397 controller
->now() + base::TimeDelta::FromMilliseconds(1));
398 controller
->setUpdateMoreTexturesTime(
399 base::TimeDelta::FromMilliseconds(100));
400 controller
->setUpdateMoreTexturesSize(1);
401 // Not enough time for any updates.
402 controller
->performMoreUpdates(
403 controller
->now() + base::TimeDelta::FromMilliseconds(90));
404 EXPECT_FALSE(thread
.hasPendingTask());
406 controller
->setUpdateMoreTexturesTime(
407 base::TimeDelta::FromMilliseconds(100));
408 controller
->setUpdateMoreTexturesSize(1);
409 // Only enough time for 1 update.
410 controller
->performMoreUpdates(
411 controller
->now() + base::TimeDelta::FromMilliseconds(120));
412 EXPECT_FALSE(thread
.hasPendingTask());
413 EXPECT_EQ(1, m_numTotalUploads
);
415 // Complete one upload.
416 makeQueryResultAvailable();
418 controller
->setUpdateMoreTexturesTime(
419 base::TimeDelta::FromMilliseconds(100));
420 controller
->setUpdateMoreTexturesSize(1);
421 // Enough time for 2 updates.
422 controller
->performMoreUpdates(
423 controller
->now() + base::TimeDelta::FromMilliseconds(220));
424 runPendingTask(&thread
, controller
.get());
425 EXPECT_FALSE(thread
.hasPendingTask());
426 EXPECT_TRUE(client
.readyToFinalizeCalled());
427 EXPECT_EQ(3, m_numTotalUploads
);
430 TEST_F(ResourceUpdateControllerTest
, NoMoreUpdates
)
432 FakeResourceUpdateControllerClient client
;
435 setMaxUploadCountPerUpdate(1);
436 appendFullUploadsToUpdateQueue(2);
437 appendPartialUploadsToUpdateQueue(0);
439 DebugScopedSetImplThreadAndMainThreadBlocked
440 implThreadAndMainThreadBlocked(&m_proxy
);
441 scoped_ptr
<FakeResourceUpdateController
> controller(FakeResourceUpdateController::create(&client
, &thread
, m_queue
.Pass(), m_resourceProvider
.get()));
444 controller
->now() + base::TimeDelta::FromMilliseconds(1));
445 controller
->setUpdateMoreTexturesTime(
446 base::TimeDelta::FromMilliseconds(100));
447 controller
->setUpdateMoreTexturesSize(1);
448 // Enough time for 3 updates but only 2 necessary.
449 controller
->performMoreUpdates(
450 controller
->now() + base::TimeDelta::FromMilliseconds(310));
451 runPendingTask(&thread
, controller
.get());
452 EXPECT_FALSE(thread
.hasPendingTask());
453 EXPECT_TRUE(client
.readyToFinalizeCalled());
454 EXPECT_EQ(2, m_numTotalUploads
);
456 controller
->setUpdateMoreTexturesTime(
457 base::TimeDelta::FromMilliseconds(100));
458 controller
->setUpdateMoreTexturesSize(1);
459 // Enough time for updates but no more updates left.
460 controller
->performMoreUpdates(
461 controller
->now() + base::TimeDelta::FromMilliseconds(310));
462 // 0-delay task used to call readyToFinalizeTextureUpdates().
463 runPendingTask(&thread
, controller
.get());
464 EXPECT_FALSE(thread
.hasPendingTask());
465 EXPECT_TRUE(client
.readyToFinalizeCalled());
466 EXPECT_EQ(2, m_numTotalUploads
);
469 TEST_F(ResourceUpdateControllerTest
, UpdatesCompleteInFiniteTime
)
471 FakeResourceUpdateControllerClient client
;
474 setMaxUploadCountPerUpdate(1);
475 appendFullUploadsToUpdateQueue(2);
476 appendPartialUploadsToUpdateQueue(0);
478 DebugScopedSetImplThreadAndMainThreadBlocked
479 implThreadAndMainThreadBlocked(&m_proxy
);
480 scoped_ptr
<FakeResourceUpdateController
> controller(FakeResourceUpdateController::create(&client
, &thread
, m_queue
.Pass(), m_resourceProvider
.get()));
483 controller
->now() + base::TimeDelta::FromMilliseconds(1));
484 controller
->setUpdateMoreTexturesTime(
485 base::TimeDelta::FromMilliseconds(500));
486 controller
->setUpdateMoreTexturesSize(1);
488 for (int i
= 0; i
< 100; i
++) {
489 if (client
.readyToFinalizeCalled())
492 // Not enough time for any updates.
493 controller
->performMoreUpdates(
494 controller
->now() + base::TimeDelta::FromMilliseconds(400));
496 if (thread
.hasPendingTask())
497 runPendingTask(&thread
, controller
.get());
500 EXPECT_FALSE(thread
.hasPendingTask());
501 EXPECT_TRUE(client
.readyToFinalizeCalled());
502 EXPECT_EQ(2, m_numTotalUploads
);