9c3837eeac6dcaa61bbc7d2ee23e86d226ba7e28
[WebKit-https.git] / Source / WebKit / chromium / tests / CCThreadedTest.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "CCThreadedTest.h"
28
29 #include "AnimationIdVendor.h"
30 #include "CCAnimationTestCommon.h"
31 #include "CCOcclusionTrackerTestCommon.h"
32 #include "CCTiledLayerTestCommon.h"
33 #include "ContentLayerChromium.h"
34 #include "FakeWebGraphicsContext3D.h"
35 #include "GraphicsContext3DPrivate.h"
36 #include "LayerChromium.h"
37 #include "WebCompositor.h"
38 #include "WebKit.h"
39 #include "cc/CCActiveAnimation.h"
40 #include "cc/CCLayerAnimationController.h"
41 #include "cc/CCLayerImpl.h"
42 #include "cc/CCLayerTreeHostImpl.h"
43 #include "cc/CCScopedThreadProxy.h"
44 #include "cc/CCSingleThreadProxy.h"
45 #include "cc/CCTextureUpdateQueue.h"
46 #include "cc/CCThreadTask.h"
47 #include "cc/CCTimingFunction.h"
48 #include "platform/WebThread.h"
49 #include <gmock/gmock.h>
50 #include <public/Platform.h>
51 #include <public/WebFilterOperation.h>
52 #include <public/WebFilterOperations.h>
53 #include <wtf/Locker.h>
54 #include <wtf/MainThread.h>
55 #include <wtf/PassRefPtr.h>
56 #include <wtf/ThreadingPrimitives.h>
57 #include <wtf/Vector.h>
58
59 using namespace WebCore;
60 using namespace WebKit;
61 using namespace WTF;
62
63 namespace WebKitTests {
64
65 PassOwnPtr<CompositorFakeWebGraphicsContext3DWithTextureTracking> CompositorFakeWebGraphicsContext3DWithTextureTracking::create(Attributes attrs)
66 {
67     return adoptPtr(new CompositorFakeWebGraphicsContext3DWithTextureTracking(attrs));
68 }
69
70 WebGLId CompositorFakeWebGraphicsContext3DWithTextureTracking::createTexture()
71 {
72     WebGLId texture = m_textures.size() + 1;
73     m_textures.append(texture);
74     return texture;
75 }
76
77 void CompositorFakeWebGraphicsContext3DWithTextureTracking::deleteTexture(WebGLId texture)
78 {
79     for (size_t i = 0; i < m_textures.size(); i++) {
80         if (m_textures[i] == texture) {
81             m_textures.remove(i);
82             break;
83         }
84     }
85 }
86
87 void CompositorFakeWebGraphicsContext3DWithTextureTracking::bindTexture(WGC3Denum /* target */, WebGLId texture)
88 {
89     m_usedTextures.add(texture);
90 }
91
92 int CompositorFakeWebGraphicsContext3DWithTextureTracking::numTextures() const { return static_cast<int>(m_textures.size()); }
93 int CompositorFakeWebGraphicsContext3DWithTextureTracking::texture(int i) const { return m_textures[i]; }
94 void CompositorFakeWebGraphicsContext3DWithTextureTracking::resetTextures() { m_textures.clear(); }
95
96 int CompositorFakeWebGraphicsContext3DWithTextureTracking::numUsedTextures() const { return static_cast<int>(m_usedTextures.size()); }
97 bool CompositorFakeWebGraphicsContext3DWithTextureTracking::usedTexture(int texture) const { return m_usedTextures.find(texture) != m_usedTextures.end(); }
98 void CompositorFakeWebGraphicsContext3DWithTextureTracking::resetUsedTextures() { m_usedTextures.clear(); }
99
100 CompositorFakeWebGraphicsContext3DWithTextureTracking::CompositorFakeWebGraphicsContext3DWithTextureTracking(Attributes attrs) : CompositorFakeWebGraphicsContext3D(attrs)
101 {
102 }
103
104 PassOwnPtr<WebGraphicsContext3D> TestHooks::createContext()
105 {
106     return CompositorFakeWebGraphicsContext3DWithTextureTracking::create(WebGraphicsContext3D::Attributes());
107 }
108
109 PassOwnPtr<MockLayerTreeHostImpl> MockLayerTreeHostImpl::create(TestHooks* testHooks, const CCLayerTreeSettings& settings, CCLayerTreeHostImplClient* client)
110 {
111     return adoptPtr(new MockLayerTreeHostImpl(testHooks, settings, client));
112 }
113
114 void MockLayerTreeHostImpl::beginCommit()
115 {
116     CCLayerTreeHostImpl::beginCommit();
117     m_testHooks->beginCommitOnCCThread(this);
118 }
119
120 void MockLayerTreeHostImpl::commitComplete()
121 {
122     CCLayerTreeHostImpl::commitComplete();
123     m_testHooks->commitCompleteOnCCThread(this);
124 }
125
126 bool MockLayerTreeHostImpl::prepareToDraw(FrameData& frame)
127 {
128     bool result = CCLayerTreeHostImpl::prepareToDraw(frame);
129     if (!m_testHooks->prepareToDrawOnCCThread(this))
130         result = false;
131     return result;
132 }
133
134 void MockLayerTreeHostImpl::drawLayers(const FrameData& frame)
135 {
136     CCLayerTreeHostImpl::drawLayers(frame);
137     m_testHooks->drawLayersOnCCThread(this);
138 }
139
140 void MockLayerTreeHostImpl::animateLayers(double monotonicTime, double wallClockTime)
141 {
142     m_testHooks->willAnimateLayers(this, monotonicTime);
143     CCLayerTreeHostImpl::animateLayers(monotonicTime, wallClockTime);
144     m_testHooks->animateLayers(this, monotonicTime);
145 }
146
147 double MockLayerTreeHostImpl::lowFrequencyAnimationInterval() const
148 {
149     return 1.0 / 60;
150 }
151
152 MockLayerTreeHostImpl::MockLayerTreeHostImpl(TestHooks* testHooks, const CCLayerTreeSettings& settings, CCLayerTreeHostImplClient* client)
153     : CCLayerTreeHostImpl(settings, client)
154     , m_testHooks(testHooks)
155 {
156 }
157
158 // Adapts CCLayerTreeHost for test. Injects MockLayerTreeHostImpl.
159 class MockLayerTreeHost : public WebCore::CCLayerTreeHost {
160 public:
161     static PassOwnPtr<MockLayerTreeHost> create(TestHooks* testHooks, WebCore::CCLayerTreeHostClient* client, PassRefPtr<WebCore::LayerChromium> rootLayer, const WebCore::CCLayerTreeSettings& settings)
162     {
163         OwnPtr<MockLayerTreeHost> layerTreeHost(adoptPtr(new MockLayerTreeHost(testHooks, client, settings)));
164         bool success = layerTreeHost->initialize();
165         EXPECT_TRUE(success);
166         layerTreeHost->setRootLayer(rootLayer);
167
168         // LayerTreeHostImpl won't draw if it has 1x1 viewport.
169         layerTreeHost->setViewportSize(IntSize(1, 1), IntSize(1, 1));
170
171         layerTreeHost->rootLayer()->setLayerAnimationDelegate(testHooks);
172
173         return layerTreeHost.release();
174     }
175
176     virtual PassOwnPtr<WebCore::CCLayerTreeHostImpl> createLayerTreeHostImpl(WebCore::CCLayerTreeHostImplClient* client)
177     {
178         return MockLayerTreeHostImpl::create(m_testHooks, settings(), client);
179     }
180
181     virtual void didAddAnimation() OVERRIDE
182     {
183         CCLayerTreeHost::didAddAnimation();
184         m_testHooks->didAddAnimation();
185     }
186
187 private:
188     MockLayerTreeHost(TestHooks* testHooks, WebCore::CCLayerTreeHostClient* client, const WebCore::CCLayerTreeSettings& settings)
189         : CCLayerTreeHost(client, settings)
190         , m_testHooks(testHooks)
191     {
192     }
193
194     TestHooks* m_testHooks;
195 };
196
197 // Implementation of CCLayerTreeHost callback interface.
198 class MockLayerTreeHostClient : public MockCCLayerTreeHostClient {
199 public:
200     static PassOwnPtr<MockLayerTreeHostClient> create(TestHooks* testHooks)
201     {
202         return adoptPtr(new MockLayerTreeHostClient(testHooks));
203     }
204
205     virtual void willBeginFrame() OVERRIDE
206     {
207     }
208
209     virtual void didBeginFrame() OVERRIDE
210     {
211     }
212
213     virtual void updateAnimations(double monotonicTime) OVERRIDE
214     {
215         m_testHooks->updateAnimations(monotonicTime);
216     }
217
218     virtual void layout() OVERRIDE
219     {
220         m_testHooks->layout();
221     }
222
223     virtual void applyScrollAndScale(const IntSize& scrollDelta, float scale) OVERRIDE
224     {
225         m_testHooks->applyScrollAndScale(scrollDelta, scale);
226     }
227
228     virtual PassOwnPtr<WebGraphicsContext3D> createContext3D() OVERRIDE
229     {
230         return m_testHooks->createContext();
231     }
232
233     virtual void willCommit() OVERRIDE
234     {
235     }
236
237     virtual void didCommit() OVERRIDE
238     {
239         m_testHooks->didCommit();
240     }
241
242     virtual void didCommitAndDrawFrame() OVERRIDE
243     {
244         m_testHooks->didCommitAndDrawFrame();
245     }
246
247     virtual void didCompleteSwapBuffers() OVERRIDE
248     {
249     }
250
251     virtual void didRecreateContext(bool succeeded) OVERRIDE
252     {
253         m_testHooks->didRecreateContext(succeeded);
254     }
255
256     virtual void scheduleComposite() OVERRIDE
257     {
258         m_testHooks->scheduleComposite();
259     }
260
261 private:
262     explicit MockLayerTreeHostClient(TestHooks* testHooks) : m_testHooks(testHooks) { }
263
264     TestHooks* m_testHooks;
265 };
266
267 class TimeoutTask : public WebThread::Task {
268 public:
269     explicit TimeoutTask(CCThreadedTest* test)
270         : m_test(test)
271     {
272     }
273
274     void clearTest()
275     {
276         m_test = 0;
277     }
278
279     virtual ~TimeoutTask()
280     {
281         if (m_test)
282             m_test->clearTimeout();
283     }
284
285     virtual void run()
286     {
287         if (m_test)
288             m_test->timeout();
289     }
290
291 private:
292     CCThreadedTest* m_test;
293 };
294
295 class BeginTask : public WebThread::Task {
296 public:
297     explicit BeginTask(CCThreadedTest* test)
298         : m_test(test)
299     {
300     }
301
302     virtual ~BeginTask() { }
303     virtual void run()
304     {
305         m_test->doBeginTest();
306     }
307 private:
308     CCThreadedTest* m_test;
309 };
310
311 class EndTestTask : public WebThread::Task {
312 public:
313     explicit EndTestTask(CCThreadedTest* test)
314         : m_test(test)
315     {
316     }
317
318     virtual ~EndTestTask()
319     {
320         if (m_test)
321             m_test->clearEndTestTask();
322     }
323
324     void clearTest()
325     {
326         m_test = 0;
327     }
328
329     virtual void run()
330     {
331         if (m_test)
332             m_test->endTest();
333     }
334
335 private:
336     CCThreadedTest* m_test;
337 };
338
339 CCThreadedTest::CCThreadedTest()
340     : m_beginning(false)
341     , m_endWhenBeginReturns(false)
342     , m_timedOut(false)
343     , m_finished(false)
344     , m_scheduled(false)
345     , m_started(false)
346     , m_endTestTask(0)
347 { }
348
349 void CCThreadedTest::endTest()
350 {
351     m_finished = true;
352
353     // If we are called from the CCThread, re-call endTest on the main thread.
354     if (!isMainThread())
355         m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadedTest::endTest));
356     else {
357         // For the case where we endTest during beginTest(), set a flag to indicate that
358         // the test should end the second beginTest regains control.
359         if (m_beginning)
360             m_endWhenBeginReturns = true;
361         else
362             onEndTest(static_cast<void*>(this));
363     }
364 }
365
366 void CCThreadedTest::endTestAfterDelay(int delayMilliseconds)
367 {
368     // If we are called from the CCThread, re-call endTest on the main thread.
369     if (!isMainThread())
370         m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadedTest::endTestAfterDelay, delayMilliseconds));
371     else {
372         m_endTestTask = new EndTestTask(this);
373         WebKit::Platform::current()->currentThread()->postDelayedTask(m_endTestTask, delayMilliseconds);
374     }
375 }
376
377 void CCThreadedTest::postSetNeedsAnimateToMainThread()
378 {
379     callOnMainThread(CCThreadedTest::dispatchSetNeedsAnimate, this);
380 }
381
382 void CCThreadedTest::postAddAnimationToMainThread()
383 {
384     callOnMainThread(CCThreadedTest::dispatchAddAnimation, this);
385 }
386
387 void CCThreadedTest::postAddInstantAnimationToMainThread()
388 {
389     callOnMainThread(CCThreadedTest::dispatchAddInstantAnimation, this);
390 }
391
392 void CCThreadedTest::postSetNeedsCommitToMainThread()
393 {
394     callOnMainThread(CCThreadedTest::dispatchSetNeedsCommit, this);
395 }
396
397 void CCThreadedTest::postAcquireLayerTextures()
398 {
399     callOnMainThread(CCThreadedTest::dispatchAcquireLayerTextures, this);
400 }
401
402 void CCThreadedTest::postSetNeedsRedrawToMainThread()
403 {
404     callOnMainThread(CCThreadedTest::dispatchSetNeedsRedraw, this);
405 }
406
407 void CCThreadedTest::postSetNeedsAnimateAndCommitToMainThread()
408 {
409     callOnMainThread(CCThreadedTest::dispatchSetNeedsAnimateAndCommit, this);
410 }
411
412 void CCThreadedTest::postSetVisibleToMainThread(bool visible)
413 {
414     callOnMainThread(visible ? CCThreadedTest::dispatchSetVisible : CCThreadedTest::dispatchSetInvisible, this);
415 }
416
417 void CCThreadedTest::postDidAddAnimationToMainThread()
418 {
419     callOnMainThread(CCThreadedTest::dispatchDidAddAnimation, this);
420 }
421
422 void CCThreadedTest::doBeginTest()
423 {
424     ASSERT(isMainThread());
425     m_client = MockLayerTreeHostClient::create(this);
426
427     RefPtr<LayerChromium> rootLayer = LayerChromium::create();
428     m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer, m_settings);
429     ASSERT_TRUE(m_layerTreeHost);
430     rootLayer->setLayerTreeHost(m_layerTreeHost.get());
431     m_layerTreeHost->setSurfaceReady();
432
433     m_started = true;
434     m_beginning = true;
435     beginTest();
436     m_beginning = false;
437     if (m_endWhenBeginReturns)
438         onEndTest(static_cast<void*>(this));
439 }
440
441 void CCThreadedTest::timeout()
442 {
443     m_timedOut = true;
444     endTest();
445 }
446
447 void CCThreadedTest::scheduleComposite()
448 {
449     if (!m_started || m_scheduled || m_finished)
450         return;
451     m_scheduled = true;
452     callOnMainThread(&CCThreadedTest::dispatchComposite, this);
453 }
454
455 void CCThreadedTest::onEndTest(void* self)
456 {
457     ASSERT(isMainThread());
458     WebKit::Platform::current()->currentThread()->exitRunLoop();
459 }
460
461 void CCThreadedTest::dispatchSetNeedsAnimate(void* self)
462 {
463     ASSERT(isMainThread());
464
465     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
466     ASSERT(test);
467     if (test->m_finished)
468         return;
469
470     if (test->m_layerTreeHost)
471         test->m_layerTreeHost->setNeedsAnimate();
472 }
473
474 void CCThreadedTest::dispatchAddInstantAnimation(void* self)
475 {
476     ASSERT(isMainThread());
477
478     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
479     ASSERT(test);
480     if (test->m_finished)
481         return;
482
483     if (test->m_layerTreeHost && test->m_layerTreeHost->rootLayer())
484         addOpacityTransitionToLayer(*test->m_layerTreeHost->rootLayer(), 0, 0, 0.5, false);
485 }
486
487 void CCThreadedTest::dispatchAddAnimation(void* self)
488 {
489     ASSERT(isMainThread());
490
491     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
492     ASSERT(test);
493     if (test->m_finished)
494         return;
495
496     if (test->m_layerTreeHost && test->m_layerTreeHost->rootLayer())
497         addOpacityTransitionToLayer(*test->m_layerTreeHost->rootLayer(), 10, 0, 0.5, true);
498 }
499
500 void CCThreadedTest::dispatchSetNeedsAnimateAndCommit(void* self)
501 {
502     ASSERT(isMainThread());
503
504     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
505     ASSERT(test);
506     if (test->m_finished)
507         return;
508
509     if (test->m_layerTreeHost) {
510         test->m_layerTreeHost->setNeedsAnimate();
511         test->m_layerTreeHost->setNeedsCommit();
512     }
513 }
514
515 void CCThreadedTest::dispatchSetNeedsCommit(void* self)
516 {
517     ASSERT(isMainThread());
518
519     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
520     ASSERT_TRUE(test);
521     if (test->m_finished)
522         return;
523
524     if (test->m_layerTreeHost)
525         test->m_layerTreeHost->setNeedsCommit();
526 }
527
528 void CCThreadedTest::dispatchAcquireLayerTextures(void* self)
529 {
530     ASSERT(isMainThread());
531
532     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
533     ASSERT_TRUE(test);
534     if (test->m_finished)
535         return;
536
537     if (test->m_layerTreeHost)
538         test->m_layerTreeHost->acquireLayerTextures();
539 }
540
541 void CCThreadedTest::dispatchSetNeedsRedraw(void* self)
542 {
543     ASSERT(isMainThread());
544
545     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
546     ASSERT_TRUE(test);
547     if (test->m_finished)
548         return;
549
550     if (test->m_layerTreeHost)
551         test->m_layerTreeHost->setNeedsRedraw();
552 }
553
554 void CCThreadedTest::dispatchSetVisible(void* self)
555 {
556     ASSERT(isMainThread());
557
558     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
559     ASSERT(test);
560     if (test->m_finished)
561         return;
562
563     if (test->m_layerTreeHost)
564         test->m_layerTreeHost->setVisible(true);
565 }
566
567 void CCThreadedTest::dispatchSetInvisible(void* self)
568 {
569     ASSERT(isMainThread());
570
571     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
572     ASSERT(test);
573     if (test->m_finished)
574         return;
575
576     if (test->m_layerTreeHost)
577         test->m_layerTreeHost->setVisible(false);
578 }
579
580 void CCThreadedTest::dispatchComposite(void* self)
581 {
582     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
583     ASSERT(isMainThread());
584     ASSERT(test);
585     test->m_scheduled = false;
586     if (test->m_layerTreeHost && !test->m_finished)
587         test->m_layerTreeHost->composite();
588 }
589
590 void CCThreadedTest::dispatchDidAddAnimation(void* self)
591 {
592     ASSERT(isMainThread());
593
594     CCThreadedTest* test = static_cast<CCThreadedTest*>(self);
595     ASSERT(test);
596     if (test->m_finished)
597         return;
598
599     if (test->m_layerTreeHost)
600         test->m_layerTreeHost->didAddAnimation();
601 }
602
603 void CCThreadedTest::runTest(bool threaded)
604 {
605     // For these tests, we will enable threaded animations.
606     WebCompositor::setAcceleratedAnimationEnabled(true);
607
608     if (threaded) {
609         m_webThread = adoptPtr(WebKit::Platform::current()->createThread("CCThreadedTest"));
610         WebCompositor::initialize(m_webThread.get());
611     } else
612         WebCompositor::initialize(0);
613
614     ASSERT(CCProxy::isMainThread());
615     m_mainThreadProxy = CCScopedThreadProxy::create(CCProxy::mainThread());
616
617     m_beginTask = new BeginTask(this);
618     WebKit::Platform::current()->currentThread()->postDelayedTask(m_beginTask, 0); // postDelayedTask takes ownership of the task
619     m_timeoutTask = new TimeoutTask(this);
620     WebKit::Platform::current()->currentThread()->postDelayedTask(m_timeoutTask, 5000);
621     WebKit::Platform::current()->currentThread()->enterRunLoop();
622
623     if (m_layerTreeHost && m_layerTreeHost->rootLayer())
624         m_layerTreeHost->rootLayer()->setLayerTreeHost(0);
625     m_layerTreeHost.clear();
626
627     if (m_timeoutTask)
628         m_timeoutTask->clearTest();
629
630     if (m_endTestTask)
631         m_endTestTask->clearTest();
632
633     ASSERT_FALSE(m_layerTreeHost.get());
634     m_client.clear();
635     if (m_timedOut) {
636         FAIL() << "Test timed out";
637         WebCompositor::shutdown();
638         return;
639     }
640     afterTest();
641     WebCompositor::shutdown();
642 }
643
644 } // namespace WebKitTests