Don't consider a Bluetooth adapter present until it has an address.
[chromium-blink-merge.git] / cc / CCLayerTreeHostImplTest.cpp
blobe410b2208f6d159a313913a925ff0faba7d82c31
1 // Copyright 2011 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 "config.h"
7 #include "CCLayerTreeHostImpl.h"
9 #include "CCAnimationTestCommon.h"
10 #include "CCGeometryTestUtils.h"
11 #include "CCHeadsUpDisplayLayerImpl.h"
12 #include "CCIOSurfaceLayerImpl.h"
13 #include "CCLayerImpl.h"
14 #include "CCLayerTestCommon.h"
15 #include "CCLayerTilingData.h"
16 #include "CCQuadSink.h"
17 #include "CCRenderPassDrawQuad.h"
18 #include "CCRendererGL.h"
19 #include "CCScrollbarGeometryFixedThumb.h"
20 #include "CCScrollbarLayerImpl.h"
21 #include "CCSettings.h"
22 #include "CCSingleThreadProxy.h"
23 #include "CCSolidColorDrawQuad.h"
24 #include "CCTestCommon.h"
25 #include "CCTextureLayerImpl.h"
26 #include "CCTileDrawQuad.h"
27 #include "CCTiledLayerImpl.h"
28 #include "CCVideoLayerImpl.h"
29 #include "FakeWebCompositorOutputSurface.h"
30 #include "FakeWebGraphicsContext3D.h"
31 #include "FakeWebScrollbarThemeGeometry.h"
32 #include <gmock/gmock.h>
33 #include <gtest/gtest.h>
34 #include <public/WebVideoFrame.h>
35 #include <public/WebVideoFrameProvider.h>
37 using namespace CCLayerTestCommon;
38 using namespace WebCore;
39 using namespace WebKit;
40 using namespace WebKitTests;
42 using ::testing::Mock;
43 using ::testing::Return;
44 using ::testing::AnyNumber;
45 using ::testing::AtLeast;
46 using ::testing::_;
48 namespace {
50 class CCLayerTreeHostImplTest : public testing::Test, public CCLayerTreeHostImplClient {
51 public:
52 CCLayerTreeHostImplTest()
53 : m_onCanDrawStateChangedCalled(false)
54 , m_didRequestCommit(false)
55 , m_didRequestRedraw(false)
57 CCLayerTreeSettings settings;
58 settings.minimumOcclusionTrackingSize = IntSize();
60 m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
61 m_hostImpl->initializeRenderer(createContext(), UnthrottledUploader);
62 m_hostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10));
65 virtual void didLoseContextOnImplThread() OVERRIDE { }
66 virtual void onSwapBuffersCompleteOnImplThread() OVERRIDE { }
67 virtual void onVSyncParametersChanged(double, double) OVERRIDE { }
68 virtual void onCanDrawStateChanged(bool canDraw) OVERRIDE { m_onCanDrawStateChangedCalled = true; }
69 virtual void setNeedsRedrawOnImplThread() OVERRIDE { m_didRequestRedraw = true; }
70 virtual void setNeedsCommitOnImplThread() OVERRIDE { m_didRequestCommit = true; }
71 virtual void postAnimationEventsToMainThreadOnImplThread(PassOwnPtr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE { }
73 PassOwnPtr<CCLayerTreeHostImpl> createLayerTreeHost(bool partialSwap, PassOwnPtr<CCGraphicsContext> graphicsContext, PassOwnPtr<CCLayerImpl> rootPtr)
75 CCSettings::setPartialSwapEnabled(partialSwap);
77 CCLayerTreeSettings settings;
78 settings.minimumOcclusionTrackingSize = IntSize();
80 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
82 myHostImpl->initializeRenderer(graphicsContext, UnthrottledUploader);
83 myHostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10));
85 OwnPtr<CCLayerImpl> root = rootPtr;
87 root->setAnchorPoint(FloatPoint(0, 0));
88 root->setPosition(FloatPoint(0, 0));
89 root->setBounds(IntSize(10, 10));
90 root->setContentBounds(IntSize(10, 10));
91 root->setVisibleContentRect(IntRect(0, 0, 10, 10));
92 root->setDrawsContent(true);
93 myHostImpl->setRootLayer(root.release());
94 return myHostImpl.release();
97 static void expectClearedScrollDeltasRecursive(CCLayerImpl* layer)
99 ASSERT_EQ(layer->scrollDelta(), IntSize());
100 for (size_t i = 0; i < layer->children().size(); ++i)
101 expectClearedScrollDeltasRecursive(layer->children()[i].get());
104 static void expectContains(const CCScrollAndScaleSet& scrollInfo, int id, const IntSize& scrollDelta)
106 int timesEncountered = 0;
108 for (size_t i = 0; i < scrollInfo.scrolls.size(); ++i) {
109 if (scrollInfo.scrolls[i].layerId != id)
110 continue;
111 EXPECT_EQ(scrollDelta.width(), scrollInfo.scrolls[i].scrollDelta.width());
112 EXPECT_EQ(scrollDelta.height(), scrollInfo.scrolls[i].scrollDelta.height());
113 timesEncountered++;
116 ASSERT_EQ(timesEncountered, 1);
119 void setupScrollAndContentsLayers(const IntSize& contentSize)
121 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
122 root->setScrollable(true);
123 root->setScrollPosition(IntPoint(0, 0));
124 root->setMaxScrollPosition(contentSize);
125 root->setBounds(contentSize);
126 root->setContentBounds(contentSize);
127 root->setPosition(FloatPoint(0, 0));
128 root->setAnchorPoint(FloatPoint(0, 0));
130 OwnPtr<CCLayerImpl> contents = CCLayerImpl::create(2);
131 contents->setDrawsContent(true);
132 contents->setBounds(contentSize);
133 contents->setContentBounds(contentSize);
134 contents->setPosition(FloatPoint(0, 0));
135 contents->setAnchorPoint(FloatPoint(0, 0));
136 root->addChild(contents.release());
137 m_hostImpl->setRootLayer(root.release());
140 static PassOwnPtr<CCLayerImpl> createScrollableLayer(int id, const IntSize& size)
142 OwnPtr<CCLayerImpl> layer = CCLayerImpl::create(id);
143 layer->setScrollable(true);
144 layer->setDrawsContent(true);
145 layer->setBounds(size);
146 layer->setContentBounds(size);
147 layer->setMaxScrollPosition(IntSize(size.width() * 2, size.height() * 2));
148 return layer.release();
151 void initializeRendererAndDrawFrame()
153 m_hostImpl->initializeRenderer(createContext(), UnthrottledUploader);
154 CCLayerTreeHostImpl::FrameData frame;
155 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
156 m_hostImpl->drawLayers(frame);
157 m_hostImpl->didDrawAllLayers(frame);
160 protected:
161 PassOwnPtr<CCGraphicsContext> createContext()
163 return FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3D));
166 DebugScopedSetImplThread m_alwaysImplThread;
167 DebugScopedSetMainThreadBlocked m_alwaysMainThreadBlocked;
169 OwnPtr<CCLayerTreeHostImpl> m_hostImpl;
170 bool m_onCanDrawStateChangedCalled;
171 bool m_didRequestCommit;
172 bool m_didRequestRedraw;
173 CCScopedSettings m_scopedSettings;
176 class FakeWebGraphicsContext3DMakeCurrentFails : public FakeWebGraphicsContext3D {
177 public:
178 virtual bool makeContextCurrent() { return false; }
181 TEST_F(CCLayerTreeHostImplTest, notifyIfCanDrawChanged)
183 // Note: It is not possible to disable the renderer once it has been set,
184 // so we do not need to test that disabling the renderer notifies us
185 // that canDraw changed.
186 EXPECT_FALSE(m_hostImpl->canDraw());
187 m_onCanDrawStateChangedCalled = false;
189 setupScrollAndContentsLayers(IntSize(100, 100));
190 EXPECT_TRUE(m_hostImpl->canDraw());
191 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
192 m_onCanDrawStateChangedCalled = false;
194 // Toggle the root layer to make sure it toggles canDraw
195 m_hostImpl->setRootLayer(adoptPtr<CCLayerImpl>(0));
196 EXPECT_FALSE(m_hostImpl->canDraw());
197 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
198 m_onCanDrawStateChangedCalled = false;
200 setupScrollAndContentsLayers(IntSize(100, 100));
201 EXPECT_TRUE(m_hostImpl->canDraw());
202 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
203 m_onCanDrawStateChangedCalled = false;
205 // Toggle the device viewport size to make sure it toggles canDraw.
206 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(0, 0));
207 EXPECT_FALSE(m_hostImpl->canDraw());
208 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
209 m_onCanDrawStateChangedCalled = false;
211 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100));
212 EXPECT_TRUE(m_hostImpl->canDraw());
213 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
214 m_onCanDrawStateChangedCalled = false;
216 // Toggle contents textures purged to make sure it toggles canDraw
217 m_hostImpl->releaseContentsTextures();
218 EXPECT_FALSE(m_hostImpl->canDraw());
219 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
220 m_onCanDrawStateChangedCalled = false;
222 m_hostImpl->resetContentsTexturesPurged();
223 EXPECT_TRUE(m_hostImpl->canDraw());
224 EXPECT_TRUE(m_onCanDrawStateChangedCalled);
225 m_onCanDrawStateChangedCalled = false;
228 TEST_F(CCLayerTreeHostImplTest, scrollDeltaNoLayers)
230 ASSERT_FALSE(m_hostImpl->rootLayer());
232 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
233 ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
236 TEST_F(CCLayerTreeHostImplTest, scrollDeltaTreeButNoChanges)
239 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
240 root->addChild(CCLayerImpl::create(2));
241 root->addChild(CCLayerImpl::create(3));
242 root->children()[1]->addChild(CCLayerImpl::create(4));
243 root->children()[1]->addChild(CCLayerImpl::create(5));
244 root->children()[1]->children()[0]->addChild(CCLayerImpl::create(6));
245 m_hostImpl->setRootLayer(root.release());
247 CCLayerImpl* root = m_hostImpl->rootLayer();
249 expectClearedScrollDeltasRecursive(root);
251 OwnPtr<CCScrollAndScaleSet> scrollInfo;
253 scrollInfo = m_hostImpl->processScrollDeltas();
254 ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
255 expectClearedScrollDeltasRecursive(root);
257 scrollInfo = m_hostImpl->processScrollDeltas();
258 ASSERT_EQ(scrollInfo->scrolls.size(), 0u);
259 expectClearedScrollDeltasRecursive(root);
262 TEST_F(CCLayerTreeHostImplTest, scrollDeltaRepeatedScrolls)
264 IntPoint scrollPosition(20, 30);
265 IntSize scrollDelta(11, -15);
267 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
268 root->setScrollPosition(scrollPosition);
269 root->setScrollable(true);
270 root->setMaxScrollPosition(IntSize(100, 100));
271 root->scrollBy(scrollDelta);
272 m_hostImpl->setRootLayer(root.release());
274 CCLayerImpl* root = m_hostImpl->rootLayer();
276 OwnPtr<CCScrollAndScaleSet> scrollInfo;
278 scrollInfo = m_hostImpl->processScrollDeltas();
279 ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
280 EXPECT_EQ(root->sentScrollDelta(), scrollDelta);
281 expectContains(*scrollInfo, root->id(), scrollDelta);
283 IntSize scrollDelta2(-5, 27);
284 root->scrollBy(scrollDelta2);
285 scrollInfo = m_hostImpl->processScrollDeltas();
286 ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
287 EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2);
288 expectContains(*scrollInfo, root->id(), scrollDelta + scrollDelta2);
290 root->scrollBy(IntSize());
291 scrollInfo = m_hostImpl->processScrollDeltas();
292 EXPECT_EQ(root->sentScrollDelta(), scrollDelta + scrollDelta2);
295 TEST_F(CCLayerTreeHostImplTest, scrollRootCallsCommitAndRedraw)
297 setupScrollAndContentsLayers(IntSize(100, 100));
298 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
299 initializeRendererAndDrawFrame();
301 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
302 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
303 m_hostImpl->scrollEnd();
304 EXPECT_TRUE(m_didRequestRedraw);
305 EXPECT_TRUE(m_didRequestCommit);
308 TEST_F(CCLayerTreeHostImplTest, scrollWithoutRootLayer)
310 // We should not crash when trying to scroll an empty layer tree.
311 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored);
314 TEST_F(CCLayerTreeHostImplTest, scrollWithoutRenderer)
316 CCLayerTreeSettings settings;
317 m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
319 // Initialization will fail here.
320 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails)), UnthrottledUploader);
321 m_hostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10));
323 setupScrollAndContentsLayers(IntSize(100, 100));
325 // We should not crash when trying to scroll after the renderer initialization fails.
326 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored);
329 TEST_F(CCLayerTreeHostImplTest, replaceTreeWhileScrolling)
331 const int scrollLayerId = 1;
333 setupScrollAndContentsLayers(IntSize(100, 100));
334 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
335 initializeRendererAndDrawFrame();
337 // We should not crash if the tree is replaced while we are scrolling.
338 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
339 m_hostImpl->detachLayerTree();
341 setupScrollAndContentsLayers(IntSize(100, 100));
343 // We should still be scrolling, because the scrolled layer also exists in the new tree.
344 IntSize scrollDelta(0, 10);
345 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
346 m_hostImpl->scrollEnd();
347 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
348 expectContains(*scrollInfo, scrollLayerId, scrollDelta);
351 TEST_F(CCLayerTreeHostImplTest, clearRootRenderSurfaceAndScroll)
353 setupScrollAndContentsLayers(IntSize(100, 100));
354 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
355 initializeRendererAndDrawFrame();
357 // We should be able to scroll even if the root layer loses its render surface after the most
358 // recent render.
359 m_hostImpl->rootLayer()->clearRenderSurface();
360 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
363 TEST_F(CCLayerTreeHostImplTest, wheelEventHandlers)
365 setupScrollAndContentsLayers(IntSize(100, 100));
366 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
367 initializeRendererAndDrawFrame();
368 CCLayerImpl* root = m_hostImpl->rootLayer();
370 root->setHaveWheelEventHandlers(true);
372 // With registered event handlers, wheel scrolls have to go to the main thread.
373 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
375 // But gesture scrolls can still be handled.
376 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted);
379 TEST_F(CCLayerTreeHostImplTest, shouldScrollOnMainThread)
381 setupScrollAndContentsLayers(IntSize(100, 100));
382 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
383 initializeRendererAndDrawFrame();
384 CCLayerImpl* root = m_hostImpl->rootLayer();
386 root->setShouldScrollOnMainThread(true);
388 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
389 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollOnMainThread);
392 TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionBasic)
394 setupScrollAndContentsLayers(IntSize(200, 200));
395 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100));
396 initializeRendererAndDrawFrame();
397 CCLayerImpl* root = m_hostImpl->rootLayer();
399 root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50));
401 // All scroll types inside the non-fast scrollable region should fail.
402 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
403 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollOnMainThread);
405 // All scroll types outside this region should succeed.
406 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
407 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
408 m_hostImpl->scrollEnd();
409 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(75, 75), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted);
410 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
411 m_hostImpl->scrollEnd();
414 TEST_F(CCLayerTreeHostImplTest, nonFastScrollableRegionWithOffset)
416 setupScrollAndContentsLayers(IntSize(200, 200));
417 m_hostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100));
418 CCLayerImpl* root = m_hostImpl->rootLayer();
420 root->setNonFastScrollableRegion(IntRect(0, 0, 50, 50));
421 root->setPosition(FloatPoint(-25, 0));
422 initializeRendererAndDrawFrame();
424 // This point would fall into the non-fast scrollable region except that we've moved the layer down by 25 pixels.
425 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(40, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
426 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 1));
427 m_hostImpl->scrollEnd();
429 // This point is still inside the non-fast region.
430 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(10, 10), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
433 TEST_F(CCLayerTreeHostImplTest, maxScrollPositionChangedByDeviceScaleFactor)
435 setupScrollAndContentsLayers(IntSize(100, 100));
437 float deviceScaleFactor = 2;
438 IntSize layoutViewport(25, 25);
439 IntSize deviceViewport(layoutViewport);
440 deviceViewport.scale(deviceScaleFactor);
441 m_hostImpl->setViewportSize(layoutViewport, deviceViewport);
442 m_hostImpl->setDeviceScaleFactor(deviceScaleFactor);
443 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(25, 25));
445 deviceScaleFactor = 1;
446 m_hostImpl->setViewportSize(layoutViewport, layoutViewport);
447 m_hostImpl->setDeviceScaleFactor(deviceScaleFactor);
448 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), IntSize(75, 75));
451 TEST_F(CCLayerTreeHostImplTest, pinchGesture)
453 setupScrollAndContentsLayers(IntSize(100, 100));
454 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
455 initializeRendererAndDrawFrame();
457 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
458 ASSERT(scrollLayer);
460 const float minPageScale = 0.5, maxPageScale = 4;
462 // Basic pinch zoom in gesture
464 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
465 scrollLayer->setPageScaleDelta(1);
466 scrollLayer->setScrollDelta(IntSize());
468 float pageScaleDelta = 2;
469 m_hostImpl->pinchGestureBegin();
470 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50));
471 m_hostImpl->pinchGestureEnd();
472 EXPECT_TRUE(m_didRequestRedraw);
473 EXPECT_TRUE(m_didRequestCommit);
475 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
476 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
479 // Zoom-in clamping
481 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
482 scrollLayer->setPageScaleDelta(1);
483 scrollLayer->setScrollDelta(IntSize());
484 float pageScaleDelta = 10;
486 m_hostImpl->pinchGestureBegin();
487 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(50, 50));
488 m_hostImpl->pinchGestureEnd();
490 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
491 EXPECT_EQ(scrollInfo->pageScaleDelta, maxPageScale);
494 // Zoom-out clamping
496 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
497 scrollLayer->setPageScaleDelta(1);
498 scrollLayer->setScrollDelta(IntSize());
499 scrollLayer->setScrollPosition(IntPoint(50, 50));
501 float pageScaleDelta = 0.1f;
502 m_hostImpl->pinchGestureBegin();
503 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(0, 0));
504 m_hostImpl->pinchGestureEnd();
506 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
507 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
509 // Pushed to (0,0) via clamping against contents layer size.
510 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50));
513 // Two-finger panning
515 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
516 scrollLayer->setPageScaleDelta(1);
517 scrollLayer->setScrollDelta(IntSize());
518 scrollLayer->setScrollPosition(IntPoint(20, 20));
520 float pageScaleDelta = 1;
521 m_hostImpl->pinchGestureBegin();
522 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(10, 10));
523 m_hostImpl->pinchGestureUpdate(pageScaleDelta, IntPoint(20, 20));
524 m_hostImpl->pinchGestureEnd();
526 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
527 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
528 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-10, -10));
532 TEST_F(CCLayerTreeHostImplTest, pageScaleAnimation)
534 setupScrollAndContentsLayers(IntSize(100, 100));
535 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
536 initializeRendererAndDrawFrame();
538 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
539 ASSERT(scrollLayer);
541 const float minPageScale = 0.5, maxPageScale = 4;
542 const double startTime = 1;
543 const double duration = 0.1;
544 const double halfwayThroughAnimation = startTime + duration / 2;
545 const double endTime = startTime + duration;
547 // Non-anchor zoom-in
549 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
550 scrollLayer->setPageScaleDelta(1);
551 scrollLayer->setScrollPosition(IntPoint(50, 50));
553 m_hostImpl->startPageScaleAnimation(IntSize(0, 0), false, 2, startTime, duration);
554 m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation);
555 EXPECT_TRUE(m_didRequestRedraw);
556 m_hostImpl->animate(endTime, endTime);
557 EXPECT_TRUE(m_didRequestCommit);
559 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
560 EXPECT_EQ(scrollInfo->pageScaleDelta, 2);
561 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50));
564 // Anchor zoom-out
566 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
567 scrollLayer->setPageScaleDelta(1);
568 scrollLayer->setScrollPosition(IntPoint(50, 50));
570 m_hostImpl->startPageScaleAnimation(IntSize(25, 25), true, minPageScale, startTime, duration);
571 m_hostImpl->animate(endTime, endTime);
572 EXPECT_TRUE(m_didRequestRedraw);
573 EXPECT_TRUE(m_didRequestCommit);
575 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
576 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
577 // Pushed to (0,0) via clamping against contents layer size.
578 expectContains(*scrollInfo, scrollLayer->id(), IntSize(-50, -50));
582 TEST_F(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhilePinchZooming)
584 setupScrollAndContentsLayers(IntSize(100, 100));
585 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
586 initializeRendererAndDrawFrame();
588 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
589 ASSERT(scrollLayer);
591 const float minPageScale = 0.5, maxPageScale = 4;
593 // Pinch zoom in.
595 // Start a pinch in gesture at the bottom right corner of the viewport.
596 const float zoomInDelta = 2;
597 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
598 m_hostImpl->pinchGestureBegin();
599 m_hostImpl->pinchGestureUpdate(zoomInDelta, IntPoint(50, 50));
601 // Because we are pinch zooming in, we shouldn't get any scroll or page
602 // scale deltas.
603 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
604 EXPECT_EQ(scrollInfo->pageScaleDelta, 1);
605 EXPECT_EQ(scrollInfo->scrolls.size(), 0u);
607 // Once the gesture ends, we get the final scroll and page scale values.
608 m_hostImpl->pinchGestureEnd();
609 scrollInfo = m_hostImpl->processScrollDeltas();
610 EXPECT_EQ(scrollInfo->pageScaleDelta, zoomInDelta);
611 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
614 // Pinch zoom out.
616 // Start a pinch out gesture at the bottom right corner of the viewport.
617 const float zoomOutDelta = 0.75;
618 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
619 m_hostImpl->pinchGestureBegin();
620 m_hostImpl->pinchGestureUpdate(zoomOutDelta, IntPoint(50, 50));
622 // Since we are pinch zooming out, we should get an update to zoom all
623 // the way out to the minimum page scale.
624 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
625 EXPECT_EQ(scrollInfo->pageScaleDelta, minPageScale);
626 expectContains(*scrollInfo, scrollLayer->id(), IntSize(0, 0));
628 // Once the gesture ends, we get the final scroll and page scale values.
629 m_hostImpl->pinchGestureEnd();
630 scrollInfo = m_hostImpl->processScrollDeltas();
631 EXPECT_EQ(scrollInfo->pageScaleDelta, zoomOutDelta);
632 expectContains(*scrollInfo, scrollLayer->id(), IntSize(8, 8));
636 TEST_F(CCLayerTreeHostImplTest, inhibitScrollAndPageScaleUpdatesWhileAnimatingPageScale)
638 setupScrollAndContentsLayers(IntSize(100, 100));
639 m_hostImpl->setViewportSize(IntSize(50, 50), IntSize(50, 50));
640 initializeRendererAndDrawFrame();
642 CCLayerImpl* scrollLayer = m_hostImpl->rootScrollLayer();
643 ASSERT(scrollLayer);
645 const float minPageScale = 0.5, maxPageScale = 4;
646 const double startTime = 1;
647 const double duration = 0.1;
648 const double halfwayThroughAnimation = startTime + duration / 2;
649 const double endTime = startTime + duration;
651 // Start a page scale animation.
652 const float pageScaleDelta = 2;
653 m_hostImpl->setPageScaleFactorAndLimits(1, minPageScale, maxPageScale);
654 m_hostImpl->startPageScaleAnimation(IntSize(50, 50), false, pageScaleDelta, startTime, duration);
656 // We should immediately get the final zoom and scroll values for the
657 // animation.
658 m_hostImpl->animate(halfwayThroughAnimation, halfwayThroughAnimation);
659 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
660 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
661 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
663 // Scrolling during the animation is ignored.
664 const IntSize scrollDelta(0, 10);
665 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(25, 25), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
666 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
667 m_hostImpl->scrollEnd();
669 // The final page scale and scroll deltas should match what we got
670 // earlier.
671 m_hostImpl->animate(endTime, endTime);
672 scrollInfo = m_hostImpl->processScrollDeltas();
673 EXPECT_EQ(scrollInfo->pageScaleDelta, pageScaleDelta);
674 expectContains(*scrollInfo, scrollLayer->id(), IntSize(25, 25));
677 class DidDrawCheckLayer : public CCTiledLayerImpl {
678 public:
679 static PassOwnPtr<DidDrawCheckLayer> create(int id) { return adoptPtr(new DidDrawCheckLayer(id)); }
681 virtual void didDraw(CCResourceProvider*) OVERRIDE
683 m_didDrawCalled = true;
686 virtual void willDraw(CCResourceProvider*) OVERRIDE
688 m_willDrawCalled = true;
691 bool didDrawCalled() const { return m_didDrawCalled; }
692 bool willDrawCalled() const { return m_willDrawCalled; }
694 void clearDidDrawCheck()
696 m_didDrawCalled = false;
697 m_willDrawCalled = false;
700 protected:
701 explicit DidDrawCheckLayer(int id)
702 : CCTiledLayerImpl(id)
703 , m_didDrawCalled(false)
704 , m_willDrawCalled(false)
706 setAnchorPoint(FloatPoint(0, 0));
707 setBounds(IntSize(10, 10));
708 setContentBounds(IntSize(10, 10));
709 setDrawsContent(true);
710 setSkipsDraw(false);
711 setVisibleContentRect(IntRect(0, 0, 10, 10));
713 OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(100, 100), CCLayerTilingData::HasBorderTexels);
714 tiler->setBounds(contentBounds());
715 setTilingData(*tiler.get());
718 private:
719 bool m_didDrawCalled;
720 bool m_willDrawCalled;
723 TEST_F(CCLayerTreeHostImplTest, didDrawNotCalledOnHiddenLayer)
725 // The root layer is always drawn, so run this test on a child layer that
726 // will be masked out by the root layer's bounds.
727 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
728 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
729 root->setMasksToBounds(true);
731 root->addChild(DidDrawCheckLayer::create(2));
732 DidDrawCheckLayer* layer = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
733 // Ensure visibleContentRect for layer is empty
734 layer->setPosition(FloatPoint(100, 100));
735 layer->setBounds(IntSize(10, 10));
736 layer->setContentBounds(IntSize(10, 10));
738 CCLayerTreeHostImpl::FrameData frame;
740 EXPECT_FALSE(layer->willDrawCalled());
741 EXPECT_FALSE(layer->didDrawCalled());
743 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
744 m_hostImpl->drawLayers(frame);
745 m_hostImpl->didDrawAllLayers(frame);
747 EXPECT_FALSE(layer->willDrawCalled());
748 EXPECT_FALSE(layer->didDrawCalled());
750 EXPECT_TRUE(layer->visibleContentRect().isEmpty());
752 // Ensure visibleContentRect for layer layer is not empty
753 layer->setPosition(FloatPoint(0, 0));
755 EXPECT_FALSE(layer->willDrawCalled());
756 EXPECT_FALSE(layer->didDrawCalled());
758 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
759 m_hostImpl->drawLayers(frame);
760 m_hostImpl->didDrawAllLayers(frame);
762 EXPECT_TRUE(layer->willDrawCalled());
763 EXPECT_TRUE(layer->didDrawCalled());
765 EXPECT_FALSE(layer->visibleContentRect().isEmpty());
768 TEST_F(CCLayerTreeHostImplTest, willDrawNotCalledOnOccludedLayer)
770 IntSize bigSize(1000, 1000);
771 m_hostImpl->setViewportSize(bigSize, bigSize);
773 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
774 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
776 root->addChild(DidDrawCheckLayer::create(2));
777 DidDrawCheckLayer* occludedLayer = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
779 root->addChild(DidDrawCheckLayer::create(3));
780 DidDrawCheckLayer* topLayer = static_cast<DidDrawCheckLayer*>(root->children()[1].get());
781 // This layer covers the occludedLayer above. Make this layer large so it can occlude.
782 topLayer->setBounds(bigSize);
783 topLayer->setContentBounds(bigSize);
784 topLayer->setOpaque(true);
786 CCLayerTreeHostImpl::FrameData frame;
788 EXPECT_FALSE(occludedLayer->willDrawCalled());
789 EXPECT_FALSE(occludedLayer->didDrawCalled());
790 EXPECT_FALSE(topLayer->willDrawCalled());
791 EXPECT_FALSE(topLayer->didDrawCalled());
793 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
794 m_hostImpl->drawLayers(frame);
795 m_hostImpl->didDrawAllLayers(frame);
797 EXPECT_FALSE(occludedLayer->willDrawCalled());
798 EXPECT_FALSE(occludedLayer->didDrawCalled());
799 EXPECT_TRUE(topLayer->willDrawCalled());
800 EXPECT_TRUE(topLayer->didDrawCalled());
803 TEST_F(CCLayerTreeHostImplTest, didDrawCalledOnAllLayers)
805 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
806 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
808 root->addChild(DidDrawCheckLayer::create(2));
809 DidDrawCheckLayer* layer1 = static_cast<DidDrawCheckLayer*>(root->children()[0].get());
811 layer1->addChild(DidDrawCheckLayer::create(3));
812 DidDrawCheckLayer* layer2 = static_cast<DidDrawCheckLayer*>(layer1->children()[0].get());
814 layer1->setOpacity(0.3f);
815 layer1->setPreserves3D(false);
817 EXPECT_FALSE(root->didDrawCalled());
818 EXPECT_FALSE(layer1->didDrawCalled());
819 EXPECT_FALSE(layer2->didDrawCalled());
821 CCLayerTreeHostImpl::FrameData frame;
822 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
823 m_hostImpl->drawLayers(frame);
824 m_hostImpl->didDrawAllLayers(frame);
826 EXPECT_TRUE(root->didDrawCalled());
827 EXPECT_TRUE(layer1->didDrawCalled());
828 EXPECT_TRUE(layer2->didDrawCalled());
830 EXPECT_NE(root->renderSurface(), layer1->renderSurface());
831 EXPECT_TRUE(!!layer1->renderSurface());
834 class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
835 public:
836 static PassOwnPtr<MissingTextureAnimatingLayer> create(int id, bool tileMissing, bool skipsDraw, bool animating, CCResourceProvider* resourceProvider) { return adoptPtr(new MissingTextureAnimatingLayer(id, tileMissing, skipsDraw, animating, resourceProvider)); }
838 private:
839 explicit MissingTextureAnimatingLayer(int id, bool tileMissing, bool skipsDraw, bool animating, CCResourceProvider* resourceProvider)
840 : DidDrawCheckLayer(id)
842 OwnPtr<CCLayerTilingData> tilingData = CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels);
843 tilingData->setBounds(bounds());
844 setTilingData(*tilingData.get());
845 setSkipsDraw(skipsDraw);
846 if (!tileMissing) {
847 CCResourceProvider::ResourceId resource = resourceProvider->createResource(CCRenderer::ContentPool, IntSize(), GraphicsContext3D::RGBA, CCResourceProvider::TextureUsageAny);
848 pushTileProperties(0, 0, resource, IntRect());
850 if (animating)
851 addAnimatedTransformToLayer(*this, 10, 3, 0);
855 TEST_F(CCLayerTreeHostImplTest, prepareToDrawFailsWhenAnimationUsesCheckerboard)
857 // When the texture is not missing, we draw as usual.
858 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
859 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
860 root->addChild(MissingTextureAnimatingLayer::create(2, false, false, true, m_hostImpl->resourceProvider()));
862 CCLayerTreeHostImpl::FrameData frame;
864 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
865 m_hostImpl->drawLayers(frame);
866 m_hostImpl->didDrawAllLayers(frame);
868 // When a texture is missing and we're not animating, we draw as usual with checkerboarding.
869 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
870 root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
871 root->addChild(MissingTextureAnimatingLayer::create(2, true, false, false, m_hostImpl->resourceProvider()));
873 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
874 m_hostImpl->drawLayers(frame);
875 m_hostImpl->didDrawAllLayers(frame);
877 // When a texture is missing and we're animating, we don't want to draw anything.
878 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
879 root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
880 root->addChild(MissingTextureAnimatingLayer::create(2, true, false, true, m_hostImpl->resourceProvider()));
882 EXPECT_FALSE(m_hostImpl->prepareToDraw(frame));
883 m_hostImpl->drawLayers(frame);
884 m_hostImpl->didDrawAllLayers(frame);
886 // When the layer skips draw and we're animating, we still draw the frame.
887 m_hostImpl->setRootLayer(DidDrawCheckLayer::create(1));
888 root = static_cast<DidDrawCheckLayer*>(m_hostImpl->rootLayer());
889 root->addChild(MissingTextureAnimatingLayer::create(2, false, true, true, m_hostImpl->resourceProvider()));
891 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
892 m_hostImpl->drawLayers(frame);
893 m_hostImpl->didDrawAllLayers(frame);
896 TEST_F(CCLayerTreeHostImplTest, scrollRootIgnored)
898 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
899 root->setScrollable(false);
900 m_hostImpl->setRootLayer(root.release());
901 initializeRendererAndDrawFrame();
903 // Scroll event is ignored because layer is not scrollable.
904 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored);
905 EXPECT_FALSE(m_didRequestRedraw);
906 EXPECT_FALSE(m_didRequestCommit);
909 TEST_F(CCLayerTreeHostImplTest, scrollNonCompositedRoot)
911 // Test the configuration where a non-composited root layer is embedded in a
912 // scrollable outer layer.
913 IntSize surfaceSize(10, 10);
915 OwnPtr<CCLayerImpl> contentLayer = CCLayerImpl::create(1);
916 contentLayer->setUseLCDText(true);
917 contentLayer->setDrawsContent(true);
918 contentLayer->setPosition(FloatPoint(0, 0));
919 contentLayer->setAnchorPoint(FloatPoint(0, 0));
920 contentLayer->setBounds(surfaceSize);
921 contentLayer->setContentBounds(IntSize(surfaceSize.width() * 2, surfaceSize.height() * 2));
923 OwnPtr<CCLayerImpl> scrollLayer = CCLayerImpl::create(2);
924 scrollLayer->setScrollable(true);
925 scrollLayer->setMaxScrollPosition(surfaceSize);
926 scrollLayer->setBounds(surfaceSize);
927 scrollLayer->setContentBounds(surfaceSize);
928 scrollLayer->setPosition(FloatPoint(0, 0));
929 scrollLayer->setAnchorPoint(FloatPoint(0, 0));
930 scrollLayer->addChild(contentLayer.release());
932 m_hostImpl->setRootLayer(scrollLayer.release());
933 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
934 initializeRendererAndDrawFrame();
936 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
937 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
938 m_hostImpl->scrollEnd();
939 EXPECT_TRUE(m_didRequestRedraw);
940 EXPECT_TRUE(m_didRequestCommit);
943 TEST_F(CCLayerTreeHostImplTest, scrollChildCallsCommitAndRedraw)
945 IntSize surfaceSize(10, 10);
946 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
947 root->setBounds(surfaceSize);
948 root->setContentBounds(surfaceSize);
949 root->addChild(createScrollableLayer(2, surfaceSize));
950 m_hostImpl->setRootLayer(root.release());
951 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
952 initializeRendererAndDrawFrame();
954 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
955 m_hostImpl->scrollBy(IntPoint(), IntSize(0, 10));
956 m_hostImpl->scrollEnd();
957 EXPECT_TRUE(m_didRequestRedraw);
958 EXPECT_TRUE(m_didRequestCommit);
961 TEST_F(CCLayerTreeHostImplTest, scrollMissesChild)
963 IntSize surfaceSize(10, 10);
964 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
965 root->addChild(createScrollableLayer(2, surfaceSize));
966 m_hostImpl->setRootLayer(root.release());
967 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
968 initializeRendererAndDrawFrame();
970 // Scroll event is ignored because the input coordinate is outside the layer boundaries.
971 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(15, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored);
972 EXPECT_FALSE(m_didRequestRedraw);
973 EXPECT_FALSE(m_didRequestCommit);
976 TEST_F(CCLayerTreeHostImplTest, scrollMissesBackfacingChild)
978 IntSize surfaceSize(10, 10);
979 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
980 OwnPtr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize);
981 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
983 WebTransformationMatrix matrix;
984 matrix.rotate3d(180, 0, 0);
985 child->setTransform(matrix);
986 child->setDoubleSided(false);
988 root->addChild(child.release());
989 m_hostImpl->setRootLayer(root.release());
990 initializeRendererAndDrawFrame();
992 // Scroll event is ignored because the scrollable layer is not facing the viewer and there is
993 // nothing scrollable behind it.
994 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollIgnored);
995 EXPECT_FALSE(m_didRequestRedraw);
996 EXPECT_FALSE(m_didRequestCommit);
999 TEST_F(CCLayerTreeHostImplTest, scrollBlockedByContentLayer)
1001 IntSize surfaceSize(10, 10);
1002 OwnPtr<CCLayerImpl> contentLayer = createScrollableLayer(1, surfaceSize);
1003 contentLayer->setShouldScrollOnMainThread(true);
1004 contentLayer->setScrollable(false);
1006 OwnPtr<CCLayerImpl> scrollLayer = createScrollableLayer(2, surfaceSize);
1007 scrollLayer->addChild(contentLayer.release());
1009 m_hostImpl->setRootLayer(scrollLayer.release());
1010 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1011 initializeRendererAndDrawFrame();
1013 // Scrolling fails because the content layer is asking to be scrolled on the main thread.
1014 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollOnMainThread);
1017 TEST_F(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnMainThread)
1019 IntSize surfaceSize(10, 10);
1020 float pageScale = 2;
1021 OwnPtr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize);
1022 m_hostImpl->setRootLayer(root.release());
1023 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1024 initializeRendererAndDrawFrame();
1026 IntSize scrollDelta(0, 10);
1027 IntSize expectedScrollDelta(scrollDelta);
1028 IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition());
1029 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
1030 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1031 m_hostImpl->scrollEnd();
1033 // Set new page scale from main thread.
1034 m_hostImpl->setPageScaleFactorAndLimits(pageScale, pageScale, pageScale);
1036 // The scale should apply to the scroll delta.
1037 expectedScrollDelta.scale(pageScale);
1038 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
1039 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta);
1041 // The scroll range should also have been updated.
1042 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll);
1044 // The page scale delta remains constant because the impl thread did not scale.
1045 EXPECT_EQ(m_hostImpl->rootLayer()->pageScaleDelta(), 1);
1048 TEST_F(CCLayerTreeHostImplTest, scrollRootAndChangePageScaleOnImplThread)
1050 IntSize surfaceSize(10, 10);
1051 float pageScale = 2;
1052 OwnPtr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize);
1053 m_hostImpl->setRootLayer(root.release());
1054 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1055 m_hostImpl->setPageScaleFactorAndLimits(1, 1, pageScale);
1056 initializeRendererAndDrawFrame();
1058 IntSize scrollDelta(0, 10);
1059 IntSize expectedScrollDelta(scrollDelta);
1060 IntSize expectedMaxScroll(m_hostImpl->rootLayer()->maxScrollPosition());
1061 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
1062 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1063 m_hostImpl->scrollEnd();
1065 // Set new page scale on impl thread by pinching.
1066 m_hostImpl->pinchGestureBegin();
1067 m_hostImpl->pinchGestureUpdate(pageScale, IntPoint());
1068 m_hostImpl->pinchGestureEnd();
1070 // The scroll delta is not scaled because the main thread did not scale.
1071 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
1072 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedScrollDelta);
1074 // The scroll range should also have been updated.
1075 EXPECT_EQ(m_hostImpl->rootLayer()->maxScrollPosition(), expectedMaxScroll);
1077 // The page scale delta should match the new scale on the impl side.
1078 EXPECT_EQ(m_hostImpl->rootLayer()->pageScaleDelta(), pageScale);
1081 TEST_F(CCLayerTreeHostImplTest, pageScaleDeltaAppliedToRootScrollLayerOnly)
1083 IntSize surfaceSize(10, 10);
1084 float defaultPageScale = 1;
1085 float newPageScale = 2;
1087 // Create a normal scrollable root layer and another scrollable child layer.
1088 setupScrollAndContentsLayers(surfaceSize);
1089 CCLayerImpl* root = m_hostImpl->rootLayer();
1090 CCLayerImpl* child = root->children()[0].get();
1092 OwnPtr<CCLayerImpl> scrollableChild = createScrollableLayer(3, surfaceSize);
1093 child->addChild(scrollableChild.release());
1094 CCLayerImpl* grandChild = child->children()[0].get();
1096 // Set new page scale on impl thread by pinching.
1097 m_hostImpl->pinchGestureBegin();
1098 m_hostImpl->pinchGestureUpdate(newPageScale, IntPoint());
1099 m_hostImpl->pinchGestureEnd();
1101 // The page scale delta should only be applied to the scrollable root layer.
1102 EXPECT_EQ(root->pageScaleDelta(), newPageScale);
1103 EXPECT_EQ(child->pageScaleDelta(), defaultPageScale);
1104 EXPECT_EQ(grandChild->pageScaleDelta(), defaultPageScale);
1106 // Make sure all the layers are drawn with the page scale delta applied, i.e., the page scale
1107 // delta on the root layer is applied hierarchically.
1108 CCLayerTreeHostImpl::FrameData frame;
1109 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1110 m_hostImpl->drawLayers(frame);
1111 m_hostImpl->didDrawAllLayers(frame);
1113 EXPECT_EQ(root->drawTransform().m11(), newPageScale);
1114 EXPECT_EQ(root->drawTransform().m22(), newPageScale);
1115 EXPECT_EQ(child->drawTransform().m11(), newPageScale);
1116 EXPECT_EQ(child->drawTransform().m22(), newPageScale);
1117 EXPECT_EQ(grandChild->drawTransform().m11(), newPageScale);
1118 EXPECT_EQ(grandChild->drawTransform().m22(), newPageScale);
1121 TEST_F(CCLayerTreeHostImplTest, scrollChildAndChangePageScaleOnMainThread)
1123 IntSize surfaceSize(10, 10);
1124 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
1125 root->setBounds(surfaceSize);
1126 root->setContentBounds(surfaceSize);
1127 // Also mark the root scrollable so it becomes the root scroll layer.
1128 root->setScrollable(true);
1129 int scrollLayerId = 2;
1130 root->addChild(createScrollableLayer(scrollLayerId, surfaceSize));
1131 m_hostImpl->setRootLayer(root.release());
1132 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1133 initializeRendererAndDrawFrame();
1135 CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0].get();
1137 IntSize scrollDelta(0, 10);
1138 IntSize expectedScrollDelta(scrollDelta);
1139 IntSize expectedMaxScroll(child->maxScrollPosition());
1140 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
1141 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1142 m_hostImpl->scrollEnd();
1144 float pageScale = 2;
1145 m_hostImpl->setPageScaleFactorAndLimits(pageScale, 1, pageScale);
1147 // The scale should apply to the scroll delta.
1148 expectedScrollDelta.scale(pageScale);
1149 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
1150 expectContains(*scrollInfo.get(), scrollLayerId, expectedScrollDelta);
1152 // The scroll range should not have changed.
1153 EXPECT_EQ(child->maxScrollPosition(), expectedMaxScroll);
1155 // The page scale delta remains constant because the impl thread did not scale.
1156 EXPECT_EQ(child->pageScaleDelta(), 1);
1159 TEST_F(CCLayerTreeHostImplTest, scrollChildBeyondLimit)
1161 // Scroll a child layer beyond its maximum scroll range and make sure the
1162 // parent layer is scrolled on the axis on which the child was unable to
1163 // scroll.
1164 IntSize surfaceSize(10, 10);
1165 OwnPtr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize);
1167 OwnPtr<CCLayerImpl> grandChild = createScrollableLayer(3, surfaceSize);
1168 grandChild->setScrollPosition(IntPoint(0, 5));
1170 OwnPtr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize);
1171 child->setScrollPosition(IntPoint(3, 0));
1172 child->addChild(grandChild.release());
1174 root->addChild(child.release());
1175 m_hostImpl->setRootLayer(root.release());
1176 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1177 initializeRendererAndDrawFrame();
1179 IntSize scrollDelta(-8, -7);
1180 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
1181 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1182 m_hostImpl->scrollEnd();
1184 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
1186 // The grand child should have scrolled up to its limit.
1187 CCLayerImpl* child = m_hostImpl->rootLayer()->children()[0].get();
1188 CCLayerImpl* grandChild = child->children()[0].get();
1189 expectContains(*scrollInfo.get(), grandChild->id(), IntSize(0, -5));
1191 // The child should have only scrolled on the other axis.
1192 expectContains(*scrollInfo.get(), child->id(), IntSize(-3, 0));
1196 TEST_F(CCLayerTreeHostImplTest, scrollEventBubbling)
1198 // When we try to scroll a non-scrollable child layer, the scroll delta
1199 // should be applied to one of its ancestors if possible.
1200 IntSize surfaceSize(10, 10);
1201 OwnPtr<CCLayerImpl> root = createScrollableLayer(1, surfaceSize);
1202 OwnPtr<CCLayerImpl> child = createScrollableLayer(2, surfaceSize);
1204 child->setScrollable(false);
1205 root->addChild(child.release());
1207 m_hostImpl->setRootLayer(root.release());
1208 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1209 initializeRendererAndDrawFrame();
1211 IntSize scrollDelta(0, 4);
1212 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
1213 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1214 m_hostImpl->scrollEnd();
1216 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
1218 // Only the root should have scrolled.
1219 ASSERT_EQ(scrollInfo->scrolls.size(), 1u);
1220 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), scrollDelta);
1224 TEST_F(CCLayerTreeHostImplTest, scrollBeforeRedraw)
1226 IntSize surfaceSize(10, 10);
1227 m_hostImpl->setRootLayer(createScrollableLayer(1, surfaceSize));
1228 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1230 // Draw one frame and then immediately rebuild the layer tree to mimic a tree synchronization.
1231 initializeRendererAndDrawFrame();
1232 m_hostImpl->detachLayerTree();
1233 m_hostImpl->setRootLayer(createScrollableLayer(2, surfaceSize));
1235 // Scrolling should still work even though we did not draw yet.
1236 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(5, 5), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
1239 TEST_F(CCLayerTreeHostImplTest, scrollAxisAlignedRotatedLayer)
1241 setupScrollAndContentsLayers(IntSize(100, 100));
1243 // Rotate the root layer 90 degrees counter-clockwise about its center.
1244 WebTransformationMatrix rotateTransform;
1245 rotateTransform.rotate(-90);
1246 m_hostImpl->rootLayer()->setTransform(rotateTransform);
1248 IntSize surfaceSize(50, 50);
1249 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1250 initializeRendererAndDrawFrame();
1252 // Scroll to the right in screen coordinates with a gesture.
1253 IntSize gestureScrollDelta(10, 0);
1254 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted);
1255 m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta);
1256 m_hostImpl->scrollEnd();
1258 // The layer should have scrolled down in its local coordinates.
1259 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
1260 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), IntSize(0, gestureScrollDelta.width()));
1262 // Reset and scroll down with the wheel.
1263 m_hostImpl->rootLayer()->setScrollDelta(FloatSize());
1264 IntSize wheelScrollDelta(0, 10);
1265 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
1266 m_hostImpl->scrollBy(IntPoint(), wheelScrollDelta);
1267 m_hostImpl->scrollEnd();
1269 // The layer should have scrolled down in its local coordinates.
1270 scrollInfo = m_hostImpl->processScrollDeltas();
1271 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), wheelScrollDelta);
1274 TEST_F(CCLayerTreeHostImplTest, scrollNonAxisAlignedRotatedLayer)
1276 setupScrollAndContentsLayers(IntSize(100, 100));
1277 int childLayerId = 3;
1278 float childLayerAngle = -20;
1280 // Create a child layer that is rotated to a non-axis-aligned angle.
1281 OwnPtr<CCLayerImpl> child = createScrollableLayer(childLayerId, m_hostImpl->rootLayer()->contentBounds());
1282 WebTransformationMatrix rotateTransform;
1283 rotateTransform.translate(-50, -50);
1284 rotateTransform.rotate(childLayerAngle);
1285 rotateTransform.translate(50, 50);
1286 child->setTransform(rotateTransform);
1288 // Only allow vertical scrolling.
1289 child->setMaxScrollPosition(IntSize(0, child->contentBounds().height()));
1290 m_hostImpl->rootLayer()->addChild(child.release());
1292 IntSize surfaceSize(50, 50);
1293 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1294 initializeRendererAndDrawFrame();
1297 // Scroll down in screen coordinates with a gesture.
1298 IntSize gestureScrollDelta(0, 10);
1299 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted);
1300 m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta);
1301 m_hostImpl->scrollEnd();
1303 // The child layer should have scrolled down in its local coordinates an amount proportional to
1304 // the angle between it and the input scroll delta.
1305 IntSize expectedScrollDelta(0, gestureScrollDelta.height() * cosf(deg2rad(childLayerAngle)));
1306 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
1307 expectContains(*scrollInfo.get(), childLayerId, expectedScrollDelta);
1309 // The root layer should not have scrolled, because the input delta was close to the layer's
1310 // axis of movement.
1311 EXPECT_EQ(scrollInfo->scrolls.size(), 1u);
1315 // Now reset and scroll the same amount horizontally.
1316 m_hostImpl->rootLayer()->children()[1]->setScrollDelta(FloatSize());
1317 IntSize gestureScrollDelta(10, 0);
1318 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted);
1319 m_hostImpl->scrollBy(IntPoint(), gestureScrollDelta);
1320 m_hostImpl->scrollEnd();
1322 // The child layer should have scrolled down in its local coordinates an amount proportional to
1323 // the angle between it and the input scroll delta.
1324 IntSize expectedScrollDelta(0, -gestureScrollDelta.width() * sinf(deg2rad(childLayerAngle)));
1325 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
1326 expectContains(*scrollInfo.get(), childLayerId, expectedScrollDelta);
1328 // The root layer should have scrolled more, since the input scroll delta was mostly
1329 // orthogonal to the child layer's vertical scroll axis.
1330 IntSize expectedRootScrollDelta(gestureScrollDelta.width() * pow(cosf(deg2rad(childLayerAngle)), 2), 0);
1331 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), expectedRootScrollDelta);
1335 TEST_F(CCLayerTreeHostImplTest, scrollScaledLayer)
1337 setupScrollAndContentsLayers(IntSize(100, 100));
1339 // Scale the layer to twice its normal size.
1340 int scale = 2;
1341 WebTransformationMatrix scaleTransform;
1342 scaleTransform.scale(scale);
1343 m_hostImpl->rootLayer()->setTransform(scaleTransform);
1345 IntSize surfaceSize(50, 50);
1346 m_hostImpl->setViewportSize(surfaceSize, surfaceSize);
1347 initializeRendererAndDrawFrame();
1349 // Scroll down in screen coordinates with a gesture.
1350 IntSize scrollDelta(0, 10);
1351 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Gesture), CCInputHandlerClient::ScrollStarted);
1352 m_hostImpl->scrollBy(IntPoint(), scrollDelta);
1353 m_hostImpl->scrollEnd();
1355 // The layer should have scrolled down in its local coordinates, but half he amount.
1356 OwnPtr<CCScrollAndScaleSet> scrollInfo = m_hostImpl->processScrollDeltas();
1357 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), IntSize(0, scrollDelta.height() / scale));
1359 // Reset and scroll down with the wheel.
1360 m_hostImpl->rootLayer()->setScrollDelta(FloatSize());
1361 IntSize wheelScrollDelta(0, 10);
1362 EXPECT_EQ(m_hostImpl->scrollBegin(IntPoint(0, 0), CCInputHandlerClient::Wheel), CCInputHandlerClient::ScrollStarted);
1363 m_hostImpl->scrollBy(IntPoint(), wheelScrollDelta);
1364 m_hostImpl->scrollEnd();
1366 // The scale should not have been applied to the scroll delta.
1367 scrollInfo = m_hostImpl->processScrollDeltas();
1368 expectContains(*scrollInfo.get(), m_hostImpl->rootLayer()->id(), wheelScrollDelta);
1371 class BlendStateTrackerContext: public FakeWebGraphicsContext3D {
1372 public:
1373 BlendStateTrackerContext() : m_blend(false) { }
1375 virtual void enable(WGC3Denum cap)
1377 if (cap == GraphicsContext3D::BLEND)
1378 m_blend = true;
1381 virtual void disable(WGC3Denum cap)
1383 if (cap == GraphicsContext3D::BLEND)
1384 m_blend = false;
1387 bool blend() const { return m_blend; }
1389 private:
1390 bool m_blend;
1393 class BlendStateCheckLayer : public CCLayerImpl {
1394 public:
1395 static PassOwnPtr<BlendStateCheckLayer> create(int id, CCResourceProvider* resourceProvider) { return adoptPtr(new BlendStateCheckLayer(id, resourceProvider)); }
1397 virtual void appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuadsData) OVERRIDE
1399 m_quadsAppended = true;
1401 IntRect opaqueRect;
1402 if (opaque() || m_opaqueContents)
1403 opaqueRect = m_quadRect;
1404 else
1405 opaqueRect = m_opaqueContentRect;
1407 CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createSharedQuadState());
1408 OwnPtr<CCDrawQuad> testBlendingDrawQuad = CCTileDrawQuad::create(sharedQuadState, m_quadRect, opaqueRect, m_resourceId, IntPoint(), IntSize(1, 1), 0, false, false, false, false, false);
1409 testBlendingDrawQuad->setQuadVisibleRect(m_quadVisibleRect);
1410 EXPECT_EQ(m_blend, testBlendingDrawQuad->needsBlending());
1411 EXPECT_EQ(m_hasRenderSurface, !!renderSurface());
1412 quadSink.append(testBlendingDrawQuad.release(), appendQuadsData);
1415 void setExpectation(bool blend, bool hasRenderSurface)
1417 m_blend = blend;
1418 m_hasRenderSurface = hasRenderSurface;
1419 m_quadsAppended = false;
1422 bool quadsAppended() const { return m_quadsAppended; }
1424 void setQuadRect(const IntRect& rect) { m_quadRect = rect; }
1425 void setQuadVisibleRect(const IntRect& rect) { m_quadVisibleRect = rect; }
1426 void setOpaqueContents(bool opaque) { m_opaqueContents = opaque; }
1427 void setOpaqueContentRect(const IntRect& rect) { m_opaqueContentRect = rect; }
1429 private:
1430 explicit BlendStateCheckLayer(int id, CCResourceProvider* resourceProvider)
1431 : CCLayerImpl(id)
1432 , m_blend(false)
1433 , m_hasRenderSurface(false)
1434 , m_quadsAppended(false)
1435 , m_opaqueContents(false)
1436 , m_quadRect(5, 5, 5, 5)
1437 , m_quadVisibleRect(5, 5, 5, 5)
1438 , m_resourceId(resourceProvider->createResource(CCRenderer::ContentPool, IntSize(1, 1), GraphicsContext3D::RGBA, CCResourceProvider::TextureUsageAny))
1440 setAnchorPoint(FloatPoint(0, 0));
1441 setBounds(IntSize(10, 10));
1442 setContentBounds(IntSize(10, 10));
1443 setDrawsContent(true);
1446 bool m_blend;
1447 bool m_hasRenderSurface;
1448 bool m_quadsAppended;
1449 bool m_opaqueContents;
1450 IntRect m_quadRect;
1451 IntRect m_opaqueContentRect;
1452 IntRect m_quadVisibleRect;
1453 CCResourceProvider::ResourceId m_resourceId;
1456 TEST_F(CCLayerTreeHostImplTest, blendingOffWhenDrawingOpaqueLayers)
1459 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
1460 root->setAnchorPoint(FloatPoint(0, 0));
1461 root->setBounds(IntSize(10, 10));
1462 root->setContentBounds(root->bounds());
1463 root->setDrawsContent(false);
1464 m_hostImpl->setRootLayer(root.release());
1466 CCLayerImpl* root = m_hostImpl->rootLayer();
1468 root->addChild(BlendStateCheckLayer::create(2, m_hostImpl->resourceProvider()));
1469 BlendStateCheckLayer* layer1 = static_cast<BlendStateCheckLayer*>(root->children()[0].get());
1470 layer1->setPosition(FloatPoint(2, 2));
1472 CCLayerTreeHostImpl::FrameData frame;
1474 // Opaque layer, drawn without blending.
1475 layer1->setOpaque(true);
1476 layer1->setOpaqueContents(true);
1477 layer1->setExpectation(false, false);
1478 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1479 m_hostImpl->drawLayers(frame);
1480 EXPECT_TRUE(layer1->quadsAppended());
1481 m_hostImpl->didDrawAllLayers(frame);
1483 // Layer with translucent content, but opaque content, so drawn without blending.
1484 layer1->setOpaque(false);
1485 layer1->setOpaqueContents(true);
1486 layer1->setExpectation(false, false);
1487 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1488 m_hostImpl->drawLayers(frame);
1489 EXPECT_TRUE(layer1->quadsAppended());
1490 m_hostImpl->didDrawAllLayers(frame);
1492 // Layer with translucent content and painting, so drawn with blending.
1493 layer1->setOpaque(false);
1494 layer1->setOpaqueContents(false);
1495 layer1->setExpectation(true, false);
1496 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1497 m_hostImpl->drawLayers(frame);
1498 EXPECT_TRUE(layer1->quadsAppended());
1499 m_hostImpl->didDrawAllLayers(frame);
1501 // Layer with translucent opacity, drawn with blending.
1502 layer1->setOpaque(true);
1503 layer1->setOpaqueContents(true);
1504 layer1->setOpacity(0.5);
1505 layer1->setExpectation(true, false);
1506 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1507 m_hostImpl->drawLayers(frame);
1508 EXPECT_TRUE(layer1->quadsAppended());
1509 m_hostImpl->didDrawAllLayers(frame);
1511 // Layer with translucent opacity and painting, drawn with blending.
1512 layer1->setOpaque(true);
1513 layer1->setOpaqueContents(false);
1514 layer1->setOpacity(0.5);
1515 layer1->setExpectation(true, false);
1516 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1517 m_hostImpl->drawLayers(frame);
1518 EXPECT_TRUE(layer1->quadsAppended());
1519 m_hostImpl->didDrawAllLayers(frame);
1521 layer1->addChild(BlendStateCheckLayer::create(3, m_hostImpl->resourceProvider()));
1522 BlendStateCheckLayer* layer2 = static_cast<BlendStateCheckLayer*>(layer1->children()[0].get());
1523 layer2->setPosition(FloatPoint(4, 4));
1525 // 2 opaque layers, drawn without blending.
1526 layer1->setOpaque(true);
1527 layer1->setOpaqueContents(true);
1528 layer1->setOpacity(1);
1529 layer1->setExpectation(false, false);
1530 layer2->setOpaque(true);
1531 layer2->setOpaqueContents(true);
1532 layer2->setOpacity(1);
1533 layer2->setExpectation(false, false);
1534 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1535 m_hostImpl->drawLayers(frame);
1536 EXPECT_TRUE(layer1->quadsAppended());
1537 EXPECT_TRUE(layer2->quadsAppended());
1538 m_hostImpl->didDrawAllLayers(frame);
1540 // Parent layer with translucent content, drawn with blending.
1541 // Child layer with opaque content, drawn without blending.
1542 layer1->setOpaque(false);
1543 layer1->setOpaqueContents(false);
1544 layer1->setExpectation(true, false);
1545 layer2->setExpectation(false, false);
1546 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1547 m_hostImpl->drawLayers(frame);
1548 EXPECT_TRUE(layer1->quadsAppended());
1549 EXPECT_TRUE(layer2->quadsAppended());
1550 m_hostImpl->didDrawAllLayers(frame);
1552 // Parent layer with translucent content but opaque painting, drawn without blending.
1553 // Child layer with opaque content, drawn without blending.
1554 layer1->setOpaque(false);
1555 layer1->setOpaqueContents(true);
1556 layer1->setExpectation(false, false);
1557 layer2->setExpectation(false, false);
1558 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1559 m_hostImpl->drawLayers(frame);
1560 EXPECT_TRUE(layer1->quadsAppended());
1561 EXPECT_TRUE(layer2->quadsAppended());
1562 m_hostImpl->didDrawAllLayers(frame);
1564 // Parent layer with translucent opacity and opaque content. Since it has a
1565 // drawing child, it's drawn to a render surface which carries the opacity,
1566 // so it's itself drawn without blending.
1567 // Child layer with opaque content, drawn without blending (parent surface
1568 // carries the inherited opacity).
1569 layer1->setOpaque(true);
1570 layer1->setOpaqueContents(true);
1571 layer1->setOpacity(0.5);
1572 layer1->setExpectation(false, true);
1573 layer2->setExpectation(false, false);
1574 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1575 m_hostImpl->drawLayers(frame);
1576 EXPECT_TRUE(layer1->quadsAppended());
1577 EXPECT_TRUE(layer2->quadsAppended());
1578 m_hostImpl->didDrawAllLayers(frame);
1580 // Draw again, but with child non-opaque, to make sure
1581 // layer1 not culled.
1582 layer1->setOpaque(true);
1583 layer1->setOpaqueContents(true);
1584 layer1->setOpacity(1);
1585 layer1->setExpectation(false, false);
1586 layer2->setOpaque(true);
1587 layer2->setOpaqueContents(true);
1588 layer2->setOpacity(0.5);
1589 layer2->setExpectation(true, false);
1590 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1591 m_hostImpl->drawLayers(frame);
1592 EXPECT_TRUE(layer1->quadsAppended());
1593 EXPECT_TRUE(layer2->quadsAppended());
1594 m_hostImpl->didDrawAllLayers(frame);
1596 // A second way of making the child non-opaque.
1597 layer1->setOpaque(true);
1598 layer1->setOpacity(1);
1599 layer1->setExpectation(false, false);
1600 layer2->setOpaque(false);
1601 layer2->setOpaqueContents(false);
1602 layer2->setOpacity(1);
1603 layer2->setExpectation(true, false);
1604 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1605 m_hostImpl->drawLayers(frame);
1606 EXPECT_TRUE(layer1->quadsAppended());
1607 EXPECT_TRUE(layer2->quadsAppended());
1608 m_hostImpl->didDrawAllLayers(frame);
1610 // And when the layer says its not opaque but is painted opaque, it is not blended.
1611 layer1->setOpaque(true);
1612 layer1->setOpacity(1);
1613 layer1->setExpectation(false, false);
1614 layer2->setOpaque(false);
1615 layer2->setOpaqueContents(true);
1616 layer2->setOpacity(1);
1617 layer2->setExpectation(false, false);
1618 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1619 m_hostImpl->drawLayers(frame);
1620 EXPECT_TRUE(layer1->quadsAppended());
1621 EXPECT_TRUE(layer2->quadsAppended());
1622 m_hostImpl->didDrawAllLayers(frame);
1624 // Layer with partially opaque contents, drawn with blending.
1625 layer1->setOpaque(false);
1626 layer1->setQuadRect(IntRect(5, 5, 5, 5));
1627 layer1->setQuadVisibleRect(IntRect(5, 5, 5, 5));
1628 layer1->setOpaqueContents(false);
1629 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
1630 layer1->setExpectation(true, false);
1631 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1632 m_hostImpl->drawLayers(frame);
1633 EXPECT_TRUE(layer1->quadsAppended());
1634 m_hostImpl->didDrawAllLayers(frame);
1636 // Layer with partially opaque contents partially culled, drawn with blending.
1637 layer1->setOpaque(false);
1638 layer1->setQuadRect(IntRect(5, 5, 5, 5));
1639 layer1->setQuadVisibleRect(IntRect(5, 5, 5, 2));
1640 layer1->setOpaqueContents(false);
1641 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
1642 layer1->setExpectation(true, false);
1643 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1644 m_hostImpl->drawLayers(frame);
1645 EXPECT_TRUE(layer1->quadsAppended());
1646 m_hostImpl->didDrawAllLayers(frame);
1648 // Layer with partially opaque contents culled, drawn with blending.
1649 layer1->setOpaque(false);
1650 layer1->setQuadRect(IntRect(5, 5, 5, 5));
1651 layer1->setQuadVisibleRect(IntRect(7, 5, 3, 5));
1652 layer1->setOpaqueContents(false);
1653 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
1654 layer1->setExpectation(true, false);
1655 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1656 m_hostImpl->drawLayers(frame);
1657 EXPECT_TRUE(layer1->quadsAppended());
1658 m_hostImpl->didDrawAllLayers(frame);
1660 // Layer with partially opaque contents and translucent contents culled, drawn without blending.
1661 layer1->setOpaque(false);
1662 layer1->setQuadRect(IntRect(5, 5, 5, 5));
1663 layer1->setQuadVisibleRect(IntRect(5, 5, 2, 5));
1664 layer1->setOpaqueContents(false);
1665 layer1->setOpaqueContentRect(IntRect(5, 5, 2, 5));
1666 layer1->setExpectation(false, false);
1667 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1668 m_hostImpl->drawLayers(frame);
1669 EXPECT_TRUE(layer1->quadsAppended());
1670 m_hostImpl->didDrawAllLayers(frame);
1674 TEST_F(CCLayerTreeHostImplTest, viewportCovered)
1676 m_hostImpl->initializeRenderer(createContext(), UnthrottledUploader);
1677 m_hostImpl->setBackgroundColor(SK_ColorGRAY);
1679 IntSize viewportSize(1000, 1000);
1680 m_hostImpl->setViewportSize(viewportSize, viewportSize);
1682 m_hostImpl->setRootLayer(BlendStateCheckLayer::create(1, m_hostImpl->resourceProvider()));
1683 BlendStateCheckLayer* root = static_cast<BlendStateCheckLayer*>(m_hostImpl->rootLayer());
1684 root->setExpectation(false, true);
1685 root->setOpaque(true);
1687 // No gutter rects
1689 IntRect layerRect(0, 0, 1000, 1000);
1690 root->setPosition(layerRect.location());
1691 root->setBounds(layerRect.size());
1692 root->setContentBounds(layerRect.size());
1693 root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
1694 root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
1696 CCLayerTreeHostImpl::FrameData frame;
1697 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1698 ASSERT_EQ(1u, frame.renderPasses.size());
1700 size_t numGutterQuads = 0;
1701 for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
1702 numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
1703 EXPECT_EQ(0u, numGutterQuads);
1704 EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size());
1706 verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize));
1707 m_hostImpl->didDrawAllLayers(frame);
1710 // Empty visible content area (fullscreen gutter rect)
1712 IntRect layerRect(0, 0, 0, 0);
1713 root->setPosition(layerRect.location());
1714 root->setBounds(layerRect.size());
1715 root->setContentBounds(layerRect.size());
1716 root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
1717 root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
1719 CCLayerTreeHostImpl::FrameData frame;
1720 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1721 ASSERT_EQ(1u, frame.renderPasses.size());
1722 m_hostImpl->didDrawAllLayers(frame);
1724 size_t numGutterQuads = 0;
1725 for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
1726 numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
1727 EXPECT_EQ(1u, numGutterQuads);
1728 EXPECT_EQ(1u, frame.renderPasses[0]->quadList().size());
1730 verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize));
1731 m_hostImpl->didDrawAllLayers(frame);
1734 // Content area in middle of clip rect (four surrounding gutter rects)
1736 IntRect layerRect(500, 500, 200, 200);
1737 root->setPosition(layerRect.location());
1738 root->setBounds(layerRect.size());
1739 root->setContentBounds(layerRect.size());
1740 root->setQuadRect(IntRect(IntPoint(), layerRect.size()));
1741 root->setQuadVisibleRect(IntRect(IntPoint(), layerRect.size()));
1743 CCLayerTreeHostImpl::FrameData frame;
1744 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1745 ASSERT_EQ(1u, frame.renderPasses.size());
1747 size_t numGutterQuads = 0;
1748 for (size_t i = 0; i < frame.renderPasses[0]->quadList().size(); ++i)
1749 numGutterQuads += (frame.renderPasses[0]->quadList()[i]->material() == CCDrawQuad::SolidColor) ? 1 : 0;
1750 EXPECT_EQ(4u, numGutterQuads);
1751 EXPECT_EQ(5u, frame.renderPasses[0]->quadList().size());
1753 verifyQuadsExactlyCoverRect(frame.renderPasses[0]->quadList(), IntRect(-layerRect.location(), viewportSize));
1754 m_hostImpl->didDrawAllLayers(frame);
1760 class ReshapeTrackerContext: public FakeWebGraphicsContext3D {
1761 public:
1762 ReshapeTrackerContext() : m_reshapeCalled(false) { }
1764 virtual void reshape(int width, int height)
1766 m_reshapeCalled = true;
1769 bool reshapeCalled() const { return m_reshapeCalled; }
1771 private:
1772 bool m_reshapeCalled;
1775 class FakeDrawableCCLayerImpl: public CCLayerImpl {
1776 public:
1777 explicit FakeDrawableCCLayerImpl(int id) : CCLayerImpl(id) { }
1780 // Only reshape when we know we are going to draw. Otherwise, the reshape
1781 // can leave the window at the wrong size if we never draw and the proper
1782 // viewport size is never set.
1783 TEST_F(CCLayerTreeHostImplTest, reshapeNotCalledUntilDraw)
1785 OwnPtr<CCGraphicsContext> ccContext = FakeWebCompositorOutputSurface::create(adoptPtr(new ReshapeTrackerContext));
1786 ReshapeTrackerContext* reshapeTracker = static_cast<ReshapeTrackerContext*>(ccContext->context3D());
1787 m_hostImpl->initializeRenderer(ccContext.release(), UnthrottledUploader);
1789 CCLayerImpl* root = new FakeDrawableCCLayerImpl(1);
1790 root->setAnchorPoint(FloatPoint(0, 0));
1791 root->setBounds(IntSize(10, 10));
1792 root->setDrawsContent(true);
1793 m_hostImpl->setRootLayer(adoptPtr(root));
1794 EXPECT_FALSE(reshapeTracker->reshapeCalled());
1796 CCLayerTreeHostImpl::FrameData frame;
1797 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1798 m_hostImpl->drawLayers(frame);
1799 EXPECT_TRUE(reshapeTracker->reshapeCalled());
1800 m_hostImpl->didDrawAllLayers(frame);
1803 class PartialSwapTrackerContext : public FakeWebGraphicsContext3D {
1804 public:
1805 virtual void postSubBufferCHROMIUM(int x, int y, int width, int height)
1807 m_partialSwapRect = IntRect(x, y, width, height);
1810 virtual WebString getString(WGC3Denum name)
1812 if (name == GraphicsContext3D::EXTENSIONS)
1813 return WebString("GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibility");
1815 return WebString();
1818 IntRect partialSwapRect() const { return m_partialSwapRect; }
1820 private:
1821 IntRect m_partialSwapRect;
1824 // Make sure damage tracking propagates all the way to the graphics context,
1825 // where it should request to swap only the subBuffer that is damaged.
1826 TEST_F(CCLayerTreeHostImplTest, partialSwapReceivesDamageRect)
1828 OwnPtr<CCGraphicsContext> ccContext = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapTrackerContext));
1829 PartialSwapTrackerContext* partialSwapTracker = static_cast<PartialSwapTrackerContext*>(ccContext->context3D());
1831 // This test creates its own CCLayerTreeHostImpl, so
1832 // that we can force partial swap enabled.
1833 CCLayerTreeSettings settings;
1834 CCSettings::setPartialSwapEnabled(true);
1835 OwnPtr<CCLayerTreeHostImpl> layerTreeHostImpl = CCLayerTreeHostImpl::create(settings, this);
1836 layerTreeHostImpl->initializeRenderer(ccContext.release(), UnthrottledUploader);
1837 layerTreeHostImpl->setViewportSize(IntSize(500, 500), IntSize(500, 500));
1839 CCLayerImpl* root = new FakeDrawableCCLayerImpl(1);
1840 CCLayerImpl* child = new FakeDrawableCCLayerImpl(2);
1841 child->setPosition(FloatPoint(12, 13));
1842 child->setAnchorPoint(FloatPoint(0, 0));
1843 child->setBounds(IntSize(14, 15));
1844 child->setContentBounds(IntSize(14, 15));
1845 child->setDrawsContent(true);
1846 root->setAnchorPoint(FloatPoint(0, 0));
1847 root->setBounds(IntSize(500, 500));
1848 root->setContentBounds(IntSize(500, 500));
1849 root->setDrawsContent(true);
1850 root->addChild(adoptPtr(child));
1851 layerTreeHostImpl->setRootLayer(adoptPtr(root));
1853 CCLayerTreeHostImpl::FrameData frame;
1855 // First frame, the entire screen should get swapped.
1856 EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1857 layerTreeHostImpl->drawLayers(frame);
1858 layerTreeHostImpl->didDrawAllLayers(frame);
1859 layerTreeHostImpl->swapBuffers();
1860 IntRect actualSwapRect = partialSwapTracker->partialSwapRect();
1861 IntRect expectedSwapRect = IntRect(IntPoint::zero(), IntSize(500, 500));
1862 EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1863 EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1864 EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1865 EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1867 // Second frame, only the damaged area should get swapped. Damage should be the union
1868 // of old and new child rects.
1869 // expected damage rect: IntRect(IntPoint::zero(), IntSize(26, 28));
1870 // expected swap rect: vertically flipped, with origin at bottom left corner.
1871 child->setPosition(FloatPoint(0, 0));
1872 EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1873 layerTreeHostImpl->drawLayers(frame);
1874 m_hostImpl->didDrawAllLayers(frame);
1875 layerTreeHostImpl->swapBuffers();
1876 actualSwapRect = partialSwapTracker->partialSwapRect();
1877 expectedSwapRect = IntRect(IntPoint(0, 500-28), IntSize(26, 28));
1878 EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1879 EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1880 EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1881 EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1883 // Make sure that partial swap is constrained to the viewport dimensions
1884 // expected damage rect: IntRect(IntPoint::zero(), IntSize(500, 500));
1885 // expected swap rect: flipped damage rect, but also clamped to viewport
1886 layerTreeHostImpl->setViewportSize(IntSize(10, 10), IntSize(10, 10));
1887 root->setOpacity(0.7f); // this will damage everything
1888 EXPECT_TRUE(layerTreeHostImpl->prepareToDraw(frame));
1889 layerTreeHostImpl->drawLayers(frame);
1890 m_hostImpl->didDrawAllLayers(frame);
1891 layerTreeHostImpl->swapBuffers();
1892 actualSwapRect = partialSwapTracker->partialSwapRect();
1893 expectedSwapRect = IntRect(IntPoint::zero(), IntSize(10, 10));
1894 EXPECT_EQ(expectedSwapRect.x(), actualSwapRect.x());
1895 EXPECT_EQ(expectedSwapRect.y(), actualSwapRect.y());
1896 EXPECT_EQ(expectedSwapRect.width(), actualSwapRect.width());
1897 EXPECT_EQ(expectedSwapRect.height(), actualSwapRect.height());
1900 TEST_F(CCLayerTreeHostImplTest, rootLayerDoesntCreateExtraSurface)
1902 CCLayerImpl* root = new FakeDrawableCCLayerImpl(1);
1903 CCLayerImpl* child = new FakeDrawableCCLayerImpl(2);
1904 child->setAnchorPoint(FloatPoint(0, 0));
1905 child->setBounds(IntSize(10, 10));
1906 child->setContentBounds(IntSize(10, 10));
1907 child->setDrawsContent(true);
1908 root->setAnchorPoint(FloatPoint(0, 0));
1909 root->setBounds(IntSize(10, 10));
1910 root->setContentBounds(IntSize(10, 10));
1911 root->setDrawsContent(true);
1912 root->setOpacity(0.7f);
1913 root->addChild(adoptPtr(child));
1915 m_hostImpl->setRootLayer(adoptPtr(root));
1917 CCLayerTreeHostImpl::FrameData frame;
1919 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
1920 EXPECT_EQ(1u, frame.renderSurfaceLayerList->size());
1921 EXPECT_EQ(1u, frame.renderPasses.size());
1922 m_hostImpl->didDrawAllLayers(frame);
1925 } // namespace
1927 class FakeLayerWithQuads : public CCLayerImpl {
1928 public:
1929 static PassOwnPtr<FakeLayerWithQuads> create(int id) { return adoptPtr(new FakeLayerWithQuads(id)); }
1931 virtual void appendQuads(CCQuadSink& quadSink, CCAppendQuadsData& appendQuadsData) OVERRIDE
1933 CCSharedQuadState* sharedQuadState = quadSink.useSharedQuadState(createSharedQuadState());
1935 SkColor gray = SkColorSetRGB(100, 100, 100);
1936 IntRect quadRect(IntPoint(0, 0), contentBounds());
1937 OwnPtr<CCDrawQuad> myQuad = CCSolidColorDrawQuad::create(sharedQuadState, quadRect, gray);
1938 quadSink.append(myQuad.release(), appendQuadsData);
1941 private:
1942 FakeLayerWithQuads(int id)
1943 : CCLayerImpl(id)
1948 namespace {
1950 class MockContext : public FakeWebGraphicsContext3D {
1951 public:
1952 MOCK_METHOD1(useProgram, void(WebGLId program));
1953 MOCK_METHOD5(uniform4f, void(WGC3Dint location, WGC3Dfloat x, WGC3Dfloat y, WGC3Dfloat z, WGC3Dfloat w));
1954 MOCK_METHOD4(uniformMatrix4fv, void(WGC3Dint location, WGC3Dsizei count, WGC3Dboolean transpose, const WGC3Dfloat* value));
1955 MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
1956 MOCK_METHOD1(getString, WebString(WGC3Denum name));
1957 MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebString());
1958 MOCK_METHOD1(enable, void(WGC3Denum cap));
1959 MOCK_METHOD1(disable, void(WGC3Denum cap));
1960 MOCK_METHOD4(scissor, void(WGC3Dint x, WGC3Dint y, WGC3Dsizei width, WGC3Dsizei height));
1963 class MockContextHarness {
1964 private:
1965 MockContext* m_context;
1966 public:
1967 MockContextHarness(MockContext* context)
1968 : m_context(context)
1970 // Catch "uninteresting" calls
1971 EXPECT_CALL(*m_context, useProgram(_))
1972 .Times(0);
1974 EXPECT_CALL(*m_context, drawElements(_, _, _, _))
1975 .Times(0);
1977 // These are not asserted
1978 EXPECT_CALL(*m_context, uniformMatrix4fv(_, _, _, _))
1979 .WillRepeatedly(Return());
1981 EXPECT_CALL(*m_context, uniform4f(_, _, _, _, _))
1982 .WillRepeatedly(Return());
1984 // Any other strings are empty
1985 EXPECT_CALL(*m_context, getString(_))
1986 .WillRepeatedly(Return(WebString()));
1988 // Support for partial swap, if needed
1989 EXPECT_CALL(*m_context, getString(GraphicsContext3D::EXTENSIONS))
1990 .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
1992 EXPECT_CALL(*m_context, getRequestableExtensionsCHROMIUM())
1993 .WillRepeatedly(Return(WebString("GL_CHROMIUM_post_sub_buffer")));
1995 // Any un-sanctioned calls to enable() are OK
1996 EXPECT_CALL(*m_context, enable(_))
1997 .WillRepeatedly(Return());
1999 // Any un-sanctioned calls to disable() are OK
2000 EXPECT_CALL(*m_context, disable(_))
2001 .WillRepeatedly(Return());
2004 void mustDrawSolidQuad()
2006 EXPECT_CALL(*m_context, drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0))
2007 .WillOnce(Return())
2008 .RetiresOnSaturation();
2010 // 1 is hardcoded return value of fake createProgram()
2011 EXPECT_CALL(*m_context, useProgram(1))
2012 .WillOnce(Return())
2013 .RetiresOnSaturation();
2017 void mustSetScissor(int x, int y, int width, int height)
2019 EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST))
2020 .WillRepeatedly(Return());
2022 EXPECT_CALL(*m_context, scissor(x, y, width, height))
2023 .Times(AtLeast(1))
2024 .WillRepeatedly(Return());
2027 void mustSetNoScissor()
2029 EXPECT_CALL(*m_context, disable(GraphicsContext3D::SCISSOR_TEST))
2030 .WillRepeatedly(Return());
2032 EXPECT_CALL(*m_context, enable(GraphicsContext3D::SCISSOR_TEST))
2033 .Times(0);
2035 EXPECT_CALL(*m_context, scissor(_, _, _, _))
2036 .Times(0);
2040 TEST_F(CCLayerTreeHostImplTest, noPartialSwap)
2042 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new MockContext));
2043 MockContext* mockContext = static_cast<MockContext*>(context->context3D());
2044 MockContextHarness harness(mockContext);
2046 harness.mustDrawSolidQuad();
2047 harness.mustSetScissor(0, 0, 10, 10);
2049 // Run test case
2050 OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, context.release(), FakeLayerWithQuads::create(1));
2052 CCLayerTreeHostImpl::FrameData frame;
2053 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2054 myHostImpl->drawLayers(frame);
2055 myHostImpl->didDrawAllLayers(frame);
2056 Mock::VerifyAndClearExpectations(&mockContext);
2059 TEST_F(CCLayerTreeHostImplTest, partialSwap)
2061 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new MockContext));
2062 MockContext* mockContext = static_cast<MockContext*>(context->context3D());
2063 MockContextHarness harness(mockContext);
2065 OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(true, context.release(), FakeLayerWithQuads::create(1));
2067 // The first frame is not a partially-swapped one.
2068 harness.mustSetScissor(0, 0, 10, 10);
2069 harness.mustDrawSolidQuad();
2071 CCLayerTreeHostImpl::FrameData frame;
2072 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2073 myHostImpl->drawLayers(frame);
2074 myHostImpl->didDrawAllLayers(frame);
2076 Mock::VerifyAndClearExpectations(&mockContext);
2078 // Damage a portion of the frame.
2079 myHostImpl->rootLayer()->setUpdateRect(IntRect(0, 0, 2, 3));
2081 // The second frame will be partially-swapped (the y coordinates are flipped).
2082 harness.mustSetScissor(0, 7, 2, 3);
2083 harness.mustDrawSolidQuad();
2085 CCLayerTreeHostImpl::FrameData frame;
2086 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2087 myHostImpl->drawLayers(frame);
2088 myHostImpl->didDrawAllLayers(frame);
2090 Mock::VerifyAndClearExpectations(&mockContext);
2093 class PartialSwapContext : public FakeWebGraphicsContext3D {
2094 public:
2095 WebString getString(WGC3Denum name)
2097 if (name == GraphicsContext3D::EXTENSIONS)
2098 return WebString("GL_CHROMIUM_post_sub_buffer");
2099 return WebString();
2102 WebString getRequestableExtensionsCHROMIUM()
2104 return WebString("GL_CHROMIUM_post_sub_buffer");
2107 // Unlimited texture size.
2108 virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value)
2110 if (pname == WebCore::GraphicsContext3D::MAX_TEXTURE_SIZE)
2111 *value = 8192;
2115 static PassOwnPtr<CCLayerTreeHostImpl> setupLayersForOpacity(bool partialSwap, CCLayerTreeHostImplClient* client)
2117 CCSettings::setPartialSwapEnabled(partialSwap);
2119 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext));
2121 CCLayerTreeSettings settings;
2122 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, client);
2123 myHostImpl->initializeRenderer(context.release(), UnthrottledUploader);
2124 myHostImpl->setViewportSize(IntSize(100, 100), IntSize(100, 100));
2127 Layers are created as follows:
2129 +--------------------+
2130 | 1 |
2131 | +-----------+ |
2132 | | 2 | |
2133 | | +-------------------+
2134 | | | 3 |
2135 | | +-------------------+
2136 | | | |
2137 | +-----------+ |
2140 +--------------------+
2142 Layers 1, 2 have render surfaces
2144 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
2145 OwnPtr<CCLayerImpl> child = CCLayerImpl::create(2);
2146 OwnPtr<CCLayerImpl> grandChild = FakeLayerWithQuads::create(3);
2148 IntRect rootRect(0, 0, 100, 100);
2149 IntRect childRect(10, 10, 50, 50);
2150 IntRect grandChildRect(5, 5, 150, 150);
2152 root->createRenderSurface();
2153 root->setAnchorPoint(FloatPoint(0, 0));
2154 root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
2155 root->setBounds(IntSize(rootRect.width(), rootRect.height()));
2156 root->setContentBounds(root->bounds());
2157 root->setVisibleContentRect(rootRect);
2158 root->setDrawsContent(false);
2159 root->renderSurface()->setContentRect(IntRect(IntPoint(), IntSize(rootRect.width(), rootRect.height())));
2161 child->setAnchorPoint(FloatPoint(0, 0));
2162 child->setPosition(FloatPoint(childRect.x(), childRect.y()));
2163 child->setOpacity(0.5f);
2164 child->setBounds(IntSize(childRect.width(), childRect.height()));
2165 child->setContentBounds(child->bounds());
2166 child->setVisibleContentRect(childRect);
2167 child->setDrawsContent(false);
2169 grandChild->setAnchorPoint(FloatPoint(0, 0));
2170 grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
2171 grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
2172 grandChild->setContentBounds(grandChild->bounds());
2173 grandChild->setVisibleContentRect(grandChildRect);
2174 grandChild->setDrawsContent(true);
2176 child->addChild(grandChild.release());
2177 root->addChild(child.release());
2179 myHostImpl->setRootLayer(root.release());
2180 return myHostImpl.release();
2183 TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorPartialSwap)
2185 OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(true, this);
2188 CCLayerTreeHostImpl::FrameData frame;
2189 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2191 // Just for consistency, the most interesting stuff already happened
2192 myHostImpl->drawLayers(frame);
2193 myHostImpl->didDrawAllLayers(frame);
2195 // Verify all quads have been computed
2196 ASSERT_EQ(2U, frame.renderPasses.size());
2197 ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
2198 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
2199 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
2200 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
2204 TEST_F(CCLayerTreeHostImplTest, contributingLayerEmptyScissorNoPartialSwap)
2206 OwnPtr<CCLayerTreeHostImpl> myHostImpl = setupLayersForOpacity(false, this);
2209 CCLayerTreeHostImpl::FrameData frame;
2210 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2212 // Just for consistency, the most interesting stuff already happened
2213 myHostImpl->drawLayers(frame);
2214 myHostImpl->didDrawAllLayers(frame);
2216 // Verify all quads have been computed
2217 ASSERT_EQ(2U, frame.renderPasses.size());
2218 ASSERT_EQ(1U, frame.renderPasses[0]->quadList().size());
2219 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
2220 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
2221 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
2225 // Make sure that context lost notifications are propagated through the tree.
2226 class ContextLostNotificationCheckLayer : public CCLayerImpl {
2227 public:
2228 static PassOwnPtr<ContextLostNotificationCheckLayer> create(int id) { return adoptPtr(new ContextLostNotificationCheckLayer(id)); }
2230 virtual void didLoseContext() OVERRIDE
2232 m_didLoseContextCalled = true;
2235 bool didLoseContextCalled() const { return m_didLoseContextCalled; }
2237 private:
2238 explicit ContextLostNotificationCheckLayer(int id)
2239 : CCLayerImpl(id)
2240 , m_didLoseContextCalled(false)
2244 bool m_didLoseContextCalled;
2247 TEST_F(CCLayerTreeHostImplTest, contextLostAndRestoredNotificationSentToAllLayers)
2249 m_hostImpl->setRootLayer(ContextLostNotificationCheckLayer::create(1));
2250 ContextLostNotificationCheckLayer* root = static_cast<ContextLostNotificationCheckLayer*>(m_hostImpl->rootLayer());
2252 root->addChild(ContextLostNotificationCheckLayer::create(1));
2253 ContextLostNotificationCheckLayer* layer1 = static_cast<ContextLostNotificationCheckLayer*>(root->children()[0].get());
2255 layer1->addChild(ContextLostNotificationCheckLayer::create(2));
2256 ContextLostNotificationCheckLayer* layer2 = static_cast<ContextLostNotificationCheckLayer*>(layer1->children()[0].get());
2258 EXPECT_FALSE(root->didLoseContextCalled());
2259 EXPECT_FALSE(layer1->didLoseContextCalled());
2260 EXPECT_FALSE(layer2->didLoseContextCalled());
2262 m_hostImpl->initializeRenderer(createContext(), UnthrottledUploader);
2264 EXPECT_TRUE(root->didLoseContextCalled());
2265 EXPECT_TRUE(layer1->didLoseContextCalled());
2266 EXPECT_TRUE(layer2->didLoseContextCalled());
2269 TEST_F(CCLayerTreeHostImplTest, finishAllRenderingAfterContextLost)
2271 CCLayerTreeSettings settings;
2272 m_hostImpl = CCLayerTreeHostImpl::create(settings, this);
2274 // The context initialization will fail, but we should still be able to call finishAllRendering() without any ill effects.
2275 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3DMakeCurrentFails)), UnthrottledUploader);
2276 m_hostImpl->finishAllRendering();
2279 // Fake WebGraphicsContext3D that will cause a failure if trying to use a
2280 // resource that wasn't created by it (resources created by
2281 // FakeWebGraphicsContext3D have an id of 1).
2282 class StrictWebGraphicsContext3D : public FakeWebGraphicsContext3D {
2283 public:
2284 StrictWebGraphicsContext3D()
2285 : FakeWebGraphicsContext3D()
2287 m_nextTextureId = 7; // Start allocating texture ids larger than any other resource IDs so we can tell if someone's mixing up their resource types.
2290 virtual WebGLId createBuffer() { return 2; }
2291 virtual WebGLId createFramebuffer() { return 3; }
2292 virtual WebGLId createProgram() { return 4; }
2293 virtual WebGLId createRenderbuffer() { return 5; }
2294 virtual WebGLId createShader(WGC3Denum) { return 6; }
2296 virtual void deleteBuffer(WebGLId id)
2298 if (id != 2)
2299 ADD_FAILURE() << "Trying to delete buffer id " << id;
2302 virtual void deleteFramebuffer(WebGLId id)
2304 if (id != 3)
2305 ADD_FAILURE() << "Trying to delete framebuffer id " << id;
2308 virtual void deleteProgram(WebGLId id)
2310 if (id != 4)
2311 ADD_FAILURE() << "Trying to delete program id " << id;
2314 virtual void deleteRenderbuffer(WebGLId id)
2316 if (id != 5)
2317 ADD_FAILURE() << "Trying to delete renderbuffer id " << id;
2320 virtual void deleteShader(WebGLId id)
2322 if (id != 6)
2323 ADD_FAILURE() << "Trying to delete shader id " << id;
2326 virtual WebGLId createTexture()
2328 unsigned textureId = FakeWebGraphicsContext3D::createTexture();
2329 m_allocatedTextureIds.add(textureId);
2330 return textureId;
2332 virtual void deleteTexture(WebGLId id)
2334 if (!m_allocatedTextureIds.contains(id))
2335 ADD_FAILURE() << "Trying to delete texture id " << id;
2336 m_allocatedTextureIds.remove(id);
2339 virtual void bindBuffer(WGC3Denum, WebGLId id)
2341 if (id != 2 && id)
2342 ADD_FAILURE() << "Trying to bind buffer id " << id;
2345 virtual void bindFramebuffer(WGC3Denum, WebGLId id)
2347 if (id != 3 && id)
2348 ADD_FAILURE() << "Trying to bind framebuffer id " << id;
2351 virtual void useProgram(WebGLId id)
2353 if (id != 4)
2354 ADD_FAILURE() << "Trying to use program id " << id;
2357 virtual void bindRenderbuffer(WGC3Denum, WebGLId id)
2359 if (id != 5 && id)
2360 ADD_FAILURE() << "Trying to bind renderbuffer id " << id;
2363 virtual void attachShader(WebGLId program, WebGLId shader)
2365 if ((program != 4) || (shader != 6))
2366 ADD_FAILURE() << "Trying to attach shader id " << shader << " to program id " << program;
2369 virtual void bindTexture(WGC3Denum, WebGLId id)
2371 if (id && !m_allocatedTextureIds.contains(id))
2372 ADD_FAILURE() << "Trying to bind texture id " << id;
2375 private:
2376 HashSet<unsigned> m_allocatedTextureIds;
2379 // Fake video frame that represents a 4x4 YUV video frame.
2380 class FakeVideoFrame: public WebVideoFrame {
2381 public:
2382 FakeVideoFrame() : m_textureId(0) { memset(m_data, 0x80, sizeof(m_data)); }
2383 virtual ~FakeVideoFrame() { }
2384 virtual Format format() const { return m_textureId ? FormatNativeTexture : FormatYV12; }
2385 virtual unsigned width() const { return 4; }
2386 virtual unsigned height() const { return 4; }
2387 virtual unsigned planes() const { return 3; }
2388 virtual int stride(unsigned plane) const { return 4; }
2389 virtual const void* data(unsigned plane) const { return m_data; }
2390 virtual unsigned textureId() const { return m_textureId; }
2391 virtual unsigned textureTarget() const { return m_textureId ? GraphicsContext3D::TEXTURE_2D : 0; }
2393 void setTextureId(unsigned id) { m_textureId = id; }
2395 private:
2396 char m_data[16];
2397 unsigned m_textureId;
2400 // Fake video frame provider that always provides the same FakeVideoFrame.
2401 class FakeVideoFrameProvider: public WebVideoFrameProvider {
2402 public:
2403 FakeVideoFrameProvider() : m_frame(0), m_client(0) { }
2404 virtual ~FakeVideoFrameProvider()
2406 if (m_client)
2407 m_client->stopUsingProvider();
2410 virtual void setVideoFrameProviderClient(Client* client) { m_client = client; }
2411 virtual WebVideoFrame* getCurrentFrame() { return m_frame; }
2412 virtual void putCurrentFrame(WebVideoFrame*) { }
2414 void setFrame(WebVideoFrame* frame) { m_frame = frame; }
2416 private:
2417 WebVideoFrame* m_frame;
2418 Client* m_client;
2421 class StrictWebGraphicsContext3DWithIOSurface : public StrictWebGraphicsContext3D {
2422 public:
2423 virtual WebString getString(WGC3Denum name) OVERRIDE
2425 if (name == WebCore::GraphicsContext3D::EXTENSIONS)
2426 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2428 return WebString();
2432 class FakeWebGraphicsContext3DWithIOSurface : public FakeWebGraphicsContext3D {
2433 public:
2434 virtual WebString getString(WGC3Denum name) OVERRIDE
2436 if (name == WebCore::GraphicsContext3D::EXTENSIONS)
2437 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2439 return WebString();
2443 class FakeWebScrollbarThemeGeometryNonEmpty : public FakeWebScrollbarThemeGeometry {
2444 virtual WebRect trackRect(WebScrollbar*) OVERRIDE { return WebRect(0, 0, 10, 10); }
2445 virtual WebRect thumbRect(WebScrollbar*) OVERRIDE { return WebRect(0, 5, 5, 2); }
2446 virtual void splitTrack(WebScrollbar*, const WebRect& track, WebRect& startTrack, WebRect& thumb, WebRect& endTrack) OVERRIDE
2448 thumb = WebRect(0, 5, 5, 2);
2449 startTrack = WebRect(0, 5, 0, 5);
2450 endTrack = WebRect(0, 0, 0, 5);
2454 class FakeScrollbarLayerImpl : public CCScrollbarLayerImpl {
2455 public:
2456 static PassOwnPtr<FakeScrollbarLayerImpl> create(int id)
2458 return adoptPtr(new FakeScrollbarLayerImpl(id));
2461 void createResources(CCResourceProvider* provider)
2463 ASSERT(provider);
2464 int pool = 0;
2465 IntSize size(10, 10);
2466 GC3Denum format = GraphicsContext3D::RGBA;
2467 CCResourceProvider::TextureUsageHint hint = CCResourceProvider::TextureUsageAny;
2468 setScrollbarGeometry(CCScrollbarGeometryFixedThumb::create(FakeWebScrollbarThemeGeometryNonEmpty::create()));
2470 setBackTrackResourceId(provider->createResource(pool, size, format, hint));
2471 setForeTrackResourceId(provider->createResource(pool, size, format, hint));
2472 setThumbResourceId(provider->createResource(pool, size, format, hint));
2475 protected:
2476 explicit FakeScrollbarLayerImpl(int id)
2477 : CCScrollbarLayerImpl(id)
2482 TEST_F(CCLayerTreeHostImplTest, dontUseOldResourcesAfterLostContext)
2484 OwnPtr<CCLayerImpl> rootLayer(CCLayerImpl::create(1));
2485 rootLayer->setBounds(IntSize(10, 10));
2486 rootLayer->setAnchorPoint(FloatPoint(0, 0));
2488 OwnPtr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(2);
2489 tileLayer->setBounds(IntSize(10, 10));
2490 tileLayer->setAnchorPoint(FloatPoint(0, 0));
2491 tileLayer->setContentBounds(IntSize(10, 10));
2492 tileLayer->setDrawsContent(true);
2493 tileLayer->setSkipsDraw(false);
2494 OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels));
2495 tilingData->setBounds(IntSize(10, 10));
2496 tileLayer->setTilingData(*tilingData);
2497 tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10));
2498 rootLayer->addChild(tileLayer.release());
2500 OwnPtr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(3);
2501 textureLayer->setBounds(IntSize(10, 10));
2502 textureLayer->setAnchorPoint(FloatPoint(0, 0));
2503 textureLayer->setContentBounds(IntSize(10, 10));
2504 textureLayer->setDrawsContent(true);
2505 textureLayer->setTextureId(1);
2506 rootLayer->addChild(textureLayer.release());
2508 FakeVideoFrame videoFrame;
2509 FakeVideoFrameProvider provider;
2510 provider.setFrame(&videoFrame);
2511 OwnPtr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(4, &provider);
2512 videoLayer->setBounds(IntSize(10, 10));
2513 videoLayer->setAnchorPoint(FloatPoint(0, 0));
2514 videoLayer->setContentBounds(IntSize(10, 10));
2515 videoLayer->setDrawsContent(true);
2516 videoLayer->setLayerTreeHostImpl(m_hostImpl.get());
2517 rootLayer->addChild(videoLayer.release());
2519 FakeVideoFrame hwVideoFrame;
2520 FakeVideoFrameProvider hwProvider;
2521 hwProvider.setFrame(&hwVideoFrame);
2522 OwnPtr<CCVideoLayerImpl> hwVideoLayer = CCVideoLayerImpl::create(5, &hwProvider);
2523 hwVideoLayer->setBounds(IntSize(10, 10));
2524 hwVideoLayer->setAnchorPoint(FloatPoint(0, 0));
2525 hwVideoLayer->setContentBounds(IntSize(10, 10));
2526 hwVideoLayer->setDrawsContent(true);
2527 hwVideoLayer->setLayerTreeHostImpl(m_hostImpl.get());
2528 rootLayer->addChild(hwVideoLayer.release());
2530 OwnPtr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::create(6);
2531 ioSurfaceLayer->setBounds(IntSize(10, 10));
2532 ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0));
2533 ioSurfaceLayer->setContentBounds(IntSize(10, 10));
2534 ioSurfaceLayer->setDrawsContent(true);
2535 ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10));
2536 ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get());
2537 rootLayer->addChild(ioSurfaceLayer.release());
2539 OwnPtr<CCHeadsUpDisplayLayerImpl> hudLayer = CCHeadsUpDisplayLayerImpl::create(7);
2540 hudLayer->setBounds(IntSize(10, 10));
2541 hudLayer->setAnchorPoint(FloatPoint(0, 0));
2542 hudLayer->setContentBounds(IntSize(10, 10));
2543 hudLayer->setDrawsContent(true);
2544 hudLayer->setLayerTreeHostImpl(m_hostImpl.get());
2545 rootLayer->addChild(hudLayer.release());
2547 OwnPtr<FakeScrollbarLayerImpl> scrollbarLayer(FakeScrollbarLayerImpl::create(8));
2548 scrollbarLayer->setLayerTreeHostImpl(m_hostImpl.get());
2549 scrollbarLayer->setBounds(IntSize(10, 10));
2550 scrollbarLayer->setContentBounds(IntSize(10, 10));
2551 scrollbarLayer->setDrawsContent(true);
2552 scrollbarLayer->setLayerTreeHostImpl(m_hostImpl.get());
2553 scrollbarLayer->createResources(m_hostImpl->resourceProvider());
2554 rootLayer->addChild(scrollbarLayer.release());
2556 // Use a context that supports IOSurfaces
2557 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new FakeWebGraphicsContext3DWithIOSurface)), UnthrottledUploader);
2559 hwVideoFrame.setTextureId(m_hostImpl->resourceProvider()->graphicsContext3D()->createTexture());
2561 m_hostImpl->setRootLayer(rootLayer.release());
2563 CCLayerTreeHostImpl::FrameData frame;
2564 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
2565 m_hostImpl->drawLayers(frame);
2566 m_hostImpl->didDrawAllLayers(frame);
2567 m_hostImpl->swapBuffers();
2569 unsigned numResources = m_hostImpl->resourceProvider()->numResources();
2571 // Lose the context, replacing it with a StrictWebGraphicsContext3DWithIOSurface,
2572 // that will warn if any resource from the previous context gets used.
2573 m_hostImpl->initializeRenderer(FakeWebCompositorOutputSurface::create(adoptPtr(new StrictWebGraphicsContext3DWithIOSurface)), UnthrottledUploader);
2575 // Create dummy resources so that looking up an old resource will get an
2576 // invalid texture id mapping.
2577 for (unsigned i = 0; i < numResources; ++i)
2578 m_hostImpl->resourceProvider()->createResourceFromExternalTexture(1);
2580 // The WebVideoFrameProvider is expected to recreate its textures after a
2581 // lost context (or not serve a frame).
2582 hwProvider.setFrame(0);
2584 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
2585 m_hostImpl->drawLayers(frame);
2586 m_hostImpl->didDrawAllLayers(frame);
2587 m_hostImpl->swapBuffers();
2589 hwVideoFrame.setTextureId(m_hostImpl->resourceProvider()->graphicsContext3D()->createTexture());
2590 hwProvider.setFrame(&hwVideoFrame);
2592 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
2593 m_hostImpl->drawLayers(frame);
2594 m_hostImpl->didDrawAllLayers(frame);
2595 m_hostImpl->swapBuffers();
2598 // Fake WebGraphicsContext3D that tracks the number of textures in use.
2599 class TrackingWebGraphicsContext3D : public FakeWebGraphicsContext3D {
2600 public:
2601 TrackingWebGraphicsContext3D()
2602 : FakeWebGraphicsContext3D()
2603 , m_numTextures(0)
2606 virtual WebGLId createTexture() OVERRIDE
2608 WebGLId id = FakeWebGraphicsContext3D::createTexture();
2610 m_textures.set(id, true);
2611 ++m_numTextures;
2612 return id;
2615 virtual void deleteTexture(WebGLId id) OVERRIDE
2617 if (!m_textures.get(id))
2618 return;
2620 m_textures.set(id, false);
2621 --m_numTextures;
2624 virtual WebString getString(WGC3Denum name) OVERRIDE
2626 if (name == WebCore::GraphicsContext3D::EXTENSIONS)
2627 return WebString("GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
2629 return WebString();
2632 unsigned numTextures() const { return m_numTextures; }
2634 private:
2635 HashMap<WebGLId, bool> m_textures;
2636 unsigned m_numTextures;
2639 TEST_F(CCLayerTreeHostImplTest, layersFreeTextures)
2641 OwnPtr<CCLayerImpl> rootLayer(CCLayerImpl::create(1));
2642 rootLayer->setBounds(IntSize(10, 10));
2643 rootLayer->setAnchorPoint(FloatPoint(0, 0));
2645 OwnPtr<CCTiledLayerImpl> tileLayer = CCTiledLayerImpl::create(2);
2646 tileLayer->setBounds(IntSize(10, 10));
2647 tileLayer->setAnchorPoint(FloatPoint(0, 0));
2648 tileLayer->setContentBounds(IntSize(10, 10));
2649 tileLayer->setDrawsContent(true);
2650 tileLayer->setSkipsDraw(false);
2651 OwnPtr<CCLayerTilingData> tilingData(CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::NoBorderTexels));
2652 tilingData->setBounds(IntSize(10, 10));
2653 tileLayer->setTilingData(*tilingData);
2654 tileLayer->pushTileProperties(0, 0, 1, IntRect(0, 0, 10, 10));
2655 rootLayer->addChild(tileLayer.release());
2657 OwnPtr<CCTextureLayerImpl> textureLayer = CCTextureLayerImpl::create(3);
2658 textureLayer->setBounds(IntSize(10, 10));
2659 textureLayer->setAnchorPoint(FloatPoint(0, 0));
2660 textureLayer->setContentBounds(IntSize(10, 10));
2661 textureLayer->setDrawsContent(true);
2662 textureLayer->setTextureId(1);
2663 rootLayer->addChild(textureLayer.release());
2665 FakeVideoFrameProvider provider;
2666 OwnPtr<CCVideoLayerImpl> videoLayer = CCVideoLayerImpl::create(4, &provider);
2667 videoLayer->setBounds(IntSize(10, 10));
2668 videoLayer->setAnchorPoint(FloatPoint(0, 0));
2669 videoLayer->setContentBounds(IntSize(10, 10));
2670 videoLayer->setDrawsContent(true);
2671 videoLayer->setLayerTreeHostImpl(m_hostImpl.get());
2672 rootLayer->addChild(videoLayer.release());
2674 OwnPtr<CCIOSurfaceLayerImpl> ioSurfaceLayer = CCIOSurfaceLayerImpl::create(5);
2675 ioSurfaceLayer->setBounds(IntSize(10, 10));
2676 ioSurfaceLayer->setAnchorPoint(FloatPoint(0, 0));
2677 ioSurfaceLayer->setContentBounds(IntSize(10, 10));
2678 ioSurfaceLayer->setDrawsContent(true);
2679 ioSurfaceLayer->setIOSurfaceProperties(1, IntSize(10, 10));
2680 ioSurfaceLayer->setLayerTreeHostImpl(m_hostImpl.get());
2681 rootLayer->addChild(ioSurfaceLayer.release());
2683 // Lose the context, replacing it with a TrackingWebGraphicsContext3D (which the CCLayerTreeHostImpl takes ownership of).
2684 OwnPtr<CCGraphicsContext> ccContext(FakeWebCompositorOutputSurface::create(adoptPtr(new TrackingWebGraphicsContext3D)));
2685 TrackingWebGraphicsContext3D* trackingWebGraphicsContext = static_cast<TrackingWebGraphicsContext3D*>(ccContext->context3D());
2686 m_hostImpl->initializeRenderer(ccContext.release(), UnthrottledUploader);
2688 m_hostImpl->setRootLayer(rootLayer.release());
2690 CCLayerTreeHostImpl::FrameData frame;
2691 EXPECT_TRUE(m_hostImpl->prepareToDraw(frame));
2692 m_hostImpl->drawLayers(frame);
2693 m_hostImpl->didDrawAllLayers(frame);
2694 m_hostImpl->swapBuffers();
2696 EXPECT_GT(trackingWebGraphicsContext->numTextures(), 0u);
2698 // Kill the layer tree.
2699 m_hostImpl->setRootLayer(CCLayerImpl::create(100));
2700 // There should be no textures left in use after.
2701 EXPECT_EQ(0u, trackingWebGraphicsContext->numTextures());
2704 class MockDrawQuadsToFillScreenContext : public FakeWebGraphicsContext3D {
2705 public:
2706 MOCK_METHOD1(useProgram, void(WebGLId program));
2707 MOCK_METHOD4(drawElements, void(WGC3Denum mode, WGC3Dsizei count, WGC3Denum type, WGC3Dintptr offset));
2710 TEST_F(CCLayerTreeHostImplTest, hasTransparentBackground)
2712 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new MockDrawQuadsToFillScreenContext));
2713 MockDrawQuadsToFillScreenContext* mockContext = static_cast<MockDrawQuadsToFillScreenContext*>(context->context3D());
2715 // Run test case
2716 OwnPtr<CCLayerTreeHostImpl> myHostImpl = createLayerTreeHost(false, context.release(), CCLayerImpl::create(1));
2717 myHostImpl->setBackgroundColor(SK_ColorWHITE);
2719 // Verify one quad is drawn when transparent background set is not set.
2720 myHostImpl->setHasTransparentBackground(false);
2721 EXPECT_CALL(*mockContext, useProgram(_))
2722 .Times(1);
2723 EXPECT_CALL(*mockContext, drawElements(_, _, _, _))
2724 .Times(1);
2725 CCLayerTreeHostImpl::FrameData frame;
2726 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2727 myHostImpl->drawLayers(frame);
2728 myHostImpl->didDrawAllLayers(frame);
2729 Mock::VerifyAndClearExpectations(&mockContext);
2731 // Verify no quads are drawn when transparent background is set.
2732 myHostImpl->setHasTransparentBackground(true);
2733 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2734 myHostImpl->drawLayers(frame);
2735 myHostImpl->didDrawAllLayers(frame);
2736 Mock::VerifyAndClearExpectations(&mockContext);
2739 static void addDrawingLayerTo(CCLayerImpl* parent, int id, const IntRect& layerRect, CCLayerImpl** result)
2741 OwnPtr<CCLayerImpl> layer = FakeLayerWithQuads::create(id);
2742 CCLayerImpl* layerPtr = layer.get();
2743 layerPtr->setAnchorPoint(FloatPoint(0, 0));
2744 layerPtr->setPosition(FloatPoint(layerRect.location()));
2745 layerPtr->setBounds(layerRect.size());
2746 layerPtr->setContentBounds(layerRect.size());
2747 layerPtr->setDrawsContent(true); // only children draw content
2748 layerPtr->setOpaque(true);
2749 parent->addChild(layer.release());
2750 if (result)
2751 *result = layerPtr;
2754 static void setupLayersForTextureCaching(CCLayerTreeHostImpl* layerTreeHostImpl, CCLayerImpl*& rootPtr, CCLayerImpl*& intermediateLayerPtr, CCLayerImpl*& surfaceLayerPtr, CCLayerImpl*& childPtr, const IntSize& rootSize)
2756 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext));
2758 layerTreeHostImpl->initializeRenderer(context.release(), UnthrottledUploader);
2759 layerTreeHostImpl->setViewportSize(rootSize, rootSize);
2761 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
2762 rootPtr = root.get();
2764 root->setAnchorPoint(FloatPoint(0, 0));
2765 root->setPosition(FloatPoint(0, 0));
2766 root->setBounds(rootSize);
2767 root->setContentBounds(rootSize);
2768 root->setDrawsContent(true);
2769 layerTreeHostImpl->setRootLayer(root.release());
2771 addDrawingLayerTo(rootPtr, 2, IntRect(10, 10, rootSize.width(), rootSize.height()), &intermediateLayerPtr);
2772 intermediateLayerPtr->setDrawsContent(false); // only children draw content
2774 // Surface layer is the layer that changes its opacity
2775 // It will contain other layers that draw content.
2776 addDrawingLayerTo(intermediateLayerPtr, 3, IntRect(10, 10, rootSize.width(), rootSize.height()), &surfaceLayerPtr);
2777 surfaceLayerPtr->setDrawsContent(false); // only children draw content
2778 surfaceLayerPtr->setOpacity(0.5f); // This will cause it to have a surface
2780 // Child of the surface layer will produce some quads
2781 addDrawingLayerTo(surfaceLayerPtr, 4, IntRect(5, 5, rootSize.width() - 25, rootSize.height() - 25), &childPtr);
2784 class CCRendererGLWithReleaseTextures : public CCRendererGL {
2785 public:
2786 using CCRendererGL::releaseRenderPassTextures;
2789 TEST_F(CCLayerTreeHostImplTest, textureCachingWithClipping)
2791 CCSettings::setPartialSwapEnabled(true);
2793 CCLayerTreeSettings settings;
2794 settings.minimumOcclusionTrackingSize = IntSize();
2795 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
2797 CCLayerImpl* rootPtr;
2798 CCLayerImpl* surfaceLayerPtr;
2800 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext));
2802 IntSize rootSize(100, 100);
2804 myHostImpl->initializeRenderer(context.release(), UnthrottledUploader);
2805 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height()));
2807 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
2808 rootPtr = root.get();
2810 root->setAnchorPoint(FloatPoint(0, 0));
2811 root->setPosition(FloatPoint(0, 0));
2812 root->setBounds(rootSize);
2813 root->setContentBounds(rootSize);
2814 root->setDrawsContent(true);
2815 root->setMasksToBounds(true);
2816 myHostImpl->setRootLayer(root.release());
2818 addDrawingLayerTo(rootPtr, 3, IntRect(0, 0, rootSize.width(), rootSize.height()), &surfaceLayerPtr);
2819 surfaceLayerPtr->setDrawsContent(false);
2821 // Surface layer is the layer that changes its opacity
2822 // It will contain other layers that draw content.
2823 surfaceLayerPtr->setOpacity(0.5f); // This will cause it to have a surface
2825 addDrawingLayerTo(surfaceLayerPtr, 4, IntRect(0, 0, 100, 3), 0);
2826 addDrawingLayerTo(surfaceLayerPtr, 5, IntRect(0, 97, 100, 3), 0);
2828 // Rotation will put part of the child ouside the bounds of the root layer.
2829 // Nevertheless, the child layers should be drawn.
2830 WebTransformationMatrix transform = surfaceLayerPtr->transform();
2831 transform.translate(50, 50);
2832 transform.rotate(35);
2833 transform.translate(-50, -50);
2834 surfaceLayerPtr->setTransform(transform);
2837 CCLayerTreeHostImpl::FrameData frame;
2838 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2840 // Must receive two render passes, each with one quad
2841 ASSERT_EQ(2U, frame.renderPasses.size());
2842 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
2843 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
2845 // Verify that the child layers are being clipped.
2846 IntRect quadVisibleRect = frame.renderPasses[0]->quadList()[0]->quadVisibleRect();
2847 EXPECT_LT(quadVisibleRect.width(), 100);
2849 quadVisibleRect = frame.renderPasses[0]->quadList()[1]->quadVisibleRect();
2850 EXPECT_LT(quadVisibleRect.width(), 100);
2852 // Verify that the render surface texture is *not* clipped.
2853 EXPECT_RECT_EQ(IntRect(0, 0, 100, 100), frame.renderPasses[0]->outputRect());
2855 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
2856 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
2857 EXPECT_FALSE(quad->contentsChangedSinceLastFrame().isEmpty());
2859 myHostImpl->drawLayers(frame);
2860 myHostImpl->didDrawAllLayers(frame);
2863 transform = surfaceLayerPtr->transform();
2864 transform.translate(50, 50);
2865 transform.rotate(-35);
2866 transform.translate(-50, -50);
2867 surfaceLayerPtr->setTransform(transform);
2869 // The surface is now aligned again, and the clipped parts are exposed.
2870 // Since the layers were clipped, even though the render surface size
2871 // was not changed, the texture should not be saved.
2873 CCLayerTreeHostImpl::FrameData frame;
2874 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2876 // Must receive two render passes, each with one quad
2877 ASSERT_EQ(2U, frame.renderPasses.size());
2878 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
2879 ASSERT_EQ(1U, frame.renderPasses[1]->quadList().size());
2881 myHostImpl->drawLayers(frame);
2882 myHostImpl->didDrawAllLayers(frame);
2886 TEST_F(CCLayerTreeHostImplTest, textureCachingWithOcclusion)
2888 CCSettings::setPartialSwapEnabled(false);
2890 CCLayerTreeSettings settings;
2891 settings.minimumOcclusionTrackingSize = IntSize();
2892 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
2894 // Layers are structure as follows:
2896 // R +-- S1 +- L10 (owning)
2897 // | +- L11
2898 // | +- L12
2899 // |
2900 // +-- S2 +- L20 (owning)
2901 // +- L21
2903 // Occlusion:
2904 // L12 occludes L11 (internal)
2905 // L20 occludes L10 (external)
2906 // L21 occludes L20 (internal)
2908 CCLayerImpl* rootPtr;
2909 CCLayerImpl* layerS1Ptr;
2910 CCLayerImpl* layerS2Ptr;
2912 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext));
2914 IntSize rootSize(1000, 1000);
2916 myHostImpl->initializeRenderer(context.release(), UnthrottledUploader);
2917 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height()));
2919 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
2920 rootPtr = root.get();
2922 root->setAnchorPoint(FloatPoint(0, 0));
2923 root->setPosition(FloatPoint(0, 0));
2924 root->setBounds(rootSize);
2925 root->setContentBounds(rootSize);
2926 root->setDrawsContent(true);
2927 root->setMasksToBounds(true);
2928 myHostImpl->setRootLayer(root.release());
2930 addDrawingLayerTo(rootPtr, 2, IntRect(300, 300, 300, 300), &layerS1Ptr);
2931 layerS1Ptr->setForceRenderSurface(true);
2933 addDrawingLayerTo(layerS1Ptr, 3, IntRect(10, 10, 10, 10), 0); // L11
2934 addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 0, 30, 30), 0); // L12
2936 addDrawingLayerTo(rootPtr, 5, IntRect(550, 250, 300, 400), &layerS2Ptr);
2937 layerS2Ptr->setForceRenderSurface(true);
2939 addDrawingLayerTo(layerS2Ptr, 6, IntRect(20, 20, 5, 5), 0); // L21
2941 // Initial draw - must receive all quads
2943 CCLayerTreeHostImpl::FrameData frame;
2944 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2946 // Must receive 3 render passes.
2947 // For Root, there are 2 quads; for S1, there are 2 quads (1 is occluded); for S2, there is 2 quads.
2948 ASSERT_EQ(3U, frame.renderPasses.size());
2950 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
2951 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
2952 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size());
2954 myHostImpl->drawLayers(frame);
2955 myHostImpl->didDrawAllLayers(frame);
2958 // "Unocclude" surface S1 and repeat draw.
2959 // Must remove S2's render pass since it's cached;
2960 // Must keep S1 quads because texture contained external occlusion.
2961 WebTransformationMatrix transform = layerS2Ptr->transform();
2962 transform.translate(150, 150);
2963 layerS2Ptr->setTransform(transform);
2965 CCLayerTreeHostImpl::FrameData frame;
2966 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2968 // Must receive 2 render passes.
2969 // For Root, there are 2 quads
2970 // For S1, the number of quads depends on what got unoccluded, so not asserted beyond being positive.
2971 // For S2, there is no render pass
2972 ASSERT_EQ(2U, frame.renderPasses.size());
2974 EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U);
2975 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
2977 myHostImpl->drawLayers(frame);
2978 myHostImpl->didDrawAllLayers(frame);
2981 // "Re-occlude" surface S1 and repeat draw.
2982 // Must remove S1's render pass since it is now available in full.
2983 // S2 has no change so must also be removed.
2984 transform = layerS2Ptr->transform();
2985 transform.translate(-15, -15);
2986 layerS2Ptr->setTransform(transform);
2988 CCLayerTreeHostImpl::FrameData frame;
2989 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
2991 // Must receive 1 render pass - for the root.
2992 ASSERT_EQ(1U, frame.renderPasses.size());
2994 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
2996 myHostImpl->drawLayers(frame);
2997 myHostImpl->didDrawAllLayers(frame);
3002 TEST_F(CCLayerTreeHostImplTest, textureCachingWithOcclusionEarlyOut)
3004 CCSettings::setPartialSwapEnabled(false);
3006 CCLayerTreeSettings settings;
3007 settings.minimumOcclusionTrackingSize = IntSize();
3008 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
3010 // Layers are structure as follows:
3012 // R +-- S1 +- L10 (owning, non drawing)
3013 // | +- L11 (corner, unoccluded)
3014 // | +- L12 (corner, unoccluded)
3015 // | +- L13 (corner, unoccluded)
3016 // | +- L14 (corner, entirely occluded)
3017 // |
3018 // +-- S2 +- L20 (owning, drawing)
3021 CCLayerImpl* rootPtr;
3022 CCLayerImpl* layerS1Ptr;
3023 CCLayerImpl* layerS2Ptr;
3025 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext));
3027 IntSize rootSize(1000, 1000);
3029 myHostImpl->initializeRenderer(context.release(), UnthrottledUploader);
3030 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height()));
3032 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
3033 rootPtr = root.get();
3035 root->setAnchorPoint(FloatPoint(0, 0));
3036 root->setPosition(FloatPoint(0, 0));
3037 root->setBounds(rootSize);
3038 root->setContentBounds(rootSize);
3039 root->setDrawsContent(true);
3040 root->setMasksToBounds(true);
3041 myHostImpl->setRootLayer(root.release());
3043 addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 800, 800), &layerS1Ptr);
3044 layerS1Ptr->setForceRenderSurface(true);
3045 layerS1Ptr->setDrawsContent(false);
3047 addDrawingLayerTo(layerS1Ptr, 3, IntRect(0, 0, 300, 300), 0); // L11
3048 addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 500, 300, 300), 0); // L12
3049 addDrawingLayerTo(layerS1Ptr, 5, IntRect(500, 0, 300, 300), 0); // L13
3050 addDrawingLayerTo(layerS1Ptr, 6, IntRect(500, 500, 300, 300), 0); // L14
3051 addDrawingLayerTo(layerS1Ptr, 9, IntRect(500, 500, 300, 300), 0); // L14
3053 addDrawingLayerTo(rootPtr, 7, IntRect(450, 450, 450, 450), &layerS2Ptr);
3054 layerS2Ptr->setForceRenderSurface(true);
3056 // Initial draw - must receive all quads
3058 CCLayerTreeHostImpl::FrameData frame;
3059 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3061 // Must receive 3 render passes.
3062 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 1 quad.
3063 ASSERT_EQ(3U, frame.renderPasses.size());
3065 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3067 // L14 is culled, so only 3 quads.
3068 EXPECT_EQ(3U, frame.renderPasses[1]->quadList().size());
3069 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size());
3071 myHostImpl->drawLayers(frame);
3072 myHostImpl->didDrawAllLayers(frame);
3075 // "Unocclude" surface S1 and repeat draw.
3076 // Must remove S2's render pass since it's cached;
3077 // Must keep S1 quads because texture contained external occlusion.
3078 WebTransformationMatrix transform = layerS2Ptr->transform();
3079 transform.translate(100, 100);
3080 layerS2Ptr->setTransform(transform);
3082 CCLayerTreeHostImpl::FrameData frame;
3083 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3085 // Must receive 2 render passes.
3086 // For Root, there are 2 quads
3087 // For S1, the number of quads depends on what got unoccluded, so not asserted beyond being positive.
3088 // For S2, there is no render pass
3089 ASSERT_EQ(2U, frame.renderPasses.size());
3091 EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U);
3092 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3094 myHostImpl->drawLayers(frame);
3095 myHostImpl->didDrawAllLayers(frame);
3098 // "Re-occlude" surface S1 and repeat draw.
3099 // Must remove S1's render pass since it is now available in full.
3100 // S2 has no change so must also be removed.
3101 transform = layerS2Ptr->transform();
3102 transform.translate(-15, -15);
3103 layerS2Ptr->setTransform(transform);
3105 CCLayerTreeHostImpl::FrameData frame;
3106 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3108 // Must receive 1 render pass - for the root.
3109 ASSERT_EQ(1U, frame.renderPasses.size());
3111 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3113 myHostImpl->drawLayers(frame);
3114 myHostImpl->didDrawAllLayers(frame);
3118 TEST_F(CCLayerTreeHostImplTest, textureCachingWithOcclusionExternalOverInternal)
3120 CCSettings::setPartialSwapEnabled(false);
3122 CCLayerTreeSettings settings;
3123 settings.minimumOcclusionTrackingSize = IntSize();
3124 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
3126 // Layers are structured as follows:
3128 // R +-- S1 +- L10 (owning, drawing)
3129 // | +- L11 (corner, occluded by L12)
3130 // | +- L12 (opposite corner)
3131 // |
3132 // +-- S2 +- L20 (owning, drawing)
3135 CCLayerImpl* rootPtr;
3136 CCLayerImpl* layerS1Ptr;
3137 CCLayerImpl* layerS2Ptr;
3139 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext));
3141 IntSize rootSize(1000, 1000);
3143 myHostImpl->initializeRenderer(context.release(), UnthrottledUploader);
3144 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height()));
3146 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
3147 rootPtr = root.get();
3149 root->setAnchorPoint(FloatPoint(0, 0));
3150 root->setPosition(FloatPoint(0, 0));
3151 root->setBounds(rootSize);
3152 root->setContentBounds(rootSize);
3153 root->setDrawsContent(true);
3154 root->setMasksToBounds(true);
3155 myHostImpl->setRootLayer(root.release());
3157 addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 400, 400), &layerS1Ptr);
3158 layerS1Ptr->setForceRenderSurface(true);
3160 addDrawingLayerTo(layerS1Ptr, 3, IntRect(0, 0, 300, 300), 0); // L11
3161 addDrawingLayerTo(layerS1Ptr, 4, IntRect(100, 0, 300, 300), 0); // L12
3163 addDrawingLayerTo(rootPtr, 7, IntRect(200, 0, 300, 300), &layerS2Ptr);
3164 layerS2Ptr->setForceRenderSurface(true);
3166 // Initial draw - must receive all quads
3168 CCLayerTreeHostImpl::FrameData frame;
3169 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3171 // Must receive 3 render passes.
3172 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 1 quad.
3173 ASSERT_EQ(3U, frame.renderPasses.size());
3175 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3176 EXPECT_EQ(3U, frame.renderPasses[1]->quadList().size());
3177 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size());
3179 myHostImpl->drawLayers(frame);
3180 myHostImpl->didDrawAllLayers(frame);
3183 // "Unocclude" surface S1 and repeat draw.
3184 // Must remove S2's render pass since it's cached;
3185 // Must keep S1 quads because texture contained external occlusion.
3186 WebTransformationMatrix transform = layerS2Ptr->transform();
3187 transform.translate(300, 0);
3188 layerS2Ptr->setTransform(transform);
3190 CCLayerTreeHostImpl::FrameData frame;
3191 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3193 // Must receive 2 render passes.
3194 // For Root, there are 2 quads
3195 // For S1, the number of quads depends on what got unoccluded, so not asserted beyond being positive.
3196 // For S2, there is no render pass
3197 ASSERT_EQ(2U, frame.renderPasses.size());
3199 EXPECT_GT(frame.renderPasses[0]->quadList().size(), 0U);
3200 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3202 myHostImpl->drawLayers(frame);
3203 myHostImpl->didDrawAllLayers(frame);
3207 TEST_F(CCLayerTreeHostImplTest, textureCachingWithOcclusionExternalNotAligned)
3209 CCSettings::setPartialSwapEnabled(false);
3211 CCLayerTreeSettings settings;
3212 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
3214 // Layers are structured as follows:
3216 // R +-- S1 +- L10 (rotated, drawing)
3217 // +- L11 (occupies half surface)
3219 CCLayerImpl* rootPtr;
3220 CCLayerImpl* layerS1Ptr;
3222 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext));
3224 IntSize rootSize(1000, 1000);
3226 myHostImpl->initializeRenderer(context.release(), UnthrottledUploader);
3227 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height()));
3229 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
3230 rootPtr = root.get();
3232 root->setAnchorPoint(FloatPoint(0, 0));
3233 root->setPosition(FloatPoint(0, 0));
3234 root->setBounds(rootSize);
3235 root->setContentBounds(rootSize);
3236 root->setDrawsContent(true);
3237 root->setMasksToBounds(true);
3238 myHostImpl->setRootLayer(root.release());
3240 addDrawingLayerTo(rootPtr, 2, IntRect(0, 0, 400, 400), &layerS1Ptr);
3241 layerS1Ptr->setForceRenderSurface(true);
3242 WebTransformationMatrix transform = layerS1Ptr->transform();
3243 transform.translate(200, 200);
3244 transform.rotate(45);
3245 transform.translate(-200, -200);
3246 layerS1Ptr->setTransform(transform);
3248 addDrawingLayerTo(layerS1Ptr, 3, IntRect(200, 0, 200, 400), 0); // L11
3250 // Initial draw - must receive all quads
3252 CCLayerTreeHostImpl::FrameData frame;
3253 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3255 // Must receive 2 render passes.
3256 ASSERT_EQ(2U, frame.renderPasses.size());
3258 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3259 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3261 myHostImpl->drawLayers(frame);
3262 myHostImpl->didDrawAllLayers(frame);
3265 // Change opacity and draw. Verify we used cached texture.
3266 layerS1Ptr->setOpacity(0.2f);
3268 CCLayerTreeHostImpl::FrameData frame;
3269 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3271 // One render pass must be gone due to cached texture.
3272 ASSERT_EQ(1U, frame.renderPasses.size());
3274 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3276 myHostImpl->drawLayers(frame);
3277 myHostImpl->didDrawAllLayers(frame);
3281 TEST_F(CCLayerTreeHostImplTest, textureCachingWithOcclusionPartialSwap)
3283 CCSettings::setPartialSwapEnabled(true);
3285 CCLayerTreeSettings settings;
3286 settings.minimumOcclusionTrackingSize = IntSize();
3287 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
3289 // Layers are structure as follows:
3291 // R +-- S1 +- L10 (owning)
3292 // | +- L11
3293 // | +- L12
3294 // |
3295 // +-- S2 +- L20 (owning)
3296 // +- L21
3298 // Occlusion:
3299 // L12 occludes L11 (internal)
3300 // L20 occludes L10 (external)
3301 // L21 occludes L20 (internal)
3303 CCLayerImpl* rootPtr;
3304 CCLayerImpl* layerS1Ptr;
3305 CCLayerImpl* layerS2Ptr;
3307 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext));
3309 IntSize rootSize(1000, 1000);
3311 myHostImpl->initializeRenderer(context.release(), UnthrottledUploader);
3312 myHostImpl->setViewportSize(IntSize(rootSize.width(), rootSize.height()), IntSize(rootSize.width(), rootSize.height()));
3314 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
3315 rootPtr = root.get();
3317 root->setAnchorPoint(FloatPoint(0, 0));
3318 root->setPosition(FloatPoint(0, 0));
3319 root->setBounds(rootSize);
3320 root->setContentBounds(rootSize);
3321 root->setDrawsContent(true);
3322 root->setMasksToBounds(true);
3323 myHostImpl->setRootLayer(root.release());
3325 addDrawingLayerTo(rootPtr, 2, IntRect(300, 300, 300, 300), &layerS1Ptr);
3326 layerS1Ptr->setForceRenderSurface(true);
3328 addDrawingLayerTo(layerS1Ptr, 3, IntRect(10, 10, 10, 10), 0); // L11
3329 addDrawingLayerTo(layerS1Ptr, 4, IntRect(0, 0, 30, 30), 0); // L12
3331 addDrawingLayerTo(rootPtr, 5, IntRect(550, 250, 300, 400), &layerS2Ptr);
3332 layerS2Ptr->setForceRenderSurface(true);
3334 addDrawingLayerTo(layerS2Ptr, 6, IntRect(20, 20, 5, 5), 0); // L21
3336 // Initial draw - must receive all quads
3338 CCLayerTreeHostImpl::FrameData frame;
3339 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3341 // Must receive 3 render passes.
3342 // For Root, there are 2 quads; for S1, there are 2 quads (one is occluded); for S2, there is 2 quads.
3343 ASSERT_EQ(3U, frame.renderPasses.size());
3345 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3346 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3347 EXPECT_EQ(2U, frame.renderPasses[2]->quadList().size());
3349 myHostImpl->drawLayers(frame);
3350 myHostImpl->didDrawAllLayers(frame);
3353 // "Unocclude" surface S1 and repeat draw.
3354 // Must remove S2's render pass since it's cached;
3355 // Must keep S1 quads because texture contained external occlusion.
3356 WebTransformationMatrix transform = layerS2Ptr->transform();
3357 transform.translate(150, 150);
3358 layerS2Ptr->setTransform(transform);
3360 CCLayerTreeHostImpl::FrameData frame;
3361 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3363 // Must receive 2 render passes.
3364 // For Root, there are 2 quads.
3365 // For S1, there are 2 quads.
3366 // For S2, there is no render pass
3367 ASSERT_EQ(2U, frame.renderPasses.size());
3369 EXPECT_EQ(2U, frame.renderPasses[0]->quadList().size());
3370 EXPECT_EQ(2U, frame.renderPasses[1]->quadList().size());
3372 myHostImpl->drawLayers(frame);
3373 myHostImpl->didDrawAllLayers(frame);
3376 // "Re-occlude" surface S1 and repeat draw.
3377 // Must remove S1's render pass since it is now available in full.
3378 // S2 has no change so must also be removed.
3379 transform = layerS2Ptr->transform();
3380 transform.translate(-15, -15);
3381 layerS2Ptr->setTransform(transform);
3383 CCLayerTreeHostImpl::FrameData frame;
3384 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3386 // Root render pass only.
3387 ASSERT_EQ(1U, frame.renderPasses.size());
3389 myHostImpl->drawLayers(frame);
3390 myHostImpl->didDrawAllLayers(frame);
3394 TEST_F(CCLayerTreeHostImplTest, textureCachingWithScissor)
3396 CCSettings::setPartialSwapEnabled(false);
3398 CCLayerTreeSettings settings;
3399 settings.minimumOcclusionTrackingSize = IntSize();
3400 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
3403 Layers are created as follows:
3405 +--------------------+
3406 | 1 |
3407 | +-----------+ |
3408 | | 2 | |
3409 | | +-------------------+
3410 | | | 3 |
3411 | | +-------------------+
3412 | | | |
3413 | +-----------+ |
3416 +--------------------+
3418 Layers 1, 2 have render surfaces
3420 OwnPtr<CCLayerImpl> root = CCLayerImpl::create(1);
3421 OwnPtr<CCTiledLayerImpl> child = CCTiledLayerImpl::create(2);
3422 OwnPtr<CCLayerImpl> grandChild = CCLayerImpl::create(3);
3424 IntRect rootRect(0, 0, 100, 100);
3425 IntRect childRect(10, 10, 50, 50);
3426 IntRect grandChildRect(5, 5, 150, 150);
3428 OwnPtr<CCGraphicsContext> context = FakeWebCompositorOutputSurface::create(adoptPtr(new PartialSwapContext));
3429 myHostImpl->initializeRenderer(context.release(), UnthrottledUploader);
3431 root->setAnchorPoint(FloatPoint(0, 0));
3432 root->setPosition(FloatPoint(rootRect.x(), rootRect.y()));
3433 root->setBounds(IntSize(rootRect.width(), rootRect.height()));
3434 root->setContentBounds(root->bounds());
3435 root->setDrawsContent(true);
3436 root->setMasksToBounds(true);
3438 child->setAnchorPoint(FloatPoint(0, 0));
3439 child->setPosition(FloatPoint(childRect.x(), childRect.y()));
3440 child->setOpacity(0.5);
3441 child->setBounds(IntSize(childRect.width(), childRect.height()));
3442 child->setContentBounds(child->bounds());
3443 child->setDrawsContent(true);
3444 child->setSkipsDraw(false);
3446 // child layer has 10x10 tiles.
3447 OwnPtr<CCLayerTilingData> tiler = CCLayerTilingData::create(IntSize(10, 10), CCLayerTilingData::HasBorderTexels);
3448 tiler->setBounds(child->contentBounds());
3449 child->setTilingData(*tiler.get());
3451 grandChild->setAnchorPoint(FloatPoint(0, 0));
3452 grandChild->setPosition(IntPoint(grandChildRect.x(), grandChildRect.y()));
3453 grandChild->setBounds(IntSize(grandChildRect.width(), grandChildRect.height()));
3454 grandChild->setContentBounds(grandChild->bounds());
3455 grandChild->setDrawsContent(true);
3457 CCTiledLayerImpl* childPtr = child.get();
3458 CCRenderPass::Id childPassId(childPtr->id(), 0);
3460 child->addChild(grandChild.release());
3461 root->addChild(child.release());
3462 myHostImpl->setRootLayer(root.release());
3463 myHostImpl->setViewportSize(rootRect.size(), rootRect.size());
3465 EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(childPassId));
3468 CCLayerTreeHostImpl::FrameData frame;
3469 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3470 myHostImpl->drawLayers(frame);
3471 myHostImpl->didDrawAllLayers(frame);
3474 // We should have cached textures for surface 2.
3475 EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(childPassId));
3478 CCLayerTreeHostImpl::FrameData frame;
3479 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3480 myHostImpl->drawLayers(frame);
3481 myHostImpl->didDrawAllLayers(frame);
3484 // We should still have cached textures for surface 2 after drawing with no damage.
3485 EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(childPassId));
3487 // Damage a single tile of surface 2.
3488 childPtr->setUpdateRect(IntRect(10, 10, 10, 10));
3491 CCLayerTreeHostImpl::FrameData frame;
3492 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3493 myHostImpl->drawLayers(frame);
3494 myHostImpl->didDrawAllLayers(frame);
3497 // We should have a cached texture for surface 2 again even though it was damaged.
3498 EXPECT_TRUE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(childPassId));
3501 TEST_F(CCLayerTreeHostImplTest, surfaceTextureCaching)
3503 CCSettings::setPartialSwapEnabled(true);
3505 CCLayerTreeSettings settings;
3506 settings.minimumOcclusionTrackingSize = IntSize();
3507 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
3509 CCLayerImpl* rootPtr;
3510 CCLayerImpl* intermediateLayerPtr;
3511 CCLayerImpl* surfaceLayerPtr;
3512 CCLayerImpl* childPtr;
3514 setupLayersForTextureCaching(myHostImpl.get(), rootPtr, intermediateLayerPtr, surfaceLayerPtr, childPtr, IntSize(100, 100));
3517 CCLayerTreeHostImpl::FrameData frame;
3518 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3520 // Must receive two render passes, each with one quad
3521 ASSERT_EQ(2U, frame.renderPasses.size());
3522 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3523 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3525 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
3526 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
3527 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3528 EXPECT_FALSE(targetPass->damageRect().isEmpty());
3530 myHostImpl->drawLayers(frame);
3531 myHostImpl->didDrawAllLayers(frame);
3534 // Draw without any change
3536 CCLayerTreeHostImpl::FrameData frame;
3537 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3539 // Must receive one render pass, as the other one should be culled
3540 ASSERT_EQ(1U, frame.renderPasses.size());
3542 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3543 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material());
3544 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0].get());
3545 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3546 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3548 myHostImpl->drawLayers(frame);
3549 myHostImpl->didDrawAllLayers(frame);
3552 // Change opacity and draw
3553 surfaceLayerPtr->setOpacity(0.6f);
3555 CCLayerTreeHostImpl::FrameData frame;
3556 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3558 // Must receive one render pass, as the other one should be culled
3559 ASSERT_EQ(1U, frame.renderPasses.size());
3561 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3562 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material());
3563 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0].get());
3564 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3565 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3567 myHostImpl->drawLayers(frame);
3568 myHostImpl->didDrawAllLayers(frame);
3571 // Change less benign property and draw - should have contents changed flag
3572 surfaceLayerPtr->setStackingOrderChanged(true);
3574 CCLayerTreeHostImpl::FrameData frame;
3575 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3577 // Must receive two render passes, each with one quad
3578 ASSERT_EQ(2U, frame.renderPasses.size());
3580 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3581 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
3583 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
3584 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
3585 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3586 EXPECT_FALSE(targetPass->damageRect().isEmpty());
3588 myHostImpl->drawLayers(frame);
3589 myHostImpl->didDrawAllLayers(frame);
3592 // Change opacity again, and evict the cached surface texture.
3593 surfaceLayerPtr->setOpacity(0.5f);
3594 static_cast<CCRendererGLWithReleaseTextures*>(myHostImpl->renderer())->releaseRenderPassTextures();
3596 // Change opacity and draw
3597 surfaceLayerPtr->setOpacity(0.6f);
3599 CCLayerTreeHostImpl::FrameData frame;
3600 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3602 // Must receive two render passes
3603 ASSERT_EQ(2U, frame.renderPasses.size());
3605 // Even though not enough properties changed, the entire thing must be
3606 // redrawn as we don't have cached textures
3607 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3608 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3610 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
3611 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
3612 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3613 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3615 // Was our surface evicted?
3616 EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(targetPass->id()));
3618 myHostImpl->drawLayers(frame);
3619 myHostImpl->didDrawAllLayers(frame);
3622 // Draw without any change, to make sure the state is clear
3624 CCLayerTreeHostImpl::FrameData frame;
3625 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3627 // Must receive one render pass, as the other one should be culled
3628 ASSERT_EQ(1U, frame.renderPasses.size());
3630 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3631 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material());
3632 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0].get());
3633 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3634 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3636 myHostImpl->drawLayers(frame);
3637 myHostImpl->didDrawAllLayers(frame);
3640 // Change opacity on the intermediate layer
3641 WebTransformationMatrix transform = intermediateLayerPtr->transform();
3642 transform.setM11(1.0001);
3643 intermediateLayerPtr->setTransform(transform);
3645 CCLayerTreeHostImpl::FrameData frame;
3646 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3648 // Must receive one render pass, as the other one should be culled.
3649 ASSERT_EQ(1U, frame.renderPasses.size());
3650 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3652 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material());
3653 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0].get());
3654 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3655 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3657 myHostImpl->drawLayers(frame);
3658 myHostImpl->didDrawAllLayers(frame);
3662 TEST_F(CCLayerTreeHostImplTest, surfaceTextureCachingNoPartialSwap)
3664 CCSettings::setPartialSwapEnabled(false);
3666 CCLayerTreeSettings settings;
3667 settings.minimumOcclusionTrackingSize = IntSize();
3668 OwnPtr<CCLayerTreeHostImpl> myHostImpl = CCLayerTreeHostImpl::create(settings, this);
3670 CCLayerImpl* rootPtr;
3671 CCLayerImpl* intermediateLayerPtr;
3672 CCLayerImpl* surfaceLayerPtr;
3673 CCLayerImpl* childPtr;
3675 setupLayersForTextureCaching(myHostImpl.get(), rootPtr, intermediateLayerPtr, surfaceLayerPtr, childPtr, IntSize(100, 100));
3678 CCLayerTreeHostImpl::FrameData frame;
3679 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3681 // Must receive two render passes, each with one quad
3682 ASSERT_EQ(2U, frame.renderPasses.size());
3683 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3684 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3686 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
3687 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
3688 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3689 EXPECT_FALSE(targetPass->damageRect().isEmpty());
3691 EXPECT_FALSE(frame.renderPasses[0]->damageRect().isEmpty());
3692 EXPECT_FALSE(frame.renderPasses[1]->damageRect().isEmpty());
3694 EXPECT_FALSE(frame.renderPasses[0]->hasOcclusionFromOutsideTargetSurface());
3695 EXPECT_FALSE(frame.renderPasses[1]->hasOcclusionFromOutsideTargetSurface());
3697 myHostImpl->drawLayers(frame);
3698 myHostImpl->didDrawAllLayers(frame);
3701 // Draw without any change
3703 CCLayerTreeHostImpl::FrameData frame;
3704 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3706 // Even though there was no change, we set the damage to entire viewport.
3707 // One of the passes should be culled as a result, since contents didn't change
3708 // and we have cached texture.
3709 ASSERT_EQ(1U, frame.renderPasses.size());
3710 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3712 EXPECT_TRUE(frame.renderPasses[0]->damageRect().isEmpty());
3714 myHostImpl->drawLayers(frame);
3715 myHostImpl->didDrawAllLayers(frame);
3718 // Change opacity and draw
3719 surfaceLayerPtr->setOpacity(0.6f);
3721 CCLayerTreeHostImpl::FrameData frame;
3722 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3724 // Must receive one render pass, as the other one should be culled
3725 ASSERT_EQ(1U, frame.renderPasses.size());
3727 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3728 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material());
3729 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0].get());
3730 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3731 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3733 myHostImpl->drawLayers(frame);
3734 myHostImpl->didDrawAllLayers(frame);
3737 // Change less benign property and draw - should have contents changed flag
3738 surfaceLayerPtr->setStackingOrderChanged(true);
3740 CCLayerTreeHostImpl::FrameData frame;
3741 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3743 // Must receive two render passes, each with one quad
3744 ASSERT_EQ(2U, frame.renderPasses.size());
3746 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3747 EXPECT_EQ(CCDrawQuad::SolidColor, frame.renderPasses[0]->quadList()[0]->material());
3749 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
3750 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
3751 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3752 EXPECT_FALSE(targetPass->damageRect().isEmpty());
3754 myHostImpl->drawLayers(frame);
3755 myHostImpl->didDrawAllLayers(frame);
3758 // Change opacity again, and evict the cached surface texture.
3759 surfaceLayerPtr->setOpacity(0.5f);
3760 static_cast<CCRendererGLWithReleaseTextures*>(myHostImpl->renderer())->releaseRenderPassTextures();
3762 // Change opacity and draw
3763 surfaceLayerPtr->setOpacity(0.6f);
3765 CCLayerTreeHostImpl::FrameData frame;
3766 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3768 // Must receive two render passes
3769 ASSERT_EQ(2U, frame.renderPasses.size());
3771 // Even though not enough properties changed, the entire thing must be
3772 // redrawn as we don't have cached textures
3773 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3774 EXPECT_EQ(1U, frame.renderPasses[1]->quadList().size());
3776 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[1]->quadList()[0]->material());
3777 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[1]->quadList()[0].get());
3778 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3779 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3781 // Was our surface evicted?
3782 EXPECT_FALSE(myHostImpl->renderer()->haveCachedResourcesForRenderPassId(targetPass->id()));
3784 myHostImpl->drawLayers(frame);
3785 myHostImpl->didDrawAllLayers(frame);
3788 // Draw without any change, to make sure the state is clear
3790 CCLayerTreeHostImpl::FrameData frame;
3791 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3793 // Even though there was no change, we set the damage to entire viewport.
3794 // One of the passes should be culled as a result, since contents didn't change
3795 // and we have cached texture.
3796 ASSERT_EQ(1U, frame.renderPasses.size());
3797 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3799 myHostImpl->drawLayers(frame);
3800 myHostImpl->didDrawAllLayers(frame);
3803 // Change opacity on the intermediate layer
3804 WebTransformationMatrix transform = intermediateLayerPtr->transform();
3805 transform.setM11(1.0001);
3806 intermediateLayerPtr->setTransform(transform);
3808 CCLayerTreeHostImpl::FrameData frame;
3809 EXPECT_TRUE(myHostImpl->prepareToDraw(frame));
3811 // Must receive one render pass, as the other one should be culled.
3812 ASSERT_EQ(1U, frame.renderPasses.size());
3813 EXPECT_EQ(1U, frame.renderPasses[0]->quadList().size());
3815 EXPECT_EQ(CCDrawQuad::RenderPass, frame.renderPasses[0]->quadList()[0]->material());
3816 CCRenderPassDrawQuad* quad = static_cast<CCRenderPassDrawQuad*>(frame.renderPasses[0]->quadList()[0].get());
3817 CCRenderPass* targetPass = frame.renderPassesById.get(quad->renderPassId());
3818 EXPECT_TRUE(targetPass->damageRect().isEmpty());
3820 myHostImpl->drawLayers(frame);
3821 myHostImpl->didDrawAllLayers(frame);
3825 TEST_F(CCLayerTreeHostImplTest, releaseContentsTextureShouldTriggerCommit)
3827 m_hostImpl->releaseContentsTextures();
3828 EXPECT_TRUE(m_didRequestCommit);
3831 struct RenderPassCacheEntry {
3832 mutable OwnPtr<CCRenderPass> renderPassPtr;
3833 CCRenderPass* renderPass;
3835 RenderPassCacheEntry(PassOwnPtr<CCRenderPass> r)
3836 : renderPassPtr(r),
3837 renderPass(renderPassPtr.get())
3841 RenderPassCacheEntry()
3845 RenderPassCacheEntry(const RenderPassCacheEntry& entry)
3846 : renderPassPtr(entry.renderPassPtr.release()),
3847 renderPass(entry.renderPass)
3851 RenderPassCacheEntry& operator=(const RenderPassCacheEntry& entry)
3853 renderPassPtr = entry.renderPassPtr.release();
3854 renderPass = entry.renderPass;
3855 return *this;
3859 struct RenderPassRemovalTestData : public CCLayerTreeHostImpl::FrameData {
3860 std::map<CCRenderPass::Id, RenderPassCacheEntry> renderPassCache;
3861 OwnPtr<CCSharedQuadState> sharedQuadState;
3864 class CCTestRenderPass: public CCRenderPass {
3865 public:
3866 static PassOwnPtr<CCRenderPass> create(CCRenderPass::Id id, IntRect outputRect, const WebTransformationMatrix& rootTransform) { return adoptPtr(new CCTestRenderPass(id, outputRect, rootTransform)); }
3868 void appendQuad(PassOwnPtr<CCDrawQuad> quad) { m_quadList.append(quad); }
3870 protected:
3871 CCTestRenderPass(CCRenderPass::Id id, IntRect outputRect, const WebTransformationMatrix& rootTransform) : CCRenderPass(id, outputRect, rootTransform) { }
3874 class CCTestRenderer : public CCRendererGL, public CCRendererClient {
3875 public:
3876 static PassOwnPtr<CCTestRenderer> create(CCResourceProvider* resourceProvider)
3878 OwnPtr<CCTestRenderer> renderer(adoptPtr(new CCTestRenderer(resourceProvider)));
3879 if (!renderer->initialize())
3880 return nullptr;
3882 return renderer.release();
3885 void clearCachedTextures() { m_textures.clear(); }
3886 void setHaveCachedResourcesForRenderPassId(CCRenderPass::Id id) { m_textures.add(id); }
3888 virtual bool haveCachedResourcesForRenderPassId(CCRenderPass::Id id) const OVERRIDE { return m_textures.contains(id); }
3890 // CCRendererClient implementation.
3891 virtual const IntSize& deviceViewportSize() const OVERRIDE { return m_viewportSize; }
3892 virtual const CCLayerTreeSettings& settings() const OVERRIDE { return m_settings; }
3893 virtual void didLoseContext() OVERRIDE { }
3894 virtual void onSwapBuffersComplete() OVERRIDE { }
3895 virtual void setFullRootLayerDamage() OVERRIDE { }
3896 virtual void releaseContentsTextures() OVERRIDE { }
3897 virtual void setMemoryAllocationLimitBytes(size_t) OVERRIDE { }
3899 protected:
3900 CCTestRenderer(CCResourceProvider* resourceProvider) : CCRendererGL(this, resourceProvider, UnthrottledUploader) { }
3902 private:
3903 CCLayerTreeSettings m_settings;
3904 IntSize m_viewportSize;
3905 HashSet<CCRenderPass::Id> m_textures;
3908 static void configureRenderPassTestData(const char* testScript, RenderPassRemovalTestData& testData, CCTestRenderer* renderer)
3910 renderer->clearCachedTextures();
3912 // One shared state for all quads - we don't need the correct details
3913 testData.sharedQuadState = CCSharedQuadState::create(WebTransformationMatrix(), IntRect(), IntRect(), 1.0, true);
3915 const char* currentChar = testScript;
3917 // Pre-create root pass
3918 CCRenderPass::Id rootRenderPassId = CCRenderPass::Id(testScript[0], testScript[1]);
3919 OwnPtr<CCRenderPass> rootRenderPass = CCTestRenderPass::create(rootRenderPassId, IntRect(), WebTransformationMatrix());
3920 testData.renderPassCache.insert(std::pair<CCRenderPass::Id, RenderPassCacheEntry>(rootRenderPassId, RenderPassCacheEntry(rootRenderPass.release())));
3921 while (*currentChar) {
3922 int layerId = *currentChar;
3923 currentChar++;
3924 ASSERT_TRUE(currentChar);
3925 int index = *currentChar;
3926 currentChar++;
3928 CCRenderPass::Id renderPassId = CCRenderPass::Id(layerId, index);
3930 OwnPtr<CCRenderPass> renderPass;
3932 bool isReplica = false;
3933 if (!testData.renderPassCache[renderPassId].renderPassPtr.get())
3934 isReplica = true;
3936 renderPass = testData.renderPassCache[renderPassId].renderPassPtr.release();
3938 // Cycle through quad data and create all quads
3939 while (*currentChar && *currentChar != '\n') {
3940 if (*currentChar == 's') {
3941 // Solid color draw quad
3942 OwnPtr<CCDrawQuad> quad = CCSolidColorDrawQuad::create(testData.sharedQuadState.get(), IntRect(0, 0, 10, 10), SK_ColorWHITE);
3944 static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(quad.release());
3945 currentChar++;
3946 } else if ((*currentChar >= 'A') && (*currentChar <= 'Z')) {
3947 // RenderPass draw quad
3948 int layerId = *currentChar;
3949 currentChar++;
3950 ASSERT_TRUE(currentChar);
3951 int index = *currentChar;
3952 currentChar++;
3953 CCRenderPass::Id newRenderPassId = CCRenderPass::Id(layerId, index);
3954 ASSERT_NE(rootRenderPassId, newRenderPassId);
3955 bool hasTexture = false;
3956 bool contentsChanged = true;
3958 if (*currentChar == '[') {
3959 currentChar++;
3960 while (*currentChar && *currentChar != ']') {
3961 switch (*currentChar) {
3962 case 'c':
3963 contentsChanged = false;
3964 break;
3965 case 't':
3966 hasTexture = true;
3967 break;
3969 currentChar++;
3971 if (*currentChar == ']')
3972 currentChar++;
3975 if (testData.renderPassCache.find(newRenderPassId) == testData.renderPassCache.end()) {
3976 if (hasTexture)
3977 renderer->setHaveCachedResourcesForRenderPassId(newRenderPassId);
3979 OwnPtr<CCRenderPass> renderPass = CCTestRenderPass::create(newRenderPassId, IntRect(), WebTransformationMatrix());
3980 testData.renderPassCache.insert(std::pair<CCRenderPass::Id, RenderPassCacheEntry>(newRenderPassId, RenderPassCacheEntry(renderPass.release())));
3983 IntRect quadRect = IntRect(0, 0, 1, 1);
3984 IntRect contentsChangedRect = contentsChanged ? quadRect : IntRect();
3985 OwnPtr<CCRenderPassDrawQuad> quad = CCRenderPassDrawQuad::create(testData.sharedQuadState.get(), quadRect, newRenderPassId, isReplica, 1, contentsChangedRect, 1, 1, 0, 0);
3986 static_cast<CCTestRenderPass*>(renderPass.get())->appendQuad(quad.release());
3989 testData.renderPasses.insert(0, renderPass.get());
3990 testData.renderPassesById.add(renderPassId, renderPass.release());
3991 if (*currentChar)
3992 currentChar++;
3996 void dumpRenderPassTestData(const RenderPassRemovalTestData& testData, char* buffer)
3998 char* pos = buffer;
3999 for (CCRenderPassList::const_reverse_iterator it = testData.renderPasses.rbegin(); it != testData.renderPasses.rend(); ++it) {
4000 const CCRenderPass* currentPass = *it;
4001 *pos = currentPass->id().layerId;
4002 pos++;
4003 *pos = currentPass->id().index;
4004 pos++;
4006 CCQuadList::const_iterator quadListIterator = currentPass->quadList().begin();
4007 while (quadListIterator != currentPass->quadList().end()) {
4008 CCDrawQuad* currentQuad = (*quadListIterator).get();
4009 switch (currentQuad->material()) {
4010 case CCDrawQuad::SolidColor:
4011 *pos = 's';
4012 pos++;
4013 break;
4014 case CCDrawQuad::RenderPass:
4015 *pos = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPassId().layerId;
4016 pos++;
4017 *pos = CCRenderPassDrawQuad::materialCast(currentQuad)->renderPassId().index;
4018 pos++;
4019 break;
4020 default:
4021 *pos = 'x';
4022 pos++;
4023 break;
4026 quadListIterator++;
4028 *pos = '\n';
4029 pos++;
4031 *pos = '\0';
4034 // Each CCRenderPassList is represented by a string which describes the configuration.
4035 // The syntax of the string is as follows:
4037 // RsssssX[c]ssYsssZ[t]ssW[ct]
4038 // Identifies the render pass---------------------------^ ^^^ ^ ^ ^ ^ ^
4039 // These are solid color quads-----------------------------+ | | | | |
4040 // Identifies RenderPassDrawQuad's RenderPass-----------------+ | | | |
4041 // This quad's contents didn't change---------------------------+ | | |
4042 // This quad's contents changed and it has no texture---------------+ | |
4043 // This quad has texture but its contents changed-------------------------+ |
4044 // This quad's contents didn't change and it has texture - will be removed------+
4046 // Expected results have exactly the same syntax, except they do not use square brackets,
4047 // since we only check the structure, not attributes.
4049 // Test case configuration consists of initialization script and expected results,
4050 // all in the same format.
4051 struct TestCase {
4052 const char* name;
4053 const char* initScript;
4054 const char* expectedResult;
4057 TestCase removeRenderPassesCases[] =
4060 "Single root pass",
4061 "R0ssss\n",
4062 "R0ssss\n"
4063 }, {
4064 "Single pass - no quads",
4065 "R0\n",
4066 "R0\n"
4067 }, {
4068 "Two passes, no removal",
4069 "R0ssssA0sss\n"
4070 "A0ssss\n",
4071 "R0ssssA0sss\n"
4072 "A0ssss\n"
4073 }, {
4074 "Two passes, remove last",
4075 "R0ssssA0[ct]sss\n"
4076 "A0ssss\n",
4077 "R0ssssA0sss\n"
4078 }, {
4079 "Have texture but contents changed - leave pass",
4080 "R0ssssA0[t]sss\n"
4081 "A0ssss\n",
4082 "R0ssssA0sss\n"
4083 "A0ssss\n"
4084 }, {
4085 "Contents didn't change but no texture - leave pass",
4086 "R0ssssA0[c]sss\n"
4087 "A0ssss\n",
4088 "R0ssssA0sss\n"
4089 "A0ssss\n"
4090 }, {
4091 "Replica: two quads reference the same pass; remove",
4092 "R0ssssA0[ct]A0[ct]sss\n"
4093 "A0ssss\n",
4094 "R0ssssA0A0sss\n"
4095 }, {
4096 "Replica: two quads reference the same pass; leave",
4097 "R0ssssA0[c]A0[c]sss\n"
4098 "A0ssss\n",
4099 "R0ssssA0A0sss\n"
4100 "A0ssss\n",
4101 }, {
4102 "Many passes, remove all",
4103 "R0ssssA0[ct]sss\n"
4104 "A0sssB0[ct]C0[ct]s\n"
4105 "B0sssD0[ct]ssE0[ct]F0[ct]\n"
4106 "E0ssssss\n"
4107 "C0G0[ct]\n"
4108 "D0sssssss\n"
4109 "F0sssssss\n"
4110 "G0sss\n",
4112 "R0ssssA0sss\n"
4113 }, {
4114 "Deep recursion, remove all",
4116 "R0sssssA0[ct]ssss\n"
4117 "A0ssssB0sss\n"
4118 "B0C0\n"
4119 "C0D0\n"
4120 "D0E0\n"
4121 "E0F0\n"
4122 "F0G0\n"
4123 "G0H0\n"
4124 "H0sssI0sss\n"
4125 "I0J0\n"
4126 "J0ssss\n",
4128 "R0sssssA0ssss\n"
4129 }, {
4130 "Wide recursion, remove all",
4131 "R0A0[ct]B0[ct]C0[ct]D0[ct]E0[ct]F0[ct]G0[ct]H0[ct]I0[ct]J0[ct]\n"
4132 "A0s\n"
4133 "B0s\n"
4134 "C0ssss\n"
4135 "D0ssss\n"
4136 "E0s\n"
4137 "F0\n"
4138 "G0s\n"
4139 "H0s\n"
4140 "I0s\n"
4141 "J0ssss\n",
4143 "R0A0B0C0D0E0F0G0H0I0J0\n"
4144 }, {
4145 "Remove passes regardless of cache state",
4146 "R0ssssA0[ct]sss\n"
4147 "A0sssB0C0s\n"
4148 "B0sssD0[c]ssE0[t]F0\n"
4149 "E0ssssss\n"
4150 "C0G0\n"
4151 "D0sssssss\n"
4152 "F0sssssss\n"
4153 "G0sss\n",
4155 "R0ssssA0sss\n"
4156 }, {
4157 "Leave some passes, remove others",
4159 "R0ssssA0[c]sss\n"
4160 "A0sssB0[t]C0[ct]s\n"
4161 "B0sssD0[c]ss\n"
4162 "C0G0\n"
4163 "D0sssssss\n"
4164 "G0sss\n",
4166 "R0ssssA0sss\n"
4167 "A0sssB0C0s\n"
4168 "B0sssD0ss\n"
4169 "D0sssssss\n"
4170 }, {
4171 0, 0, 0
4175 static void verifyRenderPassTestData(TestCase& testCase, RenderPassRemovalTestData& testData)
4177 char actualResult[1024];
4178 dumpRenderPassTestData(testData, actualResult);
4179 EXPECT_STREQ(testCase.expectedResult, actualResult) << "In test case: " << testCase.name;
4182 TEST_F(CCLayerTreeHostImplTest, testRemoveRenderPasses)
4184 OwnPtr<CCGraphicsContext> context(createContext());
4185 ASSERT_TRUE(context->context3D());
4186 OwnPtr<CCResourceProvider> resourceProvider(CCResourceProvider::create(context.get()));
4188 OwnPtr<CCTestRenderer> renderer(CCTestRenderer::create(resourceProvider.get()));
4190 int testCaseIndex = 0;
4191 while (removeRenderPassesCases[testCaseIndex].name) {
4192 RenderPassRemovalTestData testData;
4193 configureRenderPassTestData(removeRenderPassesCases[testCaseIndex].initScript, testData, renderer.get());
4194 CCLayerTreeHostImpl::removeRenderPasses(CCLayerTreeHostImpl::CullRenderPassesWithCachedTextures(*renderer), testData);
4195 verifyRenderPassTestData(removeRenderPassesCases[testCaseIndex], testData);
4196 testCaseIndex++;
4200 } // namespace