[chromium] Make CCThreadProxy draw
[WebKit-https.git] / Source / WebKit / chromium / tests / CCLayerTreeHostTest.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 #if USE(THREADED_COMPOSITING)
28
29 #include "cc/CCLayerTreeHost.h"
30
31 #include "CCThreadImpl.h"
32 #include "GraphicsContext3DPrivate.h"
33 #include "LayerChromium.h"
34 #include "LayerPainterChromium.h"
35 #include "MockWebGraphicsContext3D.h"
36 #include "TextureManager.h"
37 #include "cc/CCLayerTreeHostImpl.h"
38 #include "cc/CCMainThreadTask.h"
39 #include "cc/CCThreadTask.h"
40 #include <gtest/gtest.h>
41 #include <webkit/support/webkit_support.h>
42 #include <wtf/MainThread.h>
43 #include <wtf/PassRefPtr.h>
44 #include <wtf/Vector.h>
45
46 using namespace WebCore;
47 using namespace WebKit;
48 using namespace WTF;
49
50 namespace {
51
52 // Used by test stubs to notify the test when something interesting happens.
53 class TestHooks {
54 public:
55     virtual void beginCommitOnCCThread(CCLayerTreeHostImpl*) { }
56     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*) { }
57     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl*) { }
58 };
59
60 // Adapts CCLayerTreeHostImpl for test. Runs real code, then invokes test hooks.
61 class MockLayerTreeHostImpl : public CCLayerTreeHostImpl {
62 public:
63     static PassOwnPtr<MockLayerTreeHostImpl> create(TestHooks* testHooks, const CCSettings& settings)
64     {
65         return adoptPtr(new MockLayerTreeHostImpl(testHooks, settings));
66     }
67
68     virtual void beginCommit()
69     {
70         CCLayerTreeHostImpl::beginCommit();
71         m_testHooks->beginCommitOnCCThread(this);
72     }
73
74     virtual void commitComplete()
75     {
76         CCLayerTreeHostImpl::commitComplete();
77         m_testHooks->commitCompleteOnCCThread(this);
78     }
79
80     virtual void drawLayers()
81     {
82         CCLayerTreeHostImpl::drawLayers();
83         m_testHooks->drawLayersOnCCThread(this);
84     }
85
86 private:
87     MockLayerTreeHostImpl(TestHooks* testHooks, const CCSettings& settings)
88         : CCLayerTreeHostImpl(settings)
89         , m_testHooks(testHooks)
90     {
91     }
92
93     TestHooks* m_testHooks;
94 };
95
96 // Adapts CCLayerTreeHost for test. Injects MockLayerTreeHostImpl.
97 class MockLayerTreeHost : public CCLayerTreeHost {
98 public:
99     static PassRefPtr<MockLayerTreeHost> create(TestHooks* testHooks, CCLayerTreeHostClient* client, PassRefPtr<LayerChromium> rootLayer, const CCSettings& settings)
100     {
101         return adoptRef(new MockLayerTreeHost(testHooks, client, rootLayer, settings));
102     }
103
104     virtual PassOwnPtr<CCLayerTreeHostImpl> createLayerTreeHostImpl()
105     {
106         return MockLayerTreeHostImpl::create(m_testHooks, settings());
107     }
108
109 private:
110     MockLayerTreeHost(TestHooks* testHooks, CCLayerTreeHostClient* client, PassRefPtr<LayerChromium> rootLayer, const CCSettings& settings)
111         : CCLayerTreeHost(client, rootLayer, settings)
112         , m_testHooks(testHooks)
113     {
114         bool success = initialize();
115         ASSERT(success);
116     }
117
118     TestHooks* m_testHooks;
119 };
120
121 // Test stub for WebGraphicsContext3D. Returns canned values needed for compositor initialization.
122 class CompositorMockWebGraphicsContext3D : public MockWebGraphicsContext3D {
123 public:
124     static PassOwnPtr<CompositorMockWebGraphicsContext3D> create()
125     {
126         return adoptPtr(new CompositorMockWebGraphicsContext3D());
127     }
128
129     virtual bool makeContextCurrent() { return true; }
130     virtual WebGLId createProgram() { return 1; }
131     virtual WebGLId createShader(WGC3Denum) { return 1; }
132     virtual void getShaderiv(WebGLId, WGC3Denum, WGC3Dint* value) { *value = 1; }
133     virtual void getProgramiv(WebGLId, WGC3Denum, WGC3Dint* value) { *value = 1; }
134
135 private:
136     CompositorMockWebGraphicsContext3D() { }
137 };
138
139 // Implementation of CCLayerTreeHost callback interface.
140 class MockLayerTreeHostClient : public CCLayerTreeHostClient {
141 public:
142     static PassOwnPtr<MockLayerTreeHostClient> create(TestHooks* testHooks)
143     {
144         return adoptPtr(new MockLayerTreeHostClient(testHooks));
145     }
146
147     virtual void animateAndLayout(double frameBeginTime)
148     {
149     }
150
151     virtual PassOwnPtr<CCThread> createCompositorThread()
152     {
153         return CCThreadImpl::create();
154     }
155
156     virtual PassRefPtr<GraphicsContext3D> createLayerTreeHostContext3D()
157     {
158         OwnPtr<WebGraphicsContext3D> mock = CompositorMockWebGraphicsContext3D::create();
159         GraphicsContext3D::Attributes attrs;
160         RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(mock.release(), attrs, 0, GraphicsContext3D::RenderDirectlyToHostWindow, GraphicsContext3DPrivate::ForUseOnAnotherThread);
161         return context;
162     }
163
164     virtual PassOwnPtr<LayerPainterChromium> createRootLayerPainter()
165     {
166         return nullptr;
167     }
168
169     virtual void didRecreateGraphicsContext(bool)
170     {
171     }
172
173 #if !USE(THREADED_COMPOSITING)
174     virtual void scheduleComposite() { }
175 #endif
176
177 private:
178     explicit MockLayerTreeHostClient(TestHooks* testHooks) : m_testHooks(testHooks) { }
179
180     TestHooks* m_testHooks;
181 };
182
183 // The CCLayerTreeHostTest runs with the main loop running. It instantiates a single MockLayerTreeHost and associated
184 // MockLayerTreeHostImpl/MockLayerTreeHostClient.
185 //
186 // beginTest() is called once the main message loop is running and the layer tree host is initialized.
187 //
188 // Key stages of the drawing loop, e.g. drawing or commiting, redirect to CCLayerTreeHostTest methods of similar names.
189 // To track the commit process, override these functions.
190 //
191 // The test continues until someone calls endTest. endTest can be called on any thread, but be aware that
192 // ending the test is an asynchronous process.
193 class CCLayerTreeHostTest : public testing::TestWithParam<CCSettings>, TestHooks {
194 public:
195     virtual void SetUp()
196     {
197     }
198     virtual void afterTest() = 0;
199     virtual void beginTest() = 0;
200
201     void endTest();
202
203     void postSetNeedsCommitToMainThread()
204     {
205         callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsCommit, this);
206     }
207
208     void postSetNeedsRedrawToMainThread()
209     {
210         callOnMainThread(CCLayerTreeHostTest::dispatchSetNeedsRedraw, this);
211     }
212
213 protected:
214     CCLayerTreeHostTest()
215         : m_beginning(false)
216         , m_endWhenBeginReturns(false)
217         , m_running(false)
218         , m_timedOut(false) { }
219
220     void doBeginTest();
221
222     static void onBeginTest(void* self)
223     {
224         static_cast<CCLayerTreeHostTest*>(self)->doBeginTest();
225     }
226
227     static void onEndTest(void* self)
228     {
229         ASSERT(isMainThread());
230         webkit_support::QuitMessageLoop();
231         CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
232         ASSERT(test);
233         test->m_layerTreeHost.clear();
234     }
235
236     static void dispatchSetNeedsCommit(void* self)
237     {
238       ASSERT(isMainThread());
239       CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
240       ASSERT(test);
241       if (test->m_layerTreeHost)
242           test->m_layerTreeHost->setNeedsCommitAndRedraw();
243     }
244
245     static void dispatchSetNeedsRedraw(void* self)
246     {
247       ASSERT(isMainThread());
248       CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
249       ASSERT(test);
250       if (test->m_layerTreeHost)
251           test->m_layerTreeHost->setNeedsRedraw();
252     }
253
254     void runTest()
255     {
256         webkit_support::PostDelayedTask(CCLayerTreeHostTest::onBeginTest, static_cast<void*>(this), 0);
257         webkit_support::PostDelayedTask(CCLayerTreeHostTest::testTimeout, static_cast<void*>(this), 5000);
258         webkit_support::RunMessageLoop();
259         m_running = false;
260         bool timedOut = m_timedOut; // Save whether we're timed out in case RunAllPendingMessages has the timeout.
261         webkit_support::RunAllPendingMessages();
262         ASSERT(!m_layerTreeHost.get());
263         m_client.clear();
264         if (timedOut) {
265             FAIL() << "Test timed out";
266             return;
267         }
268         afterTest();
269     }
270
271     static void testTimeout(void* self)
272     {
273         CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
274         if (!test->m_running)
275             return;
276         test->m_timedOut = true;
277         test->endTest();
278     }
279
280     OwnPtr<MockLayerTreeHostClient> m_client;
281     RefPtr<CCLayerTreeHost> m_layerTreeHost;
282
283 private:
284     bool m_beginning;
285     bool m_endWhenBeginReturns;
286     bool m_running;
287     bool m_timedOut;
288 };
289
290 void CCLayerTreeHostTest::doBeginTest()
291 {
292     ASSERT(isMainThread());
293     ASSERT(!m_running);
294     m_running = true;
295     m_client = MockLayerTreeHostClient::create(this);
296
297     RefPtr<LayerChromium> rootLayer;
298     m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer, GetParam());
299     ASSERT(m_layerTreeHost);
300
301     m_beginning = true;
302     beginTest();
303     m_beginning = false;
304     if (m_endWhenBeginReturns)
305         onEndTest(static_cast<void*>(this));
306 }
307 INSTANTIATE_TEST_CASE_P(
308     ProxyTests, CCLayerTreeHostTest,
309     testing::Values(
310         CCSettings(false, false, false, false, false),
311         CCSettings(false, false, true, false, false)));
312
313 void CCLayerTreeHostTest::endTest()
314 {
315     // If we are called from the CCThread, re-call endTest on the main thread.
316     if (!isMainThread())
317         CCMainThread::postTask(createMainThreadTask(this, &CCLayerTreeHostTest::endTest));
318     else {
319         // For the case where we endTest during beginTest(), set a flag to indicate that
320         // the test should end the second beginTest regains control.
321         if (m_beginning)
322             m_endWhenBeginReturns = true;
323         else
324             onEndTest(static_cast<void*>(this));
325     }
326 }
327
328 // Shortlived layerTreeHosts shouldn't die.
329 class CCLayerTreeHostTestShortlived1 : public CCLayerTreeHostTest {
330 public:
331     CCLayerTreeHostTestShortlived1() { }
332
333     virtual void beginTest()
334     {
335         endTest();
336     }
337
338     virtual void afterTest()
339     {
340     }
341 };
342 TEST_F(CCLayerTreeHostTestShortlived1, run)
343 {
344     runTest();
345 }
346
347 // Shortlived layerTreeHosts shouldn't die with a commit in flight.
348 class CCLayerTreeHostTestShortlived2 : public CCLayerTreeHostTest {
349 public:
350     CCLayerTreeHostTestShortlived2() { }
351
352     virtual void beginTest()
353     {
354         postSetNeedsCommitToMainThread();
355         endTest();
356     }
357
358     virtual void afterTest()
359     {
360     }
361 };
362 TEST_F(CCLayerTreeHostTestShortlived2, run)
363 {
364     runTest();
365 }
366
367 // Shortlived layerTreeHosts shouldn't die with a redraw in flight.
368 class CCLayerTreeHostTestShortlived3 : public CCLayerTreeHostTest {
369 public:
370     CCLayerTreeHostTestShortlived3() { }
371
372     virtual void beginTest()
373     {
374         postSetNeedsRedrawToMainThread();
375         endTest();
376     }
377
378     virtual void afterTest()
379     {
380     }
381 };
382 TEST_F(CCLayerTreeHostTestShortlived3, run)
383 {
384     runTest();
385 }
386
387 // Constantly redrawing layerTreeHosts shouldn't die when they commit
388 class CCLayerTreeHostTestCommitingWithContinuousRedraw : public CCLayerTreeHostTest {
389 public:
390     CCLayerTreeHostTestCommitingWithContinuousRedraw()
391         : m_numCompleteCommits(0)
392         , m_numDraws(0)
393     {
394     }
395
396     virtual void beginTest()
397     {
398         postSetNeedsCommitToMainThread();
399         endTest();
400     }
401
402     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*)
403     {
404         m_numCompleteCommits++;
405         if (m_numCompleteCommits == 2)
406             endTest();
407     }
408
409     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl*)
410     {
411         if (m_numDraws == 1)
412           postSetNeedsCommitToMainThread();
413         m_numDraws++;
414         postSetNeedsRedrawToMainThread();
415     }
416
417     virtual void afterTest()
418     {
419     }
420
421 private:
422     int m_numCompleteCommits;
423     int m_numDraws;
424 };
425 TEST_F(CCLayerTreeHostTestCommitingWithContinuousRedraw, run)
426 {
427     runTest();
428 }
429
430 // Two setNeedsCommits in a row should lead to at least 1 commit and at least 1
431 // draw with frame 0.
432 class CCLayerTreeHostTestSetNeedsCommit1 : public CCLayerTreeHostTest {
433 public:
434     CCLayerTreeHostTestSetNeedsCommit1()
435         : m_numCommits(0)
436         , m_numDraws(0)
437     {
438     }
439
440     virtual void beginTest()
441     {
442         postSetNeedsCommitToMainThread();
443         postSetNeedsCommitToMainThread();
444     }
445
446     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
447     {
448         m_numDraws++;
449         if (!impl->sourceFrameNumber())
450             endTest();
451     }
452
453     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*)
454     {
455         m_numCommits++;
456     }
457
458     virtual void afterTest()
459     {
460         EXPECT_GE(1, m_numCommits);
461         EXPECT_GE(1, m_numDraws);
462     }
463
464 private:
465     int m_numCommits;
466     int m_numDraws;
467 };
468 TEST_F(CCLayerTreeHostTestSetNeedsCommit1, run)
469 {
470     runTest();
471 }
472
473 // A setNeedsCommit should lead to 1 commit. Issuing a second commit after that
474 // first committed frame draws should lead to another commit.
475 class CCLayerTreeHostTestSetNeedsCommit2 : public CCLayerTreeHostTest {
476 public:
477     CCLayerTreeHostTestSetNeedsCommit2()
478         : m_numCommits(0)
479         , m_numDraws(0)
480     {
481     }
482
483     virtual void beginTest()
484     {
485         postSetNeedsCommitToMainThread();
486     }
487
488     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
489     {
490         if (!impl->sourceFrameNumber())
491             postSetNeedsCommitToMainThread();
492         else if (impl->sourceFrameNumber() == 1)
493             endTest();
494     }
495
496     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*)
497     {
498         m_numCommits++;
499     }
500
501     virtual void afterTest()
502     {
503         EXPECT_EQ(2, m_numCommits);
504         EXPECT_GE(2, m_numDraws);
505     }
506
507 private:
508     int m_numCommits;
509     int m_numDraws;
510 };
511 TEST_F(CCLayerTreeHostTestSetNeedsCommit2, run)
512 {
513     runTest();
514 }
515
516 // 1 setNeedsRedraw after the first commit has completed should lead to 1
517 // additional draw.
518 class CCLayerTreeHostTestSetNeedsRedraw : public CCLayerTreeHostTest {
519 public:
520     CCLayerTreeHostTestSetNeedsRedraw()
521         : m_numCommits(0)
522         , m_numDraws(0)
523     {
524     }
525
526     virtual void beginTest()
527     {
528         postSetNeedsCommitToMainThread();
529     }
530
531     virtual void drawLayersOnCCThread(CCLayerTreeHostImpl* impl)
532     {
533         EXPECT_EQ(0, impl->sourceFrameNumber());
534         if (!m_numDraws)
535             postSetNeedsRedrawToMainThread(); // Redraw again to verify that the second redraw doesn't commit.
536         else
537             endTest();
538         m_numDraws++;
539     }
540
541     virtual void commitCompleteOnCCThread(CCLayerTreeHostImpl*)
542     {
543         m_numCommits++;
544     }
545
546     virtual void afterTest()
547     {
548         EXPECT_GE(2, m_numDraws);
549         EXPECT_EQ(1, m_numCommits);
550     }
551
552 private:
553     int m_numCommits;
554     int m_numDraws;
555 };
556 TEST_F(CCLayerTreeHostTestSetNeedsRedraw, run)
557 {
558     CCSettings setings;
559     runTest();
560 }
561
562 } // namespace
563
564 #endif